@intlayer/core 9.0.0-canary.12 → 9.0.0-canary.13

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 (78) hide show
  1. package/dist/cjs/index.cjs +5 -0
  2. package/dist/cjs/localization/domainUtils.cjs +82 -0
  3. package/dist/cjs/localization/domainUtils.cjs.map +1 -0
  4. package/dist/cjs/localization/getLocalizedUrl.cjs +4 -11
  5. package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
  6. package/dist/cjs/localization/getPrefix.cjs +5 -9
  7. package/dist/cjs/localization/getPrefix.cjs.map +1 -1
  8. package/dist/cjs/localization/index.cjs +5 -0
  9. package/dist/esm/index.mjs +2 -1
  10. package/dist/esm/localization/domainUtils.mjs +77 -0
  11. package/dist/esm/localization/domainUtils.mjs.map +1 -0
  12. package/dist/esm/localization/getLocalizedUrl.mjs +4 -11
  13. package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
  14. package/dist/esm/localization/getPrefix.mjs +5 -9
  15. package/dist/esm/localization/getPrefix.mjs.map +1 -1
  16. package/dist/esm/localization/index.mjs +2 -1
  17. package/dist/types/index.d.ts +2 -1
  18. package/dist/types/localization/domainUtils.d.ts +70 -0
  19. package/dist/types/localization/domainUtils.d.ts.map +1 -0
  20. package/dist/types/localization/getLocalizedUrl.d.ts.map +1 -1
  21. package/dist/types/localization/getPrefix.d.ts.map +1 -1
  22. package/dist/types/localization/index.d.ts +2 -1
  23. package/package.json +6 -6
  24. package/dist/types/@intlayer/core/dist/types/formatters/compact.d.ts +0 -1
  25. package/dist/types/@intlayer/core/dist/types/formatters/currency.d.ts +0 -1
  26. package/dist/types/@intlayer/core/dist/types/formatters/date.d.ts +0 -1
  27. package/dist/types/@intlayer/core/dist/types/formatters/index.d.ts +0 -1
  28. package/dist/types/@intlayer/core/dist/types/formatters/list.d.ts +0 -1
  29. package/dist/types/@intlayer/core/dist/types/formatters/number.d.ts +0 -1
  30. package/dist/types/@intlayer/core/dist/types/formatters/percentage.d.ts +0 -1
  31. package/dist/types/@intlayer/core/dist/types/formatters/relativeTime.d.ts +0 -1
  32. package/dist/types/@intlayer/core/dist/types/formatters/units.d.ts +0 -1
  33. package/dist/types/@intlayer/core/dist/types/interpreter/getCondition.d.ts +0 -1
  34. package/dist/types/@intlayer/core/dist/types/interpreter/getContent/deepTransform.d.ts +0 -1
  35. package/dist/types/@intlayer/core/dist/types/interpreter/getContent/getContent.d.ts +0 -2
  36. package/dist/types/@intlayer/core/dist/types/interpreter/getContent/plugins.d.ts +0 -4
  37. package/dist/types/@intlayer/core/dist/types/interpreter/getDictionary.d.ts +0 -2
  38. package/dist/types/@intlayer/core/dist/types/interpreter/getEnumeration.d.ts +0 -1
  39. package/dist/types/@intlayer/core/dist/types/interpreter/getIntlayer.d.ts +0 -2
  40. package/dist/types/@intlayer/core/dist/types/interpreter/getNesting.d.ts +0 -2
  41. package/dist/types/@intlayer/core/dist/types/interpreter/getPlural.d.ts +0 -1
  42. package/dist/types/@intlayer/core/dist/types/interpreter/getTranslation.d.ts +0 -1
  43. package/dist/types/@intlayer/core/dist/types/interpreter/index.d.ts +0 -1
  44. package/dist/types/@intlayer/core/dist/types/localization/comparePaths.d.ts +0 -1
  45. package/dist/types/@intlayer/core/dist/types/localization/generateSitemap.d.ts +0 -2
  46. package/dist/types/@intlayer/core/dist/types/localization/getBrowserLocale.d.ts +0 -1
  47. package/dist/types/@intlayer/core/dist/types/localization/getHTMLTextDir.d.ts +0 -1
  48. package/dist/types/@intlayer/core/dist/types/localization/getLocale.d.ts +0 -1
  49. package/dist/types/@intlayer/core/dist/types/localization/getLocaleFromPath.d.ts +0 -1
  50. package/dist/types/@intlayer/core/dist/types/localization/getLocaleLang.d.ts +0 -1
  51. package/dist/types/@intlayer/core/dist/types/localization/getLocaleName.d.ts +0 -1
  52. package/dist/types/@intlayer/core/dist/types/localization/getLocalizedUrl.d.ts +0 -1
  53. package/dist/types/@intlayer/core/dist/types/localization/getMultilingualUrls.d.ts +0 -1
  54. package/dist/types/@intlayer/core/dist/types/localization/getPathWithoutLocale.d.ts +0 -1
  55. package/dist/types/@intlayer/core/dist/types/localization/getPrefix.d.ts +0 -3
  56. package/dist/types/@intlayer/core/dist/types/localization/index.d.ts +0 -1
  57. package/dist/types/@intlayer/core/dist/types/localization/localeDetector.d.ts +0 -1
  58. package/dist/types/@intlayer/core/dist/types/localization/localeMapper.d.ts +0 -2
  59. package/dist/types/@intlayer/core/dist/types/localization/localeResolver.d.ts +0 -2
  60. package/dist/types/@intlayer/core/dist/types/localization/rewriteUtils.d.ts +0 -3
  61. package/dist/types/@intlayer/core/dist/types/localization/validatePrefix.d.ts +0 -1
  62. package/dist/types/@intlayer/core/dist/types/markdown/index.d.ts +0 -1
  63. package/dist/types/@intlayer/core/dist/types/transpiler/condition/condition.d.ts +0 -1
  64. package/dist/types/@intlayer/core/dist/types/transpiler/enumeration/enumeration.d.ts +0 -1
  65. package/dist/types/@intlayer/core/dist/types/transpiler/file/file.d.ts +0 -1
  66. package/dist/types/@intlayer/core/dist/types/transpiler/gender/gender.d.ts +0 -1
  67. package/dist/types/@intlayer/core/dist/types/transpiler/html/html.d.ts +0 -1
  68. package/dist/types/@intlayer/core/dist/types/transpiler/index.d.ts +0 -1
  69. package/dist/types/@intlayer/core/dist/types/transpiler/insertion/insertion.d.ts +0 -1
  70. package/dist/types/@intlayer/core/dist/types/transpiler/markdown/markdown.d.ts +0 -1
  71. package/dist/types/@intlayer/core/dist/types/transpiler/nesting/nesting.d.ts +0 -2
  72. package/dist/types/@intlayer/core/dist/types/transpiler/plural/plural.d.ts +0 -1
  73. package/dist/types/@intlayer/core/dist/types/transpiler/translation/translation.d.ts +0 -2
  74. package/dist/types/@intlayer/core/dist/types/utils/index.d.ts +0 -1
  75. package/dist/types/@intlayer/core/dist/types/utils/intl.d.ts +0 -1
  76. package/dist/types/@intlayer/core/dist/types/utils/isSameKeyPath.d.ts +0 -1
  77. package/dist/types/@intlayer/core/dist/types/utils/localeStorage.d.ts +0 -2
  78. package/dist/types/intlayer/dist/types/index.d.ts +0 -4
@@ -64,6 +64,7 @@ const require_dictionaryManipulator_updateNodeChildren = require('./dictionaryMa
64
64
  const require_utils_checkIsURLAbsolute = require('./utils/checkIsURLAbsolute.cjs');
65
65
  const require_localization_getPathWithoutLocale = require('./localization/getPathWithoutLocale.cjs');
66
66
  const require_localization_comparePaths = require('./localization/comparePaths.cjs');
67
+ const require_localization_domainUtils = require('./localization/domainUtils.cjs');
67
68
  const require_localization_getPrefix = require('./localization/getPrefix.cjs');
68
69
  const require_localization_rewriteUtils = require('./localization/rewriteUtils.cjs');
69
70
  const require_localization_getLocalizedUrl = require('./localization/getLocalizedUrl.cjs');
@@ -230,6 +231,8 @@ exports.getDictionaryCompositeIds = require_dictionaryManipulator_qualifiedDicti
230
231
  exports.getDictionaryQualifierIds = require_dictionaryManipulator_qualifiedDictionary.getDictionaryQualifierIds;
231
232
  exports.getDictionaryQualifierTypes = require_dictionaryManipulator_qualifiedDictionary.getDictionaryQualifierTypes;
232
233
  exports.getDictionarySelectorCacheKey = require_dictionaryManipulator_qualifiedDictionary.getDictionarySelectorCacheKey;
234
+ exports.getDomainHostname = require_localization_domainUtils.getDomainHostname;
235
+ exports.getDomainOrigin = require_localization_domainUtils.getDomainOrigin;
233
236
  exports.getEditedContent = require_deepTransformPlugins_getEditedContent.getEditedContent;
234
237
  exports.getEditedDictionary = require_deepTransformPlugins_getEditedContent.getEditedDictionary;
235
238
  exports.getEmptyNode = require_dictionaryManipulator_getEmptyNode.getEmptyNode;
@@ -246,6 +249,7 @@ exports.getInsertionValues = require_transpiler_insertion_getInsertionValues.get
246
249
  exports.getInternalPath = require_localization_rewriteUtils.getInternalPath;
247
250
  exports.getIntlayer = require_interpreter_getIntlayer.getIntlayer;
248
251
  exports.getLocale = require_localization_getLocale.getLocale;
252
+ exports.getLocaleFromDomain = require_localization_domainUtils.getLocaleFromDomain;
249
253
  exports.getLocaleFromPath = require_localization_getLocaleFromPath.getLocaleFromPath;
250
254
  exports.getLocaleFromStorage = require_utils_localeStorage.getLocaleFromStorage;
251
255
  exports.getLocaleFromStorageClient = require_utils_localeStorage.getLocaleFromStorageClient;
@@ -287,6 +291,7 @@ exports.intlayerToI18nextFormatter = require_messageFormat_i18next.intlayerToI18
287
291
  exports.intlayerToICUFormatter = require_messageFormat_ICU.intlayerToICUFormatter;
288
292
  exports.intlayerToPortableObjectFormatter = require_messageFormat_po.intlayerToPortableObjectFormatter;
289
293
  exports.intlayerToVueI18nFormatter = require_messageFormat_vue_i18n.intlayerToVueI18nFormatter;
294
+ exports.isLocaleExclusiveOnDomain = require_localization_domainUtils.isLocaleExclusiveOnDomain;
290
295
  exports.isQualifiedDictionaryGroup = require_dictionaryManipulator_qualifiedDictionary.isQualifiedDictionaryGroup;
291
296
  exports.isQualifiedDynamicLoaderMap = require_dictionaryManipulator_qualifiedDictionary.isQualifiedDynamicLoaderMap;
292
297
  exports.isSameKeyPath = require_utils_isSameKeyPath.isSameKeyPath;
@@ -0,0 +1,82 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/localization/domainUtils.ts
4
+ /**
5
+ * Strips the protocol from a domain string and returns only the hostname.
6
+ *
7
+ * Example:
8
+ *
9
+ * ```ts
10
+ * getDomainHostname('https://intlayer.cn') // 'intlayer.cn'
11
+ * getDomainHostname('intlayer.cn') // 'intlayer.cn'
12
+ * ```
13
+ *
14
+ * @param domain - A domain value from `routing.domains`, with or without protocol.
15
+ * @returns The bare hostname.
16
+ */
17
+ const getDomainHostname = (domain) => {
18
+ try {
19
+ return /^https?:\/\//.test(domain) ? new URL(domain).hostname : domain;
20
+ } catch {
21
+ return domain;
22
+ }
23
+ };
24
+ /**
25
+ * Returns the absolute origin for a domain value, prepending `https://`
26
+ * when no protocol is present.
27
+ *
28
+ * Example:
29
+ *
30
+ * ```ts
31
+ * getDomainOrigin('intlayer.cn') // 'https://intlayer.cn'
32
+ * getDomainOrigin('http://intlayer.cn') // 'http://intlayer.cn'
33
+ * ```
34
+ *
35
+ * @param domain - A domain value from `routing.domains`, with or without protocol.
36
+ * @returns The origin usable as a URL base.
37
+ */
38
+ const getDomainOrigin = (domain) => /^https?:\/\//.test(domain) ? domain : `https://${domain}`;
39
+ /**
40
+ * Returns the locale exclusively mapped to a given hostname via `routing.domains`,
41
+ * or `undefined` when zero or more than one locale share that hostname.
42
+ *
43
+ * Example: with `domains = { zh: 'intlayer.cn', en: 'intlayer.org', fr: 'intlayer.org' }`
44
+ *
45
+ * ```ts
46
+ * getLocaleFromDomain('intlayer.cn', domains) // 'zh'
47
+ * getLocaleFromDomain('intlayer.org', domains) // undefined (en and fr share it)
48
+ * getLocaleFromDomain('example.com', domains) // undefined (not mapped)
49
+ * ```
50
+ *
51
+ * @param hostname - The bare hostname of the incoming request.
52
+ * @param domains - The configured locale → domain map.
53
+ * @returns The exclusively mapped locale, or `undefined`.
54
+ */
55
+ const getLocaleFromDomain = (hostname, domains) => {
56
+ if (!domains) return void 0;
57
+ const matchingLocales = Object.entries(domains).filter(([, domain]) => typeof domain === "string" && getDomainHostname(domain) === hostname);
58
+ return matchingLocales.length === 1 ? matchingLocales[0]?.[0] : void 0;
59
+ };
60
+ /**
61
+ * Checks whether a locale is the only locale mapped to its configured domain.
62
+ * When true, the domain alone identifies the locale and no URL prefix is needed.
63
+ * Hostnames are compared after protocol stripping, so
64
+ * `{ en: 'https://intlayer.org', fr: 'intlayer.org' }` counts as a shared domain.
65
+ *
66
+ * @param locale - The locale to check.
67
+ * @param domains - The configured locale → domain map.
68
+ * @returns `true` when the locale has a domain shared with no other locale.
69
+ */
70
+ const isLocaleExclusiveOnDomain = (locale, domains) => {
71
+ const localeDomain = domains?.[locale];
72
+ if (!localeDomain) return false;
73
+ const localeHostname = getDomainHostname(localeDomain);
74
+ return Object.values(domains).filter((domain) => typeof domain === "string" && getDomainHostname(domain) === localeHostname).length === 1;
75
+ };
76
+
77
+ //#endregion
78
+ exports.getDomainHostname = getDomainHostname;
79
+ exports.getDomainOrigin = getDomainOrigin;
80
+ exports.getLocaleFromDomain = getLocaleFromDomain;
81
+ exports.isLocaleExclusiveOnDomain = isLocaleExclusiveOnDomain;
82
+ //# sourceMappingURL=domainUtils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domainUtils.cjs","names":[],"sources":["../../../src/localization/domainUtils.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n/**\n * The locale → domain map configured under `routing.domains`\n * (e.g. `{ en: 'intlayer.org', zh: 'intlayer.cn' }`).\n */\nexport type LocaleDomainMap = RoutingConfig['domains'];\n\n/**\n * Strips the protocol from a domain string and returns only the hostname.\n *\n * Example:\n *\n * ```ts\n * getDomainHostname('https://intlayer.cn') // 'intlayer.cn'\n * getDomainHostname('intlayer.cn') // 'intlayer.cn'\n * ```\n *\n * @param domain - A domain value from `routing.domains`, with or without protocol.\n * @returns The bare hostname.\n */\nexport const getDomainHostname = (domain: string): string => {\n try {\n return /^https?:\\/\\//.test(domain) ? new URL(domain).hostname : domain;\n } catch {\n return domain;\n }\n};\n\n/**\n * Returns the absolute origin for a domain value, prepending `https://`\n * when no protocol is present.\n *\n * Example:\n *\n * ```ts\n * getDomainOrigin('intlayer.cn') // 'https://intlayer.cn'\n * getDomainOrigin('http://intlayer.cn') // 'http://intlayer.cn'\n * ```\n *\n * @param domain - A domain value from `routing.domains`, with or without protocol.\n * @returns The origin usable as a URL base.\n */\nexport const getDomainOrigin = (domain: string): string =>\n /^https?:\\/\\//.test(domain) ? domain : `https://${domain}`;\n\n/**\n * Returns the locale exclusively mapped to a given hostname via `routing.domains`,\n * or `undefined` when zero or more than one locale share that hostname.\n *\n * Example: with `domains = { zh: 'intlayer.cn', en: 'intlayer.org', fr: 'intlayer.org' }`\n *\n * ```ts\n * getLocaleFromDomain('intlayer.cn', domains) // 'zh'\n * getLocaleFromDomain('intlayer.org', domains) // undefined (en and fr share it)\n * getLocaleFromDomain('example.com', domains) // undefined (not mapped)\n * ```\n *\n * @param hostname - The bare hostname of the incoming request.\n * @param domains - The configured locale → domain map.\n * @returns The exclusively mapped locale, or `undefined`.\n */\nexport const getLocaleFromDomain = (\n hostname: string,\n domains: LocaleDomainMap\n): Locale | undefined => {\n if (!domains) return undefined;\n\n const matchingLocales = Object.entries(domains).filter(\n ([, domain]) =>\n typeof domain === 'string' && getDomainHostname(domain) === hostname\n );\n\n return matchingLocales.length === 1\n ? (matchingLocales[0]?.[0] as Locale)\n : undefined;\n};\n\n/**\n * Checks whether a locale is the only locale mapped to its configured domain.\n * When true, the domain alone identifies the locale and no URL prefix is needed.\n * Hostnames are compared after protocol stripping, so\n * `{ en: 'https://intlayer.org', fr: 'intlayer.org' }` counts as a shared domain.\n *\n * @param locale - The locale to check.\n * @param domains - The configured locale → domain map.\n * @returns `true` when the locale has a domain shared with no other locale.\n */\nexport const isLocaleExclusiveOnDomain = (\n locale: LocalesValues,\n domains: LocaleDomainMap\n): boolean => {\n const localeDomain = domains?.[locale];\n\n if (!localeDomain) return false;\n\n const localeHostname = getDomainHostname(localeDomain);\n\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) =>\n typeof domain === 'string' && getDomainHostname(domain) === localeHostname\n ).length;\n\n return localesOnSameDomain === 1;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,MAAa,qBAAqB,WAA2B;AAC3D,KAAI;AACF,SAAO,eAAe,KAAK,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,WAAW;SAC1D;AACN,SAAO;;;;;;;;;;;;;;;;;AAkBX,MAAa,mBAAmB,WAC9B,eAAe,KAAK,OAAO,GAAG,SAAS,WAAW;;;;;;;;;;;;;;;;;AAkBpD,MAAa,uBACX,UACA,YACuB;AACvB,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,kBAAkB,OAAO,QAAQ,QAAQ,CAAC,QAC7C,GAAG,YACF,OAAO,WAAW,YAAY,kBAAkB,OAAO,KAAK,SAC/D;AAED,QAAO,gBAAgB,WAAW,IAC7B,gBAAgB,KAAK,KACtB;;;;;;;;;;;;AAaN,MAAa,6BACX,QACA,YACY;CACZ,MAAM,eAAe,UAAU;AAE/B,KAAI,CAAC,aAAc,QAAO;CAE1B,MAAM,iBAAiB,kBAAkB,aAAa;AAOtD,QAL4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WACC,OAAO,WAAW,YAAY,kBAAkB,OAAO,KAAK,eAC/D,CAAC,WAE6B"}
@@ -2,19 +2,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
3
  const require_utils_checkIsURLAbsolute = require('../utils/checkIsURLAbsolute.cjs');
4
4
  const require_localization_getPathWithoutLocale = require('./getPathWithoutLocale.cjs');
5
+ const require_localization_domainUtils = require('./domainUtils.cjs');
5
6
  const require_localization_getPrefix = require('./getPrefix.cjs');
6
7
  const require_localization_rewriteUtils = require('./rewriteUtils.cjs');
7
8
  let _intlayer_config_built = require("@intlayer/config/built");
8
9
 
9
10
  //#region src/localization/getLocalizedUrl.ts
10
- /** Strips the protocol and returns the bare hostname of a domain string. */
11
- const extractHostname = (domain) => {
12
- try {
13
- return /^https?:\/\//.test(domain) ? new URL(domain).hostname : domain;
14
- } catch {
15
- return domain;
16
- }
17
- };
18
11
  /**
19
12
  * Generate URL by prefixing the given URL with the referenced locale or adding search parameters
20
13
  * based on the routing mode. Handles both absolute and relative URLs appropriately.
@@ -67,10 +60,10 @@ const getLocalizedUrl = (url, currentLocale = _intlayer_config_built.internation
67
60
  const isAbsoluteUrl = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(urlWithoutLocale);
68
61
  const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com");
69
62
  const translatedPathname = require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(parsedUrl.pathname, void 0, rewriteRules), currentLocale, rewriteRules).path;
70
- const detectedCurrentHostname = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? extractHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null;
63
+ const detectedCurrentHostname = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? require_localization_domainUtils.getDomainHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null;
71
64
  const localeDomain = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? domains?.[currentLocale] : void 0;
72
- const localeDomainHostname = localeDomain ? extractHostname(localeDomain) : null;
73
- const normalizedDomain = localeDomainHostname !== null && detectedCurrentHostname !== null && localeDomainHostname !== detectedCurrentHostname && localeDomain ? /^https?:\/\//.test(localeDomain) ? localeDomain : `https://${localeDomain}` : null;
65
+ const localeDomainHostname = localeDomain ? require_localization_domainUtils.getDomainHostname(localeDomain) : null;
66
+ const normalizedDomain = localeDomainHostname !== null && (detectedCurrentHostname === null || localeDomainHostname !== detectedCurrentHostname) && localeDomain ? require_localization_domainUtils.getDomainOrigin(localeDomain) : null;
74
67
  const baseUrl = normalizedDomain ? normalizedDomain : isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : "";
75
68
  if (!(process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "search-params") && mode === "search-params") {
76
69
  const searchParams = new URLSearchParams(parsedUrl.search);
@@ -1 +1 @@
1
- {"version":3,"file":"getLocalizedUrl.cjs","names":["internationalization","resolveRoutingConfig","getPathWithoutLocale","getRewriteRules","getLocalizedPath","getCanonicalPath","checkIsURLAbsolute","getPrefix"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n LocalesValues,\n LocalizedUrl,\n ResolvedDefaultLocale,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\nexport type { RoutingOptions };\n\n/** Strips the protocol and returns the bare hostname of a domain string. */\nconst extractHostname = (domain: string): string => {\n try {\n return /^https?:\\/\\//.test(domain) ? new URL(domain).hostname : domain;\n } catch {\n return domain;\n }\n};\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @param options.currentDomain - Hostname of the page being rendered. Used to decide\n * whether to emit a relative URL (same domain) or an absolute URL (cross-domain).\n * Auto-detected from the input URL or `window.location` when omitted.\n * @returns The localized URL for the current locale.\n */\n/**\n * The return type is narrowed to a template-literal type when both `url` and\n * `currentLocale` are string literals and the routing mode / defaultLocale are\n * not overridden via `options`.\n */\nexport const getLocalizedUrl = <\n const T extends string,\n const L extends LocalesValues = ResolvedDefaultLocale,\n>(\n url: T,\n currentLocale: L = internationalization?.defaultLocale as L,\n options: RoutingOptions = {}\n): LocalizedUrl<T, L> => {\n const { defaultLocale, mode, locales, rewrite, domains, currentDomain } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'no-prefix'\n ) &&\n mode === 'no-prefix'\n ) {\n return getLocalizedPath(\n getCanonicalPath(urlWithoutLocale, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path as LocalizedUrl<T, L>;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const translatedPathname = getLocalizedPath(\n getCanonicalPath(parsedUrl.pathname, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n\n // ── Domain routing ────────────────────────────────────────────────────────\n // Resolve the \"current\" hostname so we can choose between a relative URL\n // (same domain) and an absolute URL (cross-domain).\n //\n // Detection priority:\n // 1. Explicit `currentDomain` option passed by the caller.\n // 2. Hostname extracted from an absolute input URL.\n // 3. `window.location.hostname` in browser environments.\n // When none of these is available we fall back to always generating an\n // absolute URL (the previous behaviour, safe for SSR/static generation).\n const detectedCurrentHostname =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? extractHostname(\n currentDomain ??\n (isAbsoluteUrl ? parsedUrl.hostname : undefined) ??\n (typeof window !== 'undefined'\n ? window?.location?.hostname\n : undefined) ??\n ''\n ) || null\n : null;\n\n const localeDomain =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? domains?.[currentLocale as LocalesValues]\n : undefined;\n\n const localeDomainHostname = localeDomain\n ? extractHostname(localeDomain)\n : null;\n\n // Only prepend the locale's domain when it differs from the current hostname.\n const isCrossDomain =\n localeDomainHostname !== null &&\n detectedCurrentHostname !== null &&\n localeDomainHostname !== detectedCurrentHostname;\n\n const normalizedDomain =\n isCrossDomain && localeDomain\n ? /^https?:\\/\\//.test(localeDomain)\n ? localeDomain\n : `https://${localeDomain}`\n : null;\n\n const baseUrl = normalizedDomain\n ? normalizedDomain\n : isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n // ─────────────────────────────────────────────────────────────────────────\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params'\n ) &&\n mode === 'search-params'\n ) {\n const searchParams = new URLSearchParams(parsedUrl.search);\n\n searchParams.set('locale', currentLocale.toString());\n\n const queryParams = searchParams.toString();\n const path = queryParams\n ? `${translatedPathname}?${queryParams}`\n : translatedPathname;\n\n return `${baseUrl}${path}${parsedUrl.hash}` as LocalizedUrl<T, L>;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n domains,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`.replace(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}` as LocalizedUrl<\n T,\n L\n >;\n};\n"],"mappings":";;;;;;;;;;AA4BA,MAAM,mBAAmB,WAA2B;AAClD,KAAI;AACF,SAAO,eAAe,KAAK,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,WAAW;SAC1D;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDX,MAAa,mBAIX,KACA,gBAAmBA,6CAAsB,eACzC,UAA0B,EAAE,KACL;CACvB,MAAM,EAAE,eAAe,MAAM,SAAS,SAAS,SAAS,kBACtDC,oDAAqB,QAAQ;CAE/B,MAAM,mBAAmBC,+DAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAeC,kDAAgB,SAAS,MAAM;AAEpD,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,gBAExC,SAAS,YAET,QAAOC,mDACLC,mDAAiB,kBAAkB,QAAW,aAAa,EAC3D,eACA,aACD,CAAC;CAGJ,MAAM,gBAAgBC,oDAAmB,iBAAiB;CAC1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,qBAAqBF,mDACzBC,mDAAiB,UAAU,UAAU,QAAW,aAAa,EAC7D,eACA,aACD,CAAC;CAYF,MAAM,0BACJ,QAAQ,IAAI,6BAA6B,UACrC,gBACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,GACH,IAAI,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,6BAA6B,UACrC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzB,gBAAgB,aAAa,GAC7B;CAQJ,MAAM,mBAJJ,yBAAyB,QACzB,4BAA4B,QAC5B,yBAAyB,2BAGR,eACb,eAAe,KAAK,aAAa,GAC/B,eACA,WAAW,iBACb;CAEN,MAAM,UAAU,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAGN,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,oBAExC,SAAS,iBACT;EACA,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAE1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;AAK3C,SAAO,GAAG,UAJG,cACT,GAAG,mBAAmB,GAAG,gBACzB,qBAEuB,UAAU;;CAGvC,MAAM,EAAE,WAAWE,yCAAU,eAAe;EAC1C;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS,qBAAqB,QAAQ,QAAQ,IAAI;AAE1E,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU"}
1
+ {"version":3,"file":"getLocalizedUrl.cjs","names":["internationalization","resolveRoutingConfig","getPathWithoutLocale","getRewriteRules","getLocalizedPath","getCanonicalPath","checkIsURLAbsolute","getDomainHostname","getDomainOrigin","getPrefix"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n LocalesValues,\n LocalizedUrl,\n ResolvedDefaultLocale,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getDomainHostname, getDomainOrigin } from './domainUtils';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\nexport type { RoutingOptions };\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @param options.currentDomain - Hostname of the page being rendered. Used to decide\n * whether to emit a relative URL (same domain) or an absolute URL (cross-domain).\n * Auto-detected from the input URL or `window.location` when omitted.\n * @returns The localized URL for the current locale.\n */\n/**\n * The return type is narrowed to a template-literal type when both `url` and\n * `currentLocale` are string literals and the routing mode / defaultLocale are\n * not overridden via `options`.\n */\nexport const getLocalizedUrl = <\n const T extends string,\n const L extends LocalesValues = ResolvedDefaultLocale,\n>(\n url: T,\n currentLocale: L = internationalization?.defaultLocale as L,\n options: RoutingOptions = {}\n): LocalizedUrl<T, L> => {\n const { defaultLocale, mode, locales, rewrite, domains, currentDomain } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'no-prefix'\n ) &&\n mode === 'no-prefix'\n ) {\n return getLocalizedPath(\n getCanonicalPath(urlWithoutLocale, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path as LocalizedUrl<T, L>;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const translatedPathname = getLocalizedPath(\n getCanonicalPath(parsedUrl.pathname, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n\n // ── Domain routing ────────────────────────────────────────────────────────\n // Resolve the \"current\" hostname so we can choose between a relative URL\n // (same domain) and an absolute URL (cross-domain).\n //\n // Detection priority:\n // 1. Explicit `currentDomain` option passed by the caller.\n // 2. Hostname extracted from an absolute input URL.\n // 3. `window.location.hostname` in browser environments.\n // When none of these is available we fall back to generating an absolute\n // URL for domain-mapped locales (safe for SSR/static generation): the\n // locale prefix may already be stripped for domain-exclusive locales, so a\n // relative URL would silently point to the wrong locale on the current\n // domain.\n const detectedCurrentHostname =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? getDomainHostname(\n currentDomain ??\n (isAbsoluteUrl ? parsedUrl.hostname : undefined) ??\n (typeof window !== 'undefined'\n ? window?.location?.hostname\n : undefined) ??\n ''\n ) || null\n : null;\n\n const localeDomain =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? domains?.[currentLocale as LocalesValues]\n : undefined;\n\n const localeDomainHostname = localeDomain\n ? getDomainHostname(localeDomain)\n : null;\n\n // Prepend the locale's domain when it differs from the current hostname,\n // or when the current hostname is unknown (SSR without `currentDomain`).\n const isCrossDomain =\n localeDomainHostname !== null &&\n (detectedCurrentHostname === null ||\n localeDomainHostname !== detectedCurrentHostname);\n\n const normalizedDomain =\n isCrossDomain && localeDomain ? getDomainOrigin(localeDomain) : null;\n\n const baseUrl = normalizedDomain\n ? normalizedDomain\n : isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n // ─────────────────────────────────────────────────────────────────────────\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params'\n ) &&\n mode === 'search-params'\n ) {\n const searchParams = new URLSearchParams(parsedUrl.search);\n\n searchParams.set('locale', currentLocale.toString());\n\n const queryParams = searchParams.toString();\n const path = queryParams\n ? `${translatedPathname}?${queryParams}`\n : translatedPathname;\n\n return `${baseUrl}${path}${parsedUrl.hash}` as LocalizedUrl<T, L>;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n domains,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`.replace(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}` as LocalizedUrl<\n T,\n L\n >;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEA,MAAa,mBAIX,KACA,gBAAmBA,6CAAsB,eACzC,UAA0B,EAAE,KACL;CACvB,MAAM,EAAE,eAAe,MAAM,SAAS,SAAS,SAAS,kBACtDC,oDAAqB,QAAQ;CAE/B,MAAM,mBAAmBC,+DAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAeC,kDAAgB,SAAS,MAAM;AAEpD,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,gBAExC,SAAS,YAET,QAAOC,mDACLC,mDAAiB,kBAAkB,QAAW,aAAa,EAC3D,eACA,aACD,CAAC;CAGJ,MAAM,gBAAgBC,oDAAmB,iBAAiB;CAC1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,qBAAqBF,mDACzBC,mDAAiB,UAAU,UAAU,QAAW,aAAa,EAC7D,eACA,aACD,CAAC;CAeF,MAAM,0BACJ,QAAQ,IAAI,6BAA6B,UACrCE,mDACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,GACH,IAAI,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,6BAA6B,UACrC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzBA,mDAAkB,aAAa,GAC/B;CASJ,MAAM,mBAJJ,yBAAyB,SACxB,4BAA4B,QAC3B,yBAAyB,4BAGV,eAAeC,iDAAgB,aAAa,GAAG;CAElE,MAAM,UAAU,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAGN,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,oBAExC,SAAS,iBACT;EACA,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAE1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;AAK3C,SAAO,GAAG,UAJG,cACT,GAAG,mBAAmB,GAAG,gBACzB,qBAEuB,UAAU;;CAGvC,MAAM,EAAE,WAAWC,yCAAU,eAAe;EAC1C;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS,qBAAqB,QAAQ,QAAQ,IAAI;AAE1E,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU"}
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ const require_localization_domainUtils = require('./domainUtils.cjs');
3
4
  let _intlayer_config_built = require("@intlayer/config/built");
4
5
  let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
5
6
 
@@ -55,15 +56,10 @@ const getPrefix = (locale, options = {}) => {
55
56
  prefix: "",
56
57
  localePrefix: void 0
57
58
  };
58
- if (process.env.INTLAYER_ROUTING_DOMAINS !== "false" && domains) {
59
- const localeDomain = domains[locale];
60
- if (localeDomain) {
61
- if (Object.values(domains).filter((domain) => domain === localeDomain).length === 1) return {
62
- prefix: "",
63
- localePrefix: void 0
64
- };
65
- }
66
- }
59
+ if (process.env.INTLAYER_ROUTING_DOMAINS !== "false" && require_localization_domainUtils.isLocaleExclusiveOnDomain(locale, domains)) return {
60
+ prefix: "",
61
+ localePrefix: void 0
62
+ };
67
63
  if (mode === "prefix-all" || mode === "prefix-no-default" && defaultLocale !== locale) return {
68
64
  prefix: `${locale}/`,
69
65
  localePrefix: locale
@@ -1 +1 @@
1
- {"version":3,"file":"getPrefix.cjs","names":["internationalization","DEFAULT_LOCALE","routing","ROUTING_MODE","LOCALES"],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n DeclaredLocales,\n LocalesValues,\n ResolvedDefaultLocale,\n ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (\n options: RoutingOptions = {}\n): Omit<RoutingOptions, 'defaultLocale' | 'mode' | 'locales'> & {\n defaultLocale: LocalesValues;\n mode: RoutingConfig['mode'];\n locales: LocalesValues[];\n} => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n * Empty string when no prefix is needed.\n */\n prefix: string;\n /**\n * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n L extends LocalesValues | undefined,\n Mode extends string = ResolvedRoutingMode,\n Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n : [string] extends [Mode]\n ? GetPrefixResult // mode is wide → fall back to generic result\n : Mode extends 'prefix-all'\n ? { prefix: `${L}/`; localePrefix: L }\n : Mode extends 'prefix-no-default'\n ? L extends Default\n ? { prefix: ''; localePrefix: undefined }\n : { prefix: `${L}/`; localePrefix: L }\n : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n locale: L,\n options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (process.env.INTLAYER_ROUTING_DOMAINS !== 'false' && domains) {\n const localeDomain = domains[locale as LocalesValues];\n\n if (localeDomain) {\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) => domain === localeDomain\n ).length;\n\n if (localesOnSameDomain === 1) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n }\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;;;AA+CA,MAAa,wBACX,UAA0B,EAAE,MAKxB;CACJ,eAAeA,6CAAsB,iBAAiBC;CACtD,MAAMC,gCAAS,QAAQC;CACvB,SAASH,6CAAsB,WAAWI;CAC1C,SAASF,gCAAS;CAClB,SAASA,gCAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,yBACX,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B,uBACxC,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,6BAA6B,WAAW,SAAS;EAC/D,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
1
+ {"version":3,"file":"getPrefix.cjs","names":["internationalization","DEFAULT_LOCALE","routing","ROUTING_MODE","LOCALES","isLocaleExclusiveOnDomain"],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n DeclaredLocales,\n LocalesValues,\n ResolvedDefaultLocale,\n ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\nimport { isLocaleExclusiveOnDomain } from './domainUtils';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (\n options: RoutingOptions = {}\n): Omit<RoutingOptions, 'defaultLocale' | 'mode' | 'locales'> & {\n defaultLocale: LocalesValues;\n mode: RoutingConfig['mode'];\n locales: LocalesValues[];\n} => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n * Empty string when no prefix is needed.\n */\n prefix: string;\n /**\n * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n L extends LocalesValues | undefined,\n Mode extends string = ResolvedRoutingMode,\n Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n : [string] extends [Mode]\n ? GetPrefixResult // mode is wide → fall back to generic result\n : Mode extends 'prefix-all'\n ? { prefix: `${L}/`; localePrefix: L }\n : Mode extends 'prefix-no-default'\n ? L extends Default\n ? { prefix: ''; localePrefix: undefined }\n : { prefix: `${L}/`; localePrefix: L }\n : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n locale: L,\n options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false' &&\n isLocaleExclusiveOnDomain(locale as LocalesValues, domains)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;;;;AAgDA,MAAa,wBACX,UAA0B,EAAE,MAKxB;CACJ,eAAeA,6CAAsB,iBAAiBC;CACtD,MAAMC,gCAAS,QAAQC;CACvB,SAASH,6CAAsB,WAAWI;CAC1C,SAASF,gCAAS;CAClB,SAASA,gCAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,yBACX,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B,uBACxC,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KACE,QAAQ,IAAI,6BAA6B,WACzCG,2DAA0B,QAAyB,QAAQ,CAE3D,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAQH,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_localization_getPathWithoutLocale = require('./getPathWithoutLocale.cjs');
3
3
  const require_localization_comparePaths = require('./comparePaths.cjs');
4
+ const require_localization_domainUtils = require('./domainUtils.cjs');
4
5
  const require_localization_getPrefix = require('./getPrefix.cjs');
5
6
  const require_localization_rewriteUtils = require('./rewriteUtils.cjs');
6
7
  const require_localization_getLocalizedUrl = require('./getLocalizedUrl.cjs');
@@ -22,9 +23,12 @@ exports.generateSitemap = require_localization_generateSitemap.generateSitemap;
22
23
  exports.generateSitemapUrl = require_localization_generateSitemap.generateSitemapUrl;
23
24
  exports.getBrowserLocale = require_localization_getBrowserLocale.getBrowserLocale;
24
25
  exports.getCanonicalPath = require_localization_rewriteUtils.getCanonicalPath;
26
+ exports.getDomainHostname = require_localization_domainUtils.getDomainHostname;
27
+ exports.getDomainOrigin = require_localization_domainUtils.getDomainOrigin;
25
28
  exports.getHTMLTextDir = require_localization_getHTMLTextDir.getHTMLTextDir;
26
29
  exports.getInternalPath = require_localization_rewriteUtils.getInternalPath;
27
30
  exports.getLocale = require_localization_getLocale.getLocale;
31
+ exports.getLocaleFromDomain = require_localization_domainUtils.getLocaleFromDomain;
28
32
  exports.getLocaleFromPath = require_localization_getLocaleFromPath.getLocaleFromPath;
29
33
  exports.getLocaleLang = require_localization_getLocaleLang.getLocaleLang;
30
34
  exports.getLocaleName = require_localization_getLocaleName.getLocaleName;
@@ -35,6 +39,7 @@ exports.getPathWithoutLocale = require_localization_getPathWithoutLocale.getPath
35
39
  exports.getPrefix = require_localization_getPrefix.getPrefix;
36
40
  exports.getRewritePath = require_localization_rewriteUtils.getRewritePath;
37
41
  exports.getRewriteRules = require_localization_rewriteUtils.getRewriteRules;
42
+ exports.isLocaleExclusiveOnDomain = require_localization_domainUtils.isLocaleExclusiveOnDomain;
38
43
  exports.localeDetector = require_localization_localeDetector.localeDetector;
39
44
  exports.localeFlatMap = require_localization_localeMapper.localeFlatMap;
40
45
  exports.localeMap = require_localization_localeMapper.localeMap;
@@ -63,6 +63,7 @@ import { updateNodeChildren } from "./dictionaryManipulator/updateNodeChildren.m
63
63
  import { checkIsURLAbsolute } from "./utils/checkIsURLAbsolute.mjs";
64
64
  import { getPathWithoutLocale } from "./localization/getPathWithoutLocale.mjs";
65
65
  import { comparePaths, normalizePath } from "./localization/comparePaths.mjs";
66
+ import { getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain } from "./localization/domainUtils.mjs";
66
67
  import { getPrefix } from "./localization/getPrefix.mjs";
67
68
  import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./localization/rewriteUtils.mjs";
68
69
  import { getLocalizedUrl } from "./localization/getLocalizedUrl.mjs";
@@ -94,4 +95,4 @@ import { interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageN
94
95
  import { isSameKeyPath } from "./utils/isSameKeyPath.mjs";
95
96
  import { stringifyYaml } from "./utils/stringifyYaml.mjs";
96
97
 
97
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleType, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, serializeVariant, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
98
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleType, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isLocaleExclusiveOnDomain, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, serializeVariant, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
@@ -0,0 +1,77 @@
1
+ //#region src/localization/domainUtils.ts
2
+ /**
3
+ * Strips the protocol from a domain string and returns only the hostname.
4
+ *
5
+ * Example:
6
+ *
7
+ * ```ts
8
+ * getDomainHostname('https://intlayer.cn') // 'intlayer.cn'
9
+ * getDomainHostname('intlayer.cn') // 'intlayer.cn'
10
+ * ```
11
+ *
12
+ * @param domain - A domain value from `routing.domains`, with or without protocol.
13
+ * @returns The bare hostname.
14
+ */
15
+ const getDomainHostname = (domain) => {
16
+ try {
17
+ return /^https?:\/\//.test(domain) ? new URL(domain).hostname : domain;
18
+ } catch {
19
+ return domain;
20
+ }
21
+ };
22
+ /**
23
+ * Returns the absolute origin for a domain value, prepending `https://`
24
+ * when no protocol is present.
25
+ *
26
+ * Example:
27
+ *
28
+ * ```ts
29
+ * getDomainOrigin('intlayer.cn') // 'https://intlayer.cn'
30
+ * getDomainOrigin('http://intlayer.cn') // 'http://intlayer.cn'
31
+ * ```
32
+ *
33
+ * @param domain - A domain value from `routing.domains`, with or without protocol.
34
+ * @returns The origin usable as a URL base.
35
+ */
36
+ const getDomainOrigin = (domain) => /^https?:\/\//.test(domain) ? domain : `https://${domain}`;
37
+ /**
38
+ * Returns the locale exclusively mapped to a given hostname via `routing.domains`,
39
+ * or `undefined` when zero or more than one locale share that hostname.
40
+ *
41
+ * Example: with `domains = { zh: 'intlayer.cn', en: 'intlayer.org', fr: 'intlayer.org' }`
42
+ *
43
+ * ```ts
44
+ * getLocaleFromDomain('intlayer.cn', domains) // 'zh'
45
+ * getLocaleFromDomain('intlayer.org', domains) // undefined (en and fr share it)
46
+ * getLocaleFromDomain('example.com', domains) // undefined (not mapped)
47
+ * ```
48
+ *
49
+ * @param hostname - The bare hostname of the incoming request.
50
+ * @param domains - The configured locale → domain map.
51
+ * @returns The exclusively mapped locale, or `undefined`.
52
+ */
53
+ const getLocaleFromDomain = (hostname, domains) => {
54
+ if (!domains) return void 0;
55
+ const matchingLocales = Object.entries(domains).filter(([, domain]) => typeof domain === "string" && getDomainHostname(domain) === hostname);
56
+ return matchingLocales.length === 1 ? matchingLocales[0]?.[0] : void 0;
57
+ };
58
+ /**
59
+ * Checks whether a locale is the only locale mapped to its configured domain.
60
+ * When true, the domain alone identifies the locale and no URL prefix is needed.
61
+ * Hostnames are compared after protocol stripping, so
62
+ * `{ en: 'https://intlayer.org', fr: 'intlayer.org' }` counts as a shared domain.
63
+ *
64
+ * @param locale - The locale to check.
65
+ * @param domains - The configured locale → domain map.
66
+ * @returns `true` when the locale has a domain shared with no other locale.
67
+ */
68
+ const isLocaleExclusiveOnDomain = (locale, domains) => {
69
+ const localeDomain = domains?.[locale];
70
+ if (!localeDomain) return false;
71
+ const localeHostname = getDomainHostname(localeDomain);
72
+ return Object.values(domains).filter((domain) => typeof domain === "string" && getDomainHostname(domain) === localeHostname).length === 1;
73
+ };
74
+
75
+ //#endregion
76
+ export { getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain };
77
+ //# sourceMappingURL=domainUtils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domainUtils.mjs","names":[],"sources":["../../../src/localization/domainUtils.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n/**\n * The locale → domain map configured under `routing.domains`\n * (e.g. `{ en: 'intlayer.org', zh: 'intlayer.cn' }`).\n */\nexport type LocaleDomainMap = RoutingConfig['domains'];\n\n/**\n * Strips the protocol from a domain string and returns only the hostname.\n *\n * Example:\n *\n * ```ts\n * getDomainHostname('https://intlayer.cn') // 'intlayer.cn'\n * getDomainHostname('intlayer.cn') // 'intlayer.cn'\n * ```\n *\n * @param domain - A domain value from `routing.domains`, with or without protocol.\n * @returns The bare hostname.\n */\nexport const getDomainHostname = (domain: string): string => {\n try {\n return /^https?:\\/\\//.test(domain) ? new URL(domain).hostname : domain;\n } catch {\n return domain;\n }\n};\n\n/**\n * Returns the absolute origin for a domain value, prepending `https://`\n * when no protocol is present.\n *\n * Example:\n *\n * ```ts\n * getDomainOrigin('intlayer.cn') // 'https://intlayer.cn'\n * getDomainOrigin('http://intlayer.cn') // 'http://intlayer.cn'\n * ```\n *\n * @param domain - A domain value from `routing.domains`, with or without protocol.\n * @returns The origin usable as a URL base.\n */\nexport const getDomainOrigin = (domain: string): string =>\n /^https?:\\/\\//.test(domain) ? domain : `https://${domain}`;\n\n/**\n * Returns the locale exclusively mapped to a given hostname via `routing.domains`,\n * or `undefined` when zero or more than one locale share that hostname.\n *\n * Example: with `domains = { zh: 'intlayer.cn', en: 'intlayer.org', fr: 'intlayer.org' }`\n *\n * ```ts\n * getLocaleFromDomain('intlayer.cn', domains) // 'zh'\n * getLocaleFromDomain('intlayer.org', domains) // undefined (en and fr share it)\n * getLocaleFromDomain('example.com', domains) // undefined (not mapped)\n * ```\n *\n * @param hostname - The bare hostname of the incoming request.\n * @param domains - The configured locale → domain map.\n * @returns The exclusively mapped locale, or `undefined`.\n */\nexport const getLocaleFromDomain = (\n hostname: string,\n domains: LocaleDomainMap\n): Locale | undefined => {\n if (!domains) return undefined;\n\n const matchingLocales = Object.entries(domains).filter(\n ([, domain]) =>\n typeof domain === 'string' && getDomainHostname(domain) === hostname\n );\n\n return matchingLocales.length === 1\n ? (matchingLocales[0]?.[0] as Locale)\n : undefined;\n};\n\n/**\n * Checks whether a locale is the only locale mapped to its configured domain.\n * When true, the domain alone identifies the locale and no URL prefix is needed.\n * Hostnames are compared after protocol stripping, so\n * `{ en: 'https://intlayer.org', fr: 'intlayer.org' }` counts as a shared domain.\n *\n * @param locale - The locale to check.\n * @param domains - The configured locale → domain map.\n * @returns `true` when the locale has a domain shared with no other locale.\n */\nexport const isLocaleExclusiveOnDomain = (\n locale: LocalesValues,\n domains: LocaleDomainMap\n): boolean => {\n const localeDomain = domains?.[locale];\n\n if (!localeDomain) return false;\n\n const localeHostname = getDomainHostname(localeDomain);\n\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) =>\n typeof domain === 'string' && getDomainHostname(domain) === localeHostname\n ).length;\n\n return localesOnSameDomain === 1;\n};\n"],"mappings":";;;;;;;;;;;;;;AAuBA,MAAa,qBAAqB,WAA2B;AAC3D,KAAI;AACF,SAAO,eAAe,KAAK,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,WAAW;SAC1D;AACN,SAAO;;;;;;;;;;;;;;;;;AAkBX,MAAa,mBAAmB,WAC9B,eAAe,KAAK,OAAO,GAAG,SAAS,WAAW;;;;;;;;;;;;;;;;;AAkBpD,MAAa,uBACX,UACA,YACuB;AACvB,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,kBAAkB,OAAO,QAAQ,QAAQ,CAAC,QAC7C,GAAG,YACF,OAAO,WAAW,YAAY,kBAAkB,OAAO,KAAK,SAC/D;AAED,QAAO,gBAAgB,WAAW,IAC7B,gBAAgB,KAAK,KACtB;;;;;;;;;;;;AAaN,MAAa,6BACX,QACA,YACY;CACZ,MAAM,eAAe,UAAU;AAE/B,KAAI,CAAC,aAAc,QAAO;CAE1B,MAAM,iBAAiB,kBAAkB,aAAa;AAOtD,QAL4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WACC,OAAO,WAAW,YAAY,kBAAkB,OAAO,KAAK,eAC/D,CAAC,WAE6B"}
@@ -1,18 +1,11 @@
1
1
  import { checkIsURLAbsolute } from "../utils/checkIsURLAbsolute.mjs";
2
2
  import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
3
+ import { getDomainHostname, getDomainOrigin } from "./domainUtils.mjs";
3
4
  import { getPrefix, resolveRoutingConfig } from "./getPrefix.mjs";
4
5
  import { getCanonicalPath, getLocalizedPath, getRewriteRules } from "./rewriteUtils.mjs";
5
6
  import { internationalization } from "@intlayer/config/built";
6
7
 
7
8
  //#region src/localization/getLocalizedUrl.ts
8
- /** Strips the protocol and returns the bare hostname of a domain string. */
9
- const extractHostname = (domain) => {
10
- try {
11
- return /^https?:\/\//.test(domain) ? new URL(domain).hostname : domain;
12
- } catch {
13
- return domain;
14
- }
15
- };
16
9
  /**
17
10
  * Generate URL by prefixing the given URL with the referenced locale or adding search parameters
18
11
  * based on the routing mode. Handles both absolute and relative URLs appropriately.
@@ -65,10 +58,10 @@ const getLocalizedUrl = (url, currentLocale = internationalization?.defaultLocal
65
58
  const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);
66
59
  const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com");
67
60
  const translatedPathname = getLocalizedPath(getCanonicalPath(parsedUrl.pathname, void 0, rewriteRules), currentLocale, rewriteRules).path;
68
- const detectedCurrentHostname = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? extractHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null;
61
+ const detectedCurrentHostname = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? getDomainHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null;
69
62
  const localeDomain = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? domains?.[currentLocale] : void 0;
70
- const localeDomainHostname = localeDomain ? extractHostname(localeDomain) : null;
71
- const normalizedDomain = localeDomainHostname !== null && detectedCurrentHostname !== null && localeDomainHostname !== detectedCurrentHostname && localeDomain ? /^https?:\/\//.test(localeDomain) ? localeDomain : `https://${localeDomain}` : null;
63
+ const localeDomainHostname = localeDomain ? getDomainHostname(localeDomain) : null;
64
+ const normalizedDomain = localeDomainHostname !== null && (detectedCurrentHostname === null || localeDomainHostname !== detectedCurrentHostname) && localeDomain ? getDomainOrigin(localeDomain) : null;
72
65
  const baseUrl = normalizedDomain ? normalizedDomain : isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : "";
73
66
  if (!(process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "search-params") && mode === "search-params") {
74
67
  const searchParams = new URLSearchParams(parsedUrl.search);
@@ -1 +1 @@
1
- {"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n LocalesValues,\n LocalizedUrl,\n ResolvedDefaultLocale,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\nexport type { RoutingOptions };\n\n/** Strips the protocol and returns the bare hostname of a domain string. */\nconst extractHostname = (domain: string): string => {\n try {\n return /^https?:\\/\\//.test(domain) ? new URL(domain).hostname : domain;\n } catch {\n return domain;\n }\n};\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @param options.currentDomain - Hostname of the page being rendered. Used to decide\n * whether to emit a relative URL (same domain) or an absolute URL (cross-domain).\n * Auto-detected from the input URL or `window.location` when omitted.\n * @returns The localized URL for the current locale.\n */\n/**\n * The return type is narrowed to a template-literal type when both `url` and\n * `currentLocale` are string literals and the routing mode / defaultLocale are\n * not overridden via `options`.\n */\nexport const getLocalizedUrl = <\n const T extends string,\n const L extends LocalesValues = ResolvedDefaultLocale,\n>(\n url: T,\n currentLocale: L = internationalization?.defaultLocale as L,\n options: RoutingOptions = {}\n): LocalizedUrl<T, L> => {\n const { defaultLocale, mode, locales, rewrite, domains, currentDomain } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'no-prefix'\n ) &&\n mode === 'no-prefix'\n ) {\n return getLocalizedPath(\n getCanonicalPath(urlWithoutLocale, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path as LocalizedUrl<T, L>;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const translatedPathname = getLocalizedPath(\n getCanonicalPath(parsedUrl.pathname, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n\n // ── Domain routing ────────────────────────────────────────────────────────\n // Resolve the \"current\" hostname so we can choose between a relative URL\n // (same domain) and an absolute URL (cross-domain).\n //\n // Detection priority:\n // 1. Explicit `currentDomain` option passed by the caller.\n // 2. Hostname extracted from an absolute input URL.\n // 3. `window.location.hostname` in browser environments.\n // When none of these is available we fall back to always generating an\n // absolute URL (the previous behaviour, safe for SSR/static generation).\n const detectedCurrentHostname =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? extractHostname(\n currentDomain ??\n (isAbsoluteUrl ? parsedUrl.hostname : undefined) ??\n (typeof window !== 'undefined'\n ? window?.location?.hostname\n : undefined) ??\n ''\n ) || null\n : null;\n\n const localeDomain =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? domains?.[currentLocale as LocalesValues]\n : undefined;\n\n const localeDomainHostname = localeDomain\n ? extractHostname(localeDomain)\n : null;\n\n // Only prepend the locale's domain when it differs from the current hostname.\n const isCrossDomain =\n localeDomainHostname !== null &&\n detectedCurrentHostname !== null &&\n localeDomainHostname !== detectedCurrentHostname;\n\n const normalizedDomain =\n isCrossDomain && localeDomain\n ? /^https?:\\/\\//.test(localeDomain)\n ? localeDomain\n : `https://${localeDomain}`\n : null;\n\n const baseUrl = normalizedDomain\n ? normalizedDomain\n : isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n // ─────────────────────────────────────────────────────────────────────────\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params'\n ) &&\n mode === 'search-params'\n ) {\n const searchParams = new URLSearchParams(parsedUrl.search);\n\n searchParams.set('locale', currentLocale.toString());\n\n const queryParams = searchParams.toString();\n const path = queryParams\n ? `${translatedPathname}?${queryParams}`\n : translatedPathname;\n\n return `${baseUrl}${path}${parsedUrl.hash}` as LocalizedUrl<T, L>;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n domains,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`.replace(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}` as LocalizedUrl<\n T,\n L\n >;\n};\n"],"mappings":";;;;;;;;AA4BA,MAAM,mBAAmB,WAA2B;AAClD,KAAI;AACF,SAAO,eAAe,KAAK,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,WAAW;SAC1D;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDX,MAAa,mBAIX,KACA,gBAAmB,sBAAsB,eACzC,UAA0B,EAAE,KACL;CACvB,MAAM,EAAE,eAAe,MAAM,SAAS,SAAS,SAAS,kBACtD,qBAAqB,QAAQ;CAE/B,MAAM,mBAAmB,qBAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAe,gBAAgB,SAAS,MAAM;AAEpD,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,gBAExC,SAAS,YAET,QAAO,iBACL,iBAAiB,kBAAkB,QAAW,aAAa,EAC3D,eACA,aACD,CAAC;CAGJ,MAAM,gBAAgB,mBAAmB,iBAAiB;CAC1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,qBAAqB,iBACzB,iBAAiB,UAAU,UAAU,QAAW,aAAa,EAC7D,eACA,aACD,CAAC;CAYF,MAAM,0BACJ,QAAQ,IAAI,6BAA6B,UACrC,gBACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,GACH,IAAI,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,6BAA6B,UACrC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzB,gBAAgB,aAAa,GAC7B;CAQJ,MAAM,mBAJJ,yBAAyB,QACzB,4BAA4B,QAC5B,yBAAyB,2BAGR,eACb,eAAe,KAAK,aAAa,GAC/B,eACA,WAAW,iBACb;CAEN,MAAM,UAAU,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAGN,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,oBAExC,SAAS,iBACT;EACA,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAE1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;AAK3C,SAAO,GAAG,UAJG,cACT,GAAG,mBAAmB,GAAG,gBACzB,qBAEuB,UAAU;;CAGvC,MAAM,EAAE,WAAW,UAAU,eAAe;EAC1C;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS,qBAAqB,QAAQ,QAAQ,IAAI;AAE1E,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU"}
1
+ {"version":3,"file":"getLocalizedUrl.mjs","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n LocalesValues,\n LocalizedUrl,\n ResolvedDefaultLocale,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getDomainHostname, getDomainOrigin } from './domainUtils';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\nexport type { RoutingOptions };\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @param options.currentDomain - Hostname of the page being rendered. Used to decide\n * whether to emit a relative URL (same domain) or an absolute URL (cross-domain).\n * Auto-detected from the input URL or `window.location` when omitted.\n * @returns The localized URL for the current locale.\n */\n/**\n * The return type is narrowed to a template-literal type when both `url` and\n * `currentLocale` are string literals and the routing mode / defaultLocale are\n * not overridden via `options`.\n */\nexport const getLocalizedUrl = <\n const T extends string,\n const L extends LocalesValues = ResolvedDefaultLocale,\n>(\n url: T,\n currentLocale: L = internationalization?.defaultLocale as L,\n options: RoutingOptions = {}\n): LocalizedUrl<T, L> => {\n const { defaultLocale, mode, locales, rewrite, domains, currentDomain } =\n resolveRoutingConfig(options);\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n const rewriteRules = getRewriteRules(rewrite, 'url');\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'no-prefix'\n ) &&\n mode === 'no-prefix'\n ) {\n return getLocalizedPath(\n getCanonicalPath(urlWithoutLocale, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path as LocalizedUrl<T, L>;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const translatedPathname = getLocalizedPath(\n getCanonicalPath(parsedUrl.pathname, undefined, rewriteRules),\n currentLocale as Locale,\n rewriteRules\n ).path;\n\n // ── Domain routing ────────────────────────────────────────────────────────\n // Resolve the \"current\" hostname so we can choose between a relative URL\n // (same domain) and an absolute URL (cross-domain).\n //\n // Detection priority:\n // 1. Explicit `currentDomain` option passed by the caller.\n // 2. Hostname extracted from an absolute input URL.\n // 3. `window.location.hostname` in browser environments.\n // When none of these is available we fall back to generating an absolute\n // URL for domain-mapped locales (safe for SSR/static generation): the\n // locale prefix may already be stripped for domain-exclusive locales, so a\n // relative URL would silently point to the wrong locale on the current\n // domain.\n const detectedCurrentHostname =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? getDomainHostname(\n currentDomain ??\n (isAbsoluteUrl ? parsedUrl.hostname : undefined) ??\n (typeof window !== 'undefined'\n ? window?.location?.hostname\n : undefined) ??\n ''\n ) || null\n : null;\n\n const localeDomain =\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false'\n ? domains?.[currentLocale as LocalesValues]\n : undefined;\n\n const localeDomainHostname = localeDomain\n ? getDomainHostname(localeDomain)\n : null;\n\n // Prepend the locale's domain when it differs from the current hostname,\n // or when the current hostname is unknown (SSR without `currentDomain`).\n const isCrossDomain =\n localeDomainHostname !== null &&\n (detectedCurrentHostname === null ||\n localeDomainHostname !== detectedCurrentHostname);\n\n const normalizedDomain =\n isCrossDomain && localeDomain ? getDomainOrigin(localeDomain) : null;\n\n const baseUrl = normalizedDomain\n ? normalizedDomain\n : isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n // ─────────────────────────────────────────────────────────────────────────\n\n if (\n !(\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params'\n ) &&\n mode === 'search-params'\n ) {\n const searchParams = new URLSearchParams(parsedUrl.search);\n\n searchParams.set('locale', currentLocale.toString());\n\n const queryParams = searchParams.toString();\n const path = queryParams\n ? `${translatedPathname}?${queryParams}`\n : translatedPathname;\n\n return `${baseUrl}${path}${parsedUrl.hash}` as LocalizedUrl<T, L>;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n domains,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`.replace(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}` as LocalizedUrl<\n T,\n L\n >;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEA,MAAa,mBAIX,KACA,gBAAmB,sBAAsB,eACzC,UAA0B,EAAE,KACL;CACvB,MAAM,EAAE,eAAe,MAAM,SAAS,SAAS,SAAS,kBACtD,qBAAqB,QAAQ;CAE/B,MAAM,mBAAmB,qBAAqB,KAAK,QAAQ;CAC3D,MAAM,eAAe,gBAAgB,SAAS,MAAM;AAEpD,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,gBAExC,SAAS,YAET,QAAO,iBACL,iBAAiB,kBAAkB,QAAW,aAAa,EAC3D,eACA,aACD,CAAC;CAGJ,MAAM,gBAAgB,mBAAmB,iBAAiB;CAC1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,qBAAqB,iBACzB,iBAAiB,UAAU,UAAU,QAAW,aAAa,EAC7D,eACA,aACD,CAAC;CAeF,MAAM,0BACJ,QAAQ,IAAI,6BAA6B,UACrC,kBACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,GACH,IAAI,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,6BAA6B,UACrC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzB,kBAAkB,aAAa,GAC/B;CASJ,MAAM,mBAJJ,yBAAyB,SACxB,4BAA4B,QAC3B,yBAAyB,4BAGV,eAAe,gBAAgB,aAAa,GAAG;CAElE,MAAM,UAAU,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;AAGN,KACE,EACE,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,oBAExC,SAAS,iBACT;EACA,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAE1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;AAK3C,SAAO,GAAG,UAJG,cACT,GAAG,mBAAmB,GAAG,gBACzB,qBAEuB,UAAU;;CAGvC,MAAM,EAAE,WAAW,UAAU,eAAe;EAC1C;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS,qBAAqB,QAAQ,QAAQ,IAAI;AAE1E,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,QAAO,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU"}
@@ -1,3 +1,4 @@
1
+ import { isLocaleExclusiveOnDomain } from "./domainUtils.mjs";
1
2
  import { internationalization, routing } from "@intlayer/config/built";
2
3
  import { DEFAULT_LOCALE, LOCALES, ROUTING_MODE } from "@intlayer/config/defaultValues";
3
4
 
@@ -53,15 +54,10 @@ const getPrefix = (locale, options = {}) => {
53
54
  prefix: "",
54
55
  localePrefix: void 0
55
56
  };
56
- if (process.env.INTLAYER_ROUTING_DOMAINS !== "false" && domains) {
57
- const localeDomain = domains[locale];
58
- if (localeDomain) {
59
- if (Object.values(domains).filter((domain) => domain === localeDomain).length === 1) return {
60
- prefix: "",
61
- localePrefix: void 0
62
- };
63
- }
64
- }
57
+ if (process.env.INTLAYER_ROUTING_DOMAINS !== "false" && isLocaleExclusiveOnDomain(locale, domains)) return {
58
+ prefix: "",
59
+ localePrefix: void 0
60
+ };
65
61
  if (mode === "prefix-all" || mode === "prefix-no-default" && defaultLocale !== locale) return {
66
62
  prefix: `${locale}/`,
67
63
  localePrefix: locale
@@ -1 +1 @@
1
- {"version":3,"file":"getPrefix.mjs","names":[],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n DeclaredLocales,\n LocalesValues,\n ResolvedDefaultLocale,\n ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (\n options: RoutingOptions = {}\n): Omit<RoutingOptions, 'defaultLocale' | 'mode' | 'locales'> & {\n defaultLocale: LocalesValues;\n mode: RoutingConfig['mode'];\n locales: LocalesValues[];\n} => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n * Empty string when no prefix is needed.\n */\n prefix: string;\n /**\n * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n L extends LocalesValues | undefined,\n Mode extends string = ResolvedRoutingMode,\n Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n : [string] extends [Mode]\n ? GetPrefixResult // mode is wide → fall back to generic result\n : Mode extends 'prefix-all'\n ? { prefix: `${L}/`; localePrefix: L }\n : Mode extends 'prefix-no-default'\n ? L extends Default\n ? { prefix: ''; localePrefix: undefined }\n : { prefix: `${L}/`; localePrefix: L }\n : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n locale: L,\n options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (process.env.INTLAYER_ROUTING_DOMAINS !== 'false' && domains) {\n const localeDomain = domains[locale as LocalesValues];\n\n if (localeDomain) {\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) => domain === localeDomain\n ).length;\n\n if (localesOnSameDomain === 1) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n }\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;AA+CA,MAAa,wBACX,UAA0B,EAAE,MAKxB;CACJ,eAAe,sBAAsB,iBAAiB;CACtD,MAAM,SAAS,QAAQ;CACvB,SAAS,sBAAsB,WAAW;CAC1C,SAAS,SAAS;CAClB,SAAS,SAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,yBACX,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B,uBACxC,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,6BAA6B,WAAW,SAAS;EAC/D,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
1
+ {"version":3,"file":"getPrefix.mjs","names":[],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n DeclaredLocales,\n LocalesValues,\n ResolvedDefaultLocale,\n ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\nimport { isLocaleExclusiveOnDomain } from './domainUtils';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (\n options: RoutingOptions = {}\n): Omit<RoutingOptions, 'defaultLocale' | 'mode' | 'locales'> & {\n defaultLocale: LocalesValues;\n mode: RoutingConfig['mode'];\n locales: LocalesValues[];\n} => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n * Empty string when no prefix is needed.\n */\n prefix: string;\n /**\n * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n L extends LocalesValues | undefined,\n Mode extends string = ResolvedRoutingMode,\n Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n : [string] extends [Mode]\n ? GetPrefixResult // mode is wide → fall back to generic result\n : Mode extends 'prefix-all'\n ? { prefix: `${L}/`; localePrefix: L }\n : Mode extends 'prefix-no-default'\n ? L extends Default\n ? { prefix: ''; localePrefix: undefined }\n : { prefix: `${L}/`; localePrefix: L }\n : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n locale: L,\n options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (\n process.env.INTLAYER_ROUTING_DOMAINS !== 'false' &&\n isLocaleExclusiveOnDomain(locale as LocalesValues, domains)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;;AAgDA,MAAa,wBACX,UAA0B,EAAE,MAKxB;CACJ,eAAe,sBAAsB,iBAAiB;CACtD,MAAM,SAAS,QAAQ;CACvB,SAAS,sBAAsB,WAAW;CAC1C,SAAS,SAAS;CAClB,SAAS,SAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,yBACX,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B,uBACxC,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KACE,QAAQ,IAAI,6BAA6B,WACzC,0BAA0B,QAAyB,QAAQ,CAE3D,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAQH,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
@@ -1,5 +1,6 @@
1
1
  import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
2
2
  import { comparePaths, normalizePath } from "./comparePaths.mjs";
3
+ import { getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain } from "./domainUtils.mjs";
3
4
  import { getPrefix } from "./getPrefix.mjs";
4
5
  import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.mjs";
5
6
  import { getLocalizedUrl } from "./getLocalizedUrl.mjs";
@@ -16,4 +17,4 @@ import { getLocaleName } from "./getLocaleName.mjs";
16
17
  import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.mjs";
17
18
  import { validatePrefix } from "./validatePrefix.mjs";
18
19
 
19
- export { comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
20
+ export { comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getDomainHostname, getDomainOrigin, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, isLocaleExclusiveOnDomain, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
@@ -60,6 +60,7 @@ import { percentage } from "./formatters/percentage.js";
60
60
  import { relativeTime } from "./formatters/relativeTime.js";
61
61
  import { units } from "./formatters/units.js";
62
62
  import { comparePaths, normalizePath } from "./localization/comparePaths.js";
63
+ import { LocaleDomainMap, getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain } from "./localization/domainUtils.js";
63
64
  import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./localization/generateSitemap.js";
64
65
  import { getBrowserLocale } from "./localization/getBrowserLocale.js";
65
66
  import { getHTMLTextDir } from "./localization/getHTMLTextDir.js";
@@ -95,4 +96,4 @@ import { isValidElement } from "./utils/isValidReactElement.js";
95
96
  import { CookieBuildAttributes, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, localeStorageOptions, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer } from "./utils/localeStorage.js";
96
97
  import { YamlRecord, YamlValue, parseYaml } from "./utils/parseYaml.js";
97
98
  import { stringifyYaml } from "./utils/stringifyYaml.js";
98
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, CustomComponentNode, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, EscapedTextNode, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, FileContent, FileContentConstructor, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, GenerateSitemapOptions, GetNestingResult, GetPrefixOptions, GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTMLCommentNode, HTMLContent, HTMLContentConstructor, HTMLNode, HTMLSelfClosingNode, HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, HeadingNode, HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, IsAny, ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LinkAngleBraceNode, LinkBareURLNode, LinkNode, ListType, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, MarkdownContext, MarkdownOptions, MarkdownRuntime, HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedParser, NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, OrderedListNode, PARAGRAPH_R, ParagraphNode, ParseState, ParsedMarkdown, Parser, ParserResult, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, Priority, PriorityValue, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, RuleType, RuleTypeValue, Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SitemapUrlEntry, StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, TableNode, TableSeparatorNode, TaggedMessageToken, TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, file, fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, serializeVariant, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
99
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, CustomComponentNode, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, EscapedTextNode, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, FileContent, FileContentConstructor, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, GenerateSitemapOptions, GetNestingResult, GetPrefixOptions, GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTMLCommentNode, HTMLContent, HTMLContentConstructor, HTMLNode, HTMLSelfClosingNode, HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, HeadingNode, HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, IsAny, ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LinkAngleBraceNode, LinkBareURLNode, LinkNode, ListType, LocaleDomainMap, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, MarkdownContext, MarkdownOptions, MarkdownRuntime, HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedParser, NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, OrderedListNode, PARAGRAPH_R, ParagraphNode, ParseState, ParsedMarkdown, Parser, ParserResult, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, Priority, PriorityValue, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, RuleType, RuleTypeValue, Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SitemapUrlEntry, StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, TableNode, TableSeparatorNode, TaggedMessageToken, TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, file, fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isLocaleExclusiveOnDomain, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, serializeVariant, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
@@ -0,0 +1,70 @@
1
+ import { LocalesValues } from "@intlayer/types/module_augmentation";
2
+ import { Locale } from "@intlayer/types/allLocales";
3
+ import { RoutingConfig } from "@intlayer/types/config";
4
+
5
+ //#region src/localization/domainUtils.d.ts
6
+ /**
7
+ * The locale → domain map configured under `routing.domains`
8
+ * (e.g. `{ en: 'intlayer.org', zh: 'intlayer.cn' }`).
9
+ */
10
+ type LocaleDomainMap = RoutingConfig['domains'];
11
+ /**
12
+ * Strips the protocol from a domain string and returns only the hostname.
13
+ *
14
+ * Example:
15
+ *
16
+ * ```ts
17
+ * getDomainHostname('https://intlayer.cn') // 'intlayer.cn'
18
+ * getDomainHostname('intlayer.cn') // 'intlayer.cn'
19
+ * ```
20
+ *
21
+ * @param domain - A domain value from `routing.domains`, with or without protocol.
22
+ * @returns The bare hostname.
23
+ */
24
+ declare const getDomainHostname: (domain: string) => string;
25
+ /**
26
+ * Returns the absolute origin for a domain value, prepending `https://`
27
+ * when no protocol is present.
28
+ *
29
+ * Example:
30
+ *
31
+ * ```ts
32
+ * getDomainOrigin('intlayer.cn') // 'https://intlayer.cn'
33
+ * getDomainOrigin('http://intlayer.cn') // 'http://intlayer.cn'
34
+ * ```
35
+ *
36
+ * @param domain - A domain value from `routing.domains`, with or without protocol.
37
+ * @returns The origin usable as a URL base.
38
+ */
39
+ declare const getDomainOrigin: (domain: string) => string;
40
+ /**
41
+ * Returns the locale exclusively mapped to a given hostname via `routing.domains`,
42
+ * or `undefined` when zero or more than one locale share that hostname.
43
+ *
44
+ * Example: with `domains = { zh: 'intlayer.cn', en: 'intlayer.org', fr: 'intlayer.org' }`
45
+ *
46
+ * ```ts
47
+ * getLocaleFromDomain('intlayer.cn', domains) // 'zh'
48
+ * getLocaleFromDomain('intlayer.org', domains) // undefined (en and fr share it)
49
+ * getLocaleFromDomain('example.com', domains) // undefined (not mapped)
50
+ * ```
51
+ *
52
+ * @param hostname - The bare hostname of the incoming request.
53
+ * @param domains - The configured locale → domain map.
54
+ * @returns The exclusively mapped locale, or `undefined`.
55
+ */
56
+ declare const getLocaleFromDomain: (hostname: string, domains: LocaleDomainMap) => Locale | undefined;
57
+ /**
58
+ * Checks whether a locale is the only locale mapped to its configured domain.
59
+ * When true, the domain alone identifies the locale and no URL prefix is needed.
60
+ * Hostnames are compared after protocol stripping, so
61
+ * `{ en: 'https://intlayer.org', fr: 'intlayer.org' }` counts as a shared domain.
62
+ *
63
+ * @param locale - The locale to check.
64
+ * @param domains - The configured locale → domain map.
65
+ * @returns `true` when the locale has a domain shared with no other locale.
66
+ */
67
+ declare const isLocaleExclusiveOnDomain: (locale: LocalesValues, domains: LocaleDomainMap) => boolean;
68
+ //#endregion
69
+ export { LocaleDomainMap, getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain };
70
+ //# sourceMappingURL=domainUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domainUtils.d.ts","names":[],"sources":["../../../src/localization/domainUtils.ts"],"mappings":";;;;;;;AAQA;;KAAY,eAAA,GAAkB,aAAA;;;AAe9B;;;;;AAsBA;;;;;AAmBA;cAzCa,iBAAA,GAAqB,MAAA;;;;;;;;;AAmElC;;;;;;cA7Ca,eAAA,GAAmB,MAAA;;;;;;;;;;;;;;;;;cAmBnB,mBAAA,GACX,QAAA,UACA,OAAA,EAAS,eAAA,KACR,MAAA;;;;;;;;;;;cAuBU,yBAAA,GACX,MAAA,EAAQ,aAAA,EACR,OAAA,EAAS,eAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"getLocalizedUrl.d.ts","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"mappings":";;;;;AAgFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,eAAA,2CAEK,aAAA,GAAgB,qBAAA,EAEhC,GAAA,EAAK,CAAA,EACL,aAAA,GAAe,CAAA,EACf,OAAA,GAAS,cAAA,KACR,YAAA,CAAa,CAAA,EAAG,CAAA"}
1
+ {"version":3,"file":"getLocalizedUrl.d.ts","names":[],"sources":["../../../src/localization/getLocalizedUrl.ts"],"mappings":";;;;;AAwEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,eAAA,2CAEK,aAAA,GAAgB,qBAAA,EAEhC,GAAA,EAAK,CAAA,EACL,aAAA,GAAe,CAAA,EACf,OAAA,GAAS,cAAA,KACR,YAAA,CAAa,CAAA,EAAG,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"getPrefix.d.ts","names":[],"sources":["../../../src/localization/getPrefix.ts"],"mappings":";;;;;;;AAuBA;KAAY,cAAA;EACV,OAAA,GAAU,aAAA;EACV,aAAA,GAAgB,aAAA;EAChB,IAAA,GAAO,aAAA;EACP,OAAA,GAAU,aAAA;EACV,OAAA,GAAU,aAAA;EAAA;;;;;;;;;;;EAYV,aAAA;AAAA;;;;AAOF;cAAa,oBAAA,GACX,OAAA,GAAS,cAAA,KACR,IAAA,CAAK,cAAA;EACN,aAAA,EAAe,aAAA;EACf,IAAA,EAAM,aAAA;EACN,OAAA,EAAS,aAAA;AAAA;AAAA,KAUC,gBAAA;EACV,aAAA,GAAgB,aAAA;EAChB,IAAA,GAAO,aAAA;AAAA;AAAA,KAGG,eAAA;EAnBD;;;;EAwBT,MAAA;EAtBe;;;EA0Bf,YAAA,EAAc,MAAA;AAAA;;;AAdhB;;;;;;;KA0BY,uBAAA,WACA,aAAA,oCACY,mBAAA,kBACN,aAAA,GAAgB,qBAAA,IAC9B,CAAA,oCACkB,CAAA,IAChB,uBAAA,CAAwB,eAAA,EAAiB,IAAA,EAAM,OAAA,sBAC7B,IAAA,IAChB,eAAA,GACA,IAAA;EACI,MAAA,KAAW,CAAA;EAAM,YAAA,EAAc,CAAA;AAAA,IACjC,IAAA,+BACE,CAAA,SAAU,OAAA;EACN,MAAA;EAAY,YAAA;AAAA;EACZ,MAAA,KAAW,CAAA;EAAM,YAAA,EAAc,CAAA;AAAA;EACjC,MAAA;EAAY,YAAA;AAAA;EACpB,MAAA;EAAY,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmCL,SAAA,mBAA6B,aAAA,cACxC,MAAA,EAAQ,CAAA,EACR,OAAA,GAAS,cAAA,KACR,uBAAA,CAAwB,CAAA"}
1
+ {"version":3,"file":"getPrefix.d.ts","names":[],"sources":["../../../src/localization/getPrefix.ts"],"mappings":";;;;;;;AAwBA;KAAY,cAAA;EACV,OAAA,GAAU,aAAA;EACV,aAAA,GAAgB,aAAA;EAChB,IAAA,GAAO,aAAA;EACP,OAAA,GAAU,aAAA;EACV,OAAA,GAAU,aAAA;EAAA;;;;;;;;;;;EAYV,aAAA;AAAA;;;;AAOF;cAAa,oBAAA,GACX,OAAA,GAAS,cAAA,KACR,IAAA,CAAK,cAAA;EACN,aAAA,EAAe,aAAA;EACf,IAAA,EAAM,aAAA;EACN,OAAA,EAAS,aAAA;AAAA;AAAA,KAUC,gBAAA;EACV,aAAA,GAAgB,aAAA;EAChB,IAAA,GAAO,aAAA;AAAA;AAAA,KAGG,eAAA;EAnBD;;;;EAwBT,MAAA;EAtBe;;;EA0Bf,YAAA,EAAc,MAAA;AAAA;;;AAdhB;;;;;;;KA0BY,uBAAA,WACA,aAAA,oCACY,mBAAA,kBACN,aAAA,GAAgB,qBAAA,IAC9B,CAAA,oCACkB,CAAA,IAChB,uBAAA,CAAwB,eAAA,EAAiB,IAAA,EAAM,OAAA,sBAC7B,IAAA,IAChB,eAAA,GACA,IAAA;EACI,MAAA,KAAW,CAAA;EAAM,YAAA,EAAc,CAAA;AAAA,IACjC,IAAA,+BACE,CAAA,SAAU,OAAA;EACN,MAAA;EAAY,YAAA;AAAA;EACZ,MAAA,KAAW,CAAA;EAAM,YAAA,EAAc,CAAA;AAAA;EACjC,MAAA;EAAY,YAAA;AAAA;EACpB,MAAA;EAAY,YAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmCL,SAAA,mBAA6B,aAAA,cACxC,MAAA,EAAQ,CAAA,EACR,OAAA,GAAS,cAAA,KACR,uBAAA,CAAwB,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { comparePaths, normalizePath } from "./comparePaths.js";
2
+ import { LocaleDomainMap, getDomainHostname, getDomainOrigin, getLocaleFromDomain, isLocaleExclusiveOnDomain } from "./domainUtils.js";
2
3
  import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./generateSitemap.js";
3
4
  import { getBrowserLocale } from "./getBrowserLocale.js";
4
5
  import { getHTMLTextDir } from "./getHTMLTextDir.js";
@@ -15,4 +16,4 @@ import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.js";
15
16
  import { localeResolver } from "./localeResolver.js";
16
17
  import { LocalizedPathResult, getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.js";
17
18
  import { validatePrefix } from "./validatePrefix.js";
18
- export { type GenerateSitemapOptions, type GetPrefixOptions, type GetPrefixResult, type LocalizedPathResult, type SitemapUrlEntry, comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
19
+ export { type GenerateSitemapOptions, type GetPrefixOptions, type GetPrefixResult, type LocaleDomainMap, type LocalizedPathResult, type SitemapUrlEntry, comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getDomainHostname, getDomainOrigin, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, isLocaleExclusiveOnDomain, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/core",
3
- "version": "9.0.0-canary.12",
3
+ "version": "9.0.0-canary.13",
4
4
  "private": false,
5
5
  "description": "Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.",
6
6
  "keywords": [
@@ -172,11 +172,11 @@
172
172
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
173
173
  },
174
174
  "dependencies": {
175
- "@intlayer/api": "9.0.0-canary.12",
176
- "@intlayer/config": "9.0.0-canary.12",
177
- "@intlayer/dictionaries-entry": "9.0.0-canary.12",
178
- "@intlayer/types": "9.0.0-canary.12",
179
- "@intlayer/unmerged-dictionaries-entry": "9.0.0-canary.12",
175
+ "@intlayer/api": "9.0.0-canary.13",
176
+ "@intlayer/config": "9.0.0-canary.13",
177
+ "@intlayer/dictionaries-entry": "9.0.0-canary.13",
178
+ "@intlayer/types": "9.0.0-canary.13",
179
+ "@intlayer/unmerged-dictionaries-entry": "9.0.0-canary.13",
180
180
  "defu": "6.1.7"
181
181
  },
182
182
  "devDependencies": {
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1,2 +0,0 @@
1
- import { ContentNode } from "@intlayer/types/dictionary";
2
- import { DeclaredLocales, LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1,4 +0,0 @@
1
- import { DeclaredLocales, DictionaryKeys, LocalesValues } from "@intlayer/types/module_augmentation";
2
- import { NodeType } from "@intlayer/types/nodeType";
3
- import { Locale } from "@intlayer/types/allLocales";
4
- import { KeyPath } from "@intlayer/types/keyPath";
@@ -1,2 +0,0 @@
1
- import { Dictionary, DictionarySelector, QualifiedDictionaryGroup, ResolveQualifiedDictionaryContent } from "@intlayer/types/dictionary";
2
- import { DeclaredLocales, ExtractSelectorLocale, LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1,2 +0,0 @@
1
- import { DictionarySelector } from "@intlayer/types/dictionary";
2
- import { DeclaredLocales, DictionaryKeys, DictionaryRegistryResult, ExtractSelectorLocale, LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1,2 +0,0 @@
1
- import { GetSubPath } from "@intlayer/types/dictionary";
2
- import { DictionaryKeys, DictionaryRegistryContent } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { DeclaredLocales } from "@intlayer/types";
@@ -1 +0,0 @@
1
- import { LocalesValues, StrictModeLocaleMap } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { DeclaredLocales, LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1,2 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
2
- import { RoutingConfig } from "@intlayer/types/config";
@@ -1 +0,0 @@
1
- import { Locale } from "@intlayer/types/allLocales";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { Locale } from "@intlayer/types/allLocales";
@@ -1 +0,0 @@
1
- import { Locale } from "@intlayer/types/allLocales";
@@ -1 +0,0 @@
1
- import { GetLocaleLang, LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { LocalesValues, LocalizedUrl, ResolvedDefaultLocale } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { StrictModeLocaleMap } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { DeclaredLocales, LocalesValues, PathWithoutLocale } from "@intlayer/types/module_augmentation";
@@ -1,3 +0,0 @@
1
- import { DeclaredLocales, LocalesValues, ResolvedDefaultLocale, ResolvedRoutingMode } from "@intlayer/types/module_augmentation";
2
- import { Locale } from "@intlayer/types/allLocales";
3
- import { RoutingConfig } from "@intlayer/types/config";
@@ -1 +0,0 @@
1
- import { Locale } from "@intlayer/types/allLocales";
@@ -1,2 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
2
- import { Locale } from "@intlayer/types/allLocales";
@@ -1,2 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
2
- import { Locale } from "@intlayer/types/allLocales";
@@ -1,3 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
2
- import { Locale } from "@intlayer/types/allLocales";
3
- import { RewriteObject, RewriteRules, RoutingConfig } from "@intlayer/types/config";
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { CONDITION, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { ENUMERATION, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { FILE, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { GENDER, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { HTML, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { INSERTION, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { MARKDOWN, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1,2 +0,0 @@
1
- import { DictionaryKeys, DictionaryRegistryContent } from "@intlayer/types/module_augmentation";
2
- import { NESTED, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- import { PLURAL, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1,2 +0,0 @@
1
- import { StrictModeLocaleMap } from "@intlayer/types/module_augmentation";
2
- import { TRANSLATION, TypedNodeModel } from "@intlayer/types/nodeType";
@@ -1 +0,0 @@
1
- export { };
@@ -1 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
@@ -1 +0,0 @@
1
- import { KeyPath } from "@intlayer/types/keyPath";
@@ -1,2 +0,0 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
2
- import { Locale } from "@intlayer/types/allLocales";
@@ -1,4 +0,0 @@
1
- import { Dictionary } from "@intlayer/types/dictionary";
2
- import { LocalesValues as LocalesValues$1 } from "@intlayer/types/module_augmentation";
3
- import { IntlayerConfig } from "@intlayer/types/config";
4
- export { type LocalesValues$1 as LocalesValues };