@inlang/paraglide-js 2.25.4 → 2.27.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 (124) hide show
  1. package/README.md +2 -1
  2. package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +2 -2
  3. package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
  4. package/dist/cli/commands/init/command.js +19 -1
  5. package/dist/cli/commands/init/command.js.map +1 -1
  6. package/dist/cli/defaults.js +2 -2
  7. package/dist/cli/defaults.js.map +1 -1
  8. package/dist/cli/steps/add-inlang-check.d.ts +19 -0
  9. package/dist/cli/steps/add-inlang-check.js +60 -0
  10. package/dist/cli/steps/add-inlang-check.js.map +1 -0
  11. package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
  12. package/dist/cli/steps/add-inlang-check.test.js +88 -0
  13. package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
  14. package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
  15. package/dist/cli/steps/agents-md-suggestion.js +19 -0
  16. package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
  17. package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
  18. package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
  19. package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
  20. package/dist/cli/steps/maybe-add-machine-translation.js +3 -2
  21. package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
  22. package/dist/cli/steps/maybe-add-sherlock.js +1 -1
  23. package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
  24. package/dist/cli/utils.d.ts +9 -0
  25. package/dist/cli/utils.js +15 -0
  26. package/dist/cli/utils.js.map +1 -1
  27. package/dist/compiler/compile-annotation.d.ts +48 -1
  28. package/dist/compiler/compile-annotation.js +238 -10
  29. package/dist/compiler/compile-annotation.js.map +1 -1
  30. package/dist/compiler/compile-bundle.d.ts +3 -2
  31. package/dist/compiler/compile-bundle.js +30 -1
  32. package/dist/compiler/compile-bundle.js.map +1 -1
  33. package/dist/compiler/compile-bundle.test.js +18 -18
  34. package/dist/compiler/compile-bundle.test.js.map +1 -1
  35. package/dist/compiler/compile-local-variable.d.ts +3 -0
  36. package/dist/compiler/compile-local-variable.js +5 -2
  37. package/dist/compiler/compile-local-variable.js.map +1 -1
  38. package/dist/compiler/compile-local-variable.test.js +44 -4
  39. package/dist/compiler/compile-local-variable.test.js.map +1 -1
  40. package/dist/compiler/compile-message.d.ts +29 -1
  41. package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
  42. package/dist/compiler/compile-message.exact-number.test.js +786 -0
  43. package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
  44. package/dist/compiler/compile-message.js +162 -66
  45. package/dist/compiler/compile-message.js.map +1 -1
  46. package/dist/compiler/compile-message.locals.test.d.ts +1 -0
  47. package/dist/compiler/compile-message.locals.test.js +498 -0
  48. package/dist/compiler/compile-message.locals.test.js.map +1 -0
  49. package/dist/compiler/compile-message.test.js +111 -20
  50. package/dist/compiler/compile-message.test.js.map +1 -1
  51. package/dist/compiler/compile-pattern.d.ts +5 -0
  52. package/dist/compiler/compile-pattern.js +6 -18
  53. package/dist/compiler/compile-pattern.js.map +1 -1
  54. package/dist/compiler/compile-pattern.test.js +165 -1
  55. package/dist/compiler/compile-pattern.test.js.map +1 -1
  56. package/dist/compiler/compile-project.js +4 -1
  57. package/dist/compiler/compile-project.js.map +1 -1
  58. package/dist/compiler/compile-project.test.js +1013 -31
  59. package/dist/compiler/compile-project.test.js.map +1 -1
  60. package/dist/compiler/compile.test.js +1 -1
  61. package/dist/compiler/compile.test.js.map +1 -1
  62. package/dist/compiler/create-readme.d.ts +4 -1
  63. package/dist/compiler/create-readme.js +33 -125
  64. package/dist/compiler/create-readme.js.map +1 -1
  65. package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
  66. package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
  67. package/dist/compiler/emit-ts-declarations.test.js +4 -4
  68. package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
  69. package/dist/compiler/index.d.ts +1 -1
  70. package/dist/compiler/index.js +1 -1
  71. package/dist/compiler/index.js.map +1 -1
  72. package/dist/compiler/input-alias.d.ts +21 -0
  73. package/dist/compiler/input-alias.js +42 -0
  74. package/dist/compiler/input-alias.js.map +1 -0
  75. package/dist/compiler/input-alias.test.d.ts +1 -0
  76. package/dist/compiler/input-alias.test.js +58 -0
  77. package/dist/compiler/input-alias.test.js.map +1 -0
  78. package/dist/compiler/message-locals.d.ts +46 -0
  79. package/dist/compiler/message-locals.js +129 -0
  80. package/dist/compiler/message-locals.js.map +1 -0
  81. package/dist/compiler/output-structure/locale-modules.js +7 -1
  82. package/dist/compiler/output-structure/locale-modules.js.map +1 -1
  83. package/dist/compiler/output-structure/locale-modules.test.js +35 -0
  84. package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
  85. package/dist/compiler/output-structure/message-modules.js +5 -3
  86. package/dist/compiler/output-structure/message-modules.js.map +1 -1
  87. package/dist/compiler/output-structure/message-modules.test.js +35 -0
  88. package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
  89. package/dist/compiler/registry.d.ts +12 -0
  90. package/dist/compiler/registry.js +97 -28
  91. package/dist/compiler/registry.js.map +1 -1
  92. package/dist/compiler/runtime/create-runtime.js +24 -1
  93. package/dist/compiler/runtime/create-runtime.js.map +1 -1
  94. package/dist/compiler/runtime/extract-locale-from-url.js +11 -4
  95. package/dist/compiler/runtime/extract-locale-from-url.js.map +1 -1
  96. package/dist/compiler/runtime/generate-static-localized-urls.js +5 -3
  97. package/dist/compiler/runtime/generate-static-localized-urls.js.map +1 -1
  98. package/dist/compiler/runtime/localize-url.js +25 -54
  99. package/dist/compiler/runtime/localize-url.js.map +1 -1
  100. package/dist/compiler/runtime/route-strategy.js +9 -3
  101. package/dist/compiler/runtime/route-strategy.js.map +1 -1
  102. package/dist/compiler/runtime/type.test.js +9 -0
  103. package/dist/compiler/runtime/type.test.js.map +1 -1
  104. package/dist/compiler/runtime/url-pattern-cache.d.ts +11 -0
  105. package/dist/compiler/runtime/url-pattern-cache.js +42 -0
  106. package/dist/compiler/runtime/url-pattern-cache.js.map +1 -0
  107. package/dist/compiler/runtime/url-pattern-index.d.ts +24 -0
  108. package/dist/compiler/runtime/url-pattern-index.differential.test.d.ts +1 -0
  109. package/dist/compiler/runtime/url-pattern-index.differential.test.js +152 -0
  110. package/dist/compiler/runtime/url-pattern-index.differential.test.js.map +1 -0
  111. package/dist/compiler/runtime/url-pattern-index.js +168 -0
  112. package/dist/compiler/runtime/url-pattern-index.js.map +1 -0
  113. package/dist/compiler/runtime/url-pattern-index.test.d.ts +1 -0
  114. package/dist/compiler/runtime/url-pattern-index.test.js +262 -0
  115. package/dist/compiler/runtime/url-pattern-index.test.js.map +1 -0
  116. package/dist/compiler/server/create-server-file.js +25 -1
  117. package/dist/compiler/server/create-server-file.js.map +1 -1
  118. package/dist/compiler/server/create-server-file.test.js +20 -2
  119. package/dist/compiler/server/create-server-file.test.js.map +1 -1
  120. package/dist/compiler/server/middleware.js +29 -4
  121. package/dist/compiler/server/middleware.js.map +1 -1
  122. package/dist/services/env-variables/index.js +1 -1
  123. package/dist/services/env-variables/index.js.map +1 -1
  124. package/package.json +3 -3
@@ -13,10 +13,12 @@ test("should emit per locale message files", () => {
13
13
  en: {
14
14
  code: 'console.log("message in English");',
15
15
  node: {},
16
+ registryFunctions: [],
16
17
  },
17
18
  de: {
18
19
  code: 'console.log("message in German");',
19
20
  node: {},
21
+ registryFunctions: [],
20
22
  },
21
23
  },
22
24
  matchTypes: new Map(),
@@ -48,6 +50,7 @@ test("handles case senstivity by creating directories and files only in lowercas
48
50
  en: {
49
51
  code: 'export const HappyElephant = () => "HappyElephant0"',
50
52
  node: {},
53
+ registryFunctions: [],
51
54
  },
52
55
  },
53
56
  matchTypes: new Map(),
@@ -63,6 +66,7 @@ test("handles case senstivity by creating directories and files only in lowercas
63
66
  en: {
64
67
  code: 'export const happyelephant = () => "happyelephant1"',
65
68
  node: {},
69
+ registryFunctions: [],
66
70
  },
67
71
  },
68
72
  matchTypes: new Map(),
@@ -91,6 +95,7 @@ test("emits minimal runtime imports when middleware splitting is disabled", () =
91
95
  en: {
92
96
  code: '() => "happy"',
93
97
  node: {},
98
+ registryFunctions: [],
94
99
  },
95
100
  },
96
101
  matchTypes: new Map(),
@@ -117,6 +122,7 @@ test("emits fallback definitions after their dependencies", () => {
117
122
  en: {
118
123
  code: '/** @type {(inputs: {}) => string} */ () => "admin"',
119
124
  node: {},
125
+ registryFunctions: [],
120
126
  },
121
127
  },
122
128
  matchTypes: new Map(),
@@ -145,4 +151,33 @@ test("emits fallback definitions after their dependencies", () => {
145
151
  expect(frCaIndex).toBeGreaterThan(-1);
146
152
  expect(frIndex).toBeLessThan(frCaIndex);
147
153
  });
154
+ test("imports the registry only when a message calls it, not when the text mentions it", () => {
155
+ const bundle = (id, code, registryFunctions) => ({
156
+ bundle: {
157
+ code: `export const ${id} = () => en_${id}()`,
158
+ node: { id },
159
+ },
160
+ messages: {
161
+ en: { code, node: {}, registryFunctions },
162
+ },
163
+ matchTypes: new Map(),
164
+ });
165
+ const settings = {
166
+ locales: ["en"],
167
+ baseLocale: "en",
168
+ };
169
+ const registryImport = /import \* as registry from ['"]\.\.\/registry\.js['"]/;
170
+ const textOnly = generateOutput([bundle("registry_text", "() => `Open the registry. Now.`", [])], settings, { en: undefined });
171
+ for (const [fileName, code] of Object.entries(textOnly)) {
172
+ if (fileName.startsWith("messages/")) {
173
+ expect(code).not.toMatch(registryImport);
174
+ }
175
+ }
176
+ const withNumber = generateOutput([
177
+ bundle("amount", '(i) => `${registry.number("en", i?.amount, {})}`', [
178
+ "number",
179
+ ]),
180
+ ], settings, { en: undefined });
181
+ expect(Object.values(withNumber).some((code) => registryImport.test(code))).toBe(true);
182
+ });
148
183
  //# sourceMappingURL=message-modules.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-modules.test.js","sourceRoot":"","sources":["../../../src/compiler/output-structure/message-modules.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect } from \"vitest\";\nimport { generateOutput } from \"./message-modules.js\";\nimport type { Bundle, Message, ProjectSettings } from \"@inlang/sdk\";\nimport type { CompiledBundleWithMessages } from \"../compile-bundle.js\";\n\ntest(\"should emit per locale message files\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: 'console.log(\"bundle code\");',\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"happy_elephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: 'console.log(\"message in English\");',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t},\n\t\t\t\tde: {\n\t\t\t\t\tcode: 'console.log(\"message in German\");',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"en\", \"de\"],\n\t\tbaseLocale: \"en\",\n\t};\n\n\tconst fallbackMap: Record<string, string | undefined> = {\n\t\ten: \"de\",\n\t\tde: \"en\",\n\t};\n\n\tconst output = generateOutput(resources, settings, fallbackMap);\n\n\texpect(output).not.toHaveProperty(\"messages/en.js\");\n\texpect(output).not.toHaveProperty(\"messages/de.js\");\n\texpect(output).toHaveProperty(\"messages/happy_elephant.js\");\n});\n\ntest(\"handles case senstivity by creating directories and files only in lowercase\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const HappyElephant = () => en.HappyElephant\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"HappyElephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: 'export const HappyElephant = () => \"HappyElephant0\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const happyelephant = () => en.happyelephant\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"happyelephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: 'export const happyelephant = () => \"happyelephant1\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"en\"],\n\t\tbaseLocale: \"en\",\n\t};\n\tconst output = generateOutput(resources, settings, {});\n\n\t// expecting only lowercase directories and files\n\texpect(output).toHaveProperty(\"messages/happyelephant.js\");\n\texpect(output).toHaveProperty(\"messages/happyelephant2.js\");\n\texpect(output).not.toHaveProperty(\"messages/HappyElephant.js\");\n});\n\ntest(\"emits minimal runtime imports when middleware splitting is disabled\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const happy_elephant = () => en_happy_elephant()\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"happy_elephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: '() => \"happy\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\n\tconst output = generateOutput(\n\t\tresources,\n\t\t{ locales: [\"en\"], baseLocale: \"en\" },\n\t\t{},\n\t\tfalse\n\t);\n\n\texpect(output[\"messages/happy_elephant.js\"]).toContain(\n\t\t\"import { getLocale, experimentalStaticLocale } from '../runtime.js';\"\n\t);\n\texpect(output[\"messages/happy_elephant.js\"]).not.toContain(\n\t\t\"trackMessageCall\"\n\t);\n\texpect(output[\"messages/happy_elephant.js\"]).not.toContain(\n\t\t\"experimentalMiddlewareLocaleSplitting\"\n\t);\n\texpect(output[\"messages/happy_elephant.js\"]).not.toContain(\"isServer\");\n});\n\n// Regression test for https://github.com/opral/inlang-paraglide-js/issues/507\ntest(\"emits fallback definitions after their dependencies\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const admin_tasks = (inputs) => inputs;\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"admin_tasks\",\n\t\t\t\t\tdeclarations: [],\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: '/** @type {(inputs: {}) => string} */ () => \"admin\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"fr-ca\", \"fr\", \"en\"],\n\t\tbaseLocale: \"en\",\n\t};\n\n\tconst fallbackMap: Record<string, string | undefined> = {\n\t\t\"fr-ca\": \"fr\",\n\t\tfr: \"en\",\n\t\ten: undefined,\n\t};\n\n\tconst output = generateOutput(resources, settings, fallbackMap);\n\n\tconst file = output[\"messages/admin_tasks.js\"];\n\n\texpect(file).toBeDefined();\n\n\tif (!file) {\n\t\tthrow new Error(\"messages/admin_tasks.js should have been generated\");\n\t}\n\n\texpect(file).toContain(\"const fr_admin_tasks = en_admin_tasks;\");\n\texpect(file).toContain(\"const fr_ca_admin_tasks = fr_admin_tasks;\");\n\n\tconst frIndex = file.indexOf(\"const fr_admin_tasks\");\n\tconst frCaIndex = file.indexOf(\"const fr_ca_admin_tasks\");\n\n\texpect(frIndex).toBeGreaterThan(-1);\n\texpect(frCaIndex).toBeGreaterThan(-1);\n\texpect(frIndex).toBeLessThan(frCaIndex);\n});\n"]}
1
+ {"version":3,"file":"message-modules.test.js","sourceRoot":"","sources":["../../../src/compiler/output-structure/message-modules.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect } from \"vitest\";\nimport { generateOutput } from \"./message-modules.js\";\nimport type { Bundle, Message, ProjectSettings } from \"@inlang/sdk\";\nimport type { CompiledBundleWithMessages } from \"../compile-bundle.js\";\n\ntest(\"should emit per locale message files\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: 'console.log(\"bundle code\");',\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"happy_elephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: 'console.log(\"message in English\");',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t\tde: {\n\t\t\t\t\tcode: 'console.log(\"message in German\");',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"en\", \"de\"],\n\t\tbaseLocale: \"en\",\n\t};\n\n\tconst fallbackMap: Record<string, string | undefined> = {\n\t\ten: \"de\",\n\t\tde: \"en\",\n\t};\n\n\tconst output = generateOutput(resources, settings, fallbackMap);\n\n\texpect(output).not.toHaveProperty(\"messages/en.js\");\n\texpect(output).not.toHaveProperty(\"messages/de.js\");\n\texpect(output).toHaveProperty(\"messages/happy_elephant.js\");\n});\n\ntest(\"handles case senstivity by creating directories and files only in lowercase\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const HappyElephant = () => en.HappyElephant\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"HappyElephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: 'export const HappyElephant = () => \"HappyElephant0\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const happyelephant = () => en.happyelephant\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"happyelephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: 'export const happyelephant = () => \"happyelephant1\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"en\"],\n\t\tbaseLocale: \"en\",\n\t};\n\tconst output = generateOutput(resources, settings, {});\n\n\t// expecting only lowercase directories and files\n\texpect(output).toHaveProperty(\"messages/happyelephant.js\");\n\texpect(output).toHaveProperty(\"messages/happyelephant2.js\");\n\texpect(output).not.toHaveProperty(\"messages/HappyElephant.js\");\n});\n\ntest(\"emits minimal runtime imports when middleware splitting is disabled\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const happy_elephant = () => en_happy_elephant()\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"happy_elephant\",\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: '() => \"happy\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\n\tconst output = generateOutput(\n\t\tresources,\n\t\t{ locales: [\"en\"], baseLocale: \"en\" },\n\t\t{},\n\t\tfalse\n\t);\n\n\texpect(output[\"messages/happy_elephant.js\"]).toContain(\n\t\t\"import { getLocale, experimentalStaticLocale } from '../runtime.js';\"\n\t);\n\texpect(output[\"messages/happy_elephant.js\"]).not.toContain(\n\t\t\"trackMessageCall\"\n\t);\n\texpect(output[\"messages/happy_elephant.js\"]).not.toContain(\n\t\t\"experimentalMiddlewareLocaleSplitting\"\n\t);\n\texpect(output[\"messages/happy_elephant.js\"]).not.toContain(\"isServer\");\n});\n\n// Regression test for https://github.com/opral/inlang-paraglide-js/issues/507\ntest(\"emits fallback definitions after their dependencies\", () => {\n\tconst resources: CompiledBundleWithMessages[] = [\n\t\t{\n\t\t\tbundle: {\n\t\t\t\tcode: \"export const admin_tasks = (inputs) => inputs;\",\n\t\t\t\tnode: {\n\t\t\t\t\tid: \"admin_tasks\",\n\t\t\t\t\tdeclarations: [],\n\t\t\t\t} as unknown as Bundle,\n\t\t\t},\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: '/** @type {(inputs: {}) => string} */ () => \"admin\"',\n\t\t\t\t\tnode: {} as unknown as Message,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t\tmatchTypes: new Map(),\n\t\t},\n\t];\n\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"fr-ca\", \"fr\", \"en\"],\n\t\tbaseLocale: \"en\",\n\t};\n\n\tconst fallbackMap: Record<string, string | undefined> = {\n\t\t\"fr-ca\": \"fr\",\n\t\tfr: \"en\",\n\t\ten: undefined,\n\t};\n\n\tconst output = generateOutput(resources, settings, fallbackMap);\n\n\tconst file = output[\"messages/admin_tasks.js\"];\n\n\texpect(file).toBeDefined();\n\n\tif (!file) {\n\t\tthrow new Error(\"messages/admin_tasks.js should have been generated\");\n\t}\n\n\texpect(file).toContain(\"const fr_admin_tasks = en_admin_tasks;\");\n\texpect(file).toContain(\"const fr_ca_admin_tasks = fr_admin_tasks;\");\n\n\tconst frIndex = file.indexOf(\"const fr_admin_tasks\");\n\tconst frCaIndex = file.indexOf(\"const fr_ca_admin_tasks\");\n\n\texpect(frIndex).toBeGreaterThan(-1);\n\texpect(frCaIndex).toBeGreaterThan(-1);\n\texpect(frIndex).toBeLessThan(frCaIndex);\n});\n\ntest(\"imports the registry only when a message calls it, not when the text mentions it\", () => {\n\tconst bundle = (\n\t\tid: string,\n\t\tcode: string,\n\t\tregistryFunctions: string[]\n\t): CompiledBundleWithMessages => ({\n\t\tbundle: {\n\t\t\tcode: `export const ${id} = () => en_${id}()`,\n\t\t\tnode: { id } as unknown as Bundle,\n\t\t},\n\t\tmessages: {\n\t\t\ten: { code, node: {} as unknown as Message, registryFunctions },\n\t\t},\n\t\tmatchTypes: new Map(),\n\t});\n\tconst settings: Pick<ProjectSettings, \"locales\" | \"baseLocale\"> = {\n\t\tlocales: [\"en\"],\n\t\tbaseLocale: \"en\",\n\t};\n\tconst registryImport =\n\t\t/import \\* as registry from ['\"]\\.\\.\\/registry\\.js['\"]/;\n\n\tconst textOnly = generateOutput(\n\t\t[bundle(\"registry_text\", \"() => `Open the registry. Now.`\", [])],\n\t\tsettings,\n\t\t{ en: undefined }\n\t);\n\tfor (const [fileName, code] of Object.entries(textOnly)) {\n\t\tif (fileName.startsWith(\"messages/\")) {\n\t\t\texpect(code).not.toMatch(registryImport);\n\t\t}\n\t}\n\n\tconst withNumber = generateOutput(\n\t\t[\n\t\t\tbundle(\"amount\", '(i) => `${registry.number(\"en\", i?.amount, {})}`', [\n\t\t\t\t\"number\",\n\t\t\t]),\n\t\t],\n\t\tsettings,\n\t\t{ en: undefined }\n\t);\n\texpect(\n\t\tObject.values(withNumber).some((code) => registryImport.test(code))\n\t).toBe(true);\n});\n"]}
@@ -11,3 +11,15 @@
11
11
  * Creates the Registry file
12
12
  */
13
13
  export declare function createRegistry(): string;
14
+ /**
15
+ * Returns the given registry functions and the registry functions they call,
16
+ * in registry order.
17
+ *
18
+ * @example
19
+ * withRegistryDependencies(["icuPound"]) // ["number", "icuPound"]
20
+ */
21
+ export declare function withRegistryDependencies(names: Iterable<string>): string[];
22
+ /**
23
+ * Returns the code of the given registry functions without `export`, by name.
24
+ */
25
+ export declare function registryFunctionCode(names: Iterable<string>): Record<string, string>;
@@ -8,53 +8,122 @@
8
8
  * For now, Paraglide ships a custom solution with INTL functions.
9
9
  */
10
10
  /**
11
- * Creates the Registry file
12
- */
13
- export function createRegistry() {
14
- return `
15
- /**
16
- * @typedef {"year" | "years" | "quarter" | "quarters" | "month" | "months" | "week" | "weeks" | "day" | "days" | "hour" | "hours" | "minute" | "minutes" | "second" | "seconds"} RelativeTimeFormatUnit
11
+ * The functions of the generated registry.js file, by name.
17
12
  */
18
-
19
- /**
13
+ const registryFunctions = {
14
+ plural: {
15
+ jsdoc: `/**
16
+ * Selects the plural category of "input - options.offset". The offset
17
+ * comes from ICU MessageFormat 1 "{count, plural, offset:1 ...}" and does not
18
+ * change exact matches like "=0", which compare the input itself.
19
+ *
20
20
  * @param {import("./runtime.js").Locale} locale
21
21
  * @param {unknown} input
22
- * @param {Intl.PluralRulesOptions} [options]
22
+ * @param {Intl.PluralRulesOptions & { offset?: unknown }} [options]
23
23
  * @returns {string}
24
- */
25
- export function plural(locale, input, options) {
26
- return new Intl.PluralRules(locale, options).select(Number(input))
27
- };
28
-
29
- /**
24
+ */`,
25
+ code: `function plural(locale, input, options) {
26
+ return new Intl.PluralRules(locale, options).select(Number(input) - Number(options?.offset ?? 0))
27
+ };`,
28
+ dependencies: [],
29
+ },
30
+ number: {
31
+ jsdoc: `/**
30
32
  * @param {import("./runtime.js").Locale} locale
31
33
  * @param {unknown} input
32
34
  * @param {Intl.NumberFormatOptions} [options]
33
35
  * @returns {string}
34
- */
35
- export function number(locale, input, options) {
36
+ */`,
37
+ code: `function number(locale, input, options) {
36
38
  return new Intl.NumberFormat(locale, options).format(Number(input))
37
- };
38
-
39
- /**
39
+ };`,
40
+ dependencies: [],
41
+ },
42
+ icuPound: {
43
+ jsdoc: `/**
44
+ * Formats "#" in ICU MessageFormat 1 plurals: the number "input - options.offset",
45
+ * formatted like number(). The offset comes from "{count, plural, offset:1 ...}".
46
+ * An input that is not a finite number (or a numeric string) is displayed as is,
47
+ * without subtracting the offset.
48
+ *
49
+ * @param {import("./runtime.js").Locale} locale
50
+ * @param {unknown} input
51
+ * @param {{ offset?: unknown }} [options]
52
+ * @returns {string}
53
+ */`,
54
+ code: `function icuPound(locale, input, options) {
55
+ const value = typeof input === "number" ? input : typeof input === "string" && input.trim() !== "" ? Number(input) : NaN
56
+ if (!Number.isFinite(value)) return String(input)
57
+ return number(locale, value - Number(options?.offset ?? 0))
58
+ };`,
59
+ dependencies: ["number"],
60
+ },
61
+ datetime: {
62
+ jsdoc: `/**
40
63
  * @param {import("./runtime.js").Locale} locale
41
64
  * @param {unknown} input
42
65
  * @param {Intl.DateTimeFormatOptions} [options]
43
66
  * @returns {string}
44
- */
45
- export function datetime(locale, input, options) {
67
+ */`,
68
+ code: `function datetime(locale, input, options) {
46
69
  return new Intl.DateTimeFormat(locale, options).format(new Date(/** @type {string} */ (input)))
47
- };
48
-
49
- /**
70
+ };`,
71
+ dependencies: [],
72
+ },
73
+ relativetime: {
74
+ jsdoc: `/**
50
75
  * @param {import("./runtime.js").Locale} locale
51
76
  * @param {unknown} input
52
77
  * @param {Intl.RelativeTimeFormatOptions & { unit: RelativeTimeFormatUnit }} options
53
78
  * @returns {string}
54
- */
55
- export function relativetime(locale, input, options) {
79
+ */`,
80
+ code: `function relativetime(locale, input, options) {
56
81
  const { unit, ...intlOptions } = options;
57
82
  return new Intl.RelativeTimeFormat(locale, intlOptions).format(Number(input), unit);
58
- };`;
83
+ };`,
84
+ dependencies: [],
85
+ },
86
+ };
87
+ /**
88
+ * Creates the Registry file
89
+ */
90
+ export function createRegistry() {
91
+ return `
92
+ /**
93
+ * @typedef {"year" | "years" | "quarter" | "quarters" | "month" | "months" | "week" | "weeks" | "day" | "days" | "hour" | "hours" | "minute" | "minutes" | "second" | "seconds"} RelativeTimeFormatUnit
94
+ */
95
+
96
+ ${Object.values(registryFunctions)
97
+ .map((fn) => `${fn.jsdoc}\nexport ${fn.code}`)
98
+ .join("\n\n")}`;
99
+ }
100
+ /**
101
+ * Returns the given registry functions and the registry functions they call,
102
+ * in registry order.
103
+ *
104
+ * @example
105
+ * withRegistryDependencies(["icuPound"]) // ["number", "icuPound"]
106
+ */
107
+ export function withRegistryDependencies(names) {
108
+ const needed = new Set();
109
+ const add = (name) => {
110
+ const fn = registryFunctions[name];
111
+ if (!fn || needed.has(name))
112
+ return;
113
+ needed.add(name);
114
+ fn.dependencies.forEach(add);
115
+ };
116
+ for (const name of names)
117
+ add(name);
118
+ return Object.keys(registryFunctions).filter((name) => needed.has(name));
119
+ }
120
+ /**
121
+ * Returns the code of the given registry functions without `export`, by name.
122
+ */
123
+ export function registryFunctionCode(names) {
124
+ return Object.fromEntries(Array.from(names).flatMap((name) => {
125
+ const fn = registryFunctions[name];
126
+ return fn ? [[name, fn.code]] : [];
127
+ }));
59
128
  }
60
129
  //# sourceMappingURL=registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/compiler/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,UAAU,cAAc;IAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CL,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Re: CUSTOMIZING THE REGISTRY\n *\n * We want to enable anyone (designer, developer, translator) to\n * specify options for functions. That requires design work in\n * the inlang SDK.\n *\n * For now, Paraglide ships a custom solution with INTL functions.\n */\n\n/**\n * Creates the Registry file\n */\nexport function createRegistry(): string {\n\treturn `\n/**\n * @typedef {\"year\" | \"years\" | \"quarter\" | \"quarters\" | \"month\" | \"months\" | \"week\" | \"weeks\" | \"day\" | \"days\" | \"hour\" | \"hours\" | \"minute\" | \"minutes\" | \"second\" | \"seconds\"} RelativeTimeFormatUnit\n */\n\n/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.PluralRulesOptions} [options]\n * @returns {string}\n */\nexport function plural(locale, input, options) { \n\treturn new Intl.PluralRules(locale, options).select(Number(input))\n};\n\n/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.NumberFormatOptions} [options]\n * @returns {string}\n */\nexport function number(locale, input, options) {\n\treturn new Intl.NumberFormat(locale, options).format(Number(input))\n};\n\n/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.DateTimeFormatOptions} [options]\n * @returns {string}\n */\nexport function datetime(locale, input, options) {\n\treturn new Intl.DateTimeFormat(locale, options).format(new Date(/** @type {string} */ (input)))\n};\n\n/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.RelativeTimeFormatOptions & { unit: RelativeTimeFormatUnit }} options\n * @returns {string}\n */\nexport function relativetime(locale, input, options) {\n\tconst { unit, ...intlOptions } = options;\n\treturn new Intl.RelativeTimeFormat(locale, intlOptions).format(Number(input), unit);\n};`;\n}\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/compiler/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH;;GAEG;AACH,MAAM,iBAAiB,GAAqC;IAC3D,MAAM,EAAE;QACP,KAAK,EAAE;;;;;;;;;IASL;QACF,IAAI,EAAE;;GAEL;QACD,YAAY,EAAE,EAAE;KAChB;IACD,MAAM,EAAE;QACP,KAAK,EAAE;;;;;IAKL;QACF,IAAI,EAAE;;GAEL;QACD,YAAY,EAAE,EAAE;KAChB;IACD,QAAQ,EAAE;QACT,KAAK,EAAE;;;;;;;;;;IAUL;QACF,IAAI,EAAE;;;;GAIL;QACD,YAAY,EAAE,CAAC,QAAQ,CAAC;KACxB;IACD,QAAQ,EAAE;QACT,KAAK,EAAE;;;;;IAKL;QACF,IAAI,EAAE;;GAEL;QACD,YAAY,EAAE,EAAE;KAChB;IACD,YAAY,EAAE;QACb,KAAK,EAAE;;;;;IAKL;QACF,IAAI,EAAE;;;GAGL;QACD,YAAY,EAAE,EAAE;KAChB;CACD,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,cAAc;IAC7B,OAAO;;;;;EAKN,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC;SAChC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC;SAC7C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAuB;IAC/D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE;QAC5B,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QACpC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjB,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CACnC,KAAuB;IAEvB,OAAO,MAAM,CAAC,WAAW,CACxB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,CAAC,CAAC,CACF,CAAC;AACH,CAAC","sourcesContent":["/**\n * Re: CUSTOMIZING THE REGISTRY\n *\n * We want to enable anyone (designer, developer, translator) to\n * specify options for functions. That requires design work in\n * the inlang SDK.\n *\n * For now, Paraglide ships a custom solution with INTL functions.\n */\n\ntype RegistryFunction = {\n\t/** JSDoc of the function in registry.js */\n\tjsdoc: string;\n\t/** The function declaration, without `export` */\n\tcode: string;\n\t/** Registry functions the code calls */\n\tdependencies: string[];\n};\n\n/**\n * The functions of the generated registry.js file, by name.\n */\nconst registryFunctions: Record<string, RegistryFunction> = {\n\tplural: {\n\t\tjsdoc: `/**\n * Selects the plural category of \"input - options.offset\". The offset\n * comes from ICU MessageFormat 1 \"{count, plural, offset:1 ...}\" and does not\n * change exact matches like \"=0\", which compare the input itself.\n *\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.PluralRulesOptions & { offset?: unknown }} [options]\n * @returns {string}\n */`,\n\t\tcode: `function plural(locale, input, options) {\n\treturn new Intl.PluralRules(locale, options).select(Number(input) - Number(options?.offset ?? 0))\n};`,\n\t\tdependencies: [],\n\t},\n\tnumber: {\n\t\tjsdoc: `/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.NumberFormatOptions} [options]\n * @returns {string}\n */`,\n\t\tcode: `function number(locale, input, options) {\n\treturn new Intl.NumberFormat(locale, options).format(Number(input))\n};`,\n\t\tdependencies: [],\n\t},\n\ticuPound: {\n\t\tjsdoc: `/**\n * Formats \"#\" in ICU MessageFormat 1 plurals: the number \"input - options.offset\",\n * formatted like number(). The offset comes from \"{count, plural, offset:1 ...}\".\n * An input that is not a finite number (or a numeric string) is displayed as is,\n * without subtracting the offset.\n *\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {{ offset?: unknown }} [options]\n * @returns {string}\n */`,\n\t\tcode: `function icuPound(locale, input, options) {\n\tconst value = typeof input === \"number\" ? input : typeof input === \"string\" && input.trim() !== \"\" ? Number(input) : NaN\n\tif (!Number.isFinite(value)) return String(input)\n\treturn number(locale, value - Number(options?.offset ?? 0))\n};`,\n\t\tdependencies: [\"number\"],\n\t},\n\tdatetime: {\n\t\tjsdoc: `/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.DateTimeFormatOptions} [options]\n * @returns {string}\n */`,\n\t\tcode: `function datetime(locale, input, options) {\n\treturn new Intl.DateTimeFormat(locale, options).format(new Date(/** @type {string} */ (input)))\n};`,\n\t\tdependencies: [],\n\t},\n\trelativetime: {\n\t\tjsdoc: `/**\n * @param {import(\"./runtime.js\").Locale} locale\n * @param {unknown} input\n * @param {Intl.RelativeTimeFormatOptions & { unit: RelativeTimeFormatUnit }} options\n * @returns {string}\n */`,\n\t\tcode: `function relativetime(locale, input, options) {\n\tconst { unit, ...intlOptions } = options;\n\treturn new Intl.RelativeTimeFormat(locale, intlOptions).format(Number(input), unit);\n};`,\n\t\tdependencies: [],\n\t},\n};\n\n/**\n * Creates the Registry file\n */\nexport function createRegistry(): string {\n\treturn `\n/**\n * @typedef {\"year\" | \"years\" | \"quarter\" | \"quarters\" | \"month\" | \"months\" | \"week\" | \"weeks\" | \"day\" | \"days\" | \"hour\" | \"hours\" | \"minute\" | \"minutes\" | \"second\" | \"seconds\"} RelativeTimeFormatUnit\n */\n\n${Object.values(registryFunctions)\n\t.map((fn) => `${fn.jsdoc}\\nexport ${fn.code}`)\n\t.join(\"\\n\\n\")}`;\n}\n\n/**\n * Returns the given registry functions and the registry functions they call,\n * in registry order.\n *\n * @example\n * withRegistryDependencies([\"icuPound\"]) // [\"number\", \"icuPound\"]\n */\nexport function withRegistryDependencies(names: Iterable<string>): string[] {\n\tconst needed = new Set<string>();\n\tconst add = (name: string) => {\n\t\tconst fn = registryFunctions[name];\n\t\tif (!fn || needed.has(name)) return;\n\t\tneeded.add(name);\n\t\tfn.dependencies.forEach(add);\n\t};\n\tfor (const name of names) add(name);\n\treturn Object.keys(registryFunctions).filter((name) => needed.has(name));\n}\n\n/**\n * Returns the code of the given registry functions without `export`, by name.\n */\nexport function registryFunctionCode(\n\tnames: Iterable<string>\n): Record<string, string> {\n\treturn Object.fromEntries(\n\t\tArray.from(names).flatMap((name) => {\n\t\t\tconst fn = registryFunctions[name];\n\t\t\treturn fn ? [[name, fn.code]] : [];\n\t\t})\n\t);\n}\n"]}
@@ -93,6 +93,29 @@ ${injectCode("./normalize-trailing-slash.js", {
93
93
  privateExports: ["normalizeTrailingSlash"],
94
94
  })}
95
95
 
96
+ ${needsUrlPatternPolyfill
97
+ ? injectCode("./url-pattern-cache.js", {
98
+ privateExports: ["getUrlPattern"],
99
+ }) +
100
+ "\n\n" +
101
+ injectCode("./url-pattern-index.js", {
102
+ privateExports: [
103
+ "getRoutingConfigVersion",
104
+ "currentRoutingConfigVersion",
105
+ "getUrlPatternCandidates",
106
+ "getRouteStrategyCandidates",
107
+ ],
108
+ })
109
+ : `// Default routing does not need a matcher cache or candidate index.
110
+ /** @param {string} pattern @param {URL} url @returns {URLPattern} */
111
+ function getUrlPattern(pattern, url) { return new URLPattern(pattern, url.href); }
112
+ function getRoutingConfigVersion() { return 0; }
113
+ function currentRoutingConfigVersion() { return 0; }
114
+ /** @param {URL} _url @returns {typeof urlPatterns} */
115
+ function getUrlPatternCandidates(_url) { return urlPatterns; }
116
+ /** @param {URL} _url @returns {typeof routeStrategies} */
117
+ function getRouteStrategyCandidates(_url) { return routeStrategies; }`}
118
+
96
119
  ${injectCode("./exec-url-pattern.js", {
97
120
  privateExports: ["execUrlPattern"],
98
121
  })}
@@ -142,7 +165,7 @@ ${injectCode("./type-definitions.js").replace(`@typedef {string} Locale`, `@type
142
165
  function injectCode(path, options) {
143
166
  const code = fs.readFileSync(new URL(path, import.meta.url), "utf-8");
144
167
  // Regex to match single-line and multi-line imports
145
- const importRegex = /import\s+[\s\S]*?from\s+['"][^'"]+['"]\s*;?/g;
168
+ const importRegex = /^\s*import\s+[\s\S]*?from\s+['"][^'"]+['"]\s*;?/gm;
146
169
  const sourceMapRegex = /\/\/# sourceMappingURL=.*$/gm;
147
170
  const blockSourceMapRegex = /\/\*# sourceMappingURL=.*?\*\//g;
148
171
  let injected = code
@@ -1 +1 @@
1
- {"version":3,"file":"create-runtime.js","sourceRoot":"","sources":["../../../src/compiler/runtime/create-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs\";\nimport type { CompilerOptions } from \"../compiler-options.js\";\nimport { perLocaleBuildStaticLocaleExpression } from \"../per-locale-build.js\";\n\n/**\n * Returns the code for the `runtime.js` module\n */\nexport function createRuntimeFile(args: {\n\tbaseLocale: string;\n\tlocales: string[];\n\tcompilerOptions: {\n\t\tstrategy: NonNullable<CompilerOptions[\"strategy\"]>;\n\t\trouteStrategies?: CompilerOptions[\"routeStrategies\"];\n\t\tcookieName: NonNullable<CompilerOptions[\"cookieName\"]>;\n\t\tcookieMaxAge: NonNullable<CompilerOptions[\"cookieMaxAge\"]>;\n\t\tcookieDomain: CompilerOptions[\"cookieDomain\"];\n\t\turlPatterns?: CompilerOptions[\"urlPatterns\"];\n\t\ttrailingSlash?: CompilerOptions[\"trailingSlash\"];\n\t\texperimentalMiddlewareLocaleSplitting: CompilerOptions[\"experimentalMiddlewareLocaleSplitting\"];\n\t\tisServer: CompilerOptions[\"isServer\"];\n\t\texperimentalStaticLocale?: CompilerOptions[\"experimentalStaticLocale\"];\n\t\tlocalStorageKey: CompilerOptions[\"localStorageKey\"];\n\t\tdisableAsyncLocalStorage: NonNullable<\n\t\t\tCompilerOptions[\"disableAsyncLocalStorage\"]\n\t\t>;\n\t};\n}): string {\n\tconst urlPatterns = args.compilerOptions.urlPatterns ?? [];\n\tconst routeStrategies = args.compilerOptions.routeStrategies ?? [];\n\n\tlet defaultUrlPatternUsed = false;\n\n\t// add default urlPatterns for a good out of the box experience\n\tif (args.compilerOptions.urlPatterns === undefined) {\n\t\tdefaultUrlPatternUsed = true;\n\t\turlPatterns.push({\n\t\t\tpattern: `:protocol://:domain(.*)::port?/:path(.*)?`,\n\t\t\tlocalized: [],\n\t\t});\n\t\tfor (const locale of args.locales) {\n\t\t\tif (locale === args.baseLocale) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\turlPatterns[0]?.localized.push([\n\t\t\t\tlocale,\n\t\t\t\t`:protocol://:domain(.*)::port?/${locale}/:path(.*)?`,\n\t\t\t]);\n\t\t}\n\t\turlPatterns[0]?.localized.push([\n\t\t\targs.baseLocale,\n\t\t\t`:protocol://:domain(.*)::port?/:path(.*)?`,\n\t\t]);\n\t}\n\tconst strategiesUsedByRoutes = routeStrategies.flatMap((routeStrategy) =>\n\t\t\"strategy\" in routeStrategy ? routeStrategy.strategy : []\n\t);\n\tconst allUsedStrategies = new Set([\n\t\t...args.compilerOptions.strategy,\n\t\t...strategiesUsedByRoutes,\n\t]);\n\tconst needsUrlPatternPolyfill =\n\t\t!defaultUrlPatternUsed || routeStrategies.length > 0;\n\n\t// verify that urlPatterns' locales are valid\n\tfor (const urlPattern of urlPatterns) {\n\t\tfor (const [locale] of urlPattern.localized) {\n\t\t\tif (!args.locales.includes(locale)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid locale \"${locale}\" in urlPatterns. It must be one of the locales defined in the \"locales\" array.`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst code = `\n${needsUrlPatternPolyfill ? `import \"@inlang/paraglide-js/urlpattern-polyfill\";` : \"/** @type {any} */\\nconst URLPattern = {}\"}\n\n${injectCode(\"./variables.js\")\n\t.replace(\n\t\t`export const baseLocale = \"en\";`,\n\t\t`export const baseLocale = \"${args.baseLocale}\";`\n\t)\n\t.replace(\n\t\t`export const locales = /** @type {readonly string[]} */ ([\"en\", \"de\"]);`,\n\t\t`export const locales = /** @type {const} */ (${JSON.stringify(args.locales)});`\n\t)\n\t.replace(\n\t\t`export const strategy = [\"globalVariable\"];`,\n\t\t`export const strategy = ${JSON.stringify(args.compilerOptions.strategy, null, 2)};`\n\t)\n\t.replace(`<cookie-name>`, `${args.compilerOptions.cookieName}`)\n\t.replace(`60 * 60 * 24 * 400`, `${args.compilerOptions.cookieMaxAge}`)\n\t.replace(`<cookie-domain>`, `${args.compilerOptions.cookieDomain}`)\n\t.replace(\n\t\t`export const routeStrategies = [];`,\n\t\t`export const routeStrategies = ${JSON.stringify(routeStrategies, null, 2)};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_COOKIE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_COOKIE_STRATEGY_USED = ${allUsedStrategies.has(\"cookie\")};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_URL_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_URL_STRATEGY_USED = ${allUsedStrategies.has(\"url\")};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = ${allUsedStrategies.has(\"globalVariable\")};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = ${allUsedStrategies.has(\"preferredLanguage\")};`\n\t)\n\t.replace(\n\t\t`export const urlPatterns = [];`,\n\t\t`export const urlPatterns = ${JSON.stringify(urlPatterns, null, 2)};`\n\t)\n\t.replace(\n\t\t`export const trailingSlash = undefined;`,\n\t\t`export const trailingSlash = ${\n\t\t\targs.compilerOptions.trailingSlash === undefined\n\t\t\t\t? \"undefined\"\n\t\t\t\t: JSON.stringify(args.compilerOptions.trailingSlash)\n\t\t};`\n\t)\n\t.replace(\n\t\t`export const disableAsyncLocalStorage = false;`,\n\t\t`export const disableAsyncLocalStorage = ${args.compilerOptions.disableAsyncLocalStorage};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = false;`,\n\t\t`const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = ${defaultUrlPatternUsed};`\n\t)\n\t.replace(\n\t\t`export const experimentalMiddlewareLocaleSplitting = false;`,\n\t\t`export const experimentalMiddlewareLocaleSplitting = ${args.compilerOptions.experimentalMiddlewareLocaleSplitting};`\n\t)\n\t.replace(\n\t\t`export const isServer = typeof window === \"undefined\";`,\n\t\t`export const isServer = ${args.compilerOptions.isServer};`\n\t)\n\t.replace(\n\t\t`export const experimentalStaticLocale = undefined;`,\n\t\targs.compilerOptions.experimentalStaticLocale\n\t\t\t? `export const experimentalStaticLocale = ${\n\t\t\t\t\targs.compilerOptions.experimentalStaticLocale ===\n\t\t\t\t\tperLocaleBuildStaticLocaleExpression\n\t\t\t\t\t\t? args.compilerOptions.experimentalStaticLocale\n\t\t\t\t\t\t: `assertIsLocale(${args.compilerOptions.experimentalStaticLocale})`\n\t\t\t\t};`\n\t\t\t: `export const experimentalStaticLocale = undefined;`\n\t)\n\t.replace(\n\t\t`export const localStorageKey = \"PARAGLIDE_LOCALE\";`,\n\t\t`export const localStorageKey = \"${args.compilerOptions.localStorageKey}\";`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = ${allUsedStrategies.has(\"localStorage\")};`\n\t)}\n\n/** @type {any} */ (globalThis).__paraglide =\n\t/** @type {any} */ (globalThis).__paraglide ?? {};\n/** @type {any} */ (globalThis).__paraglide.ssr =\n\t/** @type {any} */ (globalThis).__paraglide.ssr ?? {};\n\n${injectCode(\"./get-locale.js\")}\n\n${injectCode(\"./get-text-direction.js\")}\n\n${injectCode(\"./set-locale.js\")}\n\n${injectCode(\"./get-url-origin.js\")}\n\n${injectCode(\"./check-locale.js\")}\n\n${injectCode(\"./normalize-trailing-slash.js\", {\n\tprivateExports: [\"normalizeTrailingSlash\"],\n})}\n\n${injectCode(\"./exec-url-pattern.js\", {\n\tprivateExports: [\"execUrlPattern\"],\n})}\n\n${injectCode(\"./extract-locale-from-request.js\")}\n\n${injectCode(\"./extract-locale-from-request-async.js\")}\n\n${injectCode(\"./extract-locale-from-cookie.js\", {\n\tprivateExports: [\"clearLocaleCookieCache\"],\n})}\n\n${injectCode(\"./extract-locale-from-header.js\")}\n\n${injectCode(\"./extract-locale-from-navigator.js\")}\n\n${injectCode(\"./extract-locale-from-url.js\")}\n\n${injectCode(\"./localize-url.js\")}\n\n${injectCode(\"./route-strategy.js\")}\n\n${injectCode(\"./should-redirect.js\")}\n\n${injectCode(\"./localize-href.js\")}\n\n${injectCode(\"./track-message-call.js\")}\n\n${injectCode(\"./generate-static-localized-urls.js\")}\n\n${injectCode(\"./strategy.js\")}\n\n${injectCode(\"./type-definitions.js\").replace(\n\t`@typedef {string} Locale`,\n\t`@typedef {typeof locales[number]} Locale`\n)}\n`;\n\n\treturn code;\n}\n\n/**\n * Load a file from the current directory.\n *\n * Prunes the imports on top of the file as the runtime is\n * self-contained.\n *\n * @param {string} path\n * @param {{ privateExports?: string[] }} [options]\n * @returns {string}\n */\nfunction injectCode(\n\tpath: string,\n\toptions?: { privateExports?: string[] }\n): string {\n\tconst code = fs.readFileSync(new URL(path, import.meta.url), \"utf-8\");\n\t// Regex to match single-line and multi-line imports\n\tconst importRegex = /import\\s+[\\s\\S]*?from\\s+['\"][^'\"]+['\"]\\s*;?/g;\n\tconst sourceMapRegex = /\\/\\/# sourceMappingURL=.*$/gm;\n\tconst blockSourceMapRegex = /\\/\\*# sourceMappingURL=.*?\\*\\//g;\n\tlet injected = code\n\t\t.replace(importRegex, \"\")\n\t\t.replace(sourceMapRegex, \"\")\n\t\t.replace(blockSourceMapRegex, \"\")\n\t\t.trim();\n\tfor (const exportName of options?.privateExports ?? []) {\n\t\tinjected = injected.replace(\n\t\t\tnew RegExp(`\\\\bexport\\\\s+function\\\\s+${exportName}\\\\b`, \"g\"),\n\t\t\t`function ${exportName}`\n\t\t);\n\t}\n\treturn injected;\n}\n"]}
1
+ {"version":3,"file":"create-runtime.js","sourceRoot":"","sources":["../../../src/compiler/runtime/create-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs\";\nimport type { CompilerOptions } from \"../compiler-options.js\";\nimport { perLocaleBuildStaticLocaleExpression } from \"../per-locale-build.js\";\n\n/**\n * Returns the code for the `runtime.js` module\n */\nexport function createRuntimeFile(args: {\n\tbaseLocale: string;\n\tlocales: string[];\n\tcompilerOptions: {\n\t\tstrategy: NonNullable<CompilerOptions[\"strategy\"]>;\n\t\trouteStrategies?: CompilerOptions[\"routeStrategies\"];\n\t\tcookieName: NonNullable<CompilerOptions[\"cookieName\"]>;\n\t\tcookieMaxAge: NonNullable<CompilerOptions[\"cookieMaxAge\"]>;\n\t\tcookieDomain: CompilerOptions[\"cookieDomain\"];\n\t\turlPatterns?: CompilerOptions[\"urlPatterns\"];\n\t\ttrailingSlash?: CompilerOptions[\"trailingSlash\"];\n\t\texperimentalMiddlewareLocaleSplitting: CompilerOptions[\"experimentalMiddlewareLocaleSplitting\"];\n\t\tisServer: CompilerOptions[\"isServer\"];\n\t\texperimentalStaticLocale?: CompilerOptions[\"experimentalStaticLocale\"];\n\t\tlocalStorageKey: CompilerOptions[\"localStorageKey\"];\n\t\tdisableAsyncLocalStorage: NonNullable<\n\t\t\tCompilerOptions[\"disableAsyncLocalStorage\"]\n\t\t>;\n\t};\n}): string {\n\tconst urlPatterns = args.compilerOptions.urlPatterns ?? [];\n\tconst routeStrategies = args.compilerOptions.routeStrategies ?? [];\n\n\tlet defaultUrlPatternUsed = false;\n\n\t// add default urlPatterns for a good out of the box experience\n\tif (args.compilerOptions.urlPatterns === undefined) {\n\t\tdefaultUrlPatternUsed = true;\n\t\turlPatterns.push({\n\t\t\tpattern: `:protocol://:domain(.*)::port?/:path(.*)?`,\n\t\t\tlocalized: [],\n\t\t});\n\t\tfor (const locale of args.locales) {\n\t\t\tif (locale === args.baseLocale) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\turlPatterns[0]?.localized.push([\n\t\t\t\tlocale,\n\t\t\t\t`:protocol://:domain(.*)::port?/${locale}/:path(.*)?`,\n\t\t\t]);\n\t\t}\n\t\turlPatterns[0]?.localized.push([\n\t\t\targs.baseLocale,\n\t\t\t`:protocol://:domain(.*)::port?/:path(.*)?`,\n\t\t]);\n\t}\n\tconst strategiesUsedByRoutes = routeStrategies.flatMap((routeStrategy) =>\n\t\t\"strategy\" in routeStrategy ? routeStrategy.strategy : []\n\t);\n\tconst allUsedStrategies = new Set([\n\t\t...args.compilerOptions.strategy,\n\t\t...strategiesUsedByRoutes,\n\t]);\n\tconst needsUrlPatternPolyfill =\n\t\t!defaultUrlPatternUsed || routeStrategies.length > 0;\n\n\t// verify that urlPatterns' locales are valid\n\tfor (const urlPattern of urlPatterns) {\n\t\tfor (const [locale] of urlPattern.localized) {\n\t\t\tif (!args.locales.includes(locale)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid locale \"${locale}\" in urlPatterns. It must be one of the locales defined in the \"locales\" array.`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst code = `\n${needsUrlPatternPolyfill ? `import \"@inlang/paraglide-js/urlpattern-polyfill\";` : \"/** @type {any} */\\nconst URLPattern = {}\"}\n\n${injectCode(\"./variables.js\")\n\t.replace(\n\t\t`export const baseLocale = \"en\";`,\n\t\t`export const baseLocale = \"${args.baseLocale}\";`\n\t)\n\t.replace(\n\t\t`export const locales = /** @type {readonly string[]} */ ([\"en\", \"de\"]);`,\n\t\t`export const locales = /** @type {const} */ (${JSON.stringify(args.locales)});`\n\t)\n\t.replace(\n\t\t`export const strategy = [\"globalVariable\"];`,\n\t\t`export const strategy = ${JSON.stringify(args.compilerOptions.strategy, null, 2)};`\n\t)\n\t.replace(`<cookie-name>`, `${args.compilerOptions.cookieName}`)\n\t.replace(`60 * 60 * 24 * 400`, `${args.compilerOptions.cookieMaxAge}`)\n\t.replace(`<cookie-domain>`, `${args.compilerOptions.cookieDomain}`)\n\t.replace(\n\t\t`export const routeStrategies = [];`,\n\t\t`export const routeStrategies = ${JSON.stringify(routeStrategies, null, 2)};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_COOKIE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_COOKIE_STRATEGY_USED = ${allUsedStrategies.has(\"cookie\")};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_URL_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_URL_STRATEGY_USED = ${allUsedStrategies.has(\"url\")};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = ${allUsedStrategies.has(\"globalVariable\")};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = ${allUsedStrategies.has(\"preferredLanguage\")};`\n\t)\n\t.replace(\n\t\t`export const urlPatterns = [];`,\n\t\t`export const urlPatterns = ${JSON.stringify(urlPatterns, null, 2)};`\n\t)\n\t.replace(\n\t\t`export const trailingSlash = undefined;`,\n\t\t`export const trailingSlash = ${\n\t\t\targs.compilerOptions.trailingSlash === undefined\n\t\t\t\t? \"undefined\"\n\t\t\t\t: JSON.stringify(args.compilerOptions.trailingSlash)\n\t\t};`\n\t)\n\t.replace(\n\t\t`export const disableAsyncLocalStorage = false;`,\n\t\t`export const disableAsyncLocalStorage = ${args.compilerOptions.disableAsyncLocalStorage};`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = false;`,\n\t\t`const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = ${defaultUrlPatternUsed};`\n\t)\n\t.replace(\n\t\t`export const experimentalMiddlewareLocaleSplitting = false;`,\n\t\t`export const experimentalMiddlewareLocaleSplitting = ${args.compilerOptions.experimentalMiddlewareLocaleSplitting};`\n\t)\n\t.replace(\n\t\t`export const isServer = typeof window === \"undefined\";`,\n\t\t`export const isServer = ${args.compilerOptions.isServer};`\n\t)\n\t.replace(\n\t\t`export const experimentalStaticLocale = undefined;`,\n\t\targs.compilerOptions.experimentalStaticLocale\n\t\t\t? `export const experimentalStaticLocale = ${\n\t\t\t\t\targs.compilerOptions.experimentalStaticLocale ===\n\t\t\t\t\tperLocaleBuildStaticLocaleExpression\n\t\t\t\t\t\t? args.compilerOptions.experimentalStaticLocale\n\t\t\t\t\t\t: `assertIsLocale(${args.compilerOptions.experimentalStaticLocale})`\n\t\t\t\t};`\n\t\t\t: `export const experimentalStaticLocale = undefined;`\n\t)\n\t.replace(\n\t\t`export const localStorageKey = \"PARAGLIDE_LOCALE\";`,\n\t\t`export const localStorageKey = \"${args.compilerOptions.localStorageKey}\";`\n\t)\n\t.replace(\n\t\t`export const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;`,\n\t\t`const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = ${allUsedStrategies.has(\"localStorage\")};`\n\t)}\n\n/** @type {any} */ (globalThis).__paraglide =\n\t/** @type {any} */ (globalThis).__paraglide ?? {};\n/** @type {any} */ (globalThis).__paraglide.ssr =\n\t/** @type {any} */ (globalThis).__paraglide.ssr ?? {};\n\n${injectCode(\"./get-locale.js\")}\n\n${injectCode(\"./get-text-direction.js\")}\n\n${injectCode(\"./set-locale.js\")}\n\n${injectCode(\"./get-url-origin.js\")}\n\n${injectCode(\"./check-locale.js\")}\n\n${injectCode(\"./normalize-trailing-slash.js\", {\n\tprivateExports: [\"normalizeTrailingSlash\"],\n})}\n\n${\n\tneedsUrlPatternPolyfill\n\t\t? injectCode(\"./url-pattern-cache.js\", {\n\t\t\t\tprivateExports: [\"getUrlPattern\"],\n\t\t\t}) +\n\t\t\t\"\\n\\n\" +\n\t\t\tinjectCode(\"./url-pattern-index.js\", {\n\t\t\t\tprivateExports: [\n\t\t\t\t\t\"getRoutingConfigVersion\",\n\t\t\t\t\t\"currentRoutingConfigVersion\",\n\t\t\t\t\t\"getUrlPatternCandidates\",\n\t\t\t\t\t\"getRouteStrategyCandidates\",\n\t\t\t\t],\n\t\t\t})\n\t\t: `// Default routing does not need a matcher cache or candidate index.\n/** @param {string} pattern @param {URL} url @returns {URLPattern} */\nfunction getUrlPattern(pattern, url) { return new URLPattern(pattern, url.href); }\nfunction getRoutingConfigVersion() { return 0; }\nfunction currentRoutingConfigVersion() { return 0; }\n/** @param {URL} _url @returns {typeof urlPatterns} */\nfunction getUrlPatternCandidates(_url) { return urlPatterns; }\n/** @param {URL} _url @returns {typeof routeStrategies} */\nfunction getRouteStrategyCandidates(_url) { return routeStrategies; }`\n}\n\n${injectCode(\"./exec-url-pattern.js\", {\n\tprivateExports: [\"execUrlPattern\"],\n})}\n\n${injectCode(\"./extract-locale-from-request.js\")}\n\n${injectCode(\"./extract-locale-from-request-async.js\")}\n\n${injectCode(\"./extract-locale-from-cookie.js\", {\n\tprivateExports: [\"clearLocaleCookieCache\"],\n})}\n\n${injectCode(\"./extract-locale-from-header.js\")}\n\n${injectCode(\"./extract-locale-from-navigator.js\")}\n\n${injectCode(\"./extract-locale-from-url.js\")}\n\n${injectCode(\"./localize-url.js\")}\n\n${injectCode(\"./route-strategy.js\")}\n\n${injectCode(\"./should-redirect.js\")}\n\n${injectCode(\"./localize-href.js\")}\n\n${injectCode(\"./track-message-call.js\")}\n\n${injectCode(\"./generate-static-localized-urls.js\")}\n\n${injectCode(\"./strategy.js\")}\n\n${injectCode(\"./type-definitions.js\").replace(\n\t`@typedef {string} Locale`,\n\t`@typedef {typeof locales[number]} Locale`\n)}\n`;\n\n\treturn code;\n}\n\n/**\n * Load a file from the current directory.\n *\n * Prunes the imports on top of the file as the runtime is\n * self-contained.\n *\n * @param {string} path\n * @param {{ privateExports?: string[] }} [options]\n * @returns {string}\n */\nfunction injectCode(\n\tpath: string,\n\toptions?: { privateExports?: string[] }\n): string {\n\tconst code = fs.readFileSync(new URL(path, import.meta.url), \"utf-8\");\n\t// Regex to match single-line and multi-line imports\n\tconst importRegex = /^\\s*import\\s+[\\s\\S]*?from\\s+['\"][^'\"]+['\"]\\s*;?/gm;\n\tconst sourceMapRegex = /\\/\\/# sourceMappingURL=.*$/gm;\n\tconst blockSourceMapRegex = /\\/\\*# sourceMappingURL=.*?\\*\\//g;\n\tlet injected = code\n\t\t.replace(importRegex, \"\")\n\t\t.replace(sourceMapRegex, \"\")\n\t\t.replace(blockSourceMapRegex, \"\")\n\t\t.trim();\n\tfor (const exportName of options?.privateExports ?? []) {\n\t\tinjected = injected.replace(\n\t\t\tnew RegExp(`\\\\bexport\\\\s+function\\\\s+${exportName}\\\\b`, \"g\"),\n\t\t\t`function ${exportName}`\n\t\t);\n\t}\n\treturn injected;\n}\n"]}
@@ -1,7 +1,10 @@
1
1
  import { toLocale } from "./check-locale.js";
2
- import { baseLocale, TREE_SHAKE_DEFAULT_URL_PATTERN_USED, urlPatterns, } from "./variables.js";
2
+ import { baseLocale, TREE_SHAKE_DEFAULT_URL_PATTERN_USED, } from "./variables.js";
3
3
  import { normalizeTrailingSlash } from "./normalize-trailing-slash.js";
4
4
  import { execUrlPattern } from "./exec-url-pattern.js";
5
+ import { getUrlPattern } from "./url-pattern-cache.js";
6
+ import { getUrlPatternCandidates, getRoutingConfigVersion, } from "./url-pattern-index.js";
7
+ let cachedLocaleConfigVersion = -1;
5
8
  /**
6
9
  * If extractLocaleFromUrl is called many times on the same page and the URL
7
10
  * hasn't changed, we don't need to recompute it every time which can get expensive.
@@ -24,7 +27,10 @@ let cachedLocale;
24
27
  */
25
28
  export function extractLocaleFromUrl(url) {
26
29
  const urlString = typeof url === "string" ? url : url.href;
27
- if (cachedUrl === urlString) {
30
+ const configVersion = TREE_SHAKE_DEFAULT_URL_PATTERN_USED
31
+ ? 0
32
+ : getRoutingConfigVersion();
33
+ if (cachedUrl === urlString && cachedLocaleConfigVersion === configVersion) {
28
34
  return cachedLocale;
29
35
  }
30
36
  /** @type {Locale | undefined} */
@@ -38,9 +44,9 @@ export function extractLocaleFromUrl(url) {
38
44
  else {
39
45
  const urlObj = normalizeTrailingSlash(typeof url === "string" ? new URL(url) : new URL(url));
40
46
  // Iterate over URL patterns
41
- for (const element of urlPatterns) {
47
+ for (const element of getUrlPatternCandidates(urlObj)) {
42
48
  for (const [locale, localizedPattern] of element.localized) {
43
- const match = execUrlPattern(new URLPattern(localizedPattern, urlObj.href), urlObj);
49
+ const match = execUrlPattern(getUrlPattern(localizedPattern, urlObj), urlObj);
44
50
  if (match) {
45
51
  result = locale;
46
52
  break;
@@ -50,6 +56,7 @@ export function extractLocaleFromUrl(url) {
50
56
  break;
51
57
  }
52
58
  }
59
+ cachedLocaleConfigVersion = configVersion;
53
60
  cachedUrl = urlString;
54
61
  cachedLocale = result;
55
62
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"extract-locale-from-url.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-url.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EACN,UAAU,EACV,mCAAmC,EACnC,WAAW,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;GAKG;AACH,+BAA+B;AAC/B,IAAI,SAAS,CAAC;AACd,+BAA+B;AAC/B,IAAI,YAAY,CAAC;AAEjB;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAG;IACvC,MAAM,SAAS,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAE3D,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,iCAAiC;IACjC,IAAI,MAAM,CAAC;IACX,IAAI,mCAAmC,EAAE,CAAC;QACzC,MAAM,MAAM,GACX,OAAO,GAAG,KAAK,QAAQ;YACtB,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC;YACpC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,GAAG,8BAA8B,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAG,sBAAsB,CACpC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CACrD,CAAC;QAEF,4BAA4B;QAC5B,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;YACnC,KAAK,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC5D,MAAM,KAAK,GAAG,cAAc,CAC3B,IAAI,UAAU,CAAC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,EAC7C,MAAM,CACN,CAAC;gBAEF,IAAI,KAAK,EAAE,CAAC;oBACX,MAAM,GAAG,MAAM,CAAC;oBAChB,MAAM;gBACP,CAAC;YACF,CAAC;YACD,IAAI,MAAM;gBAAE,MAAM;QACnB,CAAC;IACF,CAAC;IAED,SAAS,GAAG,SAAS,CAAC;IACtB,YAAY,GAAG,MAAM,CAAC;IACtB,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,8BAA8B,CAAC,GAAG;IAC1C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC;AAChD,CAAC","sourcesContent":["import { toLocale } from \"./check-locale.js\";\nimport {\n\tbaseLocale,\n\tTREE_SHAKE_DEFAULT_URL_PATTERN_USED,\n\turlPatterns,\n} from \"./variables.js\";\nimport { normalizeTrailingSlash } from \"./normalize-trailing-slash.js\";\nimport { execUrlPattern } from \"./exec-url-pattern.js\";\n\n/**\n * If extractLocaleFromUrl is called many times on the same page and the URL\n * hasn't changed, we don't need to recompute it every time which can get expensive.\n * We might use a LRU cache if needed, but for now storing only the last result is enough.\n * https://github.com/opral/monorepo/pull/3575#discussion_r2066731243\n */\n/** @type {string|undefined} */\nlet cachedUrl;\n/** @type {Locale|undefined} */\nlet cachedLocale;\n\n/**\n * Extracts the locale from a given URL using native URLPattern.\n *\n * The built-in default `/:locale/...` routing is case-insensitive because it\n * canonicalizes the first path segment with `toLocale()`. Custom `urlPatterns`\n * keep URLPattern's normal exact matching semantics for path segments.\n *\n * @param {URL|string} url - The full URL from which to extract the locale.\n * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.\n */\nexport function extractLocaleFromUrl(url) {\n\tconst urlString = typeof url === \"string\" ? url : url.href;\n\n\tif (cachedUrl === urlString) {\n\t\treturn cachedLocale;\n\t}\n\n\t/** @type {Locale | undefined} */\n\tlet result;\n\tif (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n\t\tconst urlObj =\n\t\t\ttypeof url === \"string\"\n\t\t\t\t? new URL(url, \"http://example.com\")\n\t\t\t\t: new URL(url);\n\t\tresult = defaultUrlPatternExtractLocale(normalizeTrailingSlash(urlObj));\n\t} else {\n\t\tconst urlObj = normalizeTrailingSlash(\n\t\t\ttypeof url === \"string\" ? new URL(url) : new URL(url)\n\t\t);\n\n\t\t// Iterate over URL patterns\n\t\tfor (const element of urlPatterns) {\n\t\t\tfor (const [locale, localizedPattern] of element.localized) {\n\t\t\t\tconst match = execUrlPattern(\n\t\t\t\t\tnew URLPattern(localizedPattern, urlObj.href),\n\t\t\t\t\turlObj\n\t\t\t\t);\n\n\t\t\t\tif (match) {\n\t\t\t\t\tresult = locale;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (result) break;\n\t\t}\n\t}\n\n\tcachedUrl = urlString;\n\tcachedLocale = result;\n\treturn result;\n}\n\n/**\n * https://github.com/opral/inlang-paraglide-js/issues/381\n *\n * @param {URL | string} url - The full URL from which to extract the locale.\n * @returns {Locale | undefined} The extracted locale, or undefined if no locale is found.\n */\nfunction defaultUrlPatternExtractLocale(url) {\n\tconst urlObj = new URL(url, \"http://example.com\");\n\tconst pathSegments = urlObj.pathname.split(\"/\").filter(Boolean);\n\treturn toLocale(pathSegments[0]) || baseLocale;\n}\n"]}
1
+ {"version":3,"file":"extract-locale-from-url.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-url.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EACN,UAAU,EACV,mCAAmC,GACnC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACN,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,IAAI,yBAAyB,GAAG,CAAC,CAAC,CAAC;AAEnC;;;;;GAKG;AACH,+BAA+B;AAC/B,IAAI,SAAS,CAAC;AACd,+BAA+B;AAC/B,IAAI,YAAY,CAAC;AAEjB;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAG;IACvC,MAAM,SAAS,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAE3D,MAAM,aAAa,GAAG,mCAAmC;QACxD,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,uBAAuB,EAAE,CAAC;IAC7B,IAAI,SAAS,KAAK,SAAS,IAAI,yBAAyB,KAAK,aAAa,EAAE,CAAC;QAC5E,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,iCAAiC;IACjC,IAAI,MAAM,CAAC;IACX,IAAI,mCAAmC,EAAE,CAAC;QACzC,MAAM,MAAM,GACX,OAAO,GAAG,KAAK,QAAQ;YACtB,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC;YACpC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,GAAG,8BAA8B,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAG,sBAAsB,CACpC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CACrD,CAAC;QAEF,4BAA4B;QAC5B,KAAK,MAAM,OAAO,IAAI,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;YACvD,KAAK,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC5D,MAAM,KAAK,GAAG,cAAc,CAC3B,aAAa,CAAC,gBAAgB,EAAE,MAAM,CAAC,EACvC,MAAM,CACN,CAAC;gBAEF,IAAI,KAAK,EAAE,CAAC;oBACX,MAAM,GAAG,MAAM,CAAC;oBAChB,MAAM;gBACP,CAAC;YACF,CAAC;YACD,IAAI,MAAM;gBAAE,MAAM;QACnB,CAAC;IACF,CAAC;IAED,yBAAyB,GAAG,aAAa,CAAC;IAC1C,SAAS,GAAG,SAAS,CAAC;IACtB,YAAY,GAAG,MAAM,CAAC;IACtB,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,8BAA8B,CAAC,GAAG;IAC1C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC;AAChD,CAAC","sourcesContent":["import { toLocale } from \"./check-locale.js\";\nimport {\n\tbaseLocale,\n\tTREE_SHAKE_DEFAULT_URL_PATTERN_USED,\n} from \"./variables.js\";\nimport { normalizeTrailingSlash } from \"./normalize-trailing-slash.js\";\nimport { execUrlPattern } from \"./exec-url-pattern.js\";\nimport { getUrlPattern } from \"./url-pattern-cache.js\";\nimport {\n\tgetUrlPatternCandidates,\n\tgetRoutingConfigVersion,\n} from \"./url-pattern-index.js\";\n\nlet cachedLocaleConfigVersion = -1;\n\n/**\n * If extractLocaleFromUrl is called many times on the same page and the URL\n * hasn't changed, we don't need to recompute it every time which can get expensive.\n * We might use a LRU cache if needed, but for now storing only the last result is enough.\n * https://github.com/opral/monorepo/pull/3575#discussion_r2066731243\n */\n/** @type {string|undefined} */\nlet cachedUrl;\n/** @type {Locale|undefined} */\nlet cachedLocale;\n\n/**\n * Extracts the locale from a given URL using native URLPattern.\n *\n * The built-in default `/:locale/...` routing is case-insensitive because it\n * canonicalizes the first path segment with `toLocale()`. Custom `urlPatterns`\n * keep URLPattern's normal exact matching semantics for path segments.\n *\n * @param {URL|string} url - The full URL from which to extract the locale.\n * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.\n */\nexport function extractLocaleFromUrl(url) {\n\tconst urlString = typeof url === \"string\" ? url : url.href;\n\n\tconst configVersion = TREE_SHAKE_DEFAULT_URL_PATTERN_USED\n\t\t? 0\n\t\t: getRoutingConfigVersion();\n\tif (cachedUrl === urlString && cachedLocaleConfigVersion === configVersion) {\n\t\treturn cachedLocale;\n\t}\n\n\t/** @type {Locale | undefined} */\n\tlet result;\n\tif (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n\t\tconst urlObj =\n\t\t\ttypeof url === \"string\"\n\t\t\t\t? new URL(url, \"http://example.com\")\n\t\t\t\t: new URL(url);\n\t\tresult = defaultUrlPatternExtractLocale(normalizeTrailingSlash(urlObj));\n\t} else {\n\t\tconst urlObj = normalizeTrailingSlash(\n\t\t\ttypeof url === \"string\" ? new URL(url) : new URL(url)\n\t\t);\n\n\t\t// Iterate over URL patterns\n\t\tfor (const element of getUrlPatternCandidates(urlObj)) {\n\t\t\tfor (const [locale, localizedPattern] of element.localized) {\n\t\t\t\tconst match = execUrlPattern(\n\t\t\t\t\tgetUrlPattern(localizedPattern, urlObj),\n\t\t\t\t\turlObj\n\t\t\t\t);\n\n\t\t\t\tif (match) {\n\t\t\t\t\tresult = locale;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (result) break;\n\t\t}\n\t}\n\n\tcachedLocaleConfigVersion = configVersion;\n\tcachedUrl = urlString;\n\tcachedLocale = result;\n\treturn result;\n}\n\n/**\n * https://github.com/opral/inlang-paraglide-js/issues/381\n *\n * @param {URL | string} url - The full URL from which to extract the locale.\n * @returns {Locale | undefined} The extracted locale, or undefined if no locale is found.\n */\nfunction defaultUrlPatternExtractLocale(url) {\n\tconst urlObj = new URL(url, \"http://example.com\");\n\tconst pathSegments = urlObj.pathname.split(\"/\").filter(Boolean);\n\treturn toLocale(pathSegments[0]) || baseLocale;\n}\n"]}
@@ -1,7 +1,9 @@
1
1
  import { localizeUrl } from "./localize-url.js";
2
2
  import { normalizeTrailingSlash } from "./normalize-trailing-slash.js";
3
3
  import { execUrlPattern } from "./exec-url-pattern.js";
4
- import { locales, baseLocale, TREE_SHAKE_DEFAULT_URL_PATTERN_USED, trailingSlash, urlPatterns, } from "./variables.js";
4
+ import { getUrlPattern } from "./url-pattern-cache.js";
5
+ import { getUrlPatternCandidates } from "./url-pattern-index.js";
6
+ import { locales, baseLocale, TREE_SHAKE_DEFAULT_URL_PATTERN_USED, trailingSlash, } from "./variables.js";
5
7
  /**
6
8
  * Generates localized URL variants for all provided URLs based on your configured locales and URL patterns.
7
9
  *
@@ -78,10 +80,10 @@ export function generateStaticLocalizedUrls(urls) {
78
80
  const url = normalizeTrailingSlash(new URL(originalUrl));
79
81
  // Try each URL pattern to find one that matches
80
82
  let patternFound = false;
81
- for (const pattern of urlPatterns) {
83
+ for (const pattern of getUrlPatternCandidates(url)) {
82
84
  try {
83
85
  // Try to match the unlocalized pattern
84
- const unlocalizedMatch = execUrlPattern(new URLPattern(pattern.pattern, url.href), url);
86
+ const unlocalizedMatch = execUrlPattern(getUrlPattern(pattern.pattern, url), url);
85
87
  if (!unlocalizedMatch)
86
88
  continue;
87
89
  patternFound = true;
@@ -1 +1 @@
1
- {"version":3,"file":"generate-static-localized-urls.js","sourceRoot":"","sources":["../../../src/compiler/runtime/generate-static-localized-urls.js"],"names":[],"mappings":"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","sourcesContent":["import { localizeUrl } from \"./localize-url.js\";\nimport { normalizeTrailingSlash } from \"./normalize-trailing-slash.js\";\nimport { execUrlPattern } from \"./exec-url-pattern.js\";\nimport {\n\tlocales,\n\tbaseLocale,\n\tTREE_SHAKE_DEFAULT_URL_PATTERN_USED,\n\ttrailingSlash,\n\turlPatterns,\n} from \"./variables.js\";\n\n/**\n * Generates localized URL variants for all provided URLs based on your configured locales and URL patterns.\n *\n * This function is essential for Static Site Generation (SSG) where you need to tell your framework\n * which pages to pre-render at build time. It's also useful for generating sitemaps and\n * `<link rel=\"alternate\" hreflang>` tags for SEO.\n *\n * The function respects your `urlPatterns` configuration - if you have translated pathnames\n * (e.g., `/about` → `/ueber-uns` for German), it will generate the correct localized paths.\n *\n * @see https://paraglidejs.com/static-site-generation\n *\n * @example\n * // Basic usage - generate all locale variants for a list of paths\n * const localizedUrls = generateStaticLocalizedUrls([\n * \"/\",\n * \"/about\",\n * \"/blog/post-1\",\n * ]);\n * // Returns URL objects for each locale:\n * // [\"/en/\", \"/de/\", \"/en/about\", \"/de/about\", \"/en/blog/post-1\", \"/de/blog/post-1\"]\n *\n * @example\n * // Use with framework SSG APIs\n * // SvelteKit\n * export function entries() {\n * const paths = [\"/\", \"/about\", \"/contact\"];\n * return generateStaticLocalizedUrls(paths).map(url => ({\n * locale: extractLocaleFromUrl(url)\n * }));\n * }\n *\n * @example\n * // Sitemap generation\n * const allPages = [\"/\", \"/about\", \"/blog\"];\n * const sitemapUrls = generateStaticLocalizedUrls(allPages);\n *\n * @param {(string | URL)[]} urls - List of canonical URLs or paths to generate localized versions for.\n * Can be absolute URLs (`https://example.com/about`) or paths (`/about`).\n * Paths are resolved against `http://localhost` internally.\n * @returns {URL[]} Array of URL objects representing all localized variants.\n * The order follows each input URL with all its locale variants before moving to the next URL.\n */\nexport function generateStaticLocalizedUrls(urls) {\n\t/** @type {Set<URL>} */\n\tconst localizedUrls = new Set();\n\n\t// For default URL pattern, we can optimize the generation\n\tif (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n\t\tfor (const urlInput of urls) {\n\t\t\tconst originalUrl =\n\t\t\t\turlInput instanceof URL\n\t\t\t\t\t? urlInput\n\t\t\t\t\t: new URL(urlInput, \"http://localhost\");\n\t\t\tconst url =\n\t\t\t\ttrailingSlash === undefined\n\t\t\t\t\t? originalUrl\n\t\t\t\t\t: normalizeTrailingSlash(new URL(originalUrl));\n\n\t\t\t// Base locale doesn't get a prefix\n\t\t\tlocalizedUrls.add(url);\n\n\t\t\t// Other locales get their code as prefix\n\t\t\tfor (const locale of locales) {\n\t\t\t\tif (locale !== baseLocale) {\n\t\t\t\t\tconst localizedPath = `/${locale}${url.pathname}${url.search}${url.hash}`;\n\t\t\t\t\tconst localizedUrl = new URL(localizedPath, url.origin);\n\t\t\t\t\tlocalizedUrls.add(normalizeTrailingSlash(localizedUrl));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn Array.from(localizedUrls);\n\t}\n\n\t// For custom URL patterns, we need to use localizeUrl for each URL and locale\n\tfor (const urlInput of urls) {\n\t\tconst originalUrl =\n\t\t\turlInput instanceof URL\n\t\t\t\t? urlInput\n\t\t\t\t: new URL(urlInput, \"http://localhost\");\n\t\tconst url = normalizeTrailingSlash(new URL(originalUrl));\n\n\t\t// Try each URL pattern to find one that matches\n\t\tlet patternFound = false;\n\t\tfor (const pattern of urlPatterns) {\n\t\t\ttry {\n\t\t\t\t// Try to match the unlocalized pattern\n\t\t\t\tconst unlocalizedMatch = execUrlPattern(\n\t\t\t\t\tnew URLPattern(pattern.pattern, url.href),\n\t\t\t\t\turl\n\t\t\t\t);\n\n\t\t\t\tif (!unlocalizedMatch) continue;\n\n\t\t\t\tpatternFound = true;\n\n\t\t\t\t// Track unique localized URLs to avoid duplicates when patterns are the same\n\t\t\t\tconst seenUrls = new Set();\n\n\t\t\t\t// Generate localized URL for each locale\n\t\t\t\tfor (const [locale] of pattern.localized) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst localizedUrl = localizeUrl(url, { locale });\n\t\t\t\t\t\tconst urlString = localizedUrl.href;\n\n\t\t\t\t\t\t// Only add if we haven't seen this exact URL before\n\t\t\t\t\t\tif (!seenUrls.has(urlString)) {\n\t\t\t\t\t\t\tseenUrls.add(urlString);\n\t\t\t\t\t\t\tlocalizedUrls.add(localizedUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Skip if localization fails for this locale\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t} catch {\n\t\t\t\t// Skip if pattern matching fails\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// If no pattern matched, use the URL as is\n\t\tif (!patternFound) {\n\t\t\tlocalizedUrls.add(originalUrl);\n\t\t}\n\t}\n\n\treturn Array.from(localizedUrls);\n}\n"]}
1
+ {"version":3,"file":"generate-static-localized-urls.js","sourceRoot":"","sources":["../../../src/compiler/runtime/generate-static-localized-urls.js"],"names":[],"mappings":"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","sourcesContent":["import { localizeUrl } from \"./localize-url.js\";\nimport { normalizeTrailingSlash } from \"./normalize-trailing-slash.js\";\nimport { execUrlPattern } from \"./exec-url-pattern.js\";\nimport { getUrlPattern } from \"./url-pattern-cache.js\";\nimport { getUrlPatternCandidates } from \"./url-pattern-index.js\";\nimport {\n\tlocales,\n\tbaseLocale,\n\tTREE_SHAKE_DEFAULT_URL_PATTERN_USED,\n\ttrailingSlash,\n} from \"./variables.js\";\n\n/**\n * Generates localized URL variants for all provided URLs based on your configured locales and URL patterns.\n *\n * This function is essential for Static Site Generation (SSG) where you need to tell your framework\n * which pages to pre-render at build time. It's also useful for generating sitemaps and\n * `<link rel=\"alternate\" hreflang>` tags for SEO.\n *\n * The function respects your `urlPatterns` configuration - if you have translated pathnames\n * (e.g., `/about` → `/ueber-uns` for German), it will generate the correct localized paths.\n *\n * @see https://paraglidejs.com/static-site-generation\n *\n * @example\n * // Basic usage - generate all locale variants for a list of paths\n * const localizedUrls = generateStaticLocalizedUrls([\n * \"/\",\n * \"/about\",\n * \"/blog/post-1\",\n * ]);\n * // Returns URL objects for each locale:\n * // [\"/en/\", \"/de/\", \"/en/about\", \"/de/about\", \"/en/blog/post-1\", \"/de/blog/post-1\"]\n *\n * @example\n * // Use with framework SSG APIs\n * // SvelteKit\n * export function entries() {\n * const paths = [\"/\", \"/about\", \"/contact\"];\n * return generateStaticLocalizedUrls(paths).map(url => ({\n * locale: extractLocaleFromUrl(url)\n * }));\n * }\n *\n * @example\n * // Sitemap generation\n * const allPages = [\"/\", \"/about\", \"/blog\"];\n * const sitemapUrls = generateStaticLocalizedUrls(allPages);\n *\n * @param {(string | URL)[]} urls - List of canonical URLs or paths to generate localized versions for.\n * Can be absolute URLs (`https://example.com/about`) or paths (`/about`).\n * Paths are resolved against `http://localhost` internally.\n * @returns {URL[]} Array of URL objects representing all localized variants.\n * The order follows each input URL with all its locale variants before moving to the next URL.\n */\nexport function generateStaticLocalizedUrls(urls) {\n\t/** @type {Set<URL>} */\n\tconst localizedUrls = new Set();\n\n\t// For default URL pattern, we can optimize the generation\n\tif (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n\t\tfor (const urlInput of urls) {\n\t\t\tconst originalUrl =\n\t\t\t\turlInput instanceof URL\n\t\t\t\t\t? urlInput\n\t\t\t\t\t: new URL(urlInput, \"http://localhost\");\n\t\t\tconst url =\n\t\t\t\ttrailingSlash === undefined\n\t\t\t\t\t? originalUrl\n\t\t\t\t\t: normalizeTrailingSlash(new URL(originalUrl));\n\n\t\t\t// Base locale doesn't get a prefix\n\t\t\tlocalizedUrls.add(url);\n\n\t\t\t// Other locales get their code as prefix\n\t\t\tfor (const locale of locales) {\n\t\t\t\tif (locale !== baseLocale) {\n\t\t\t\t\tconst localizedPath = `/${locale}${url.pathname}${url.search}${url.hash}`;\n\t\t\t\t\tconst localizedUrl = new URL(localizedPath, url.origin);\n\t\t\t\t\tlocalizedUrls.add(normalizeTrailingSlash(localizedUrl));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn Array.from(localizedUrls);\n\t}\n\n\t// For custom URL patterns, we need to use localizeUrl for each URL and locale\n\tfor (const urlInput of urls) {\n\t\tconst originalUrl =\n\t\t\turlInput instanceof URL\n\t\t\t\t? urlInput\n\t\t\t\t: new URL(urlInput, \"http://localhost\");\n\t\tconst url = normalizeTrailingSlash(new URL(originalUrl));\n\n\t\t// Try each URL pattern to find one that matches\n\t\tlet patternFound = false;\n\t\tfor (const pattern of getUrlPatternCandidates(url)) {\n\t\t\ttry {\n\t\t\t\t// Try to match the unlocalized pattern\n\t\t\t\tconst unlocalizedMatch = execUrlPattern(\n\t\t\t\t\tgetUrlPattern(pattern.pattern, url),\n\t\t\t\t\turl\n\t\t\t\t);\n\n\t\t\t\tif (!unlocalizedMatch) continue;\n\n\t\t\t\tpatternFound = true;\n\n\t\t\t\t// Track unique localized URLs to avoid duplicates when patterns are the same\n\t\t\t\tconst seenUrls = new Set();\n\n\t\t\t\t// Generate localized URL for each locale\n\t\t\t\tfor (const [locale] of pattern.localized) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst localizedUrl = localizeUrl(url, { locale });\n\t\t\t\t\t\tconst urlString = localizedUrl.href;\n\n\t\t\t\t\t\t// Only add if we haven't seen this exact URL before\n\t\t\t\t\t\tif (!seenUrls.has(urlString)) {\n\t\t\t\t\t\t\tseenUrls.add(urlString);\n\t\t\t\t\t\t\tlocalizedUrls.add(localizedUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Skip if localization fails for this locale\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t} catch {\n\t\t\t\t// Skip if pattern matching fails\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// If no pattern matched, use the URL as is\n\t\tif (!patternFound) {\n\t\t\tlocalizedUrls.add(originalUrl);\n\t\t}\n\t}\n\n\treturn Array.from(localizedUrls);\n}\n"]}