@dialpad/i18n 1.22.3 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/bin/force-pull-translations.js +2 -0
  2. package/bin/pull-translations.js +2 -0
  3. package/bin/should-pull.js +2 -0
  4. package/bin/translate-dialpadistan.js +2 -0
  5. package/bin/translation-screenshots-check.js +2 -0
  6. package/bin/upload-translation-service.js +2 -0
  7. package/dist/i18n.cjs +883 -878
  8. package/dist/i18n.cjs.map +1 -1
  9. package/dist/i18n.js +883 -878
  10. package/dist/i18n.js.map +1 -1
  11. package/dist/types/index.d.ts +2 -4
  12. package/dist/types/index.js +1 -2
  13. package/{README.md → docs/README.md} +280 -84
  14. package/index.ts +18 -5
  15. package/package.json +50 -26
  16. package/.eslintignore +0 -1
  17. package/.eslintrc.cjs +0 -12
  18. package/.prettierignore +0 -3
  19. package/.rush/temp/chunked-rush-logs/i18n.build.chunks.jsonl +0 -22
  20. package/.rush/temp/chunked-rush-logs/i18n.format.chunks.jsonl +0 -19
  21. package/.rush/temp/chunked-rush-logs/i18n.lint.chunks.jsonl +0 -2
  22. package/.rush/temp/package-deps_build.json +0 -24
  23. package/.rush/temp/package-deps_format.json +0 -24
  24. package/.rush/temp/package-deps_lint.json +0 -24
  25. package/.rush/temp/shrinkwrap-deps.json +0 -12
  26. package/CHANGELOG.json +0 -63
  27. package/CHANGELOG.md +0 -30
  28. package/base-tsconfig.json +0 -19
  29. package/dialpad-i18n-1.22.2.tgz +0 -0
  30. package/dist/types/src/locale-manager.d.ts +0 -53
  31. package/dist/types/src/locale-manager.js +0 -146
  32. package/eslint-tsconfig.json +0 -5
  33. package/index.html +0 -11
  34. package/rush-logs/i18n.build.error.log +0 -0
  35. package/rush-logs/i18n.build.log +0 -22
  36. package/rush-logs/i18n.format.error.log +0 -0
  37. package/rush-logs/i18n.format.log +0 -19
  38. package/rush-logs/i18n.lint.error.log +0 -0
  39. package/rush-logs/i18n.lint.log +0 -2
  40. package/src/__test__/locale-manager.find.test.ts +0 -78
  41. package/src/__test__/locale-manager.formatters.test.ts +0 -139
  42. package/src/__test__/locale-manager.multiple.test.ts +0 -349
  43. package/src/__test__/locale-manager.test.ts +0 -511
  44. package/src/locale-manager.ts +0 -198
  45. package/tsconfig.json +0 -10
  46. package/vite.config.ts +0 -39
@@ -1,511 +0,0 @@
1
- /* eslint-disable max-lines */
2
- // compilation checks or maybe just be all .js files?
3
- import type { BundleSource } from '@dialpad/i18n-services/bundle-source';
4
- import { MemoryStorageWrapper } from '@dialpad/i18n-services/storage';
5
- import type { LocaleManagerParams } from '@dialpad/i18n-services/locale-manager';
6
-
7
- import { expect, describe, it, beforeEach, vi } from 'vitest';
8
- import { INJECTION_KEY_PREFIX, LocaleManager } from '../locale-manager';
9
- import type { App } from 'vue';
10
-
11
- const EN_US = 'en-US'; // for brevity...
12
-
13
- // could certainly go harder on this mock but I don't think it's worth atm.
14
- function mockBundleSource(): BundleSource {
15
- return {
16
- getBundles: (lc: string[], ns: string[]): any => {
17
- return Promise.resolve(lc.map((l) => ({ locales: [l] })));
18
- },
19
- addSource: () => {
20
- throw new Error("Don't set me up like that!");
21
- },
22
- };
23
- }
24
-
25
- function mockVueApp(): any {
26
- return { use: () => {}, provide: () => {}, component: () => {} };
27
- }
28
-
29
- // TODO - would go well in a testing util lib. not quite sync, but immediate
30
- // and reliable for stuff that you don't expect to resolve for "a hot second"
31
- async function isResolved(check: Promise<unknown>): Promise<boolean> {
32
- const dummy = {};
33
- return (await Promise.race([check, Promise.resolve(dummy)])) !== dummy;
34
- }
35
-
36
- const testManager = (props?: Partial<LocaleManagerParams>) =>
37
- new LocaleManager({
38
- bundleSource: mockBundleSource(),
39
- warmUp: false,
40
- fallbackLocale: 'en-US',
41
- ...props,
42
- });
43
-
44
- describe('LocaleManager', () => {
45
- let manager: LocaleManager = testManager();
46
- beforeEach(() => {
47
- manager = testManager();
48
- });
49
-
50
- it('initializes with fallback', () => {
51
- expect(manager['preferredLocale']).toEqual(EN_US);
52
- });
53
-
54
- it('can never have zero allowedLocales', () => {
55
- manager['setAllowedLocales']([]);
56
- expect(manager['allowedLocales'].length).toEqual(1);
57
- // EVEN IF YOU VIOLATE IT TERRIBLY
58
- manager['allowedLocales'] = []; // evil access which a just god would never allow
59
- expect(manager['preferredLocale']).toEqual(EN_US);
60
- });
61
-
62
- it('wont do anything useful without some namespaces', async () => {
63
- expect(() => manager['getCurrentBundles']()).toThrowError(/no namespaces/);
64
- });
65
-
66
- it('requires warming up before offering bundles', async () => {
67
- expect(() => manager['currentBundles']).toThrowError(
68
- /No bundles! you must await/,
69
- );
70
- expect(manager['_cachedBundles']).toEqual(null);
71
- expect(manager['_cachedHash']).toEqual(null);
72
- const spy = vi.spyOn(manager['bundleSource'], 'getBundles');
73
- await manager.change({ namespaces: ['x'] });
74
- await manager.ready;
75
- expect(spy).toHaveBeenCalled();
76
- });
77
-
78
- it('uses its cache by default', async () => {
79
- const spy = vi.spyOn(manager['bundleSource'], 'getBundles');
80
- await manager.change({ namespaces: ['x'] });
81
- const buns = manager['currentBundles'];
82
- expect(spy).toHaveBeenCalledTimes(1);
83
- expect(manager['_cachedBundles']).toBe(buns);
84
-
85
- // options were not changed, so the bundles we get must be the same object.
86
- await manager.change({});
87
- expect(spy).toHaveBeenCalledTimes(1);
88
- expect(manager['_cachedBundles']).toBe(buns);
89
-
90
- await manager.change({ useCache: true });
91
- expect(spy).toHaveBeenCalledTimes(1);
92
- expect(manager['_cachedBundles']).toBe(buns);
93
- });
94
-
95
- it('can ignore its own cache', async () => {
96
- const spy = vi.spyOn(manager['bundleSource'], 'getBundles');
97
-
98
- await manager.change({ namespaces: ['x'] });
99
- const buns = manager['currentBundles'];
100
- const hash = manager['_cachedHash'];
101
- expect(spy).toHaveBeenCalledTimes(1);
102
- expect(manager['_cachedBundles']).toBe(buns);
103
-
104
- // called even though hash was the same.
105
- await manager.change({ useCache: false });
106
- expect(spy).toHaveBeenCalledTimes(2);
107
- expect(manager['_cachedBundles']).not.toBe(buns);
108
- expect(manager['_cachedBundles']).toEqual(buns);
109
- expect(manager['_cachedHash']).toEqual(hash);
110
- });
111
-
112
- it('always ignores cache when parameters change.', async () => {
113
- const spy = vi.spyOn(manager['bundleSource'], 'getBundles');
114
-
115
- await manager.change({ namespaces: ['x'] });
116
- expect(spy).toHaveBeenCalledTimes(1);
117
-
118
- await manager.change({ namespaces: ['y'], useCache: true });
119
- expect(spy).toHaveBeenCalledTimes(2);
120
-
121
- await manager.change({ allowedLocales: ['aa-AA', 'b'], useCache: true });
122
- expect(spy).toHaveBeenCalledTimes(3);
123
-
124
- await manager.change({ allowedLocales: ['b', 'a'], useCache: true });
125
- expect(spy).toHaveBeenCalledTimes(4);
126
- });
127
-
128
- // For the forseeable future, we will only care about two locales at most: the
129
- // user's setting and the fallback (en-US). LocaleManager will seemlessly
130
- // support as many as we care to provide, but until we've settled on *how* we
131
- // might like to manage that, we should only provide those two bundles.
132
- it('only cares about the preferred and default locales.', async () => {
133
- const spy = vi.spyOn(manager['bundleSource'], 'getBundles');
134
- await manager.change({
135
- namespaces: ['x'],
136
- allowedLocales: ['aa-BB', 'xx-YY', 'pp-QQ'],
137
- });
138
- expect(spy).toHaveBeenCalledWith(['aa-BB', EN_US], ['x']);
139
- expect(manager['activeLocales']).toEqual(['aa-BB', EN_US]);
140
-
141
- await manager.change({ preferredLocale: 'pp-QQ' });
142
- expect(spy).toHaveBeenCalledWith(['aa-BB', EN_US], ['x']);
143
- expect(manager['activeLocales']).toEqual(['pp-QQ', EN_US]);
144
-
145
- // that's only one thing if they're the same, regardless of how many total
146
- // allowedLocales have been provided.
147
- await manager.change({ preferredLocale: 'en-US' });
148
- expect(spy).toHaveBeenCalledWith([EN_US], ['x']);
149
- expect(manager['activeLocales']).toEqual([EN_US]);
150
- expect(manager['allowedLocales'].length).toEqual(4);
151
- });
152
-
153
- it('warms up bundleSource at init time by default', async () => {
154
- const bundleSource = mockBundleSource();
155
- const spy = vi.spyOn(bundleSource, 'getBundles');
156
- manager = testManager({
157
- bundleSource,
158
- warmUp: undefined,
159
- namespaces: ['foo'],
160
- preferredLocale: 'aa-BB',
161
- });
162
- await manager.ready;
163
- expect(manager['activeLocales']).toEqual(['aa-BB', EN_US]);
164
- expect(spy).toHaveBeenCalledWith(['aa-BB', EN_US], ['foo']);
165
- });
166
-
167
- it('can disable warmup', async () => {
168
- const bundleSource = mockBundleSource();
169
- const bundleSpy = vi.spyOn(bundleSource, 'getBundles');
170
- // @ts-expect-error - warmUp is private so this will fail
171
- const warmUpSpy = vi.spyOn(LocaleManager.prototype, 'warmUp');
172
- manager = testManager({
173
- bundleSource,
174
- warmUp: false,
175
- namespaces: ['foo', 'bar'],
176
- preferredLocale: 'aa-BB',
177
- });
178
- await expect(isResolved(manager.ready)).resolves.toEqual(false);
179
- // options are set nonetheless
180
- expect(manager['activeLocales']).toEqual(['aa-BB', EN_US]);
181
- expect(manager['currentNamespaces']).toEqual(new Set(['foo', 'bar']));
182
- expect(bundleSpy).not.toHaveBeenCalled();
183
- expect(warmUpSpy).not.toHaveBeenCalled();
184
- });
185
-
186
- describe('vue plugin', () => {
187
- let useSpy, proSpy, app;
188
-
189
- beforeEach(async () => {
190
- app = mockVueApp();
191
- useSpy = vi.spyOn(app, 'use');
192
- proSpy = vi.spyOn(app, 'provide');
193
- manager = testManager({ warmUp: true, namespaces: ['foo'] });
194
- await manager.ready;
195
-
196
- expect(manager['fluent']).toEqual(null);
197
- });
198
-
199
- describe('install()', () => {
200
- it('should call this.addToVue with provided app and namespace', () => {
201
- const addToVueSpy = vi.spyOn(manager as any, 'addToVue');
202
- manager.install(app, 'my-namespace');
203
- expect(addToVueSpy).toHaveBeenCalledTimes(1);
204
- expect(addToVueSpy).toHaveBeenCalledWith(app, 'my-namespace');
205
- });
206
-
207
- it('should initialize this.fluent when it is null', () => {
208
- (manager as any).fluent = null;
209
- manager.install(app);
210
- expect((manager as any).fluent).not.toBeNull();
211
- });
212
-
213
- it('should call this.addToVue with provided app and namespace', () => {
214
- const namespace = 'my-namespace';
215
- manager.install(app, namespace);
216
- const addToVueSpy = vi.spyOn(manager as any, 'addToVue');
217
-
218
- manager.install(app, namespace);
219
-
220
- // Expect the addToVue method to have been called with the provided app and namespace
221
- expect(addToVueSpy).toHaveBeenCalledTimes(1);
222
- expect(addToVueSpy).toHaveBeenCalledWith(app, namespace);
223
- });
224
-
225
- it('should call this.addToVue with default namespace when not provided', () => {
226
- const addToVueSpy = vi.spyOn(manager as any, 'addToVue');
227
- manager.install(app);
228
- expect(addToVueSpy).toHaveBeenCalledTimes(1);
229
- expect(addToVueSpy).toHaveBeenCalledWith(app, 'default');
230
- });
231
- });
232
-
233
- it('cannot be installed prior to warmup', async () => {
234
- const manager = testManager({ warmUp: false, namespaces: ['foo'] });
235
- const app = mockVueApp();
236
- expect(() => {
237
- manager.install(app);
238
- }).toThrowError(/No bundles!/);
239
- });
240
-
241
- it('can be installed under the correct circumstances', async () => {
242
- manager.install(app);
243
-
244
- expect(useSpy).toHaveBeenCalledWith(manager['fluent']);
245
- // checking 'app.inject' would be much more of a pain!
246
- expect(proSpy).toHaveBeenCalledWith(
247
- `${INJECTION_KEY_PREFIX}.default`,
248
- manager,
249
- );
250
- const mf = manager['fluent'];
251
- expect(mf?.bundles).toEqual(manager['currentBundles']);
252
-
253
- // won't make another:
254
- manager.install(app);
255
- expect(manager['fluent']).toBe(mf);
256
-
257
- // changing options sets the fluent instance's new bundles:
258
- if (mf) {
259
- mf.bundles = [];
260
- }
261
- await manager.change();
262
- expect(mf?.bundles).toEqual(manager['currentBundles']);
263
- });
264
- });
265
-
266
- describe('determineLocale', () => {
267
- let storageWrapper;
268
-
269
- beforeEach(() => {
270
- storageWrapper = new MemoryStorageWrapper();
271
- });
272
-
273
- it('returns the provided locale if given', () => {
274
- const localeManager = testManager({
275
- fallbackLocale: 'es-ES',
276
- warmUp: false,
277
- namespaces: ['foo'],
278
- });
279
- const result = localeManager['determineLocale']({
280
- preferredLocale: 'fr-FR',
281
- });
282
- expect(result).toBe('fr-FR');
283
- });
284
-
285
- it('returns the first provided locale if an array is given', () => {
286
- const localeManager = testManager({
287
- fallbackLocale: 'es-ES',
288
- warmUp: false,
289
- namespaces: ['foo'],
290
- });
291
- const result = localeManager['determineLocale']({
292
- allowedLocales: ['de-DE', 'fr-FR'],
293
- });
294
- expect(result).toBe('de-DE');
295
- });
296
-
297
- it('returns stored locale if available', () => {
298
- const localeManager = new LocaleManager({
299
- allowedLocales: ['en-US'],
300
- fallbackLocale: 'es-ES',
301
- warmUp: false,
302
- bundleSource: mockBundleSource(),
303
- storageWrapper,
304
- });
305
-
306
- storageWrapper.setItem('user-locale', 'de-DE');
307
- const result = localeManager['determineLocale']({});
308
- expect(result).toBe('de-DE');
309
- });
310
-
311
- it('returns browser locale if no stored locale', () => {
312
- const localeManager = testManager({
313
- fallbackLocale: 'es-ES',
314
- warmUp: false,
315
- namespaces: ['foo'],
316
- storageWrapper,
317
- });
318
- storageWrapper.removeItem('user-locale');
319
- vi.spyOn(navigator, 'languages', 'get').mockReturnValue(['it-IT']);
320
- const result = localeManager['determineLocale']({});
321
- expect(result).toBe('it-IT');
322
- });
323
-
324
- it('returns fallback locale if no other locale is found', () => {
325
- const localeManager = testManager({
326
- fallbackLocale: 'es-ES',
327
- warmUp: false,
328
- namespaces: ['foo'],
329
- storageWrapper,
330
- });
331
- storageWrapper.removeItem('user-locale');
332
- vi.spyOn(navigator, 'languages', 'get').mockReturnValue([]);
333
- const result = localeManager['determineLocale']({});
334
- expect(result).toBe('es-ES');
335
- });
336
- });
337
-
338
- describe('change locales', () => {
339
- it('changes locale if the new locale is available', async () => {
340
- const localeManager = testManager({ warmUp: false, namespaces: ['foo'] });
341
- // @ts-expect-error - setPreferredLocale is private so this will fail
342
- vi.spyOn(localeManager, 'setPreferredLocale');
343
-
344
- // is not part of bundles but you can set it anyways (we think that's by design)
345
- await localeManager.change({ preferredLocale: 'fr-FR' });
346
- expect(localeManager['setPreferredLocale']).toHaveBeenCalledWith('fr-FR');
347
- });
348
- });
349
-
350
- describe('setOptions', () => {
351
- it('sets allowed locales and preferred locale when passing an array', () => {
352
- const localeManager = testManager({
353
- fallbackLocale: 'es-ES',
354
- warmUp: false,
355
- namespaces: ['foo'],
356
- });
357
- // @ts-expect-error - setAllowedLocales is private so this will fail
358
- vi.spyOn(localeManager, 'setAllowedLocales');
359
- // @ts-expect-error - setPreferredLocale is private so this will fail
360
- vi.spyOn(localeManager, 'setPreferredLocale');
361
- localeManager['setOptions']({ allowedLocales: ['fr-FR', 'de-DE'] });
362
- expect(localeManager['setAllowedLocales']).toHaveBeenCalledWith([
363
- 'fr-FR',
364
- 'de-DE',
365
- ]);
366
- expect(localeManager['allowedLocales']).toEqual([
367
- 'fr-FR',
368
- 'de-DE',
369
- 'es-ES',
370
- ]);
371
- expect(localeManager['setPreferredLocale']).toHaveBeenCalled();
372
- });
373
-
374
- it('sets preferred locale when passing a string', () => {
375
- const localeManager = testManager({
376
- fallbackLocale: 'es-ES',
377
- warmUp: false,
378
- namespaces: ['foo'],
379
- });
380
- // @ts-expect-error - setPreferredLocale is private so this will fail
381
- vi.spyOn(localeManager, 'setPreferredLocale');
382
- localeManager['setOptions']({ preferredLocale: 'fr-FR' });
383
- expect(localeManager['setPreferredLocale']).toHaveBeenCalledWith('fr-FR');
384
- });
385
-
386
- it('adds namespaces correctly when passing an array', () => {
387
- const localeManager = testManager({
388
- fallbackLocale: 'es-ES',
389
- warmUp: false,
390
- namespaces: ['foo'],
391
- });
392
- // @ts-expect-error - addNamespaces is private so this will fail
393
- vi.spyOn(localeManager, 'addNamespaces');
394
- localeManager['setOptions']({ namespaces: ['namespace1', 'namespace2'] });
395
- expect(localeManager['addNamespaces']).toHaveBeenCalledWith([
396
- 'namespace1',
397
- 'namespace2',
398
- ]);
399
- });
400
- });
401
-
402
- describe('setPreferredLocale', () => {
403
- it('moves existing locale to the front of the allowedLocales list', () => {
404
- const localeManager = testManager({
405
- preferredLocale: 'en-US',
406
- fallbackLocale: 'es-ES',
407
- warmUp: false,
408
- namespaces: ['foo'],
409
- });
410
- localeManager['setPreferredLocale']('fr-FR');
411
- expect(localeManager['allowedLocales'][0]).toBe('fr-FR');
412
- expect(localeManager['allowedLocales']).toEqual(['fr-FR', 'en-US']);
413
- });
414
-
415
- it('adds new locale to the front if not already present', () => {
416
- const localeManager = testManager({
417
- preferredLocale: 'en-US',
418
- fallbackLocale: 'es-ES',
419
- warmUp: false,
420
- namespaces: ['foo'],
421
- });
422
- localeManager['setPreferredLocale']('fr-FR');
423
- expect(localeManager['allowedLocales'][0]).toBe('fr-FR');
424
- expect(localeManager['allowedLocales']).toEqual(['fr-FR', 'en-US']);
425
- });
426
- });
427
-
428
- describe('changeLocale', () => {
429
- it('throws an error when namespace is provided but no matching LocaleManager is found', () => {
430
- manager.app = { _context: { provides: {} } } as App;
431
- expect(() => {
432
- manager.changeLocale({}, 'non-existent-namespace');
433
- }).toThrowError('LocaleManager not found!');
434
- });
435
-
436
- it('throws an error when no LocaleManager instances are set up yet', () => {
437
- expect(() => {
438
- manager.changeLocale();
439
- }).toThrowError('No locale managers are set up yet!');
440
- });
441
-
442
- it('updates the locale of a single LocaleManager instance when namespace is provided', () => {
443
- const localeManager = testManager({
444
- namespaces: ['your-app'],
445
- preferredLocale: 'en-US',
446
- });
447
- localeManager.app = {
448
- _context: {
449
- provides: { [`${INJECTION_KEY_PREFIX}.your-app`]: localeManager },
450
- },
451
- } as unknown as App;
452
- const updateLocaleSettingsSpy = vi.spyOn(
453
- localeManager,
454
- 'updateLocaleSettings',
455
- );
456
- localeManager.changeLocale({}, 'your-app');
457
- expect(updateLocaleSettingsSpy).toHaveBeenCalledTimes(1);
458
- expect(localeManager['preferredLocale']).toBe('en-US');
459
- });
460
-
461
- it('updates the locale of all LocaleManager instances when no namespace is provided', () => {
462
- const localeManager1 = testManager({
463
- namespaces: ['foo'],
464
- preferredLocale: 'en-US',
465
- });
466
- const localeManager2 = testManager({
467
- namespaces: ['foo'],
468
- preferredLocale: 'en-US',
469
- });
470
- localeManager1.app = {
471
- _context: {
472
- provides: {
473
- [`${INJECTION_KEY_PREFIX}.namespace-1`]: localeManager1,
474
- [`${INJECTION_KEY_PREFIX}.namespace-2`]: localeManager2,
475
- },
476
- },
477
- } as unknown as App;
478
- const updateLocaleSettingsSpy1 = vi.spyOn(
479
- localeManager1,
480
- 'updateLocaleSettings',
481
- );
482
- const updateLocaleSettingsSpy2 = vi.spyOn(
483
- localeManager2,
484
- 'updateLocaleSettings',
485
- );
486
- localeManager1.changeLocale();
487
- expect(updateLocaleSettingsSpy1).toHaveBeenCalledTimes(1);
488
- expect(updateLocaleSettingsSpy2).toHaveBeenCalledTimes(1);
489
- expect(localeManager1['preferredLocale']).toBe('en-US');
490
- expect(localeManager2['preferredLocale']).toBe('en-US');
491
- });
492
-
493
- it('passes args to the updateLocaleSettings method of each LocaleManager instance', () => {
494
- const localeManager = testManager({ namespaces: ['foo'] });
495
- localeManager.app = {
496
- _context: {
497
- provides: { [`${INJECTION_KEY_PREFIX}.namespace-1`]: localeManager },
498
- },
499
- } as unknown as App;
500
- const updateLocaleSettingsSpy = vi.spyOn(
501
- localeManager,
502
- 'updateLocaleSettings',
503
- );
504
- const args = { preferredLocale: 'es-LA' };
505
- localeManager.changeLocale(args, 'namespace-1');
506
- expect(updateLocaleSettingsSpy).toHaveBeenCalledTimes(1);
507
- expect(updateLocaleSettingsSpy).toHaveBeenCalledWith(args);
508
- expect(localeManager['preferredLocale']).toBe('es-LA');
509
- });
510
- });
511
- });