@inlang/paraglide-js 2.26.0 → 2.28.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 (225) hide show
  1. package/README.md +11 -1
  2. package/dist/bundler-plugins/per-locale-build/index.js +14 -7
  3. package/dist/bundler-plugins/per-locale-build/index.js.map +1 -1
  4. package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +237 -4
  5. package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
  6. package/dist/bundler-plugins/unplugin.d.ts +1 -1
  7. package/dist/bundler-plugins/unplugin.js +79 -10
  8. package/dist/bundler-plugins/unplugin.js.map +1 -1
  9. package/dist/bundler-plugins/unplugin.test.js +334 -1
  10. package/dist/bundler-plugins/unplugin.test.js.map +1 -1
  11. package/dist/bundler-plugins/vite.js +2 -1
  12. package/dist/bundler-plugins/vite.js.map +1 -1
  13. package/dist/bundler-plugins/vite.test.js +1 -1
  14. package/dist/bundler-plugins/vite.test.js.map +1 -1
  15. package/dist/cli/commands/compile/command.js +13 -0
  16. package/dist/cli/commands/compile/command.js.map +1 -1
  17. package/dist/cli/commands/compile/command.test.js +87 -3
  18. package/dist/cli/commands/compile/command.test.js.map +1 -1
  19. package/dist/cli/commands/init/command.d.ts +5 -0
  20. package/dist/cli/commands/init/command.js +216 -44
  21. package/dist/cli/commands/init/command.js.map +1 -1
  22. package/dist/cli/commands/init/command.test.d.ts +1 -0
  23. package/dist/cli/commands/init/command.test.js +123 -0
  24. package/dist/cli/commands/init/command.test.js.map +1 -0
  25. package/dist/cli/defaults.js +2 -2
  26. package/dist/cli/defaults.js.map +1 -1
  27. package/dist/cli/init-options.d.ts +11 -0
  28. package/dist/cli/init-options.js +2 -0
  29. package/dist/cli/init-options.js.map +1 -0
  30. package/dist/cli/steps/add-inlang-check.d.ts +19 -0
  31. package/dist/cli/steps/add-inlang-check.js +60 -0
  32. package/dist/cli/steps/add-inlang-check.js.map +1 -0
  33. package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
  34. package/dist/cli/steps/add-inlang-check.test.js +88 -0
  35. package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
  36. package/dist/cli/steps/add-message-lint.d.ts +34 -0
  37. package/dist/cli/steps/add-message-lint.js +105 -0
  38. package/dist/cli/steps/add-message-lint.js.map +1 -0
  39. package/dist/cli/steps/add-message-lint.test.d.ts +1 -0
  40. package/dist/cli/steps/add-message-lint.test.js +74 -0
  41. package/dist/cli/steps/add-message-lint.test.js.map +1 -0
  42. package/dist/cli/steps/add-vite-plugin.d.ts +18 -0
  43. package/dist/cli/steps/add-vite-plugin.js +34 -6
  44. package/dist/cli/steps/add-vite-plugin.js.map +1 -1
  45. package/dist/cli/steps/add-vite-plugin.test.js +25 -9
  46. package/dist/cli/steps/add-vite-plugin.test.js.map +1 -1
  47. package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
  48. package/dist/cli/steps/agents-md-suggestion.js +19 -0
  49. package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
  50. package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
  51. package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
  52. package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
  53. package/dist/cli/steps/check-for-uncomitted-changes.d.ts +3 -0
  54. package/dist/cli/steps/check-for-uncomitted-changes.js +15 -3
  55. package/dist/cli/steps/check-for-uncomitted-changes.js.map +1 -1
  56. package/dist/cli/steps/detect-bundler.d.ts +1 -0
  57. package/dist/cli/steps/detect-bundler.js +7 -1
  58. package/dist/cli/steps/detect-bundler.js.map +1 -1
  59. package/dist/cli/steps/initialize-inlang-project.d.ts +4 -3
  60. package/dist/cli/steps/initialize-inlang-project.js +60 -157
  61. package/dist/cli/steps/initialize-inlang-project.js.map +1 -1
  62. package/dist/cli/steps/maybe-add-machine-translation.d.ts +4 -0
  63. package/dist/cli/steps/maybe-add-machine-translation.js +14 -8
  64. package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
  65. package/dist/cli/steps/maybe-add-sherlock.d.ts +2 -0
  66. package/dist/cli/steps/maybe-add-sherlock.js +13 -7
  67. package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
  68. package/dist/cli/steps/maybe-add-sherlock.test.d.ts +1 -0
  69. package/dist/cli/steps/maybe-add-sherlock.test.js +44 -0
  70. package/dist/cli/steps/maybe-add-sherlock.test.js.map +1 -0
  71. package/dist/cli/steps/prompt-for-outdir.d.ts +2 -0
  72. package/dist/cli/steps/prompt-for-outdir.js +4 -0
  73. package/dist/cli/steps/prompt-for-outdir.js.map +1 -1
  74. package/dist/cli/steps/update-package-json.js +8 -13
  75. package/dist/cli/steps/update-package-json.js.map +1 -1
  76. package/dist/cli/steps/update-ts-config.d.ts +6 -0
  77. package/dist/cli/steps/update-ts-config.js +27 -4
  78. package/dist/cli/steps/update-ts-config.js.map +1 -1
  79. package/dist/cli/utils.d.ts +11 -0
  80. package/dist/cli/utils.js +21 -0
  81. package/dist/cli/utils.js.map +1 -1
  82. package/dist/cli/utils.test.d.ts +1 -0
  83. package/dist/cli/utils.test.js +16 -0
  84. package/dist/cli/utils.test.js.map +1 -0
  85. package/dist/compiler/compile-annotation.d.ts +48 -1
  86. package/dist/compiler/compile-annotation.js +243 -10
  87. package/dist/compiler/compile-annotation.js.map +1 -1
  88. package/dist/compiler/compile-bundle.d.ts +7 -2
  89. package/dist/compiler/compile-bundle.js +97 -3
  90. package/dist/compiler/compile-bundle.js.map +1 -1
  91. package/dist/compiler/compile-bundle.test.js +232 -19
  92. package/dist/compiler/compile-bundle.test.js.map +1 -1
  93. package/dist/compiler/compile-lifecycle.test.d.ts +1 -0
  94. package/dist/compiler/compile-lifecycle.test.js +69 -0
  95. package/dist/compiler/compile-lifecycle.test.js.map +1 -0
  96. package/dist/compiler/compile-local-variable.d.ts +3 -0
  97. package/dist/compiler/compile-local-variable.js +5 -2
  98. package/dist/compiler/compile-local-variable.js.map +1 -1
  99. package/dist/compiler/compile-local-variable.test.js +55 -15
  100. package/dist/compiler/compile-local-variable.test.js.map +1 -1
  101. package/dist/compiler/compile-message.d.ts +29 -1
  102. package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
  103. package/dist/compiler/compile-message.exact-number.test.js +786 -0
  104. package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
  105. package/dist/compiler/compile-message.js +162 -66
  106. package/dist/compiler/compile-message.js.map +1 -1
  107. package/dist/compiler/compile-message.locals.test.d.ts +1 -0
  108. package/dist/compiler/compile-message.locals.test.js +498 -0
  109. package/dist/compiler/compile-message.locals.test.js.map +1 -0
  110. package/dist/compiler/compile-message.test.js +113 -22
  111. package/dist/compiler/compile-message.test.js.map +1 -1
  112. package/dist/compiler/compile-pattern.d.ts +5 -0
  113. package/dist/compiler/compile-pattern.js +6 -18
  114. package/dist/compiler/compile-pattern.js.map +1 -1
  115. package/dist/compiler/compile-pattern.test.js +169 -5
  116. package/dist/compiler/compile-pattern.test.js.map +1 -1
  117. package/dist/compiler/compile-project.js +5 -1
  118. package/dist/compiler/compile-project.js.map +1 -1
  119. package/dist/compiler/compile-project.test.js +1260 -185
  120. package/dist/compiler/compile-project.test.js.map +1 -1
  121. package/dist/compiler/compile.js +36 -17
  122. package/dist/compiler/compile.js.map +1 -1
  123. package/dist/compiler/compile.test.js +71 -1
  124. package/dist/compiler/compile.test.js.map +1 -1
  125. package/dist/compiler/compiler-options.d.ts +41 -0
  126. package/dist/compiler/compiler-options.js.map +1 -1
  127. package/dist/compiler/create-readme.d.ts +4 -1
  128. package/dist/compiler/create-readme.js +33 -125
  129. package/dist/compiler/create-readme.js.map +1 -1
  130. package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
  131. package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
  132. package/dist/compiler/emit-ts-declarations.test.js +4 -4
  133. package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
  134. package/dist/compiler/index.d.ts +1 -1
  135. package/dist/compiler/index.js +1 -1
  136. package/dist/compiler/index.js.map +1 -1
  137. package/dist/compiler/input-alias.d.ts +21 -0
  138. package/dist/compiler/input-alias.js +42 -0
  139. package/dist/compiler/input-alias.js.map +1 -0
  140. package/dist/compiler/input-alias.test.d.ts +1 -0
  141. package/dist/compiler/input-alias.test.js +58 -0
  142. package/dist/compiler/input-alias.test.js.map +1 -0
  143. package/dist/compiler/message-locals.d.ts +46 -0
  144. package/dist/compiler/message-locals.js +129 -0
  145. package/dist/compiler/message-locals.js.map +1 -0
  146. package/dist/compiler/output-structure/locale-modules.js +7 -1
  147. package/dist/compiler/output-structure/locale-modules.js.map +1 -1
  148. package/dist/compiler/output-structure/locale-modules.test.js +35 -0
  149. package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
  150. package/dist/compiler/output-structure/message-modules.js +6 -4
  151. package/dist/compiler/output-structure/message-modules.js.map +1 -1
  152. package/dist/compiler/output-structure/message-modules.test.js +35 -0
  153. package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
  154. package/dist/compiler/registry.d.ts +12 -0
  155. package/dist/compiler/registry.js +158 -31
  156. package/dist/compiler/registry.js.map +1 -1
  157. package/dist/compiler/registry.test.d.ts +1 -0
  158. package/dist/compiler/registry.test.js +291 -0
  159. package/dist/compiler/registry.test.js.map +1 -0
  160. package/dist/compiler/runtime/create-runtime.d.ts +2 -0
  161. package/dist/compiler/runtime/create-runtime.js +9 -0
  162. package/dist/compiler/runtime/create-runtime.js.map +1 -1
  163. package/dist/compiler/runtime/extract-locale-from-cookie.js +8 -1
  164. package/dist/compiler/runtime/extract-locale-from-cookie.js.map +1 -1
  165. package/dist/compiler/runtime/extract-locale-from-cookie.test.js +26 -0
  166. package/dist/compiler/runtime/extract-locale-from-cookie.test.js.map +1 -1
  167. package/dist/compiler/runtime/extract-locale-from-header.js +47 -5
  168. package/dist/compiler/runtime/extract-locale-from-header.js.map +1 -1
  169. package/dist/compiler/runtime/extract-locale-from-header.test.js +58 -0
  170. package/dist/compiler/runtime/extract-locale-from-header.test.js.map +1 -1
  171. package/dist/compiler/runtime/get-locale.js +7 -1
  172. package/dist/compiler/runtime/get-locale.js.map +1 -1
  173. package/dist/compiler/runtime/get-locale.test.js +95 -0
  174. package/dist/compiler/runtime/get-locale.test.js.map +1 -1
  175. package/dist/compiler/runtime/localize-href.d.ts +8 -0
  176. package/dist/compiler/runtime/localize-href.js +60 -0
  177. package/dist/compiler/runtime/localize-href.js.map +1 -1
  178. package/dist/compiler/runtime/localize-href.test.js +227 -1
  179. package/dist/compiler/runtime/localize-href.test.js.map +1 -1
  180. package/dist/compiler/runtime/set-locale.js +24 -6
  181. package/dist/compiler/runtime/set-locale.js.map +1 -1
  182. package/dist/compiler/runtime/set-locale.test.js +182 -0
  183. package/dist/compiler/runtime/set-locale.test.js.map +1 -1
  184. package/dist/compiler/runtime/type.d.ts +2 -0
  185. package/dist/compiler/runtime/type.js.map +1 -1
  186. package/dist/compiler/runtime/type.test.js +34 -0
  187. package/dist/compiler/runtime/type.test.js.map +1 -1
  188. package/dist/compiler/runtime/variables.d.ts +2 -0
  189. package/dist/compiler/runtime/variables.js +7 -0
  190. package/dist/compiler/runtime/variables.js.map +1 -1
  191. package/dist/compiler/server/create-server-file.js +24 -0
  192. package/dist/compiler/server/create-server-file.js.map +1 -1
  193. package/dist/compiler/server/create-server-file.test.js +8 -2
  194. package/dist/compiler/server/create-server-file.test.js.map +1 -1
  195. package/dist/compiler/server/middleware.d.ts +8 -2
  196. package/dist/compiler/server/middleware.js +204 -11
  197. package/dist/compiler/server/middleware.js.map +1 -1
  198. package/dist/compiler/server/middleware.test.js +750 -3
  199. package/dist/compiler/server/middleware.test.js.map +1 -1
  200. package/dist/eslint/index.d.ts +4 -0
  201. package/dist/eslint/index.js +8 -0
  202. package/dist/eslint/index.js.map +1 -0
  203. package/dist/eslint/no-dynamic-message-access.d.ts +3 -0
  204. package/dist/eslint/no-dynamic-message-access.js +150 -0
  205. package/dist/eslint/no-dynamic-message-access.js.map +1 -0
  206. package/dist/eslint/no-dynamic-message-access.test.d.ts +1 -0
  207. package/dist/eslint/no-dynamic-message-access.test.js +126 -0
  208. package/dist/eslint/no-dynamic-message-access.test.js.map +1 -0
  209. package/dist/eslint/oxlint.test.d.ts +1 -0
  210. package/dist/eslint/oxlint.test.js +64 -0
  211. package/dist/eslint/oxlint.test.js.map +1 -0
  212. package/dist/services/config/config-schema.d.ts +2 -0
  213. package/dist/services/config/config-schema.js +2 -0
  214. package/dist/services/config/config-schema.js.map +1 -1
  215. package/dist/services/config/load-paraglide-config.test.js +12 -0
  216. package/dist/services/config/load-paraglide-config.test.js.map +1 -1
  217. package/dist/services/env-variables/index.js +1 -1
  218. package/dist/services/env-variables/index.js.map +1 -1
  219. package/dist/services/file-handling/write-output.bench.js +51 -11
  220. package/dist/services/file-handling/write-output.bench.js.map +1 -1
  221. package/dist/services/file-handling/write-output.js +60 -20
  222. package/dist/services/file-handling/write-output.js.map +1 -1
  223. package/dist/services/file-handling/write-output.test.js +175 -0
  224. package/dist/services/file-handling/write-output.test.js.map +1 -1
  225. package/package.json +15 -5
@@ -1 +1 @@
1
- {"version":3,"file":"get-locale.test.js","sourceRoot":"","sources":["../../../src/compiler/runtime/get-locale.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { newProject } from \"@inlang/sdk\";\nimport { expect, test, vi } from \"vitest\";\nimport { createParaglide } from \"../create-paraglide.js\";\n\ntest(\"matching by strategy works\", async () => {\n\tconst baseLocale = \"en\";\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale,\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie = \"OTHER_COOKIE=blaba;\";\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(baseLocale);\n});\n\ntest(\"experimentalStaticLocale overrides runtime strategies\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\texperimentalStaticLocale: JSON.stringify(\"de\"),\n\t});\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"invalid experimentalStaticLocale throws during runtime creation\", async () => {\n\tawait expect(\n\t\tcreateParaglide({\n\t\t\tblob: await newProject({\n\t\t\t\tsettings: {\n\t\t\t\t\tbaseLocale: \"en\",\n\t\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t\t},\n\t\t\t}),\n\t\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\t\texperimentalStaticLocale: JSON.stringify(\"fr\"),\n\t\t})\n\t).rejects.toThrow(\"Invalid locale: fr. Expected one of: en, de\");\n});\n\ntest(\"throws if variable is used without baseLocale as fallback strategy\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"globalVariable\"],\n\t});\n\n\texpect(() => runtime.getLocale()).toThrow();\n\n\truntime.setLocale(\"de\");\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"retrieves the locale for a url pattern\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\"],\n\t\tisServer: \"false\",\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.:tld/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.de/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\tglobalThis.window = { location: { href: \"https://example.com/page\" } } as any;\n\n\texpect(runtime.getLocale()).toBe(\"en\");\n\n\tglobalThis.window = { location: { href: \"https://example.de/page\" } } as any;\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"url pattern strategy doesn't throw during SSR\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\", \"baseLocale\"],\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.:tld/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.de/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\texpect(() => runtime.getLocale()).not.toThrow();\n});\n\ntest(\"doesn't throw for an old cookie locale\", async () => {\n\tconst baseLocale = \"en\";\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie = \"PARAGLIDE_LOCALE=fr;\";\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(baseLocale);\n});\n\ntest(\"returns the preferred locale from navigator.languages\", async () => {\n\tconst originalNavigator = globalThis.navigator;\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tisServer: \"false\",\n\t\tstrategy: [\"preferredLanguage\"],\n\t});\n\n\t// Mock navigator.languages\n\tObject.defineProperty(globalThis, \"navigator\", {\n\t\tvalue: {\n\t\t\tlanguages: [\"fr-FR\", \"en-US\", \"de\"],\n\t\t},\n\t\tconfigurable: true,\n\t});\n\n\texpect(runtime.getLocale()).toBe(\"fr\");\n\n\t// Restore original navigator\n\tObject.defineProperty(globalThis, \"navigator\", {\n\t\tvalue: originalNavigator,\n\t\tconfigurable: true,\n\t});\n});\n\ntest(\"returns the locale from local storage\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"localStorage\"],\n\t\tlocalStorageKey: \"PARAGLIDE_LOCALE\",\n\t\tisServer: \"false\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.localStorage = {\n\t\tsetItem: vi.fn(),\n\t\tgetItem: vi.fn(() => \"de\"),\n\t};\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"initially sets the locale after resolving it for the first time\", async () => {\n\t// Create runtime with multiple strategies\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\", \"cookie\"],\n\t\tisServer: \"false\",\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.com/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/en/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.com/de/:path*\"],\n\t\t\t\t\t[\"fr\", \"https://example.com/fr/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\t// Setup global objects for URL strategy\n\tglobalThis.window = {\n\t\t// @ts-expect-error - global variable definition\n\t\tlocation: {\n\t\t\thostname: \"example.com\",\n\t\t\thref: \"https://example.com/de/page\",\n\t\t},\n\t};\n\n\t// Create a spy on the internal _locale variable to verify it was set\n\t// We can do this by checking if setLocale works without explicitly setting it first\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = { cookie: \"\" };\n\n\t// First call to getLocale should resolve and set the locale\n\texpect(runtime.getLocale()).toBe(\"de\");\n\t// Cookie should be set, proving that the locale was initially set\n\texpect(globalThis.document.cookie).toBe(\n\t\t\"PARAGLIDE_LOCALE=de; path=/; max-age=34560000\"\n\t);\n\texpect(globalThis.window.location.href).toBe(\"https://example.com/de/page\");\n});\n\ntest(\"returns locale from custom strategy\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-client\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-client\", {\n\t\tgetLocale: () => \"fr\",\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"fr\");\n});\n\ntest(\"falls back to next strategy when custom strategy returns undefined\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-undefined\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-undefined\", {\n\t\tgetLocale: () => undefined,\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"en\"); // Should fall back to baseLocale\n});\n\ntest(\"throws error if custom strategy returns invalid locale\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-invalid\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-invalid\", {\n\t\tgetLocale: () => \"invalid-locale\",\n\t\tsetLocale: () => {},\n\t});\n\n\texpect(() => runtime.getLocale()).toThrow();\n});\n\ntest(\"custom strategy takes precedence over built-in strategies in getLocale\", async () => {\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = { cookie: \"PARAGLIDE_LOCALE=fr\" };\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-priority\", \"cookie\", \"baseLocale\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-priority\", {\n\t\tgetLocale: () => \"de\",\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"de\"); // Should use custom strategy, not cookie\n});\n\ntest(\"multiple custom strategies work in order in getLocale\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-first\", \"custom-second\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\t// Define two custom strategies\n\truntime.defineCustomClientStrategy(\"custom-first\", {\n\t\tgetLocale: () => undefined, // This one returns undefined\n\t\tsetLocale: () => {},\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-second\", {\n\t\tgetLocale: () => \"fr\", // This one returns a locale\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"fr\"); // Should use second custom strategy\n});\n\ntest(\"custom strategy works with session storage simulation\", async () => {\n\t// Simulate a custom strategy that reads from session storage\n\tlet sessionData = \"de\";\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-session\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-session\", {\n\t\tgetLocale: () => sessionData,\n\t\tsetLocale: (locale) => {\n\t\t\tsessionData = locale;\n\t\t},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"de\");\n});\n\ntest(\"custom strategy integrates with locale initialization\", async () => {\n\t// @ts-expect-error - global variable definition\n\tglobalThis.window = {};\n\n\t// Define a custom strategy that tracks if it was called\n\tlet getLocaleCalled = false;\n\tlet setLocaleCalled = false;\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-tracking\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-tracking\", {\n\t\tgetLocale: () => {\n\t\t\tgetLocaleCalled = true;\n\t\t\treturn \"fr\";\n\t\t},\n\t\tsetLocale: () => {\n\t\t\tsetLocaleCalled = true;\n\t\t},\n\t});\n\n\t// First call should trigger the custom strategy\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"fr\");\n\texpect(getLocaleCalled).toBe(true);\n\n\t// Setting the locale should also call the custom strategy\n\truntime.setLocale(\"de\");\n\n\t// The locale should be set internally after first resolution\n\texpect(setLocaleCalled).toBe(true);\n});\n"]}
1
+ {"version":3,"file":"get-locale.test.js","sourceRoot":"","sources":["../../../src/compiler/runtime/get-locale.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { newProject } from \"@inlang/sdk\";\nimport { expect, test, vi } from \"vitest\";\nimport { createParaglide } from \"../create-paraglide.js\";\n\ntest(\"matching by strategy works\", async () => {\n\tconst baseLocale = \"en\";\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale,\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie = \"OTHER_COOKIE=blaba;\";\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(baseLocale);\n});\n\ntest(\"experimentalStaticLocale overrides runtime strategies\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\texperimentalStaticLocale: JSON.stringify(\"de\"),\n\t});\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"invalid experimentalStaticLocale throws during runtime creation\", async () => {\n\tawait expect(\n\t\tcreateParaglide({\n\t\t\tblob: await newProject({\n\t\t\t\tsettings: {\n\t\t\t\t\tbaseLocale: \"en\",\n\t\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t\t},\n\t\t\t}),\n\t\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\t\texperimentalStaticLocale: JSON.stringify(\"fr\"),\n\t\t})\n\t).rejects.toThrow(\"Invalid locale: fr. Expected one of: en, de\");\n});\n\ntest(\"throws if variable is used without baseLocale as fallback strategy\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"globalVariable\"],\n\t});\n\n\texpect(() => runtime.getLocale()).toThrow();\n\n\truntime.setLocale(\"de\");\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"retrieves the locale for a url pattern\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\"],\n\t\tisServer: \"false\",\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.:tld/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.de/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\tglobalThis.window = { location: { href: \"https://example.com/page\" } } as any;\n\n\texpect(runtime.getLocale()).toBe(\"en\");\n\n\tglobalThis.window = { location: { href: \"https://example.de/page\" } } as any;\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"url pattern strategy doesn't throw during SSR\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\", \"baseLocale\"],\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.:tld/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.de/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\texpect(() => runtime.getLocale()).not.toThrow();\n});\n\ntest(\"doesn't throw for an old cookie locale\", async () => {\n\tconst baseLocale = \"en\";\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie = \"PARAGLIDE_LOCALE=fr;\";\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(baseLocale);\n});\n\ntest(\"returns the preferred locale from navigator.languages\", async () => {\n\tconst originalNavigator = globalThis.navigator;\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tisServer: \"false\",\n\t\tstrategy: [\"preferredLanguage\"],\n\t});\n\n\t// Mock navigator.languages\n\tObject.defineProperty(globalThis, \"navigator\", {\n\t\tvalue: {\n\t\t\tlanguages: [\"fr-FR\", \"en-US\", \"de\"],\n\t\t},\n\t\tconfigurable: true,\n\t});\n\n\texpect(runtime.getLocale()).toBe(\"fr\");\n\n\t// Restore original navigator\n\tObject.defineProperty(globalThis, \"navigator\", {\n\t\tvalue: originalNavigator,\n\t\tconfigurable: true,\n\t});\n});\n\ntest(\"returns the locale from local storage\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"localStorage\"],\n\t\tlocalStorageKey: \"PARAGLIDE_LOCALE\",\n\t\tisServer: \"false\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.localStorage = {\n\t\tsetItem: vi.fn(),\n\t\tgetItem: vi.fn(() => \"de\"),\n\t};\n\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"initially sets the locale after resolving it for the first time\", async () => {\n\t// Create runtime with multiple strategies\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\", \"cookie\"],\n\t\tisServer: \"false\",\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.com/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/en/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.com/de/:path*\"],\n\t\t\t\t\t[\"fr\", \"https://example.com/fr/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\t// Setup global objects for URL strategy\n\tglobalThis.window = {\n\t\t// @ts-expect-error - global variable definition\n\t\tlocation: {\n\t\t\thostname: \"example.com\",\n\t\t\thref: \"https://example.com/de/page\",\n\t\t},\n\t};\n\n\t// Create a spy on the internal _locale variable to verify it was set\n\t// We can do this by checking if setLocale works without explicitly setting it first\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = { cookie: \"\" };\n\n\t// First call to getLocale should resolve and set the locale\n\texpect(runtime.getLocale()).toBe(\"de\");\n\t// Cookie should be set, proving that the locale was initially set\n\texpect(globalThis.document.cookie).toBe(\n\t\t\"PARAGLIDE_LOCALE=de; path=/; max-age=34560000\"\n\t);\n\texpect(globalThis.window.location.href).toBe(\"https://example.com/de/page\");\n});\n\ntest(\"returns locale from custom strategy\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-client\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-client\", {\n\t\tgetLocale: () => \"fr\",\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"fr\");\n});\n\ntest(\"falls back to next strategy when custom strategy returns undefined\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-undefined\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-undefined\", {\n\t\tgetLocale: () => undefined,\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"en\"); // Should fall back to baseLocale\n});\n\ntest(\"throws error if custom strategy returns invalid locale\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-invalid\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-invalid\", {\n\t\tgetLocale: () => \"invalid-locale\",\n\t\tsetLocale: () => {},\n\t});\n\n\texpect(() => runtime.getLocale()).toThrow();\n});\n\ntest(\"custom strategy takes precedence over built-in strategies in getLocale\", async () => {\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = { cookie: \"PARAGLIDE_LOCALE=fr\" };\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-priority\", \"cookie\", \"baseLocale\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-priority\", {\n\t\tgetLocale: () => \"de\",\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"de\"); // Should use custom strategy, not cookie\n});\n\ntest(\"multiple custom strategies work in order in getLocale\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-first\", \"custom-second\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\t// Define two custom strategies\n\truntime.defineCustomClientStrategy(\"custom-first\", {\n\t\tgetLocale: () => undefined, // This one returns undefined\n\t\tsetLocale: () => {},\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-second\", {\n\t\tgetLocale: () => \"fr\", // This one returns a locale\n\t\tsetLocale: () => {},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"fr\"); // Should use second custom strategy\n});\n\ntest(\"custom strategy works with session storage simulation\", async () => {\n\t// Simulate a custom strategy that reads from session storage\n\tlet sessionData = \"de\";\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-session\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-session\", {\n\t\tgetLocale: () => sessionData,\n\t\tsetLocale: (locale) => {\n\t\t\tsessionData = locale;\n\t\t},\n\t});\n\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"de\");\n});\n\ntest(\"custom strategy integrates with locale initialization\", async () => {\n\t// @ts-expect-error - global variable definition\n\tglobalThis.window = {};\n\n\t// Define a custom strategy that tracks if it was called\n\tlet getLocaleCalled = false;\n\tlet setLocaleCalled = false;\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"custom-tracking\"],\n\t\tisServer: \"false\",\n\t});\n\n\truntime.defineCustomClientStrategy(\"custom-tracking\", {\n\t\tgetLocale: () => {\n\t\t\tgetLocaleCalled = true;\n\t\t\treturn \"fr\";\n\t\t},\n\t\tsetLocale: () => {\n\t\t\tsetLocaleCalled = true;\n\t\t},\n\t});\n\n\t// First call should trigger the custom strategy\n\tconst locale = runtime.getLocale();\n\texpect(locale).toBe(\"fr\");\n\texpect(getLocaleCalled).toBe(true);\n\n\t// Setting the locale should also call the custom strategy\n\truntime.setLocale(\"de\");\n\n\t// The locale should be set internally after first resolution\n\texpect(setLocaleCalled).toBe(true);\n});\n\n// sandboxed iframes without allow-same-origin have an opaque origin and throw\n// a SecurityError on document.cookie and localStorage access\ntest(\"resolves the url locale when document.cookie throws\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"url\", \"cookie\"],\n\t\tisServer: \"false\",\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\turlPatterns: [\n\t\t\t{\n\t\t\t\tpattern: \"https://example.com/:path*\",\n\t\t\t\tlocalized: [\n\t\t\t\t\t[\"en\", \"https://example.com/en/:path*\"],\n\t\t\t\t\t[\"de\", \"https://example.com/de/:path*\"],\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\tglobalThis.window = {\n\t\t// @ts-expect-error - global variable definition\n\t\tlocation: {\n\t\t\thostname: \"example.com\",\n\t\t\thref: \"https://example.com/de/page\",\n\t\t},\n\t};\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie(): string {\n\t\t\tthrow new DOMException(\"The operation is insecure.\", \"SecurityError\");\n\t\t},\n\t\tset cookie(_value) {\n\t\t\tthrow new DOMException(\"The operation is insecure.\", \"SecurityError\");\n\t\t},\n\t};\n\n\t// the first resolution also writes the cookie\n\texpect(runtime.getLocale()).toBe(\"de\");\n});\n\ntest(\"falls back to the next strategy when document.cookie throws\", async () => {\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.window = {};\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie(): string {\n\t\t\tthrow new DOMException(\"The operation is insecure.\", \"SecurityError\");\n\t\t},\n\t\tset cookie(_value) {\n\t\t\tthrow new DOMException(\"The operation is insecure.\", \"SecurityError\");\n\t\t},\n\t};\n\n\texpect(runtime.getLocale()).toBe(\"en\");\n});\n\ntest(\"falls back to the next strategy when localStorage throws\", async () => {\n\tconst originalLocalStorage = globalThis.localStorage;\n\n\tconst runtime = await createParaglide({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"localStorage\", \"baseLocale\"],\n\t\tisServer: \"false\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.window = {};\n\t// browsers throw when the localStorage property itself is read\n\tObject.defineProperty(globalThis, \"localStorage\", {\n\t\tget() {\n\t\t\tthrow new DOMException(\"The operation is insecure.\", \"SecurityError\");\n\t\t},\n\t\tconfigurable: true,\n\t});\n\n\texpect(runtime.getLocale()).toBe(\"en\");\n\n\tObject.defineProperty(globalThis, \"localStorage\", {\n\t\tvalue: originalLocalStorage,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t});\n});\n"]}
@@ -28,6 +28,10 @@
28
28
  * // Cross-origin links remain absolute
29
29
  * localizeHref("https://other-site.com/about")
30
30
  * // => "https://other-site.com/de/about"
31
+ *
32
+ * // Protocol-relative links stay protocol-relative
33
+ * localizeHref("//other-site.com/about")
34
+ * // => "//other-site.com/de/about"
31
35
  * ```
32
36
  *
33
37
  * For server-side URL localization (e.g., in middleware), use `localizeUrl()`
@@ -73,6 +77,10 @@ export declare function localizeHref(href: string, options?: {
73
77
  * // Cross-origin links remain absolute
74
78
  * deLocalizeHref("https://example.com/de/about")
75
79
  * // => "https://example.com/about"
80
+ *
81
+ * // Protocol-relative links stay protocol-relative
82
+ * deLocalizeHref("//example.com/de/about")
83
+ * // => "//example.com/about"
76
84
  * ```
77
85
  *
78
86
  * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`
@@ -31,6 +31,10 @@ import { deLocalizeUrl, localizeUrl } from "./localize-url.js";
31
31
  * // Cross-origin links remain absolute
32
32
  * localizeHref("https://other-site.com/about")
33
33
  * // => "https://other-site.com/de/about"
34
+ *
35
+ * // Protocol-relative links stay protocol-relative
36
+ * localizeHref("//other-site.com/about")
37
+ * // => "//other-site.com/de/about"
34
38
  * ```
35
39
  *
36
40
  * For server-side URL localization (e.g., in middleware), use `localizeUrl()`
@@ -46,6 +50,10 @@ export function localizeHref(href, options) {
46
50
  const locale = options?.locale ?? currentLocale;
47
51
  const url = new URL(href, getUrlOrigin());
48
52
  const localized = localizeUrl(url, { locale });
53
+ const protocolRelativeHref = serializeProtocolRelativeHref(href, url, localized);
54
+ if (protocolRelativeHref !== undefined) {
55
+ return protocolRelativeHref;
56
+ }
49
57
  // if the origin is identical and the href is relative,
50
58
  // return the relative path
51
59
  if (href.startsWith("/") && url.origin === localized.origin) {
@@ -94,6 +102,10 @@ export function localizeHref(href, options) {
94
102
  * // Cross-origin links remain absolute
95
103
  * deLocalizeHref("https://example.com/de/about")
96
104
  * // => "https://example.com/about"
105
+ *
106
+ * // Protocol-relative links stay protocol-relative
107
+ * deLocalizeHref("//example.com/de/about")
108
+ * // => "//example.com/about"
97
109
  * ```
98
110
  *
99
111
  * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`
@@ -105,6 +117,10 @@ export function localizeHref(href, options) {
105
117
  export function deLocalizeHref(href) {
106
118
  const url = new URL(href, getUrlOrigin());
107
119
  const deLocalized = deLocalizeUrl(url);
120
+ const protocolRelativeHref = serializeProtocolRelativeHref(href, url, deLocalized);
121
+ if (protocolRelativeHref !== undefined) {
122
+ return protocolRelativeHref;
123
+ }
108
124
  // If the origin is identical and the href is relative,
109
125
  // return the relative path instead of the full URL.
110
126
  if (href.startsWith("/") && url.origin === deLocalized.origin) {
@@ -112,4 +128,48 @@ export function deLocalizeHref(href) {
112
128
  }
113
129
  return deLocalized.href;
114
130
  }
131
+ /**
132
+ * @param {string} href
133
+ * @param {URL} url
134
+ * @param {URL} localized
135
+ * @returns {string | undefined} The serialized href, or undefined if it is not protocol-relative.
136
+ */
137
+ function serializeProtocolRelativeHref(href, url, localized) {
138
+ const first = href.charCodeAt(0);
139
+ const second = href.charCodeAt(1);
140
+ if (first > 0x20 && first !== 0x2f && first !== 0x5c)
141
+ return undefined;
142
+ if (first === 0x2f && second > 0x20 && second !== 0x2f && second !== 0x5c)
143
+ return undefined;
144
+ // URL parsing removes tabs/newlines and trims leading C0 controls and spaces.
145
+ const normalizedHref = href.replace(/[\t\n\r]/g, "");
146
+ let start = 0;
147
+ while (normalizedHref.charCodeAt(start) <= 0x20)
148
+ start++;
149
+ let end = normalizedHref.length;
150
+ while (end > start && normalizedHref.charCodeAt(end - 1) <= 0x20)
151
+ end--;
152
+ const relativeHref = normalizedHref.slice(start, end);
153
+ // Special schemes also treat backslashes as authority separators.
154
+ const specialScheme = /^(https?|wss?|ftp|file):$/.test(url.protocol);
155
+ const separators = specialScheme ? /^[/\\]{2}/ : /^\/\//;
156
+ if (!separators.test(relativeHref))
157
+ return undefined;
158
+ // Keep configured protocol and port changes independent of the page's scheme.
159
+ if (localized.protocol !== url.protocol || localized.port !== url.port) {
160
+ return localized.href;
161
+ }
162
+ // Otherwise leave the scheme to the page, including outside server middleware.
163
+ const result = localized.href.slice(localized.protocol.length);
164
+ if (localized.port || url.protocol === "file:" || !url.hostname)
165
+ return result;
166
+ // URL drops default ports. Recover an explicit port from the original authority.
167
+ const authority = (specialScheme ? relativeHref.replace(/^[/\\]+/, "") : relativeHref.slice(2)).split(specialScheme ? /[/\\?#]/ : /[/?#]/, 1)[0];
168
+ const port = authority?.match(/:(\d+)$/)?.[1];
169
+ if (port === undefined)
170
+ return result;
171
+ const pathStart = result.indexOf("/", 2);
172
+ const authorityEnd = pathStart === -1 ? result.length : pathStart;
173
+ return `${result.slice(0, authorityEnd)}:${Number(port)}${result.slice(authorityEnd)}`;
174
+ }
115
175
  //# sourceMappingURL=localize-href.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"localize-href.js","sourceRoot":"","sources":["../../../src/compiler/runtime/localize-href.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,YAAY,CAAC,IAAI,EAAE,OAAO;IACzC,MAAM,aAAa,GAAG,SAAS,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,aAAa,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAE/C,uDAAuD;IACvD,2BAA2B;IAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QAC7D,sFAAsF;QACtF,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;YAC9B,MAAM,sBAAsB,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC/C,MAAM,EAAE,aAAa;aACrB,CAAC,CAAC;YACH,IAAI,sBAAsB,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;gBACxD,OAAO,SAAS,CAAC,IAAI,CAAC;YACvB,CAAC;QACF,CAAC;QACD,OAAO,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC;IAC/D,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,cAAc,CAAC,IAAI;IAClC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAE1C,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAEvC,uDAAuD;IACvD,oDAAoD;IACpD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;QAC/D,OAAO,WAAW,CAAC,QAAQ,GAAG,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC;IACrE,CAAC;IAED,OAAO,WAAW,CAAC,IAAI,CAAC;AACzB,CAAC","sourcesContent":["import { getLocale } from \"./get-locale.js\";\nimport { getUrlOrigin } from \"./get-url-origin.js\";\nimport { deLocalizeUrl, localizeUrl } from \"./localize-url.js\";\n\n/**\n * High-level URL localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `localizeUrl()` that provides features\n * needed in UI:\n *\n * - Accepts relative paths (e.g., \"/about\")\n * - Returns relative paths when possible\n * - Automatically detects current locale if not specified\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const NavLink = ({ href }) => {\n * // Automatically uses current locale, keeps path relative\n * return <a href={localizeHref(href)}>...</a>;\n * };\n *\n * // Examples:\n * localizeHref(\"/about\")\n * // => \"/de/about\" (if current locale is \"de\")\n * localizeHref(\"/store\", { locale: \"fr\" })\n * // => \"/fr/store\" (explicit locale)\n *\n * // Cross-origin links remain absolute\n * localizeHref(\"https://other-site.com/about\")\n * // => \"https://other-site.com/de/about\"\n * ```\n *\n * For server-side URL localization (e.g., in middleware), use `localizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to localize (can be relative or absolute)\n * @param {object} [options] - Options for localization\n * @param {Locale} [options.locale] - Target locale. If not provided, uses `getLocale()`\n * @returns {string} The localized href, relative if input was relative\n */\nexport function localizeHref(href, options) {\n\tconst currentLocale = getLocale();\n\tconst locale = options?.locale ?? currentLocale;\n\tconst url = new URL(href, getUrlOrigin());\n\n\tconst localized = localizeUrl(url, { locale });\n\n\t// if the origin is identical and the href is relative,\n\t// return the relative path\n\tif (href.startsWith(\"/\") && url.origin === localized.origin) {\n\t\t// check for cross origin localization in which case an absolute URL must be returned.\n\t\tif (locale !== currentLocale) {\n\t\t\tconst localizedCurrentLocale = localizeUrl(url, {\n\t\t\t\tlocale: currentLocale,\n\t\t\t});\n\t\t\tif (localizedCurrentLocale.origin !== localized.origin) {\n\t\t\t\treturn localized.href;\n\t\t\t}\n\t\t}\n\t\treturn localized.pathname + localized.search + localized.hash;\n\t}\n\n\treturn localized.href;\n}\n\n/**\n * High-level URL de-localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `deLocalizeUrl()` that provides features\n * needed in the UI:\n *\n * - Accepts relative paths (e.g., \"/de/about\")\n * - Returns relative paths when possible\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const LocaleSwitcher = ({ href }) => {\n * // Remove locale prefix before switching\n * const baseHref = deLocalizeHref(href);\n * return locales.map(locale =>\n * <a href={localizeHref(baseHref, { locale })}>\n * Switch to {locale}\n * </a>\n * );\n * };\n *\n * // Examples:\n * deLocalizeHref(\"/de/about\") // => \"/about\"\n * deLocalizeHref(\"/fr/store\") // => \"/store\"\n *\n * // Cross-origin links remain absolute\n * deLocalizeHref(\"https://example.com/de/about\")\n * // => \"https://example.com/about\"\n * ```\n *\n * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to de-localize (can be relative or absolute)\n * @returns {string} The de-localized href, relative if input was relative\n */\nexport function deLocalizeHref(href) {\n\tconst url = new URL(href, getUrlOrigin());\n\n\tconst deLocalized = deLocalizeUrl(url);\n\n\t// If the origin is identical and the href is relative,\n\t// return the relative path instead of the full URL.\n\tif (href.startsWith(\"/\") && url.origin === deLocalized.origin) {\n\t\treturn deLocalized.pathname + deLocalized.search + deLocalized.hash;\n\t}\n\n\treturn deLocalized.href;\n}\n"]}
1
+ {"version":3,"file":"localize-href.js","sourceRoot":"","sources":["../../../src/compiler/runtime/localize-href.js"],"names":[],"mappings":"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","sourcesContent":["import { getLocale } from \"./get-locale.js\";\nimport { getUrlOrigin } from \"./get-url-origin.js\";\nimport { deLocalizeUrl, localizeUrl } from \"./localize-url.js\";\n\n/**\n * High-level URL localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `localizeUrl()` that provides features\n * needed in UI:\n *\n * - Accepts relative paths (e.g., \"/about\")\n * - Returns relative paths when possible\n * - Automatically detects current locale if not specified\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const NavLink = ({ href }) => {\n * // Automatically uses current locale, keeps path relative\n * return <a href={localizeHref(href)}>...</a>;\n * };\n *\n * // Examples:\n * localizeHref(\"/about\")\n * // => \"/de/about\" (if current locale is \"de\")\n * localizeHref(\"/store\", { locale: \"fr\" })\n * // => \"/fr/store\" (explicit locale)\n *\n * // Cross-origin links remain absolute\n * localizeHref(\"https://other-site.com/about\")\n * // => \"https://other-site.com/de/about\"\n *\n * // Protocol-relative links stay protocol-relative\n * localizeHref(\"//other-site.com/about\")\n * // => \"//other-site.com/de/about\"\n * ```\n *\n * For server-side URL localization (e.g., in middleware), use `localizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to localize (can be relative or absolute)\n * @param {object} [options] - Options for localization\n * @param {Locale} [options.locale] - Target locale. If not provided, uses `getLocale()`\n * @returns {string} The localized href, relative if input was relative\n */\nexport function localizeHref(href, options) {\n\tconst currentLocale = getLocale();\n\tconst locale = options?.locale ?? currentLocale;\n\tconst url = new URL(href, getUrlOrigin());\n\n\tconst localized = localizeUrl(url, { locale });\n\n\tconst protocolRelativeHref = serializeProtocolRelativeHref(\n\t\thref,\n\t\turl,\n\t\tlocalized\n\t);\n\tif (protocolRelativeHref !== undefined) {\n\t\treturn protocolRelativeHref;\n\t}\n\n\t// if the origin is identical and the href is relative,\n\t// return the relative path\n\tif (href.startsWith(\"/\") && url.origin === localized.origin) {\n\t\t// check for cross origin localization in which case an absolute URL must be returned.\n\t\tif (locale !== currentLocale) {\n\t\t\tconst localizedCurrentLocale = localizeUrl(url, {\n\t\t\t\tlocale: currentLocale,\n\t\t\t});\n\t\t\tif (localizedCurrentLocale.origin !== localized.origin) {\n\t\t\t\treturn localized.href;\n\t\t\t}\n\t\t}\n\t\treturn localized.pathname + localized.search + localized.hash;\n\t}\n\n\treturn localized.href;\n}\n\n/**\n * High-level URL de-localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `deLocalizeUrl()` that provides features\n * needed in the UI:\n *\n * - Accepts relative paths (e.g., \"/de/about\")\n * - Returns relative paths when possible\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const LocaleSwitcher = ({ href }) => {\n * // Remove locale prefix before switching\n * const baseHref = deLocalizeHref(href);\n * return locales.map(locale =>\n * <a href={localizeHref(baseHref, { locale })}>\n * Switch to {locale}\n * </a>\n * );\n * };\n *\n * // Examples:\n * deLocalizeHref(\"/de/about\") // => \"/about\"\n * deLocalizeHref(\"/fr/store\") // => \"/store\"\n *\n * // Cross-origin links remain absolute\n * deLocalizeHref(\"https://example.com/de/about\")\n * // => \"https://example.com/about\"\n *\n * // Protocol-relative links stay protocol-relative\n * deLocalizeHref(\"//example.com/de/about\")\n * // => \"//example.com/about\"\n * ```\n *\n * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to de-localize (can be relative or absolute)\n * @returns {string} The de-localized href, relative if input was relative\n */\nexport function deLocalizeHref(href) {\n\tconst url = new URL(href, getUrlOrigin());\n\n\tconst deLocalized = deLocalizeUrl(url);\n\n\tconst protocolRelativeHref = serializeProtocolRelativeHref(\n\t\thref,\n\t\turl,\n\t\tdeLocalized\n\t);\n\tif (protocolRelativeHref !== undefined) {\n\t\treturn protocolRelativeHref;\n\t}\n\n\t// If the origin is identical and the href is relative,\n\t// return the relative path instead of the full URL.\n\tif (href.startsWith(\"/\") && url.origin === deLocalized.origin) {\n\t\treturn deLocalized.pathname + deLocalized.search + deLocalized.hash;\n\t}\n\n\treturn deLocalized.href;\n}\n\n/**\n * @param {string} href\n * @param {URL} url\n * @param {URL} localized\n * @returns {string | undefined} The serialized href, or undefined if it is not protocol-relative.\n */\nfunction serializeProtocolRelativeHref(href, url, localized) {\n\tconst first = href.charCodeAt(0);\n\tconst second = href.charCodeAt(1);\n\tif (first > 0x20 && first !== 0x2f && first !== 0x5c) return undefined;\n\tif (first === 0x2f && second > 0x20 && second !== 0x2f && second !== 0x5c)\n\t\treturn undefined;\n\n\t// URL parsing removes tabs/newlines and trims leading C0 controls and spaces.\n\tconst normalizedHref = href.replace(/[\\t\\n\\r]/g, \"\");\n\tlet start = 0;\n\twhile (normalizedHref.charCodeAt(start) <= 0x20) start++;\n\tlet end = normalizedHref.length;\n\twhile (end > start && normalizedHref.charCodeAt(end - 1) <= 0x20) end--;\n\tconst relativeHref = normalizedHref.slice(start, end);\n\t// Special schemes also treat backslashes as authority separators.\n\tconst specialScheme = /^(https?|wss?|ftp|file):$/.test(url.protocol);\n\tconst separators = specialScheme ? /^[/\\\\]{2}/ : /^\\/\\//;\n\tif (!separators.test(relativeHref)) return undefined;\n\n\t// Keep configured protocol and port changes independent of the page's scheme.\n\tif (localized.protocol !== url.protocol || localized.port !== url.port) {\n\t\treturn localized.href;\n\t}\n\n\t// Otherwise leave the scheme to the page, including outside server middleware.\n\tconst result = localized.href.slice(localized.protocol.length);\n\tif (localized.port || url.protocol === \"file:\" || !url.hostname)\n\t\treturn result;\n\n\t// URL drops default ports. Recover an explicit port from the original authority.\n\tconst authority = (\n\t\tspecialScheme ? relativeHref.replace(/^[/\\\\]+/, \"\") : relativeHref.slice(2)\n\t).split(specialScheme ? /[/\\\\?#]/ : /[/?#]/, 1)[0];\n\tconst port = authority?.match(/:(\\d+)$/)?.[1];\n\tif (port === undefined) return result;\n\tconst pathStart = result.indexOf(\"/\", 2);\n\tconst authorityEnd = pathStart === -1 ? result.length : pathStart;\n\treturn `${result.slice(0, authorityEnd)}:${Number(port)}${result.slice(authorityEnd)}`;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { test, expect } from "vitest";
1
+ import { test, expect, vi } from "vitest";
2
2
  import { createParaglide } from "../create-paraglide.js";
3
3
  import { newProject } from "@inlang/sdk";
4
4
  test("uses the locale from getLocale() if no locale is provided", async () => {
@@ -46,6 +46,232 @@ test("returns an absolute href if the provided href is absolute", async () => {
46
46
  expect(runtime.localizeHref("http://example.com/hello", { locale: "de" })).toBe("http://example.com/de/hello");
47
47
  expect(runtime.deLocalizeHref("http://example.com/de/hello")).toBe("http://example.com/hello");
48
48
  });
49
+ test("localizeHref preserves protocol-relative authorities", async () => {
50
+ const runtime = await createParaglide({
51
+ blob: await newProject({
52
+ settings: { baseLocale: "en", locales: ["en", "de"] },
53
+ }),
54
+ strategy: ["url", "baseLocale"],
55
+ });
56
+ runtime.overwriteGetLocale(() => "en");
57
+ for (const protocol of ["http", "https"]) {
58
+ runtime.overwriteGetUrlOrigin(() => `${protocol}://app.example.com`);
59
+ for (const prefix of ["//", "/\\", "\\\\", "\\/", "///", "/\\/"]) {
60
+ for (const authority of [
61
+ "cdn.example.com:8443",
62
+ "cdn.example.com:80",
63
+ "cdn.example.com:443",
64
+ "app.example.com",
65
+ "user:p%40ss@app.example.com",
66
+ ]) {
67
+ expect(runtime.localizeHref(`${prefix}${authority}/hello?q=1#section`, {
68
+ locale: "de",
69
+ })).toBe(`//${authority}/de/hello?q=1#section`);
70
+ }
71
+ }
72
+ }
73
+ expect(runtime.localizeHref("/hello?q=1#section", { locale: "de" })).toBe("/de/hello?q=1#section");
74
+ });
75
+ test("deLocalizeHref preserves protocol-relative authorities", async () => {
76
+ const runtime = await createParaglide({
77
+ blob: await newProject({
78
+ settings: { baseLocale: "en", locales: ["en", "de"] },
79
+ }),
80
+ strategy: ["url", "baseLocale"],
81
+ });
82
+ for (const protocol of ["http", "https"]) {
83
+ runtime.overwriteGetUrlOrigin(() => `${protocol}://app.example.com`);
84
+ for (const prefix of ["//", "/\\", "\\\\", "\\/", "///", "/\\/"]) {
85
+ for (const authority of [
86
+ "cdn.example.com:8443",
87
+ "cdn.example.com:80",
88
+ "cdn.example.com:443",
89
+ "app.example.com",
90
+ "user:p%40ss@app.example.com",
91
+ ]) {
92
+ expect(runtime.deLocalizeHref(`${prefix}${authority}/de/hello?q=1#section`)).toBe(`//${authority}/hello?q=1#section`);
93
+ }
94
+ }
95
+ }
96
+ expect(runtime.deLocalizeHref("/de/hello?q=1#section")).toBe("/hello?q=1#section");
97
+ });
98
+ test("classifies protocol-relative hrefs after URL whitespace normalization", async () => {
99
+ const runtime = await createParaglide({
100
+ blob: await newProject({
101
+ settings: { baseLocale: "en", locales: ["en", "de"] },
102
+ }),
103
+ strategy: ["url", "baseLocale"],
104
+ });
105
+ runtime.overwriteGetLocale(() => "en");
106
+ runtime.overwriteGetUrlOrigin(() => "https://app.example.com");
107
+ for (const prefix of [
108
+ "/\t/",
109
+ "/\n/",
110
+ "/\r\\",
111
+ "/\t\\",
112
+ " \t//",
113
+ "\u0000//",
114
+ ]) {
115
+ expect({
116
+ localized: runtime.localizeHref(`${prefix}cdn.example.com/hello`, {
117
+ locale: "de",
118
+ }),
119
+ deLocalized: runtime.deLocalizeHref(`${prefix}cdn.example.com/de/hello`),
120
+ }).toEqual({
121
+ localized: "//cdn.example.com/de/hello",
122
+ deLocalized: "//cdn.example.com/hello",
123
+ });
124
+ }
125
+ expect(runtime.localizeHref("/%2Fcdn.example.com/hello", { locale: "de" })).toBe("/de/%2Fcdn.example.com/hello");
126
+ expect(runtime.deLocalizeHref("/de/%2Fcdn.example.com/hello")).toBe("/%2Fcdn.example.com/hello");
127
+ runtime.overwriteGetUrlOrigin(() => "custom://app.example.com");
128
+ expect(runtime.localizeHref("/\\hello", { locale: "de" })).toBe("/de/\\hello");
129
+ expect(runtime.deLocalizeHref("/de/\\hello")).toBe("/\\hello");
130
+ });
131
+ test.each(["localizeHref", "deLocalizeHref"])("%s does not interpret file path segments as ports", async (helper) => {
132
+ const runtime = await createParaglide({
133
+ blob: await newProject({
134
+ settings: { baseLocale: "en", locales: ["en", "de"] },
135
+ }),
136
+ strategy: ["url", "baseLocale"],
137
+ });
138
+ runtime.overwriteGetLocale(() => "en");
139
+ runtime.overwriteGetUrlOrigin(() => "file:///app/");
140
+ for (const [prefix, expectedPrefix] of [
141
+ ["///", "///"],
142
+ ["/\\/", "///"],
143
+ ["//localhost/", "///"],
144
+ ["//server/", "//server/"],
145
+ ]) {
146
+ const href = `${prefix}docs:80/page?q=1#part`;
147
+ const result = helper === "localizeHref"
148
+ ? runtime.localizeHref(href, { locale: "de" })
149
+ : runtime.deLocalizeHref(href);
150
+ const expected = `${expectedPrefix}${helper === "localizeHref" ? "de/" : ""}docs:80/page?q=1#part`;
151
+ expect(result).toBe(expected);
152
+ expect(new URL(result, "file:///app/").href).toBe(`file:${expected}`);
153
+ }
154
+ });
155
+ test("protocol-relative hrefs do not inherit the server fallback protocol", async () => {
156
+ vi.stubGlobal("window", undefined);
157
+ try {
158
+ const runtime = await createParaglide({
159
+ blob: await newProject({
160
+ settings: { baseLocale: "en", locales: ["en", "de"] },
161
+ }),
162
+ strategy: ["url", "baseLocale"],
163
+ // A distinct option gives these fallback tests a runtime whose origin
164
+ // was not overwritten.
165
+ isServer: "true",
166
+ });
167
+ runtime.overwriteGetLocale(() => "en");
168
+ expect(runtime.getUrlOrigin()).toBe("http://fallback.com");
169
+ for (const prefix of ["//", "/\\"]) {
170
+ const localized = runtime.localizeHref(`${prefix}cdn.example.com/hello`, {
171
+ locale: "de",
172
+ });
173
+ const deLocalized = runtime.deLocalizeHref(`${prefix}cdn.example.com/de/hello`);
174
+ expect({ localized, deLocalized }).toEqual({
175
+ localized: "//cdn.example.com/de/hello",
176
+ deLocalized: "//cdn.example.com/hello",
177
+ });
178
+ expect(new URL(localized, "https://app.example.com").href).toBe("https://cdn.example.com/de/hello");
179
+ expect(new URL(deLocalized, "https://app.example.com").href).toBe("https://cdn.example.com/hello");
180
+ }
181
+ }
182
+ finally {
183
+ vi.unstubAllGlobals();
184
+ }
185
+ });
186
+ test.each(["localizeHref", "deLocalizeHref"])("%s preserves explicit default ports on the server", async (helper) => {
187
+ const runtime = await createParaglide({
188
+ blob: await newProject({
189
+ settings: { baseLocale: "en", locales: ["en", "de"] },
190
+ }),
191
+ strategy: ["url", "baseLocale"],
192
+ isServer: "true",
193
+ });
194
+ runtime.overwriteGetLocale(() => "en");
195
+ expect(runtime.getUrlOrigin()).toBe("http://fallback.com");
196
+ for (const prefix of ["//", "/\\", "/\t/"]) {
197
+ for (const authority of [
198
+ "cdn.example.com:80",
199
+ "cdn.example.com:00080",
200
+ "user:p%40ss@cdn.example.com:80",
201
+ "[::1]:80",
202
+ "user:p%40ss@[::1]:80",
203
+ ]) {
204
+ const input = `${prefix}${authority}${helper === "localizeHref" ? "/docs" : "/de/docs"}?q=1#part`;
205
+ const output = helper === "localizeHref"
206
+ ? runtime.localizeHref(input, { locale: "de" })
207
+ : runtime.deLocalizeHref(input);
208
+ const resolved = new URL(output, "https://app.example.com");
209
+ expect(resolved.port).toBe("80");
210
+ expect(resolved.href).toBe(new URL(`https://${authority}${helper === "localizeHref" ? "/de/docs" : "/docs"}?q=1#part`).href);
211
+ expect(output.startsWith("//")).toBe(true);
212
+ }
213
+ }
214
+ });
215
+ test.each([
216
+ ["80", "8080"],
217
+ ["8080", "80"],
218
+ ])("configured port changes from %s to %s take precedence", async (basePort, localizedPort) => {
219
+ const runtime = await createParaglide({
220
+ blob: await newProject({
221
+ settings: { baseLocale: "en", locales: ["en", "de"] },
222
+ }),
223
+ strategy: ["url", "baseLocale"],
224
+ urlPatterns: [
225
+ {
226
+ pattern: `http://example.com:${basePort}/:path(.*)?`,
227
+ localized: [
228
+ ["en", `http://example.com:${basePort}/:path(.*)?`],
229
+ ["de", `http://de.example.com:${localizedPort}/:path(.*)?`],
230
+ ],
231
+ },
232
+ ],
233
+ });
234
+ runtime.overwriteGetLocale(() => "en");
235
+ runtime.overwriteGetUrlOrigin(() => "http://app.example.com");
236
+ for (const prefix of ["//", "/\\", "/\n/"]) {
237
+ expect(runtime.localizeHref(`${prefix}example.com:${basePort}/docs?q=1#part`, {
238
+ locale: "de",
239
+ })).toBe(new URL(`http://de.example.com:${localizedPort}/docs?q=1#part`).href);
240
+ expect(runtime.deLocalizeHref(`${prefix}de.example.com:${localizedPort}/docs?q=1#part`)).toBe(new URL(`http://example.com:${basePort}/docs?q=1#part`).href);
241
+ }
242
+ });
243
+ test.each(["http", "https"])("protocol-relative hrefs respect domain localization between http and %s", async (protocol) => {
244
+ const runtime = await createParaglide({
245
+ blob: await newProject({
246
+ settings: { baseLocale: "en", locales: ["en", "de"] },
247
+ }),
248
+ strategy: ["url", "baseLocale"],
249
+ urlPatterns: [
250
+ {
251
+ pattern: "http://example.com/:path(.*)?",
252
+ localized: [
253
+ ["en", "http://example.com/:path(.*)?"],
254
+ ["de", `${protocol}://de.example.com/:path(.*)?`],
255
+ ],
256
+ },
257
+ ],
258
+ });
259
+ runtime.overwriteGetLocale(() => "en");
260
+ for (const prefix of ["//", "/\\", "/\t/"]) {
261
+ runtime.overwriteGetUrlOrigin(() => "http://app.example.com");
262
+ expect(runtime.localizeHref(`${prefix}example.com/hello?q=1#section`, {
263
+ locale: "de",
264
+ })).toBe(`${protocol === "http" ? "" : "https:"}//de.example.com/hello?q=1#section`);
265
+ expect(runtime.localizeHref(`${prefix}example.com:80/hello`, { locale: "de" })).toBe(protocol === "http"
266
+ ? "//de.example.com:80/hello"
267
+ : "https://de.example.com/hello");
268
+ runtime.overwriteGetUrlOrigin(() => `${protocol}://app.example.com`);
269
+ expect(runtime.deLocalizeHref(`${prefix}de.example.com/hello?q=1#section`)).toBe(`${protocol === "http" ? "" : "http:"}//example.com/hello?q=1#section`);
270
+ expect(runtime.deLocalizeHref(`${prefix}de.example.com:${protocol === "http" ? "80" : "443"}/hello`)).toBe(protocol === "http"
271
+ ? "//example.com:80/hello"
272
+ : "http://example.com/hello");
273
+ }
274
+ });
49
275
  // useful if domain based localization is used for example
50
276
  test("returns an absolute href if the provided href is relative but the origin of the localized href differs", async () => {
51
277
  const runtime = await createParaglide({