@inlang/paraglide-js 2.3.0 → 2.3.2

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.
@@ -6,16 +6,19 @@
6
6
  * reloading is disabled, you need to ensure that the UI is updated
7
7
  * to reflect the new locale.
8
8
  *
9
+ * If any custom strategy's \`setLocale\` function is async, then this
10
+ * function will become async as well.
11
+ *
9
12
  * @example
10
13
  * setLocale('en');
11
14
  *
12
15
  * @example
13
16
  * setLocale('en', { reload: false });
14
17
  *
15
- * @type {(newLocale: Locale, options?: { reload?: boolean }) => void}
18
+ * @type {(newLocale: Locale, options?: { reload?: boolean }) => Promise<any> | void}
16
19
  */
17
20
  export let setLocale: (newLocale: Locale, options?: {
18
21
  reload?: boolean;
19
- }) => void;
22
+ }) => Promise<any> | void;
20
23
  export function overwriteSetLocale(fn: (newLocale: Locale) => void): void;
21
24
  //# sourceMappingURL=set-locale.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"set-locale.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/set-locale.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AACH,sBAFU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,CA8FnE;AAgBK,uCAFI,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,QAIrC"}
1
+ {"version":3,"file":"set-locale.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/set-locale.js"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;;;;GAkBG;AACH,sBAFU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAuGlF;AAgBK,uCAFI,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,QAIrC"}
@@ -2,6 +2,22 @@ import { getLocale } from "./get-locale.js";
2
2
  import { localizeUrl } from "./localize-url.js";
3
3
  import { customClientStrategies, isCustomStrategy } from "./strategy.js";
4
4
  import { cookieDomain, cookieMaxAge, cookieName, isServer, localStorageKey, strategy, TREE_SHAKE_COOKIE_STRATEGY_USED, TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED, TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED, TREE_SHAKE_URL_STRATEGY_USED, } from "./variables.js";
5
+ /**
6
+ * Navigates to the localized URL, or reloads the current page
7
+ *
8
+ * @param {string} [newLocation] The new location
9
+ * @return {undefined}
10
+ */
11
+ const navigateOrReload = (newLocation) => {
12
+ if (newLocation) {
13
+ // reload the page by navigating to the new url
14
+ window.location.href = newLocation;
15
+ }
16
+ else {
17
+ // reload the page to reflect the new locale
18
+ window.location.reload();
19
+ }
20
+ };
5
21
  /**
6
22
  * Set the locale.
7
23
  *
@@ -10,13 +26,16 @@ import { cookieDomain, cookieMaxAge, cookieName, isServer, localStorageKey, stra
10
26
  * reloading is disabled, you need to ensure that the UI is updated
11
27
  * to reflect the new locale.
12
28
  *
29
+ * If any custom strategy's \`setLocale\` function is async, then this
30
+ * function will become async as well.
31
+ *
13
32
  * @example
14
33
  * setLocale('en');
15
34
  *
16
35
  * @example
17
36
  * setLocale('en', { reload: false });
18
37
  *
19
- * @type {(newLocale: Locale, options?: { reload?: boolean }) => void}
38
+ * @type {(newLocale: Locale, options?: { reload?: boolean }) => Promise<any> | void}
20
39
  */
21
40
  export let setLocale = (newLocale, options) => {
22
41
  const optionsWithDefaults = {
@@ -32,6 +51,8 @@ export let setLocale = (newLocale, options) => {
32
51
  catch {
33
52
  // do nothing, no locale has been set yet.
34
53
  }
54
+ /** @type {Array<Promise<any>>} */
55
+ const customSetLocalePromises = [];
35
56
  /** @type {string | undefined} */
36
57
  let newLocation = undefined;
37
58
  for (const strat of strategy) {
@@ -81,12 +102,15 @@ export let setLocale = (newLocale, options) => {
81
102
  else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {
82
103
  const handler = customClientStrategies.get(strat);
83
104
  if (handler) {
84
- const result = handler.setLocale(newLocale);
105
+ let result = handler.setLocale(newLocale);
85
106
  // Handle async setLocale - fire and forget
86
107
  if (result instanceof Promise) {
87
- result.catch((error) => {
88
- console.warn(`Custom strategy "${strat}" setLocale failed:`, error);
108
+ result = result.catch((error) => {
109
+ throw new Error(`Custom strategy "${strat}" setLocale failed.`, {
110
+ cause: error,
111
+ });
89
112
  });
113
+ customSetLocalePromises.push(result);
90
114
  }
91
115
  }
92
116
  }
@@ -95,15 +119,19 @@ export let setLocale = (newLocale, options) => {
95
119
  optionsWithDefaults.reload &&
96
120
  window.location &&
97
121
  newLocale !== currentLocale) {
98
- if (newLocation) {
99
- // reload the page by navigating to the new url
100
- window.location.href = newLocation;
122
+ if (customSetLocalePromises.length) {
123
+ // Wait for any async custom setLocale functions
124
+ return Promise.all(customSetLocalePromises).then(() => {
125
+ navigateOrReload(newLocation);
126
+ });
101
127
  }
102
128
  else {
103
- // reload the page to reflect the new locale
104
- window.location.reload();
129
+ navigateOrReload(newLocation);
105
130
  }
106
131
  }
132
+ else if (customSetLocalePromises.length) {
133
+ return Promise.all(customSetLocalePromises);
134
+ }
107
135
  return;
108
136
  };
109
137
  /**
@@ -317,6 +317,129 @@ test("calls setLocale on multiple custom strategies", async () => {
317
317
  expect(customLocale1).toBe("de");
318
318
  expect(customLocale2).toBe("de");
319
319
  });
320
+ test("setLocale should return a promise if any custom setLocale function is async", async () => {
321
+ let customLocale1 = "en";
322
+ const runtime = await createParaglide({
323
+ blob: await newProject({
324
+ settings: {
325
+ baseLocale: "en",
326
+ locales: ["en", "fr", "de"],
327
+ },
328
+ }),
329
+ strategy: ["custom-async", "baseLocale"],
330
+ isServer: "false",
331
+ });
332
+ runtime.defineCustomClientStrategy("custom-async", {
333
+ getLocale: () => customLocale1,
334
+ setLocale: async (locale) => {
335
+ customLocale1 = locale;
336
+ },
337
+ });
338
+ const setLocalePromise = runtime.setLocale("de");
339
+ const setLocalePromiseWithoutReload = runtime.setLocale("de", {
340
+ reload: false,
341
+ });
342
+ expect(setLocalePromise).toBeInstanceOf(Promise);
343
+ expect(setLocalePromiseWithoutReload).toBeInstanceOf(Promise);
344
+ });
345
+ test("awaits async setLocale functions to resolve in custom strategy", async () => {
346
+ let customLocale1 = "en";
347
+ globalThis.window = {
348
+ location: {
349
+ reload: vi.fn(),
350
+ },
351
+ };
352
+ const runtime = await createParaglide({
353
+ blob: await newProject({
354
+ settings: {
355
+ baseLocale: "en",
356
+ locales: ["en", "fr", "de"],
357
+ },
358
+ }),
359
+ strategy: ["custom-async", "baseLocale"],
360
+ isServer: "false",
361
+ });
362
+ runtime.defineCustomClientStrategy("custom-async", {
363
+ getLocale: () => customLocale1,
364
+ setLocale: async (locale) => {
365
+ customLocale1 = locale;
366
+ },
367
+ });
368
+ const setLocalePromise = runtime.setLocale("de");
369
+ expect(window.location.reload).not.toHaveBeenCalled();
370
+ await setLocalePromise;
371
+ // Verify that setLocale resolved before reload was called
372
+ expect(window.location.reload).toHaveBeenCalledTimes(1);
373
+ expect(customLocale1).toBe("de");
374
+ });
375
+ test("awaits async setLocale functions to resolve in multiple custom strategies", async () => {
376
+ let customLocale1 = "en";
377
+ let customLocale2 = "en";
378
+ globalThis.window = {
379
+ location: {
380
+ reload: vi.fn(),
381
+ },
382
+ };
383
+ const runtime = await createParaglide({
384
+ blob: await newProject({
385
+ settings: {
386
+ baseLocale: "en",
387
+ locales: ["en", "fr", "de"],
388
+ },
389
+ }),
390
+ strategy: ["custom-async1", "custom-async2", "baseLocale"],
391
+ isServer: "false",
392
+ });
393
+ runtime.defineCustomClientStrategy("custom-async1", {
394
+ getLocale: () => customLocale1,
395
+ setLocale: async (locale) => {
396
+ customLocale1 = locale;
397
+ },
398
+ });
399
+ runtime.defineCustomClientStrategy("custom-async2", {
400
+ getLocale: () => customLocale2,
401
+ setLocale: async (locale) => {
402
+ customLocale2 = locale;
403
+ },
404
+ });
405
+ const setLocalePromise = runtime.setLocale("de");
406
+ expect(window.location.reload).not.toHaveBeenCalled();
407
+ await setLocalePromise;
408
+ // Verify that setLocale resolved before reload was called
409
+ expect(window.location.reload).toHaveBeenCalledTimes(1);
410
+ expect(customLocale1).toBe("de");
411
+ expect(customLocale2).toBe("de");
412
+ });
413
+ test("reload should not run if async setLocale function rejects in custom strategy", async () => {
414
+ const customLocale1 = "en";
415
+ globalThis.window = {
416
+ location: {
417
+ reload: vi.fn(),
418
+ },
419
+ };
420
+ const runtime = await createParaglide({
421
+ blob: await newProject({
422
+ settings: {
423
+ baseLocale: "en",
424
+ locales: ["en", "fr", "de"],
425
+ },
426
+ }),
427
+ strategy: ["custom-async", "baseLocale"],
428
+ isServer: "false",
429
+ });
430
+ runtime.defineCustomClientStrategy("custom-async", {
431
+ getLocale: () => customLocale1,
432
+ setLocale: async () => {
433
+ throw new Error("fetch error");
434
+ },
435
+ });
436
+ const error = expect(() => runtime.setLocale("de")).rejects;
437
+ await error.toThrowError(`Custom strategy "custom-async" setLocale failed.`);
438
+ await error.toMatchObject({ cause: { message: "fetch error" } });
439
+ // Verify that reload was never called
440
+ expect(window.location.reload).toHaveBeenCalledTimes(0);
441
+ expect(customLocale1).toBe("en");
442
+ });
320
443
  test("custom strategy setLocale works with cookie and localStorage", async () => {
321
444
  let customData = "en";
322
445
  globalThis.document = { cookie: "" };
@@ -1,5 +1,5 @@
1
1
  export const ENV_VARIABLES = {
2
2
  PARJS_APP_ID: "library.inlang.paraglideJs",
3
3
  PARJS_POSTHOG_TOKEN: undefined,
4
- PARJS_PACKAGE_VERSION: "2.3.0",
4
+ PARJS_PACKAGE_VERSION: "2.3.2",
5
5
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inlang/paraglide-js",
3
3
  "type": "module",
4
- "version": "2.3.0",
4
+ "version": "2.3.2",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public",