@inlang/paraglide-js 2.0.12 → 2.1.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 (61) hide show
  1. package/dist/cli/steps/initialize-inlang-project.d.ts.map +1 -1
  2. package/dist/cli/utils.d.ts.map +1 -1
  3. package/dist/compiler/compile-bundle.d.ts +2 -1
  4. package/dist/compiler/compile-bundle.d.ts.map +1 -1
  5. package/dist/compiler/compile-bundle.js +4 -3
  6. package/dist/compiler/compile-bundle.test.js +64 -0
  7. package/dist/compiler/compile-message.d.ts.map +1 -1
  8. package/dist/compiler/compile-pattern.d.ts.map +1 -1
  9. package/dist/compiler/compile-project.d.ts.map +1 -1
  10. package/dist/compiler/compile-project.js +1 -0
  11. package/dist/compiler/compiler-options.d.ts +2 -0
  12. package/dist/compiler/compiler-options.d.ts.map +1 -1
  13. package/dist/compiler/runtime/create-runtime.d.ts.map +1 -1
  14. package/dist/compiler/runtime/create-runtime.js +6 -0
  15. package/dist/compiler/runtime/extract-locale-from-cookie.d.ts +1 -1
  16. package/dist/compiler/runtime/extract-locale-from-cookie.js +1 -1
  17. package/dist/compiler/runtime/extract-locale-from-header.d.ts +2 -0
  18. package/dist/compiler/runtime/extract-locale-from-header.d.ts.map +1 -0
  19. package/dist/compiler/runtime/extract-locale-from-header.js +43 -0
  20. package/dist/compiler/runtime/extract-locale-from-header.test.d.ts +2 -0
  21. package/dist/compiler/runtime/extract-locale-from-header.test.d.ts.map +1 -0
  22. package/dist/compiler/runtime/extract-locale-from-header.test.js +51 -0
  23. package/dist/compiler/runtime/extract-locale-from-navigator.d.ts +2 -0
  24. package/dist/compiler/runtime/extract-locale-from-navigator.d.ts.map +1 -0
  25. package/dist/compiler/runtime/extract-locale-from-navigator.js +31 -0
  26. package/dist/compiler/runtime/extract-locale-from-navigator.test.d.ts +2 -0
  27. package/dist/compiler/runtime/extract-locale-from-navigator.test.d.ts.map +1 -0
  28. package/dist/compiler/runtime/extract-locale-from-navigator.test.js +29 -0
  29. package/dist/compiler/runtime/extract-locale-from-request.d.ts.map +1 -1
  30. package/dist/compiler/runtime/extract-locale-from-request.js +8 -36
  31. package/dist/compiler/runtime/extract-locale-from-request.test.js +83 -2
  32. package/dist/compiler/runtime/extract-locale-from-url.d.ts.map +1 -1
  33. package/dist/compiler/runtime/extract-locale-from-url.js +35 -13
  34. package/dist/compiler/runtime/get-locale.d.ts.map +1 -1
  35. package/dist/compiler/runtime/get-locale.js +8 -26
  36. package/dist/compiler/runtime/get-locale.test.js +153 -0
  37. package/dist/compiler/runtime/localize-href.d.ts.map +1 -1
  38. package/dist/compiler/runtime/localize-href.js +7 -4
  39. package/dist/compiler/runtime/set-locale.d.ts.map +1 -1
  40. package/dist/compiler/runtime/set-locale.js +6 -1
  41. package/dist/compiler/runtime/set-locale.test.js +140 -0
  42. package/dist/compiler/runtime/strategy.d.ts +60 -0
  43. package/dist/compiler/runtime/strategy.d.ts.map +1 -0
  44. package/dist/compiler/runtime/strategy.js +62 -0
  45. package/dist/compiler/runtime/strategy.test.d.ts +2 -0
  46. package/dist/compiler/runtime/strategy.test.d.ts.map +1 -0
  47. package/dist/compiler/runtime/strategy.test.js +94 -0
  48. package/dist/compiler/runtime/type.d.ts +4 -0
  49. package/dist/compiler/runtime/type.d.ts.map +1 -1
  50. package/dist/compiler/runtime/variables.d.ts +2 -2
  51. package/dist/compiler/runtime/variables.d.ts.map +1 -1
  52. package/dist/compiler/runtime/variables.js +1 -1
  53. package/dist/compiler/server/middleware.d.ts +4 -2
  54. package/dist/compiler/server/middleware.d.ts.map +1 -1
  55. package/dist/compiler/server/middleware.js +17 -3
  56. package/dist/compiler/server/middleware.test.js +151 -0
  57. package/dist/services/codegen/quotes.d.ts.map +1 -1
  58. package/dist/services/env-variables/index.js +1 -1
  59. package/dist/services/telemetry/capture.d.ts.map +1 -1
  60. package/dist/utilities/detect-json-formatting.d.ts.map +1 -1
  61. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"initialize-inlang-project.d.ts","sourceRoot":"","sources":["../../../src/cli/steps/initialize-inlang-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,KAAK,aAAa,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,eAAO,MAAM,uBAAuB,EAAE,OAAO,CAC5C;IACC,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC;IACvB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb,EACD;IACC,OAAO,EAAE,aAAa,CAAC;IACvB,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;CACpB,CA2BD,CAAC;AAgHF,eAAO,MAAM,oBAAoB,QAAe;IAC/C,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC;IACvB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf,KAAG,OAAO,CAAC;IACX,OAAO,EAAE,aAAa,CAAC;IACvB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;CACpB,CAwEA,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAazD;AAcD;;GAEG;AACH,eAAO,MAAM,OAAO,sbACga,CAAC"}
1
+ {"version":3,"file":"initialize-inlang-project.d.ts","sourceRoot":"","sources":["../../../src/cli/steps/initialize-inlang-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,KAAK,aAAa,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,eAAO,MAAM,uBAAuB,EAAE,OAAO,CAC5C;IACC,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC;IACvB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb,EACD;IACC,OAAO,EAAE,aAAa,CAAC;IACvB,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;CACpB,CA2BD,CAAC;AAgHF,eAAO,MAAM,oBAAoB,GAAU,KAAK;IAC/C,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC;IACvB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf,KAAG,OAAO,CAAC;IACX,OAAO,EAAE,aAAa,CAAC;IACvB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;CACpB,CAwEA,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAazD;AAcD;;GAEG;AACH,eAAO,MAAM,OAAO,sbACga,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,EAAE,EAC5D,GAAG,EAAE,GAAG,KACJ,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,OAAO,OAAO,CAAC,MAMnC,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,CAAC,SAAS,MAAM,WAC5C,MAAM,YACN;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,EAAE,CAAA;CAAE,KAG9D,OAAO,CAAC,CAAC,CAKX,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,EAAE,EAC5D,GAAG,EAAE,GAAG,KACJ,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,OAAO,OAAO,CAAC,MAMnC,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,CAAC,SAAS,MAAM,EACrD,SAAS,MAAM,EACf,UAAS;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,EAAE,CAAA;CAE7D,KACC,OAAO,CAAC,CAAC,CAKX,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { Bundle, BundleNested, Message } from "@inlang/sdk";
1
+ import type { Bundle, BundleNested, Message, ProjectSettings } from "@inlang/sdk";
2
2
  import type { Compiled } from "./types.js";
3
3
  export type CompiledBundleWithMessages = {
4
4
  /** The compilation result for the bundle index */
@@ -15,5 +15,6 @@ export declare const compileBundle: (args: {
15
15
  bundle: BundleNested;
16
16
  fallbackMap: Record<string, string | undefined>;
17
17
  messageReferenceExpression: (locale: string, bundleId: string) => string;
18
+ settings?: ProjectSettings;
18
19
  }) => CompiledBundleWithMessages;
19
20
  //# sourceMappingURL=compile-bundle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile-bundle.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C,MAAM,MAAM,0BAA0B,GAAG;IACxC,kDAAkD;IAClD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,gDAAgD;IAChD,QAAQ,EAAE;QACT,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;KACpC,CAAC;CACF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,SAAU;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,0BAA0B,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACzE,KAAG,0BA0BH,CAAC"}
1
+ {"version":3,"file":"compile-bundle.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,MAAM,EACN,YAAY,EACZ,OAAO,EACP,eAAe,EACf,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C,MAAM,MAAM,0BAA0B,GAAG;IACxC,kDAAkD;IAClD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,gDAAgD;IAChD,QAAQ,EAAE;QACT,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;KACpC,CAAC;CACF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,0BAA0B,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzE,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC3B,KAAG,0BA2BH,CAAC"}
@@ -20,6 +20,7 @@ export const compileBundle = (args) => {
20
20
  bundle: args.bundle,
21
21
  availableLocales: Object.keys(args.fallbackMap),
22
22
  messageReferenceExpression: args.messageReferenceExpression,
23
+ settings: args.settings,
23
24
  }),
24
25
  messages: compiledMessages,
25
26
  };
@@ -29,6 +30,7 @@ const compileBundleFunction = (args) => {
29
30
  const hasInputs = inputs.length > 0;
30
31
  const safeBundleId = toSafeModuleId(args.bundle.id);
31
32
  const isSafeBundleId = safeBundleId === args.bundle.id;
33
+ const isFullyTranslated = args.availableLocales.length === args.settings?.locales.length;
32
34
  let code = `/**
33
35
  * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
34
36
  *
@@ -46,9 +48,8 @@ ${isSafeBundleId ? "export " : ""}const ${safeBundleId} = (inputs${hasInputs ? "
46
48
  const locale = options.locale ?? getLocale()
47
49
  trackMessageCall("${safeBundleId}", locale)
48
50
  ${args.availableLocales
49
- .map((locale, index) => `${index > 0 ? " " : ""}if (locale === "${locale}") return ${args.messageReferenceExpression(locale, args.bundle.id)}(inputs)`)
50
- .join("\n")}
51
- return "${args.bundle.id}"
51
+ .map((locale, index) => `${index > 0 ? " " : ""}${!isFullyTranslated || index < args.availableLocales.length - 1 ? `if (locale === "${locale}") ` : ""}return ${args.messageReferenceExpression(locale, args.bundle.id)}(inputs)`)
52
+ .join("\n")}${!isFullyTranslated ? `\n return "${args.bundle.id}"` : ""}
52
53
  };`;
53
54
  if (isSafeBundleId === false) {
54
55
  code += `\nexport { ${safeBundleId} as "${escapeForDoubleQuoteString(args.bundle.id)}" }`;
@@ -35,6 +35,70 @@ test("compiles to jsdoc", async () => {
35
35
  },
36
36
  bundle: mockBundle,
37
37
  messageReferenceExpression: (locale) => `${toSafeModuleId(locale)}.blue_moon_bottle`,
38
+ settings: {
39
+ locales: ["en", "en-US"],
40
+ },
41
+ });
42
+ expect(result.bundle.code).toMatchInlineSnapshot(`"/**
43
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
44
+ *
45
+ * - Changing this function will be over-written by the next build.
46
+ *
47
+ * - If you want to change the translations, you can either edit the source files e.g. \`en.json\`, or
48
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
49
+ *
50
+ * @param {{ age: NonNullable<unknown> }} inputs
51
+ * @param {{ locale?: "en" | "en-US" }} options
52
+ * @returns {string}
53
+ */
54
+ /* @__NO_SIDE_EFFECTS__ */
55
+ export const blue_moon_bottle = (inputs, options = {}) => {
56
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
57
+ return /** @type {any} */ (globalThis).__paraglide_ssr.blue_moon_bottle(inputs)
58
+ }
59
+ const locale = options.locale ?? getLocale()
60
+ trackMessageCall("blue_moon_bottle", locale)
61
+ if (locale === "en") return en.blue_moon_bottle(inputs)
62
+ return en_us2.blue_moon_bottle(inputs)
63
+ };"`);
64
+ });
65
+ test("compiles to jsdoc with missing translation", async () => {
66
+ const mockBundle = {
67
+ id: "blue_moon_bottle",
68
+ declarations: [{ type: "input-variable", name: "age" }],
69
+ messages: [
70
+ {
71
+ id: "message-id",
72
+ bundleId: "blue_moon_bottle",
73
+ locale: "en",
74
+ selectors: [],
75
+ variants: [
76
+ {
77
+ id: "1",
78
+ messageId: "message-id",
79
+ matches: [],
80
+ pattern: [
81
+ { type: "text", value: "Hello" },
82
+ {
83
+ type: "expression",
84
+ arg: { type: "variable-reference", name: "age" },
85
+ },
86
+ ],
87
+ },
88
+ ],
89
+ },
90
+ ],
91
+ };
92
+ const result = compileBundle({
93
+ fallbackMap: {
94
+ en: "en",
95
+ "en-US": "en",
96
+ },
97
+ bundle: mockBundle,
98
+ messageReferenceExpression: (locale) => `${toSafeModuleId(locale)}.blue_moon_bottle`,
99
+ settings: {
100
+ locales: ["en", "en-US", "fr"],
101
+ },
38
102
  });
39
103
  expect(result.bundle.code).toMatchInlineSnapshot(`"/**
40
104
  * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
@@ -1 +1 @@
1
- {"version":3,"file":"compile-message.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C;;;GAGG;AACH,eAAO,MAAM,cAAc,iBACZ,WAAW,EAAE,WAClB,OAAO,YACN,OAAO,EAAE,KACjB,QAAQ,CAAC,OAAO,CAUlB,CAAC"}
1
+ {"version":3,"file":"compile-message.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C;;;GAGG;AACH,eAAO,MAAM,cAAc,GAC1B,cAAc,WAAW,EAAE,EAC3B,SAAS,OAAO,EAChB,UAAU,OAAO,EAAE,KACjB,QAAQ,CAAC,OAAO,CAUlB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"compile-pattern.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAqB,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,SAAU;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,WAAW,EAAE,CAAC;CAC5B,KAAG,QAAQ,CAAC,OAAO,CA4BnB,CAAC"}
1
+ {"version":3,"file":"compile-pattern.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAqB,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,WAAW,EAAE,CAAC;CAC5B,KAAG,QAAQ,CAAC,OAAO,CA4BnB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"compile-project.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-project.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAIrE,OAAO,EAEN,KAAK,eAAe,EACpB,MAAM,uBAAuB,CAAC;AAU/B;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,SAAgB;IAC1C,OAAO,EAAE,aAAa,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;CACrE,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsEjC,CAAC;AAEF,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAC9C,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,GACpB,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAY1B"}
1
+ {"version":3,"file":"compile-project.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-project.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAIrE,OAAO,EAEN,KAAK,eAAe,EACpB,MAAM,uBAAuB,CAAC;AAU/B;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAU,MAAM;IAC1C,OAAO,EAAE,aAAa,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;CACrE,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuEjC,CAAC;AAEF,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAC9C,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,GACpB,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAY1B"}
@@ -36,6 +36,7 @@ export const compileProject = async (args) => {
36
36
  bundle,
37
37
  fallbackMap,
38
38
  messageReferenceExpression: outputStructure.messageReferenceExpression,
39
+ settings,
39
40
  }));
40
41
  const output = {
41
42
  ["runtime.js"]: createRuntimeFile({
@@ -52,6 +52,8 @@ export type CompilerOptions = {
52
52
  * server-side takes the globalVariable (because cookie is unavailable),
53
53
  * whereas both fallback to the base locale if not available.
54
54
  *
55
+ * Custom strategies with the pattern `custom-[A-Za-z0-9]+` are supported.
56
+ *
55
57
  * @default ["cookie", "globalVariable", "baseLocale"]
56
58
  */
57
59
  strategy?: Runtime["strategy"];
@@ -1 +1 @@
1
- {"version":3,"file":"compiler-options.d.ts","sourceRoot":"","sources":["../../src/compiler/compiler-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;CAcU,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC7B;;;;;;;;;;OAUG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiDG;IACH,eAAe,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;IACvD;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,EAAE,CAAC,EAAE,GAAG,CAAC;CACT,CAAC"}
1
+ {"version":3,"file":"compiler-options.d.ts","sourceRoot":"","sources":["../../src/compiler/compiler-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;CAcU,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC7B;;;;;;;;;;OAUG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiDG;IACH,eAAe,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;IACvD;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,EAAE,CAAC,EAAE,GAAG,CAAC;CACT,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-runtime.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/create-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE;QAChB,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;QACnD,UAAU,EAAE,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;QACvD,YAAY,EAAE,WAAW,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3D,YAAY,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;QAC9C,WAAW,CAAC,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC;QAC7C,qCAAqC,EAAE,eAAe,CAAC,uCAAuC,CAAC,CAAC;QAChG,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;QACtC,eAAe,EAAE,eAAe,CAAC,iBAAiB,CAAC,CAAC;QACpD,wBAAwB,EAAE,WAAW,CACpC,eAAe,CAAC,0BAA0B,CAAC,CAC3C,CAAC;KACF,CAAC;CACF,GAAG,MAAM,CAkIT"}
1
+ {"version":3,"file":"create-runtime.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/create-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE;QAChB,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;QACnD,UAAU,EAAE,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;QACvD,YAAY,EAAE,WAAW,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3D,YAAY,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;QAC9C,WAAW,CAAC,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC;QAC7C,qCAAqC,EAAE,eAAe,CAAC,uCAAuC,CAAC,CAAC;QAChG,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;QACtC,eAAe,EAAE,eAAe,CAAC,iBAAiB,CAAC,CAAC;QACpD,wBAAwB,EAAE,WAAW,CACpC,eAAe,CAAC,0BAA0B,CAAC,CAC3C,CAAC;KACF,CAAC;CACF,GAAG,MAAM,CAwIT"}
@@ -64,6 +64,10 @@ ${injectCode("./extract-locale-from-request.js")}
64
64
 
65
65
  ${injectCode("./extract-locale-from-cookie.js")}
66
66
 
67
+ ${injectCode("./extract-locale-from-header.js")}
68
+
69
+ ${injectCode("./extract-locale-from-navigator.js")}
70
+
67
71
  ${injectCode("./extract-locale-from-url.js")}
68
72
 
69
73
  ${injectCode("./localize-url.js")}
@@ -74,6 +78,8 @@ ${injectCode("./track-message-call.js")}
74
78
 
75
79
  ${injectCode("./generate-static-localized-urls.js")}
76
80
 
81
+ ${injectCode("./strategy.js")}
82
+
77
83
  // ------ TYPES ------
78
84
 
79
85
  /**
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Extracts a cookie from the document.
3
3
  *
4
- * Will return undefined if the docuement is not available or if the cookie is not set.
4
+ * Will return undefined if the document is not available or if the cookie is not set.
5
5
  * The `document` object is not available in server-side rendering, so this function should not be called in that context.
6
6
  *
7
7
  * @returns {string | undefined}
@@ -3,7 +3,7 @@ import { cookieName } from "./variables.js";
3
3
  /**
4
4
  * Extracts a cookie from the document.
5
5
  *
6
- * Will return undefined if the docuement is not available or if the cookie is not set.
6
+ * Will return undefined if the document is not available or if the cookie is not set.
7
7
  * The `document` object is not available in server-side rendering, so this function should not be called in that context.
8
8
  *
9
9
  * @returns {string | undefined}
@@ -0,0 +1,2 @@
1
+ export function extractLocaleFromHeader(request: Request): Locale;
2
+ //# sourceMappingURL=extract-locale-from-header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-locale-from-header.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-header.js"],"names":[],"mappings":"AAWU,iDAAU,OAAO,GAAK,MAAM,CAAA"}
@@ -0,0 +1,43 @@
1
+ import { isLocale } from "./is-locale.js";
2
+ /**
3
+ * Extracts a locale from the accept-language header.
4
+ *
5
+ * Use the function on the server to extract the locale
6
+ * from the accept-language header that is sent by the client.
7
+ *
8
+ * @example
9
+ * const locale = extractLocaleFromHeader(request);
10
+ *
11
+ * @type {(request: Request) => Locale}
12
+ * @param {Request} request - The request object to extract the locale from.
13
+ * @returns {string|undefined} The negotiated preferred language.
14
+ */
15
+ export function extractLocaleFromHeader(request) {
16
+ const acceptLanguageHeader = request.headers.get("accept-language");
17
+ if (acceptLanguageHeader) {
18
+ // Parse language preferences with their q-values and base language codes
19
+ const languages = acceptLanguageHeader
20
+ .split(",")
21
+ .map((lang) => {
22
+ const [tag, q = "1"] = lang.trim().split(";q=");
23
+ // Get both the full tag and base language code
24
+ const baseTag = tag?.split("-")[0]?.toLowerCase();
25
+ return {
26
+ fullTag: tag?.toLowerCase(),
27
+ baseTag,
28
+ q: Number(q),
29
+ };
30
+ })
31
+ .sort((a, b) => b.q - a.q);
32
+ for (const lang of languages) {
33
+ if (isLocale(lang.fullTag)) {
34
+ return lang.fullTag;
35
+ }
36
+ else if (isLocale(lang.baseTag)) {
37
+ return lang.baseTag;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+ return undefined;
43
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extract-locale-from-header.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-locale-from-header.test.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-header.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ import { test, expect } from "vitest";
2
+ import { createParaglide } from "../create-paraglide.js";
3
+ import { newProject } from "@inlang/sdk";
4
+ test("returns the preferred locale from Accept-Language header", async () => {
5
+ const runtime = await createParaglide({
6
+ blob: await newProject({
7
+ settings: {
8
+ baseLocale: "en",
9
+ locales: ["en", "fr", "de"],
10
+ },
11
+ }),
12
+ });
13
+ // simple direct match
14
+ const request = new Request("http://example.com", {
15
+ headers: {
16
+ "Accept-Language": "en-US;q=0.8,fr;q=0.9,de;q=0.6",
17
+ },
18
+ });
19
+ const locale = runtime.extractLocaleFromHeader(request);
20
+ expect(locale).toBe("fr");
21
+ // language tag match
22
+ const request2 = new Request("http://example.com", {
23
+ headers: {
24
+ "Accept-Language": "en-US;q=0.8,nl;q=0.9,de;q=0.7",
25
+ },
26
+ });
27
+ const locale2 = runtime.extractLocaleFromHeader(request2);
28
+ // Since "nl" isn't in our locales, and "de" has the highest q-value after "nl"
29
+ expect(locale2).toBe("en");
30
+ // no match
31
+ const request3 = new Request("http://example.com", {
32
+ headers: {
33
+ "Accept-Language": "nl;q=0.9,es;q=0.6",
34
+ },
35
+ });
36
+ const locale3 = runtime.extractLocaleFromHeader(request3);
37
+ expect(locale3).toBeUndefined();
38
+ });
39
+ test("returns undefined if no Accept-Language header is present", async () => {
40
+ const runtime = await createParaglide({
41
+ blob: await newProject({
42
+ settings: {
43
+ baseLocale: "en",
44
+ locales: ["en", "fr", "de"],
45
+ },
46
+ }),
47
+ });
48
+ const request = new Request("http://example.com");
49
+ const locale = runtime.extractLocaleFromHeader(request);
50
+ expect(locale).toBeUndefined();
51
+ });
@@ -0,0 +1,2 @@
1
+ export function extractLocaleFromNavigator(): Locale | undefined;
2
+ //# sourceMappingURL=extract-locale-from-navigator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-locale-from-navigator.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-navigator.js"],"names":[],"mappings":"AAWU,8CAAM,MAAM,GAAG,SAAS,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { isLocale } from "./is-locale.js";
2
+ /**
3
+ * Negotiates a preferred language from navigator.languages.
4
+ *
5
+ * Use the function on the client to extract the locale
6
+ * from the navigator.languages array.
7
+ *
8
+ * @example
9
+ * const locale = extractLocaleFromNavigator();
10
+ *
11
+ * @type {() => Locale | undefined}
12
+ * @returns {string | undefined}
13
+ */
14
+ export function extractLocaleFromNavigator() {
15
+ if (!navigator?.languages?.length) {
16
+ return undefined;
17
+ }
18
+ const languages = navigator.languages.map((lang) => ({
19
+ fullTag: lang.toLowerCase(),
20
+ baseTag: lang.split("-")[0]?.toLowerCase(),
21
+ }));
22
+ for (const lang of languages) {
23
+ if (isLocale(lang.fullTag)) {
24
+ return lang.fullTag;
25
+ }
26
+ else if (isLocale(lang.baseTag)) {
27
+ return lang.baseTag;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extract-locale-from-navigator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-locale-from-navigator.test.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-navigator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { newProject } from "@inlang/sdk";
2
+ import { expect, test } from "vitest";
3
+ import { createParaglide } from "../create-paraglide.js";
4
+ test("returns the preferred locale from navigator.languages", async () => {
5
+ const originalNavigator = globalThis.navigator;
6
+ const runtime = await createParaglide({
7
+ blob: await newProject({
8
+ settings: {
9
+ baseLocale: "en",
10
+ locales: ["en", "fr", "de"],
11
+ },
12
+ }),
13
+ isServer: "false",
14
+ strategy: ["preferredLanguage"],
15
+ });
16
+ // Mock navigator.languages
17
+ Object.defineProperty(globalThis, "navigator", {
18
+ value: {
19
+ languages: ["fr-FR", "en-US", "de"],
20
+ },
21
+ configurable: true,
22
+ });
23
+ expect(runtime.getLocale()).toBe("fr");
24
+ // Restore original navigator
25
+ Object.defineProperty(globalThis, "navigator", {
26
+ value: originalNavigator,
27
+ configurable: true,
28
+ });
29
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"extract-locale-from-request.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-request.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;GAcG;AACH,uCAFU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAyCpC"}
1
+ {"version":3,"file":"extract-locale-from-request.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-request.js"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;GAcG;AACH,uCAFU,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAyCpC"}
@@ -1,7 +1,9 @@
1
1
  import { assertIsLocale } from "./assert-is-locale.js";
2
- import { baseLocale, cookieName, strategy, TREE_SHAKE_COOKIE_STRATEGY_USED, TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED, TREE_SHAKE_URL_STRATEGY_USED, } from "./variables.js";
2
+ import { extractLocaleFromHeader } from "./extract-locale-from-header.js";
3
3
  import { extractLocaleFromUrl } from "./extract-locale-from-url.js";
4
4
  import { isLocale } from "./is-locale.js";
5
+ import { customServerStrategies, isCustomStrategy } from "./strategy.js";
6
+ import { baseLocale, cookieName, strategy, TREE_SHAKE_COOKIE_STRATEGY_USED, TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED, TREE_SHAKE_URL_STRATEGY_USED, } from "./variables.js";
5
7
  /**
6
8
  * Extracts a locale from a request.
7
9
  *
@@ -33,10 +35,7 @@ export const extractLocaleFromRequest = (request) => {
33
35
  }
34
36
  else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&
35
37
  strat === "preferredLanguage") {
36
- const acceptLanguageHeader = request.headers.get("accept-language");
37
- if (acceptLanguageHeader) {
38
- locale = negotiatePreferredLanguageFromHeader(acceptLanguageHeader);
39
- }
38
+ locale = extractLocaleFromHeader(request);
40
39
  }
41
40
  else if (strat === "globalVariable") {
42
41
  locale = _locale;
@@ -47,6 +46,10 @@ export const extractLocaleFromRequest = (request) => {
47
46
  else if (strat === "localStorage") {
48
47
  continue;
49
48
  }
49
+ else if (isCustomStrategy(strat) && customServerStrategies.has(strat)) {
50
+ const handler = customServerStrategies.get(strat);
51
+ locale = handler.getLocale(request);
52
+ }
50
53
  if (locale !== undefined) {
51
54
  if (!isLocale(locale)) {
52
55
  locale = undefined;
@@ -58,34 +61,3 @@ export const extractLocaleFromRequest = (request) => {
58
61
  }
59
62
  throw new Error("No locale found. There is an error in your strategy. Try adding 'baseLocale' as the very last strategy. Read more here https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
60
63
  };
61
- /**
62
- * Negotiates a preferred language from a header.
63
- *
64
- * @param {string} header - The header to negotiate from.
65
- * @returns {string|undefined} The negotiated preferred language.
66
- */
67
- function negotiatePreferredLanguageFromHeader(header) {
68
- // Parse language preferences with their q-values and base language codes
69
- const languages = header
70
- .split(",")
71
- .map((lang) => {
72
- const [tag, q = "1"] = lang.trim().split(";q=");
73
- // Get both the full tag and base language code
74
- const baseTag = tag?.split("-")[0]?.toLowerCase();
75
- return {
76
- fullTag: tag?.toLowerCase(),
77
- baseTag,
78
- q: Number(q),
79
- };
80
- })
81
- .sort((a, b) => b.q - a.q);
82
- for (const lang of languages) {
83
- if (isLocale(lang.fullTag)) {
84
- return lang.fullTag;
85
- }
86
- else if (isLocale(lang.baseTag)) {
87
- return lang.baseTag;
88
- }
89
- }
90
- return undefined;
91
- }
@@ -1,6 +1,6 @@
1
- import { test, expect } from "vitest";
2
- import { createParaglide } from "../create-paraglide.js";
3
1
  import { newProject } from "@inlang/sdk";
2
+ import { expect, test } from "vitest";
3
+ import { createParaglide } from "../create-paraglide.js";
4
4
  test("returns the locale from the cookie", async () => {
5
5
  const runtime = await createParaglide({
6
6
  blob: await newProject({
@@ -238,3 +238,84 @@ test("preferredLanguage precedence over url", async () => {
238
238
  const locale = runtime.extractLocaleFromRequest(request);
239
239
  expect(locale).toBe("de");
240
240
  });
241
+ test("returns locale from custom strategy", async () => {
242
+ const runtime = await createParaglide({
243
+ blob: await newProject({
244
+ settings: {
245
+ baseLocale: "en",
246
+ locales: ["en", "fr", "de"],
247
+ },
248
+ }),
249
+ strategy: ["custom-header", "baseLocale"],
250
+ });
251
+ // Define a custom strategy that extracts locale from a custom header
252
+ runtime.defineCustomServerStrategy("custom-header", {
253
+ getLocale: (request) => request?.headers.get("X-Custom-Locale") ?? undefined,
254
+ });
255
+ const request = new Request("http://example.com", {
256
+ headers: {
257
+ "X-Custom-Locale": "fr",
258
+ },
259
+ });
260
+ const locale = runtime.extractLocaleFromRequest(request);
261
+ expect(locale).toBe("fr");
262
+ });
263
+ test("falls back to next strategy when custom strategy returns undefined", async () => {
264
+ const runtime = await createParaglide({
265
+ blob: await newProject({
266
+ settings: {
267
+ baseLocale: "en",
268
+ locales: ["en", "fr"],
269
+ },
270
+ }),
271
+ strategy: ["custom-fallback", "baseLocale"],
272
+ });
273
+ runtime.defineCustomServerStrategy("custom-fallback", {
274
+ getLocale: () => undefined,
275
+ });
276
+ const request = new Request("http://example.com");
277
+ const locale = runtime.extractLocaleFromRequest(request);
278
+ expect(locale).toBe("en"); // Should fall back to baseLocale
279
+ });
280
+ test("custom strategy takes precedence over built-in strategies", async () => {
281
+ const runtime = await createParaglide({
282
+ blob: await newProject({
283
+ settings: {
284
+ baseLocale: "en",
285
+ locales: ["en", "fr", "de"],
286
+ },
287
+ }),
288
+ strategy: ["custom-priority", "cookie", "baseLocale"],
289
+ cookieName: "PARAGLIDE_LOCALE",
290
+ });
291
+ runtime.defineCustomServerStrategy("custom-priority", {
292
+ getLocale: () => "de",
293
+ });
294
+ const request = new Request("http://example.com", {
295
+ headers: {
296
+ cookie: "PARAGLIDE_LOCALE=fr", // Cookie has different locale
297
+ },
298
+ });
299
+ const locale = runtime.extractLocaleFromRequest(request);
300
+ expect(locale).toBe("de"); // Should use custom strategy, not cookie
301
+ });
302
+ test("multiple custom strategies work in order", async () => {
303
+ const runtime = await createParaglide({
304
+ blob: await newProject({
305
+ settings: {
306
+ baseLocale: "en",
307
+ locales: ["en", "fr", "de"],
308
+ },
309
+ }),
310
+ strategy: ["custom-first", "custom-second", "baseLocale"],
311
+ });
312
+ runtime.defineCustomServerStrategy("custom-first", {
313
+ getLocale: () => undefined,
314
+ });
315
+ runtime.defineCustomServerStrategy("custom-second", {
316
+ getLocale: () => "fr",
317
+ });
318
+ const request = new Request("http://example.com");
319
+ const locale = runtime.extractLocaleFromRequest(request);
320
+ expect(locale).toBe("fr"); // Should use second custom strategy
321
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"extract-locale-from-url.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-url.js"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,0CAHW,GAAG,GAAC,MAAM,GACR,MAAM,GAAC,SAAS,CA4B5B"}
1
+ {"version":3,"file":"extract-locale-from-url.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-url.js"],"names":[],"mappings":"AAmBA;;;;;GAKG;AACH,0CAHW,GAAG,GAAC,MAAM,GACR,MAAM,GAAC,SAAS,CAuC5B"}