@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.
- package/README.md +11 -1
- package/dist/bundler-plugins/per-locale-build/index.js +14 -7
- package/dist/bundler-plugins/per-locale-build/index.js.map +1 -1
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +237 -4
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
- package/dist/bundler-plugins/unplugin.d.ts +1 -1
- package/dist/bundler-plugins/unplugin.js +79 -10
- package/dist/bundler-plugins/unplugin.js.map +1 -1
- package/dist/bundler-plugins/unplugin.test.js +334 -1
- package/dist/bundler-plugins/unplugin.test.js.map +1 -1
- package/dist/bundler-plugins/vite.js +2 -1
- package/dist/bundler-plugins/vite.js.map +1 -1
- package/dist/bundler-plugins/vite.test.js +1 -1
- package/dist/bundler-plugins/vite.test.js.map +1 -1
- package/dist/cli/commands/compile/command.js +13 -0
- package/dist/cli/commands/compile/command.js.map +1 -1
- package/dist/cli/commands/compile/command.test.js +87 -3
- package/dist/cli/commands/compile/command.test.js.map +1 -1
- package/dist/cli/commands/init/command.d.ts +5 -0
- package/dist/cli/commands/init/command.js +216 -44
- package/dist/cli/commands/init/command.js.map +1 -1
- package/dist/cli/commands/init/command.test.d.ts +1 -0
- package/dist/cli/commands/init/command.test.js +123 -0
- package/dist/cli/commands/init/command.test.js.map +1 -0
- package/dist/cli/defaults.js +2 -2
- package/dist/cli/defaults.js.map +1 -1
- package/dist/cli/init-options.d.ts +11 -0
- package/dist/cli/init-options.js +2 -0
- package/dist/cli/init-options.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.d.ts +19 -0
- package/dist/cli/steps/add-inlang-check.js +60 -0
- package/dist/cli/steps/add-inlang-check.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
- package/dist/cli/steps/add-inlang-check.test.js +88 -0
- package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
- package/dist/cli/steps/add-message-lint.d.ts +34 -0
- package/dist/cli/steps/add-message-lint.js +105 -0
- package/dist/cli/steps/add-message-lint.js.map +1 -0
- package/dist/cli/steps/add-message-lint.test.d.ts +1 -0
- package/dist/cli/steps/add-message-lint.test.js +74 -0
- package/dist/cli/steps/add-message-lint.test.js.map +1 -0
- package/dist/cli/steps/add-vite-plugin.d.ts +18 -0
- package/dist/cli/steps/add-vite-plugin.js +34 -6
- package/dist/cli/steps/add-vite-plugin.js.map +1 -1
- package/dist/cli/steps/add-vite-plugin.test.js +25 -9
- package/dist/cli/steps/add-vite-plugin.test.js.map +1 -1
- package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
- package/dist/cli/steps/agents-md-suggestion.js +19 -0
- package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
- package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
- package/dist/cli/steps/check-for-uncomitted-changes.d.ts +3 -0
- package/dist/cli/steps/check-for-uncomitted-changes.js +15 -3
- package/dist/cli/steps/check-for-uncomitted-changes.js.map +1 -1
- package/dist/cli/steps/detect-bundler.d.ts +1 -0
- package/dist/cli/steps/detect-bundler.js +7 -1
- package/dist/cli/steps/detect-bundler.js.map +1 -1
- package/dist/cli/steps/initialize-inlang-project.d.ts +4 -3
- package/dist/cli/steps/initialize-inlang-project.js +60 -157
- package/dist/cli/steps/initialize-inlang-project.js.map +1 -1
- package/dist/cli/steps/maybe-add-machine-translation.d.ts +4 -0
- package/dist/cli/steps/maybe-add-machine-translation.js +14 -8
- package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.d.ts +2 -0
- package/dist/cli/steps/maybe-add-sherlock.js +13 -7
- package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.test.d.ts +1 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js +44 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js.map +1 -0
- package/dist/cli/steps/prompt-for-outdir.d.ts +2 -0
- package/dist/cli/steps/prompt-for-outdir.js +4 -0
- package/dist/cli/steps/prompt-for-outdir.js.map +1 -1
- package/dist/cli/steps/update-package-json.js +8 -13
- package/dist/cli/steps/update-package-json.js.map +1 -1
- package/dist/cli/steps/update-ts-config.d.ts +6 -0
- package/dist/cli/steps/update-ts-config.js +27 -4
- package/dist/cli/steps/update-ts-config.js.map +1 -1
- package/dist/cli/utils.d.ts +11 -0
- package/dist/cli/utils.js +21 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/utils.test.d.ts +1 -0
- package/dist/cli/utils.test.js +16 -0
- package/dist/cli/utils.test.js.map +1 -0
- package/dist/compiler/compile-annotation.d.ts +48 -1
- package/dist/compiler/compile-annotation.js +243 -10
- package/dist/compiler/compile-annotation.js.map +1 -1
- package/dist/compiler/compile-bundle.d.ts +7 -2
- package/dist/compiler/compile-bundle.js +97 -3
- package/dist/compiler/compile-bundle.js.map +1 -1
- package/dist/compiler/compile-bundle.test.js +232 -19
- package/dist/compiler/compile-bundle.test.js.map +1 -1
- package/dist/compiler/compile-lifecycle.test.d.ts +1 -0
- package/dist/compiler/compile-lifecycle.test.js +69 -0
- package/dist/compiler/compile-lifecycle.test.js.map +1 -0
- package/dist/compiler/compile-local-variable.d.ts +3 -0
- package/dist/compiler/compile-local-variable.js +5 -2
- package/dist/compiler/compile-local-variable.js.map +1 -1
- package/dist/compiler/compile-local-variable.test.js +55 -15
- package/dist/compiler/compile-local-variable.test.js.map +1 -1
- package/dist/compiler/compile-message.d.ts +29 -1
- package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
- package/dist/compiler/compile-message.exact-number.test.js +786 -0
- package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
- package/dist/compiler/compile-message.js +162 -66
- package/dist/compiler/compile-message.js.map +1 -1
- package/dist/compiler/compile-message.locals.test.d.ts +1 -0
- package/dist/compiler/compile-message.locals.test.js +498 -0
- package/dist/compiler/compile-message.locals.test.js.map +1 -0
- package/dist/compiler/compile-message.test.js +113 -22
- package/dist/compiler/compile-message.test.js.map +1 -1
- package/dist/compiler/compile-pattern.d.ts +5 -0
- package/dist/compiler/compile-pattern.js +6 -18
- package/dist/compiler/compile-pattern.js.map +1 -1
- package/dist/compiler/compile-pattern.test.js +169 -5
- package/dist/compiler/compile-pattern.test.js.map +1 -1
- package/dist/compiler/compile-project.js +5 -1
- package/dist/compiler/compile-project.js.map +1 -1
- package/dist/compiler/compile-project.test.js +1260 -185
- package/dist/compiler/compile-project.test.js.map +1 -1
- package/dist/compiler/compile.js +36 -17
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/compile.test.js +71 -1
- package/dist/compiler/compile.test.js.map +1 -1
- package/dist/compiler/compiler-options.d.ts +41 -0
- package/dist/compiler/compiler-options.js.map +1 -1
- package/dist/compiler/create-readme.d.ts +4 -1
- package/dist/compiler/create-readme.js +33 -125
- package/dist/compiler/create-readme.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
- package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.test.js +4 -4
- package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/index.js +1 -1
- package/dist/compiler/index.js.map +1 -1
- package/dist/compiler/input-alias.d.ts +21 -0
- package/dist/compiler/input-alias.js +42 -0
- package/dist/compiler/input-alias.js.map +1 -0
- package/dist/compiler/input-alias.test.d.ts +1 -0
- package/dist/compiler/input-alias.test.js +58 -0
- package/dist/compiler/input-alias.test.js.map +1 -0
- package/dist/compiler/message-locals.d.ts +46 -0
- package/dist/compiler/message-locals.js +129 -0
- package/dist/compiler/message-locals.js.map +1 -0
- package/dist/compiler/output-structure/locale-modules.js +7 -1
- package/dist/compiler/output-structure/locale-modules.js.map +1 -1
- package/dist/compiler/output-structure/locale-modules.test.js +35 -0
- package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +6 -4
- package/dist/compiler/output-structure/message-modules.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.test.js +35 -0
- package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
- package/dist/compiler/registry.d.ts +12 -0
- package/dist/compiler/registry.js +158 -31
- package/dist/compiler/registry.js.map +1 -1
- package/dist/compiler/registry.test.d.ts +1 -0
- package/dist/compiler/registry.test.js +291 -0
- package/dist/compiler/registry.test.js.map +1 -0
- package/dist/compiler/runtime/create-runtime.d.ts +2 -0
- package/dist/compiler/runtime/create-runtime.js +9 -0
- package/dist/compiler/runtime/create-runtime.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js +8 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js +26 -0
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.js +47 -5
- package/dist/compiler/runtime/extract-locale-from-header.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.test.js +58 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.js.map +1 -1
- package/dist/compiler/runtime/get-locale.js +7 -1
- package/dist/compiler/runtime/get-locale.js.map +1 -1
- package/dist/compiler/runtime/get-locale.test.js +95 -0
- package/dist/compiler/runtime/get-locale.test.js.map +1 -1
- package/dist/compiler/runtime/localize-href.d.ts +8 -0
- package/dist/compiler/runtime/localize-href.js +60 -0
- package/dist/compiler/runtime/localize-href.js.map +1 -1
- package/dist/compiler/runtime/localize-href.test.js +227 -1
- package/dist/compiler/runtime/localize-href.test.js.map +1 -1
- package/dist/compiler/runtime/set-locale.js +24 -6
- package/dist/compiler/runtime/set-locale.js.map +1 -1
- package/dist/compiler/runtime/set-locale.test.js +182 -0
- package/dist/compiler/runtime/set-locale.test.js.map +1 -1
- package/dist/compiler/runtime/type.d.ts +2 -0
- package/dist/compiler/runtime/type.js.map +1 -1
- package/dist/compiler/runtime/type.test.js +34 -0
- package/dist/compiler/runtime/type.test.js.map +1 -1
- package/dist/compiler/runtime/variables.d.ts +2 -0
- package/dist/compiler/runtime/variables.js +7 -0
- package/dist/compiler/runtime/variables.js.map +1 -1
- package/dist/compiler/server/create-server-file.js +24 -0
- package/dist/compiler/server/create-server-file.js.map +1 -1
- package/dist/compiler/server/create-server-file.test.js +8 -2
- package/dist/compiler/server/create-server-file.test.js.map +1 -1
- package/dist/compiler/server/middleware.d.ts +8 -2
- package/dist/compiler/server/middleware.js +204 -11
- package/dist/compiler/server/middleware.js.map +1 -1
- package/dist/compiler/server/middleware.test.js +750 -3
- package/dist/compiler/server/middleware.test.js.map +1 -1
- package/dist/eslint/index.d.ts +4 -0
- package/dist/eslint/index.js +8 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.d.ts +3 -0
- package/dist/eslint/no-dynamic-message-access.js +150 -0
- package/dist/eslint/no-dynamic-message-access.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.test.d.ts +1 -0
- package/dist/eslint/no-dynamic-message-access.test.js +126 -0
- package/dist/eslint/no-dynamic-message-access.test.js.map +1 -0
- package/dist/eslint/oxlint.test.d.ts +1 -0
- package/dist/eslint/oxlint.test.js +64 -0
- package/dist/eslint/oxlint.test.js.map +1 -0
- package/dist/services/config/config-schema.d.ts +2 -0
- package/dist/services/config/config-schema.js +2 -0
- package/dist/services/config/config-schema.js.map +1 -1
- package/dist/services/config/load-paraglide-config.test.js +12 -0
- package/dist/services/config/load-paraglide-config.test.js.map +1 -1
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/env-variables/index.js.map +1 -1
- package/dist/services/file-handling/write-output.bench.js +51 -11
- package/dist/services/file-handling/write-output.bench.js.map +1 -1
- package/dist/services/file-handling/write-output.js +60 -20
- package/dist/services/file-handling/write-output.js.map +1 -1
- package/dist/services/file-handling/write-output.test.js +175 -0
- package/dist/services/file-handling/write-output.test.js.map +1 -1
- package/package.json +15 -5
|
@@ -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${\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
|
+
{"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\tcookieSameSite?: CompilerOptions[\"cookieSameSite\"];\n\t\tcookieSecure?: CompilerOptions[\"cookieSecure\"];\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 cookieSecure = args.compilerOptions.cookieSecure ?? false;\n\n\tif (\n\t\targs.compilerOptions.cookieSameSite === \"none\" &&\n\t\tcookieSecure === false\n\t) {\n\t\tthrow new Error(\n\t\t\t`cookieSameSite \"none\" requires cookieSecure to be true or \"auto\". Browsers reject SameSite=None cookies without the Secure attribute.`\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`/** @type {\"lax\" | \"strict\" | \"none\" | undefined} */ (undefined)`,\n\t\t`/** @type {\"lax\" | \"strict\" | \"none\" | undefined} */ (${\n\t\t\targs.compilerOptions.cookieSameSite === undefined\n\t\t\t\t? \"undefined\"\n\t\t\t\t: JSON.stringify(args.compilerOptions.cookieSameSite)\n\t\t})`\n\t)\n\t.replace(\n\t\t`/** @type {boolean | \"auto\"} */ (false)`,\n\t\t`/** @type {boolean | \"auto\"} */ (${JSON.stringify(cookieSecure)})`\n\t)\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"]}
|
|
@@ -34,7 +34,14 @@ export function extractLocaleFromCookie() {
|
|
|
34
34
|
if (cachedLocaleFromCookie !== noCachedLocale) {
|
|
35
35
|
return cachedLocaleFromCookie;
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
let match;
|
|
38
|
+
try {
|
|
39
|
+
match = document.cookie.match(localeCookiePattern);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// document.cookie throws in sandboxed iframes and other opaque origins
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
38
45
|
const locale = match?.[1];
|
|
39
46
|
cachedLocaleFromCookie = toLocale(locale);
|
|
40
47
|
scheduleLocaleCookieCacheClear();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-locale-from-cookie.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-cookie.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC5E,MAAM,mBAAmB,GAAG,IAAI,MAAM,CACrC,cAAc,iBAAiB,UAAU,CACzC,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC;AAChC,yDAAyD;AACzD,IAAI,sBAAsB,GAAG,cAAc,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACrC,sBAAsB,GAAG,cAAc,CAAC;AACzC,CAAC;AAED,SAAS,8BAA8B;IACtC,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE,CAAC;QAC1C,cAAc,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAChD,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACtC,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,OAAO;IACR,CAAC;IACD,IAAI,sBAAsB,KAAK,cAAc,EAAE,CAAC;QAC/C,OAAO,sBAAsB,CAAC;IAC/B,CAAC;IACD,
|
|
1
|
+
{"version":3,"file":"extract-locale-from-cookie.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-cookie.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC5E,MAAM,mBAAmB,GAAG,IAAI,MAAM,CACrC,cAAc,iBAAiB,UAAU,CACzC,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC;AAChC,yDAAyD;AACzD,IAAI,sBAAsB,GAAG,cAAc,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACrC,sBAAsB,GAAG,cAAc,CAAC;AACzC,CAAC;AAED,SAAS,8BAA8B;IACtC,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE,CAAC;QAC1C,cAAc,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAChD,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACtC,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,OAAO;IACR,CAAC;IACD,IAAI,sBAAsB,KAAK,cAAc,EAAE,CAAC;QAC/C,OAAO,sBAAsB,CAAC;IAC/B,CAAC;IACD,IAAI,KAAK,CAAC;IACV,IAAI,CAAC;QACJ,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACR,uEAAuE;QACvE,OAAO;IACR,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1B,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1C,8BAA8B,EAAE,CAAC;IACjC,OAAO,sBAAsB,CAAC;AAC/B,CAAC","sourcesContent":["import { toLocale } from \"./check-locale.js\";\nimport { cookieName } from \"./variables.js\";\n\nconst cookieNamePattern = cookieName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\nconst localeCookiePattern = new RegExp(\n\t`(?:^|;\\\\s*)${cookieNamePattern}=([^;]*)`\n);\n\nconst noCachedLocale = Symbol();\n/** @type {Locale | undefined | typeof noCachedLocale} */\nlet cachedLocaleFromCookie = noCachedLocale;\n\n/**\n * Clears the cached locale from `document.cookie`.\n */\nexport function clearLocaleCookieCache() {\n\tcachedLocaleFromCookie = noCachedLocale;\n}\n\nfunction scheduleLocaleCookieCacheClear() {\n\tif (typeof queueMicrotask === \"function\") {\n\t\tqueueMicrotask(clearLocaleCookieCache);\n\t} else {\n\t\tPromise.resolve().then(clearLocaleCookieCache);\n\t}\n}\n\n/**\n * Extracts a cookie from the document.\n *\n * Will return undefined if the document is not available or if the cookie is not set.\n * The `document` object is not available in server-side rendering, so this function should not be called in that context.\n *\n * @returns {Locale | undefined}\n */\nexport function extractLocaleFromCookie() {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tif (cachedLocaleFromCookie !== noCachedLocale) {\n\t\treturn cachedLocaleFromCookie;\n\t}\n\tlet match;\n\ttry {\n\t\tmatch = document.cookie.match(localeCookiePattern);\n\t} catch {\n\t\t// document.cookie throws in sandboxed iframes and other opaque origins\n\t\treturn;\n\t}\n\tconst locale = match?.[1];\n\tcachedLocaleFromCookie = toLocale(locale);\n\tscheduleLocaleCookieCacheClear();\n\treturn cachedLocaleFromCookie;\n}\n"]}
|
|
@@ -183,4 +183,30 @@ test("returns undefined if the locale is not defined in the locales", async () =
|
|
|
183
183
|
const locale = runtime.extractLocaleFromCookie();
|
|
184
184
|
expect(locale).toBeUndefined();
|
|
185
185
|
});
|
|
186
|
+
// sandboxed iframes without allow-same-origin have an opaque origin and throw
|
|
187
|
+
// a SecurityError when document.cookie is read
|
|
188
|
+
test("returns undefined if reading document.cookie throws", async () => {
|
|
189
|
+
const runtime = await createParaglide({
|
|
190
|
+
blob: await newProject({
|
|
191
|
+
settings: {
|
|
192
|
+
baseLocale: "en",
|
|
193
|
+
locales: ["en", "de"],
|
|
194
|
+
},
|
|
195
|
+
}),
|
|
196
|
+
strategy: ["cookie"],
|
|
197
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
198
|
+
});
|
|
199
|
+
let cookieReadCount = 0;
|
|
200
|
+
// @ts-expect-error - global variable definition
|
|
201
|
+
globalThis.document = {
|
|
202
|
+
get cookie() {
|
|
203
|
+
cookieReadCount += 1;
|
|
204
|
+
throw new DOMException("The operation is insecure.", "SecurityError");
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
expect(runtime.extractLocaleFromCookie()).toBeUndefined();
|
|
208
|
+
expect(runtime.extractLocaleFromCookie()).toBeUndefined();
|
|
209
|
+
// a failed read is not cached
|
|
210
|
+
expect(cookieReadCount).toBe(2);
|
|
211
|
+
});
|
|
186
212
|
//# sourceMappingURL=extract-locale-from-cookie.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-locale-from-cookie.test.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-cookie.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect } from \"vitest\";\nimport { createParaglide } from \"../create-paraglide.js\";\nimport { newProject } from \"@inlang/sdk\";\n\ntest(\"returns undefined if document is not available\", async () => {\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = undefined;\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});\n\n\texpect(runtime.extractLocaleFromCookie()).toBeUndefined();\n});\n\ntest(\"matches the locale of a cookie\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie =\n\t\t\"OTHER_COOKIE=fr; PARAGLIDE_LOCALE=de; ANOTHER_COOKIE=en; EXPIRES_COOKIE=es; Max-Age=3600\";\n\n\tconst locale = runtime.extractLocaleFromCookie();\n\texpect(locale).toBe(\"de\");\n});\n\ntest(\"caches the locale during immediate repeated cookie reads\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie() {\n\t\t\tcookieReadCount += 1;\n\t\t\treturn \"OTHER_COOKIE=fr; PARAGLIDE_LOCALE=de; ANOTHER_COOKIE=en;\";\n\t\t},\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(cookieReadCount).toBe(1);\n});\n\ntest(\"cache expires after a microtask\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\tlet cookie = \"PARAGLIDE_LOCALE=en;\";\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie() {\n\t\t\tcookieReadCount += 1;\n\t\t\treturn cookie;\n\t\t},\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"en\");\n\tcookie = \"PARAGLIDE_LOCALE=de;\";\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"en\");\n\n\tawait Promise.resolve();\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(cookieReadCount).toBe(2);\n});\n\ntest(\"clears the cache after setLocale writes the cookie\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\tisServer: \"false\",\n\t});\n\n\tlet cookie = \"PARAGLIDE_LOCALE=en;\";\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie() {\n\t\t\tcookieReadCount += 1;\n\t\t\treturn cookie;\n\t\t},\n\t\tset cookie(value) {\n\t\t\tcookie = value;\n\t\t},\n\t};\n\t(globalThis as any).window = {\n\t\tlocation: { href: \"https://example.com\", reload() {} },\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"en\");\n\truntime.setLocale(\"de\", { reload: false });\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(cookieReadCount).toBe(2);\n});\n\ntest(\"escapes regex characters in cookie names\", 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\"],\n\t\tcookieName: \"PARAGLIDE.LOCALE[app]\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie =\n\t\t\"PARAGLIDE_LOCALE_APP_=en;PARAGLIDE.LOCALE[app]=de;\";\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n});\n\ntest(\"returns undefined for an empty cookie 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\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\"],\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=de;PARAGLIDE_LOCALE=;\";\n\n\texpect(runtime.extractLocaleFromCookie()).toBeUndefined();\n});\n\ntest(\"canonicalizes cookie locale casing\", 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-CH\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\"],\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=de-ch;\";\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de-CH\");\n});\n\n// useful scenario that avoids throws if the cookie uses an old locale that is\n// not supported anymore or development on localhost shares multiple apps with\n// different locales\ntest(\"returns undefined if the locale is not defined in the locales\", 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\"],\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.extractLocaleFromCookie();\n\texpect(locale).toBeUndefined();\n});\n"]}
|
|
1
|
+
{"version":3,"file":"extract-locale-from-cookie.test.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-cookie.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect } from \"vitest\";\nimport { createParaglide } from \"../create-paraglide.js\";\nimport { newProject } from \"@inlang/sdk\";\n\ntest(\"returns undefined if document is not available\", async () => {\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = undefined;\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});\n\n\texpect(runtime.extractLocaleFromCookie()).toBeUndefined();\n});\n\ntest(\"matches the locale of a cookie\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie =\n\t\t\"OTHER_COOKIE=fr; PARAGLIDE_LOCALE=de; ANOTHER_COOKIE=en; EXPIRES_COOKIE=es; Max-Age=3600\";\n\n\tconst locale = runtime.extractLocaleFromCookie();\n\texpect(locale).toBe(\"de\");\n});\n\ntest(\"caches the locale during immediate repeated cookie reads\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie() {\n\t\t\tcookieReadCount += 1;\n\t\t\treturn \"OTHER_COOKIE=fr; PARAGLIDE_LOCALE=de; ANOTHER_COOKIE=en;\";\n\t\t},\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(cookieReadCount).toBe(1);\n});\n\ntest(\"cache expires after a microtask\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\tlet cookie = \"PARAGLIDE_LOCALE=en;\";\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie() {\n\t\t\tcookieReadCount += 1;\n\t\t\treturn cookie;\n\t\t},\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"en\");\n\tcookie = \"PARAGLIDE_LOCALE=de;\";\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"en\");\n\n\tawait Promise.resolve();\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(cookieReadCount).toBe(2);\n});\n\ntest(\"clears the cache after setLocale writes the cookie\", 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t\tisServer: \"false\",\n\t});\n\n\tlet cookie = \"PARAGLIDE_LOCALE=en;\";\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie() {\n\t\t\tcookieReadCount += 1;\n\t\t\treturn cookie;\n\t\t},\n\t\tset cookie(value) {\n\t\t\tcookie = value;\n\t\t},\n\t};\n\t(globalThis as any).window = {\n\t\tlocation: { href: \"https://example.com\", reload() {} },\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"en\");\n\truntime.setLocale(\"de\", { reload: false });\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n\texpect(cookieReadCount).toBe(2);\n});\n\ntest(\"escapes regex characters in cookie names\", 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\"],\n\t\tcookieName: \"PARAGLIDE.LOCALE[app]\",\n\t});\n\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {};\n\tglobalThis.document.cookie =\n\t\t\"PARAGLIDE_LOCALE_APP_=en;PARAGLIDE.LOCALE[app]=de;\";\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de\");\n});\n\ntest(\"returns undefined for an empty cookie 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\", \"de\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\"],\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=de;PARAGLIDE_LOCALE=;\";\n\n\texpect(runtime.extractLocaleFromCookie()).toBeUndefined();\n});\n\ntest(\"canonicalizes cookie locale casing\", 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-CH\"],\n\t\t\t},\n\t\t}),\n\t\tstrategy: [\"cookie\"],\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=de-ch;\";\n\n\texpect(runtime.extractLocaleFromCookie()).toBe(\"de-CH\");\n});\n\n// useful scenario that avoids throws if the cookie uses an old locale that is\n// not supported anymore or development on localhost shares multiple apps with\n// different locales\ntest(\"returns undefined if the locale is not defined in the locales\", 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\"],\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.extractLocaleFromCookie();\n\texpect(locale).toBeUndefined();\n});\n\n// sandboxed iframes without allow-same-origin have an opaque origin and throw\n// a SecurityError when document.cookie is read\ntest(\"returns undefined if reading 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\"],\n\t\tcookieName: \"PARAGLIDE_LOCALE\",\n\t});\n\n\tlet cookieReadCount = 0;\n\t// @ts-expect-error - global variable definition\n\tglobalThis.document = {\n\t\tget cookie(): string {\n\t\t\tcookieReadCount += 1;\n\t\t\tthrow new DOMException(\"The operation is insecure.\", \"SecurityError\");\n\t\t},\n\t};\n\n\texpect(runtime.extractLocaleFromCookie()).toBeUndefined();\n\texpect(runtime.extractLocaleFromCookie()).toBeUndefined();\n\t// a failed read is not cached\n\texpect(cookieReadCount).toBe(2);\n});\n"]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { toLocale } from "./check-locale.js";
|
|
2
|
+
// qvalue grammar from https://www.rfc-editor.org/rfc/rfc9110#section-12.4.2
|
|
3
|
+
const qvaluePattern = /^(?:0(?:\.\d{0,3})?|1(?:\.0{0,3})?)$/;
|
|
2
4
|
/**
|
|
3
5
|
* Extracts a locale from the accept-language header.
|
|
4
6
|
*
|
|
@@ -15,18 +17,21 @@ export function extractLocaleFromHeader(request) {
|
|
|
15
17
|
const acceptLanguageHeader = request.headers.get("accept-language");
|
|
16
18
|
if (acceptLanguageHeader) {
|
|
17
19
|
// Parse language preferences with their q-values and base language codes
|
|
18
|
-
const languages = acceptLanguageHeader
|
|
19
|
-
.split(",")
|
|
20
|
+
const languages = splitOutsideQuotes(acceptLanguageHeader, ",")
|
|
20
21
|
.map((lang) => {
|
|
21
|
-
const [tag
|
|
22
|
+
const [tag = "", ...params] = splitOutsideQuotes(lang, ";").map((p) => p.trim());
|
|
23
|
+
const weight = params.find((param) => /^q(?:\s|=|$)/i.test(param));
|
|
24
|
+
const q = weight ? weight.replace(/^q\s*=\s*/i, "") : "1";
|
|
22
25
|
// Get both the full tag and base language code
|
|
23
|
-
const baseTag = tag
|
|
26
|
+
const baseTag = tag.split("-")[0];
|
|
24
27
|
return {
|
|
25
28
|
fullTag: tag,
|
|
26
29
|
baseTag,
|
|
27
|
-
q: Number(q),
|
|
30
|
+
q: qvaluePattern.test(q) ? Number(q) : 0,
|
|
28
31
|
};
|
|
29
32
|
})
|
|
33
|
+
// Skip ranges that are not acceptable (q=0) or have an invalid weight
|
|
34
|
+
.filter((lang) => lang.q > 0)
|
|
30
35
|
.sort((a, b) => b.q - a.q);
|
|
31
36
|
for (const lang of languages) {
|
|
32
37
|
const fullLocale = toLocale(lang.fullTag);
|
|
@@ -42,4 +47,41 @@ export function extractLocaleFromHeader(request) {
|
|
|
42
47
|
}
|
|
43
48
|
return undefined;
|
|
44
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Splits on a separator that is not inside a quoted string, since parameter
|
|
52
|
+
* values may be quoted strings that contain `,` or `;`.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} value
|
|
55
|
+
* @param {string} separator
|
|
56
|
+
* @returns {string[]}
|
|
57
|
+
*/
|
|
58
|
+
function splitOutsideQuotes(value, separator) {
|
|
59
|
+
/** @type {string[]} */
|
|
60
|
+
const parts = [];
|
|
61
|
+
let start = 0;
|
|
62
|
+
// Index of the quote that opened the current quoted string, or -1
|
|
63
|
+
let quoteStart = -1;
|
|
64
|
+
for (let i = 0; i < value.length; i++) {
|
|
65
|
+
const char = value[i];
|
|
66
|
+
if (quoteStart !== -1 && char === "\\") {
|
|
67
|
+
i++;
|
|
68
|
+
}
|
|
69
|
+
else if (char === '"') {
|
|
70
|
+
quoteStart = quoteStart === -1 ? i : -1;
|
|
71
|
+
}
|
|
72
|
+
else if (quoteStart === -1 && char === separator) {
|
|
73
|
+
parts.push(value.slice(start, i));
|
|
74
|
+
start = i + 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (quoteStart === -1) {
|
|
78
|
+
parts.push(value.slice(start));
|
|
79
|
+
return parts;
|
|
80
|
+
}
|
|
81
|
+
// A quote that is never closed would swallow everything after it, so only
|
|
82
|
+
// the text from that quote on is split as if it weren't quoted
|
|
83
|
+
const [rest = "", ...tail] = value.slice(quoteStart).split(separator);
|
|
84
|
+
parts.push(value.slice(start, quoteStart) + rest, ...tail);
|
|
85
|
+
return parts;
|
|
86
|
+
}
|
|
45
87
|
//# sourceMappingURL=extract-locale-from-header.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-locale-from-header.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-header.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAO;IAC9C,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACpE,IAAI,oBAAoB,EAAE,CAAC;QAC1B,yEAAyE;QACzE,MAAM,SAAS,GAAG,oBAAoB
|
|
1
|
+
{"version":3,"file":"extract-locale-from-header.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-header.js"],"names":[],"mappings":"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","sourcesContent":["import { toLocale } from \"./check-locale.js\";\n\n// qvalue grammar from https://www.rfc-editor.org/rfc/rfc9110#section-12.4.2\nconst qvaluePattern = /^(?:0(?:\\.\\d{0,3})?|1(?:\\.0{0,3})?)$/;\n\n/**\n * Extracts a locale from the accept-language header.\n *\n * Use the function on the server to extract the locale\n * from the accept-language header that is sent by the client.\n *\n * @example\n * const locale = extractLocaleFromHeader(request);\n *\n * @param {Request} request - The request object to extract the locale from.\n * @returns {Locale | undefined} The negotiated preferred language.\n */\nexport function extractLocaleFromHeader(request) {\n\tconst acceptLanguageHeader = request.headers.get(\"accept-language\");\n\tif (acceptLanguageHeader) {\n\t\t// Parse language preferences with their q-values and base language codes\n\t\tconst languages = splitOutsideQuotes(acceptLanguageHeader, \",\")\n\t\t\t.map((lang) => {\n\t\t\t\tconst [tag = \"\", ...params] = splitOutsideQuotes(lang, \";\").map((p) =>\n\t\t\t\t\tp.trim()\n\t\t\t\t);\n\t\t\t\tconst weight = params.find((param) => /^q(?:\\s|=|$)/i.test(param));\n\t\t\t\tconst q = weight ? weight.replace(/^q\\s*=\\s*/i, \"\") : \"1\";\n\t\t\t\t// Get both the full tag and base language code\n\t\t\t\tconst baseTag = tag.split(\"-\")[0];\n\t\t\t\treturn {\n\t\t\t\t\tfullTag: tag,\n\t\t\t\t\tbaseTag,\n\t\t\t\t\tq: qvaluePattern.test(q) ? Number(q) : 0,\n\t\t\t\t};\n\t\t\t})\n\t\t\t// Skip ranges that are not acceptable (q=0) or have an invalid weight\n\t\t\t.filter((lang) => lang.q > 0)\n\t\t\t.sort((a, b) => b.q - a.q);\n\n\t\tfor (const lang of languages) {\n\t\t\tconst fullLocale = toLocale(lang.fullTag);\n\t\t\tif (fullLocale) {\n\t\t\t\treturn fullLocale;\n\t\t\t}\n\n\t\t\tconst baseLocale = toLocale(lang.baseTag);\n\t\t\tif (baseLocale) {\n\t\t\t\treturn baseLocale;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Splits on a separator that is not inside a quoted string, since parameter\n * values may be quoted strings that contain `,` or `;`.\n *\n * @param {string} value\n * @param {string} separator\n * @returns {string[]}\n */\nfunction splitOutsideQuotes(value, separator) {\n\t/** @type {string[]} */\n\tconst parts = [];\n\tlet start = 0;\n\t// Index of the quote that opened the current quoted string, or -1\n\tlet quoteStart = -1;\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst char = value[i];\n\t\tif (quoteStart !== -1 && char === \"\\\\\") {\n\t\t\ti++;\n\t\t} else if (char === '\"') {\n\t\t\tquoteStart = quoteStart === -1 ? i : -1;\n\t\t} else if (quoteStart === -1 && char === separator) {\n\t\t\tparts.push(value.slice(start, i));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\tif (quoteStart === -1) {\n\t\tparts.push(value.slice(start));\n\t\treturn parts;\n\t}\n\t// A quote that is never closed would swallow everything after it, so only\n\t// the text from that quote on is split as if it weren't quoted\n\tconst [rest = \"\", ...tail] = value.slice(quoteStart).split(separator);\n\tparts.push(value.slice(start, quoteStart) + rest, ...tail);\n\treturn parts;\n}\n"]}
|
|
@@ -65,4 +65,62 @@ test("canonicalizes matched locale from Accept-Language header", async () => {
|
|
|
65
65
|
});
|
|
66
66
|
expect(runtime.extractLocaleFromHeader(request)).toBe("pt-BR");
|
|
67
67
|
});
|
|
68
|
+
// https://www.rfc-editor.org/rfc/rfc9110#section-12.4.2
|
|
69
|
+
test.each([
|
|
70
|
+
// q=0 means "not acceptable"
|
|
71
|
+
{ header: "fr;q=0", expected: undefined },
|
|
72
|
+
{ header: "fr;q=0.000, nl", expected: undefined },
|
|
73
|
+
// whitespace, uppercase Q and other parameters, with the weight still applied
|
|
74
|
+
{ header: "fr; q=0.5, de;q=0.4", expected: "fr" },
|
|
75
|
+
{ header: "fr; q=0.5, de;q=0.8", expected: "de" },
|
|
76
|
+
{ header: "fr ; q = 0.5, de;q=0.4", expected: "fr" },
|
|
77
|
+
{ header: "fr ; q = 0.5, de;q=0.8", expected: "de" },
|
|
78
|
+
{ header: "fr;Q=0.9, de;q=0.8", expected: "fr" },
|
|
79
|
+
{ header: "fr;Q=0.5, de;q=0.8", expected: "de" },
|
|
80
|
+
{ header: "fr;level=1;q=0.9, de;q=0.8", expected: "fr" },
|
|
81
|
+
{ header: "fr;level=1;q=0.5, de;q=0.8", expected: "de" },
|
|
82
|
+
// delimiters inside quoted parameter values
|
|
83
|
+
{ header: 'fr;note="x;q=1;y";q=0, de;q=0.5', expected: "de" },
|
|
84
|
+
{ header: 'fr;note="x;q=0;y";q=0.9, de;q=0.5', expected: "fr" },
|
|
85
|
+
{ header: 'fr;note="a,b";q=0.5, de;q=0.8', expected: "de" },
|
|
86
|
+
{ header: 'fr;note="a\\";q=0";q=0.9, de;q=0.5', expected: "fr" },
|
|
87
|
+
// an unclosed quote neither hides later ranges nor changes earlier ones
|
|
88
|
+
{ header: 'en", fr', expected: "fr" },
|
|
89
|
+
{ header: 'fr";q=0.9, de', expected: "de" },
|
|
90
|
+
{ header: 'fr;note="a,b";q=0, de;q=0.5, en"', expected: "de" },
|
|
91
|
+
{ header: 'fr;note="a,b";q=2, de;q=0.5, en"', expected: "de" },
|
|
92
|
+
{ header: 'nl;note="x,fr,y";q=0, de;q=0.5, en"', expected: "de" },
|
|
93
|
+
// weights outside the qvalue grammar
|
|
94
|
+
{ header: "fr;q=abc, de;q=0.5", expected: "de" },
|
|
95
|
+
{ header: "fr;q=2, de;q=0.5", expected: "de" },
|
|
96
|
+
{ header: "fr;q=-1", expected: undefined },
|
|
97
|
+
{ header: "fr;q=0.1234", expected: undefined },
|
|
98
|
+
{ header: "fr;q=1.001", expected: undefined },
|
|
99
|
+
{ header: "fr;q=1.0000", expected: undefined },
|
|
100
|
+
{ header: "fr;q=.5, de;q=0.4", expected: "de" },
|
|
101
|
+
{ header: "fr;q, de;q=0.5", expected: "de" },
|
|
102
|
+
{ header: "de;q 0,en;q=0.5", expected: "en" },
|
|
103
|
+
{ header: "fr;q 0.5, de;q=0.4", expected: "de" },
|
|
104
|
+
{ header: "fr;q=, de;q=0.5", expected: "de" },
|
|
105
|
+
// valid weights and ties
|
|
106
|
+
{ header: "fr;q=1.000, de;q=0.5", expected: "fr" },
|
|
107
|
+
{ header: "fr;q=1., de;q=0.5", expected: "fr" },
|
|
108
|
+
{ header: "fr;q=0.001", expected: "fr" },
|
|
109
|
+
{ header: "fr;q=0.8, de;q=0.8", expected: "fr" },
|
|
110
|
+
])("applies Accept-Language quality values in $header", async ({ header, expected }) => {
|
|
111
|
+
const runtime = await createParaglide({
|
|
112
|
+
blob: await newProject({
|
|
113
|
+
settings: {
|
|
114
|
+
baseLocale: "en",
|
|
115
|
+
locales: ["en", "fr", "de"],
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
});
|
|
119
|
+
const request = new Request("http://example.com", {
|
|
120
|
+
headers: {
|
|
121
|
+
"Accept-Language": header,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
expect(runtime.extractLocaleFromHeader(request)).toBe(expected);
|
|
125
|
+
});
|
|
68
126
|
//# sourceMappingURL=extract-locale-from-header.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-locale-from-header.test.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-header.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,IAAI,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC;QACrC,IAAI,EAAE,MAAM,UAAU,CAAC;YACtB,QAAQ,EAAE;gBACT,UAAU,EAAE,IAAI;gBAChB,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;aAC3B;SACD,CAAC;KACF,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,oBAAoB,EAAE;QACjD,OAAO,EAAE;YACR,iBAAiB,EAAE,+BAA+B;SAClD;KACD,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE1B,qBAAqB;IACrB,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,oBAAoB,EAAE;QAClD,OAAO,EAAE;YACR,iBAAiB,EAAE,+BAA+B;SAClD;KACD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAC1D,+EAA+E;IAC/E,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE3B,WAAW;IACX,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,oBAAoB,EAAE;QAClD,OAAO,EAAE;YACR,iBAAiB,EAAE,mBAAmB;SACtC;KACD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;AACjC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;IAC5E,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC;QACrC,IAAI,EAAE,MAAM,UAAU,CAAC;YACtB,QAAQ,EAAE;gBACT,UAAU,EAAE,IAAI;gBAChB,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;aAC3B;SACD,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;IAC3E,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC;QACrC,IAAI,EAAE,MAAM,UAAU,CAAC;YACtB,QAAQ,EAAE;gBACT,UAAU,EAAE,IAAI;gBAChB,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;aACxB;SACD,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,oBAAoB,EAAE;QACjD,OAAO,EAAE;YACR,iBAAiB,EAAE,iBAAiB;SACpC;KACD,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC","sourcesContent":["import { test, expect } from \"vitest\";\nimport { createParaglide } from \"../create-paraglide.js\";\nimport { newProject } from \"@inlang/sdk\";\n\ntest(\"returns the preferred locale from Accept-Language header\", 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});\n\n\t// simple direct match\n\tconst request = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"en-US;q=0.8,fr;q=0.9,de;q=0.6\",\n\t\t},\n\t});\n\tconst locale = runtime.extractLocaleFromHeader(request);\n\texpect(locale).toBe(\"fr\");\n\n\t// language tag match\n\tconst request2 = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"en-US;q=0.8,nl;q=0.9,de;q=0.7\",\n\t\t},\n\t});\n\tconst locale2 = runtime.extractLocaleFromHeader(request2);\n\t// Since \"nl\" isn't in our locales, and \"de\" has the highest q-value after \"nl\"\n\texpect(locale2).toBe(\"en\");\n\n\t// no match\n\tconst request3 = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"nl;q=0.9,es;q=0.6\",\n\t\t},\n\t});\n\tconst locale3 = runtime.extractLocaleFromHeader(request3);\n\texpect(locale3).toBeUndefined();\n});\n\ntest(\"returns undefined if no Accept-Language header is present\", 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});\n\n\tconst request = new Request(\"http://example.com\");\n\tconst locale = runtime.extractLocaleFromHeader(request);\n\texpect(locale).toBeUndefined();\n});\n\ntest(\"canonicalizes matched locale from Accept-Language header\", 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\", \"pt-BR\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tconst request = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"pt-br, en;q=0.8\",\n\t\t},\n\t});\n\n\texpect(runtime.extractLocaleFromHeader(request)).toBe(\"pt-BR\");\n});\n"]}
|
|
1
|
+
{"version":3,"file":"extract-locale-from-header.test.js","sourceRoot":"","sources":["../../../src/compiler/runtime/extract-locale-from-header.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect } from \"vitest\";\nimport { createParaglide } from \"../create-paraglide.js\";\nimport { newProject } from \"@inlang/sdk\";\n\ntest(\"returns the preferred locale from Accept-Language header\", 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});\n\n\t// simple direct match\n\tconst request = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"en-US;q=0.8,fr;q=0.9,de;q=0.6\",\n\t\t},\n\t});\n\tconst locale = runtime.extractLocaleFromHeader(request);\n\texpect(locale).toBe(\"fr\");\n\n\t// language tag match\n\tconst request2 = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"en-US;q=0.8,nl;q=0.9,de;q=0.7\",\n\t\t},\n\t});\n\tconst locale2 = runtime.extractLocaleFromHeader(request2);\n\t// Since \"nl\" isn't in our locales, and \"de\" has the highest q-value after \"nl\"\n\texpect(locale2).toBe(\"en\");\n\n\t// no match\n\tconst request3 = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"nl;q=0.9,es;q=0.6\",\n\t\t},\n\t});\n\tconst locale3 = runtime.extractLocaleFromHeader(request3);\n\texpect(locale3).toBeUndefined();\n});\n\ntest(\"returns undefined if no Accept-Language header is present\", 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});\n\n\tconst request = new Request(\"http://example.com\");\n\tconst locale = runtime.extractLocaleFromHeader(request);\n\texpect(locale).toBeUndefined();\n});\n\ntest(\"canonicalizes matched locale from Accept-Language header\", 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\", \"pt-BR\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tconst request = new Request(\"http://example.com\", {\n\t\theaders: {\n\t\t\t\"Accept-Language\": \"pt-br, en;q=0.8\",\n\t\t},\n\t});\n\n\texpect(runtime.extractLocaleFromHeader(request)).toBe(\"pt-BR\");\n});\n\n// https://www.rfc-editor.org/rfc/rfc9110#section-12.4.2\ntest.each([\n\t// q=0 means \"not acceptable\"\n\t{ header: \"fr;q=0\", expected: undefined },\n\t{ header: \"fr;q=0.000, nl\", expected: undefined },\n\t// whitespace, uppercase Q and other parameters, with the weight still applied\n\t{ header: \"fr; q=0.5, de;q=0.4\", expected: \"fr\" },\n\t{ header: \"fr; q=0.5, de;q=0.8\", expected: \"de\" },\n\t{ header: \"fr ; q = 0.5, de;q=0.4\", expected: \"fr\" },\n\t{ header: \"fr ; q = 0.5, de;q=0.8\", expected: \"de\" },\n\t{ header: \"fr;Q=0.9, de;q=0.8\", expected: \"fr\" },\n\t{ header: \"fr;Q=0.5, de;q=0.8\", expected: \"de\" },\n\t{ header: \"fr;level=1;q=0.9, de;q=0.8\", expected: \"fr\" },\n\t{ header: \"fr;level=1;q=0.5, de;q=0.8\", expected: \"de\" },\n\t// delimiters inside quoted parameter values\n\t{ header: 'fr;note=\"x;q=1;y\";q=0, de;q=0.5', expected: \"de\" },\n\t{ header: 'fr;note=\"x;q=0;y\";q=0.9, de;q=0.5', expected: \"fr\" },\n\t{ header: 'fr;note=\"a,b\";q=0.5, de;q=0.8', expected: \"de\" },\n\t{ header: 'fr;note=\"a\\\\\";q=0\";q=0.9, de;q=0.5', expected: \"fr\" },\n\t// an unclosed quote neither hides later ranges nor changes earlier ones\n\t{ header: 'en\", fr', expected: \"fr\" },\n\t{ header: 'fr\";q=0.9, de', expected: \"de\" },\n\t{ header: 'fr;note=\"a,b\";q=0, de;q=0.5, en\"', expected: \"de\" },\n\t{ header: 'fr;note=\"a,b\";q=2, de;q=0.5, en\"', expected: \"de\" },\n\t{ header: 'nl;note=\"x,fr,y\";q=0, de;q=0.5, en\"', expected: \"de\" },\n\t// weights outside the qvalue grammar\n\t{ header: \"fr;q=abc, de;q=0.5\", expected: \"de\" },\n\t{ header: \"fr;q=2, de;q=0.5\", expected: \"de\" },\n\t{ header: \"fr;q=-1\", expected: undefined },\n\t{ header: \"fr;q=0.1234\", expected: undefined },\n\t{ header: \"fr;q=1.001\", expected: undefined },\n\t{ header: \"fr;q=1.0000\", expected: undefined },\n\t{ header: \"fr;q=.5, de;q=0.4\", expected: \"de\" },\n\t{ header: \"fr;q, de;q=0.5\", expected: \"de\" },\n\t{ header: \"de;q 0,en;q=0.5\", expected: \"en\" },\n\t{ header: \"fr;q 0.5, de;q=0.4\", expected: \"de\" },\n\t{ header: \"fr;q=, de;q=0.5\", expected: \"de\" },\n\t// valid weights and ties\n\t{ header: \"fr;q=1.000, de;q=0.5\", expected: \"fr\" },\n\t{ header: \"fr;q=1., de;q=0.5\", expected: \"fr\" },\n\t{ header: \"fr;q=0.001\", expected: \"fr\" },\n\t{ header: \"fr;q=0.8, de;q=0.8\", expected: \"fr\" },\n])(\n\t\"applies Accept-Language quality values in $header\",\n\tasync ({ header, expected }) => {\n\t\tconst runtime = await createParaglide({\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\", \"fr\", \"de\"],\n\t\t\t\t},\n\t\t\t}),\n\t\t});\n\n\t\tconst request = new Request(\"http://example.com\", {\n\t\t\theaders: {\n\t\t\t\t\"Accept-Language\": header,\n\t\t\t},\n\t\t});\n\n\t\texpect(runtime.extractLocaleFromHeader(request)).toBe(expected);\n\t}\n);\n"]}
|
|
@@ -114,7 +114,13 @@ function resolveLocaleWithStrategies(strategyToUse, urlForUrlStrategy) {
|
|
|
114
114
|
else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&
|
|
115
115
|
strat === "localStorage" &&
|
|
116
116
|
!isServer) {
|
|
117
|
-
|
|
117
|
+
try {
|
|
118
|
+
locale = localStorage.getItem(localStorageKey) ?? undefined;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// localStorage throws when storage access is denied
|
|
122
|
+
locale = undefined;
|
|
123
|
+
}
|
|
118
124
|
}
|
|
119
125
|
else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {
|
|
120
126
|
const handler = customClientStrategies.get(strat);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-locale.js","sourceRoot":"","sources":["../../../src/compiler/runtime/get-locale.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EACN,UAAU,EACV,QAAQ,EACR,eAAe,EACf,uBAAuB,EACvB,wBAAwB,EACxB,QAAQ,EACR,+BAA+B,EAC/B,wCAAwC,EACxC,sCAAsC,EACtC,2CAA2C,EAC3C,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;GAQG;AACH,IAAI,OAAO,CAAC;AAEZ,IAAI,kBAAkB,GAAG,KAAK,CAAC;AAE/B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,IAAI,SAAS,GAAG,GAAG,EAAE;IAC3B,IAAI,wBAAwB,KAAK,SAAS,EAAE,CAAC;QAC5C,OAAO,wBAAwB,CAAC;IACjC,CAAC;IAED,gDAAgD;IAChD,mDAAmD;IACnD,IAAI,uBAAuB,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,uBAAuB,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC;QAC3D,IAAI,MAAM,EAAE,CAAC;YACZ,OAAO,MAAM,CAAC;QACf,CAAC;IACF,CAAC;IAED,IAAI,aAAa,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,QAAQ,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;QACzE,aAAa,GAAG,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,QAAQ,GAAG,2BAA2B,CAC3C,aAAa,EACb,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CACjE,CAAC;IACF,IAAI,QAAQ,EAAE,CAAC;QACd,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACzB,OAAO,GAAG,QAAQ,CAAC;YACnB,0DAA0D;YAC1D,kBAAkB,GAAG,IAAI,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,MAAM,IAAI,KAAK,CACd,+EAA+E,CAC/E,CAAC;AACH,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG;IAClC,IAAI,wBAAwB,KAAK,SAAS,EAAE,CAAC;QAC5C,OAAO,wBAAwB,CAAC;IACjC,CAAC;IAED,MAAM,aAAa,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,2BAA2B,CAC3C,aAAa,EACb,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CACxC,CAAC;IACF,IAAI,QAAQ,EAAE,CAAC;QACd,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,MAAM,IAAI,KAAK,CACd,+EAA+E,CAC/E,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,2BAA2B,CAAC,aAAa,EAAE,iBAAiB;IACpE,iCAAiC;IACjC,IAAI,MAAM,CAAC;IAEX,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QACnC,IAAI,+BAA+B,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC3D,MAAM,GAAG,uBAAuB,EAAE,CAAC;QACpC,CAAC;aAAM,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;YACnC,MAAM,GAAG,UAAU,CAAC;QACrB,CAAC;aAAM,IACN,4BAA4B;YAC5B,KAAK,KAAK,KAAK;YACf,CAAC,QAAQ;YACT,OAAO,iBAAiB,KAAK,QAAQ,EACpC,CAAC;YACF,MAAM,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;QAClD,CAAC;aAAM,IACN,wCAAwC;YACxC,KAAK,KAAK,gBAAgB;YAC1B,OAAO,KAAK,SAAS,EACpB,CAAC;YACF,MAAM,GAAG,OAAO,CAAC;QAClB,CAAC;aAAM,IACN,2CAA2C;YAC3C,KAAK,KAAK,mBAAmB;YAC7B,CAAC,QAAQ,EACR,CAAC;YACF,MAAM,GAAG,0BAA0B,EAAE,CAAC;QACvC,CAAC;aAAM,IACN,sCAAsC;YACtC,KAAK,KAAK,cAAc;YACxB,CAAC,QAAQ,EACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"get-locale.js","sourceRoot":"","sources":["../../../src/compiler/runtime/get-locale.js"],"names":[],"mappings":"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","sourcesContent":["import { assertIsLocale, toLocale } from \"./check-locale.js\";\nimport { extractLocaleFromCookie } from \"./extract-locale-from-cookie.js\";\nimport { extractLocaleFromNavigator } from \"./extract-locale-from-navigator.js\";\nimport { extractLocaleFromUrl } from \"./extract-locale-from-url.js\";\nimport { getStrategyForUrl } from \"./route-strategy.js\";\nimport { setLocale } from \"./set-locale.js\";\nimport { customClientStrategies, isCustomStrategy } from \"./strategy.js\";\nimport {\n\tbaseLocale,\n\tisServer,\n\tlocalStorageKey,\n\tserverAsyncLocalStorage,\n\texperimentalStaticLocale,\n\tstrategy,\n\tTREE_SHAKE_COOKIE_STRATEGY_USED,\n\tTREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED,\n\tTREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED,\n\tTREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED,\n\tTREE_SHAKE_URL_STRATEGY_USED,\n} from \"./variables.js\";\n\n/**\n * This is a fallback to get started with a custom\n * strategy and avoid type errors.\n *\n * The implementation is overwritten\n * by `overwriteGetLocale()` and `defineSetLocale()`.\n *\n * @type {Locale | undefined}\n */\nlet _locale;\n\nlet localeInitiallySet = false;\n\n/**\n * Get the current locale.\n *\n * The locale is resolved using your configured strategies (URL, cookie, localStorage, etc.)\n * in the order they are defined. In SSR contexts, the locale is retrieved from AsyncLocalStorage\n * which is set by the `paraglideMiddleware()`.\n *\n * @see https://paraglidejs.com/strategy - Configure locale detection strategies\n *\n * @example\n * if (getLocale() === 'de') {\n * console.log('Germany 🇩🇪');\n * } else if (getLocale() === 'nl') {\n * console.log('Netherlands 🇳🇱');\n * }\n *\n * @returns {Locale} The current locale.\n */\nexport let getLocale = () => {\n\tif (experimentalStaticLocale !== undefined) {\n\t\treturn experimentalStaticLocale;\n\t}\n\n\t// if running in a server-side rendering context\n\t// retrieve the locale from the async local storage\n\tif (serverAsyncLocalStorage) {\n\t\tconst locale = serverAsyncLocalStorage?.getStore()?.locale;\n\t\tif (locale) {\n\t\t\treturn locale;\n\t\t}\n\t}\n\n\tlet strategyToUse = strategy;\n\tif (!isServer && typeof window !== \"undefined\" && window.location?.href) {\n\t\tstrategyToUse = getStrategyForUrl(window.location.href);\n\t}\n\n\tconst resolved = resolveLocaleWithStrategies(\n\t\tstrategyToUse,\n\t\ttypeof window !== \"undefined\" ? window.location?.href : undefined\n\t);\n\tif (resolved) {\n\t\tif (!localeInitiallySet) {\n\t\t\t_locale = resolved;\n\t\t\t// https://github.com/opral/inlang-paraglide-js/issues/455\n\t\t\tlocaleInitiallySet = true;\n\t\t\tsetLocale(resolved, { reload: false });\n\t\t}\n\t\treturn resolved;\n\t}\n\n\tthrow new Error(\n\t\t\"No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found\"\n\t);\n};\n\n/**\n * Resolve locale for a given URL using route-aware strategies.\n *\n * @param {string | URL} url\n * @returns {Locale}\n */\nexport function getLocaleForUrl(url) {\n\tif (experimentalStaticLocale !== undefined) {\n\t\treturn experimentalStaticLocale;\n\t}\n\n\tconst strategyToUse = getStrategyForUrl(url);\n\tconst resolved = resolveLocaleWithStrategies(\n\t\tstrategyToUse,\n\t\ttypeof url === \"string\" ? url : url.href\n\t);\n\tif (resolved) {\n\t\treturn resolved;\n\t}\n\n\tthrow new Error(\n\t\t\"No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found\"\n\t);\n}\n\n/**\n * @param {typeof strategy} strategyToUse\n * @param {string | undefined} urlForUrlStrategy\n * @returns {Locale | undefined}\n */\nfunction resolveLocaleWithStrategies(strategyToUse, urlForUrlStrategy) {\n\t/** @type {string | undefined} */\n\tlet locale;\n\n\tfor (const strat of strategyToUse) {\n\t\tif (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n\t\t\tlocale = extractLocaleFromCookie();\n\t\t} else if (strat === \"baseLocale\") {\n\t\t\tlocale = baseLocale;\n\t\t} else if (\n\t\t\tTREE_SHAKE_URL_STRATEGY_USED &&\n\t\t\tstrat === \"url\" &&\n\t\t\t!isServer &&\n\t\t\ttypeof urlForUrlStrategy === \"string\"\n\t\t) {\n\t\t\tlocale = extractLocaleFromUrl(urlForUrlStrategy);\n\t\t} else if (\n\t\t\tTREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&\n\t\t\tstrat === \"globalVariable\" &&\n\t\t\t_locale !== undefined\n\t\t) {\n\t\t\tlocale = _locale;\n\t\t} else if (\n\t\t\tTREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&\n\t\t\tstrat === \"preferredLanguage\" &&\n\t\t\t!isServer\n\t\t) {\n\t\t\tlocale = extractLocaleFromNavigator();\n\t\t} else if (\n\t\t\tTREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&\n\t\t\tstrat === \"localStorage\" &&\n\t\t\t!isServer\n\t\t) {\n\t\t\ttry {\n\t\t\t\tlocale = localStorage.getItem(localStorageKey) ?? undefined;\n\t\t\t} catch {\n\t\t\t\t// localStorage throws when storage access is denied\n\t\t\t\tlocale = undefined;\n\t\t\t}\n\t\t} else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {\n\t\t\tconst handler = customClientStrategies.get(strat);\n\t\t\tif (handler) {\n\t\t\t\tconst result = handler.getLocale();\n\t\t\t\t// Handle both sync and async results - skip async in sync getLocale\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t// Can't await in sync function, skip async strategies\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (result !== undefined) {\n\t\t\t\t\treturn assertIsLocale(result);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst matchedLocale = toLocale(locale);\n\t\tif (matchedLocale) {\n\t\t\treturn matchedLocale;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Overwrite the `getLocale()` function.\n *\n * Use this function to overwrite how the locale is resolved. This is useful\n * for custom locale resolution or advanced use cases like SSG with concurrent rendering.\n *\n * @see https://paraglidejs.com/strategy\n *\n * @example\n * overwriteGetLocale(() => {\n * return Cookies.get('locale') ?? baseLocale\n * });\n *\n * @param {() => Locale} fn - The new implementation for `getLocale()`.\n */\nexport const overwriteGetLocale = (fn) => {\n\tgetLocale = fn;\n};\n"]}
|
|
@@ -361,4 +361,99 @@ test("custom strategy integrates with locale initialization", async () => {
|
|
|
361
361
|
// The locale should be set internally after first resolution
|
|
362
362
|
expect(setLocaleCalled).toBe(true);
|
|
363
363
|
});
|
|
364
|
+
// sandboxed iframes without allow-same-origin have an opaque origin and throw
|
|
365
|
+
// a SecurityError on document.cookie and localStorage access
|
|
366
|
+
test("resolves the url locale when document.cookie throws", async () => {
|
|
367
|
+
const runtime = await createParaglide({
|
|
368
|
+
blob: await newProject({
|
|
369
|
+
settings: {
|
|
370
|
+
baseLocale: "en",
|
|
371
|
+
locales: ["en", "de"],
|
|
372
|
+
},
|
|
373
|
+
}),
|
|
374
|
+
strategy: ["url", "cookie"],
|
|
375
|
+
isServer: "false",
|
|
376
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
377
|
+
urlPatterns: [
|
|
378
|
+
{
|
|
379
|
+
pattern: "https://example.com/:path*",
|
|
380
|
+
localized: [
|
|
381
|
+
["en", "https://example.com/en/:path*"],
|
|
382
|
+
["de", "https://example.com/de/:path*"],
|
|
383
|
+
],
|
|
384
|
+
},
|
|
385
|
+
],
|
|
386
|
+
});
|
|
387
|
+
globalThis.window = {
|
|
388
|
+
// @ts-expect-error - global variable definition
|
|
389
|
+
location: {
|
|
390
|
+
hostname: "example.com",
|
|
391
|
+
href: "https://example.com/de/page",
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
// @ts-expect-error - global variable definition
|
|
395
|
+
globalThis.document = {
|
|
396
|
+
get cookie() {
|
|
397
|
+
throw new DOMException("The operation is insecure.", "SecurityError");
|
|
398
|
+
},
|
|
399
|
+
set cookie(_value) {
|
|
400
|
+
throw new DOMException("The operation is insecure.", "SecurityError");
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
// the first resolution also writes the cookie
|
|
404
|
+
expect(runtime.getLocale()).toBe("de");
|
|
405
|
+
});
|
|
406
|
+
test("falls back to the next strategy when document.cookie throws", async () => {
|
|
407
|
+
const runtime = await createParaglide({
|
|
408
|
+
blob: await newProject({
|
|
409
|
+
settings: {
|
|
410
|
+
baseLocale: "en",
|
|
411
|
+
locales: ["en", "de"],
|
|
412
|
+
},
|
|
413
|
+
}),
|
|
414
|
+
strategy: ["cookie", "baseLocale"],
|
|
415
|
+
isServer: "false",
|
|
416
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
417
|
+
});
|
|
418
|
+
// @ts-expect-error - global variable definition
|
|
419
|
+
globalThis.window = {};
|
|
420
|
+
// @ts-expect-error - global variable definition
|
|
421
|
+
globalThis.document = {
|
|
422
|
+
get cookie() {
|
|
423
|
+
throw new DOMException("The operation is insecure.", "SecurityError");
|
|
424
|
+
},
|
|
425
|
+
set cookie(_value) {
|
|
426
|
+
throw new DOMException("The operation is insecure.", "SecurityError");
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
expect(runtime.getLocale()).toBe("en");
|
|
430
|
+
});
|
|
431
|
+
test("falls back to the next strategy when localStorage throws", async () => {
|
|
432
|
+
const originalLocalStorage = globalThis.localStorage;
|
|
433
|
+
const runtime = await createParaglide({
|
|
434
|
+
blob: await newProject({
|
|
435
|
+
settings: {
|
|
436
|
+
baseLocale: "en",
|
|
437
|
+
locales: ["en", "de"],
|
|
438
|
+
},
|
|
439
|
+
}),
|
|
440
|
+
strategy: ["localStorage", "baseLocale"],
|
|
441
|
+
isServer: "false",
|
|
442
|
+
});
|
|
443
|
+
// @ts-expect-error - global variable definition
|
|
444
|
+
globalThis.window = {};
|
|
445
|
+
// browsers throw when the localStorage property itself is read
|
|
446
|
+
Object.defineProperty(globalThis, "localStorage", {
|
|
447
|
+
get() {
|
|
448
|
+
throw new DOMException("The operation is insecure.", "SecurityError");
|
|
449
|
+
},
|
|
450
|
+
configurable: true,
|
|
451
|
+
});
|
|
452
|
+
expect(runtime.getLocale()).toBe("en");
|
|
453
|
+
Object.defineProperty(globalThis, "localStorage", {
|
|
454
|
+
value: originalLocalStorage,
|
|
455
|
+
configurable: true,
|
|
456
|
+
writable: true,
|
|
457
|
+
});
|
|
458
|
+
});
|
|
364
459
|
//# sourceMappingURL=get-locale.test.js.map
|