@intlayer/core 9.3.2 → 9.4.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/dictionaryManipulator/index.cjs +5 -1
- package/dist/cjs/dictionaryManipulator/plainDynamicLoader.cjs +71 -0
- package/dist/cjs/dictionaryManipulator/plainDynamicLoader.cjs.map +1 -0
- package/dist/cjs/dictionaryManipulator/preloadedDynamicLoader.cjs +29 -0
- package/dist/cjs/dictionaryManipulator/preloadedDynamicLoader.cjs.map +1 -0
- package/dist/cjs/dictionaryManipulator/qualifiedDynamicLoader.cjs +4 -10
- package/dist/cjs/dictionaryManipulator/qualifiedDynamicLoader.cjs.map +1 -1
- package/dist/cjs/index.cjs +13 -2
- package/dist/cjs/localization/comparePaths.cjs +1 -1
- package/dist/cjs/localization/comparePaths.cjs.map +1 -1
- package/dist/cjs/localization/domainUtils.cjs.map +1 -1
- package/dist/cjs/localization/getHTMLTextDir.cjs +11 -10
- package/dist/cjs/localization/getHTMLTextDir.cjs.map +1 -1
- package/dist/cjs/localization/getLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocaleFromPath.cjs +3 -3
- package/dist/cjs/localization/getLocaleFromPath.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedPath.cjs +74 -0
- package/dist/cjs/localization/getLocalizedPath.cjs.map +1 -0
- package/dist/cjs/localization/getLocalizedPath.test-d.cjs +83 -0
- package/dist/cjs/localization/getLocalizedPath.test-d.cjs.map +1 -0
- package/dist/cjs/localization/getLocalizedUrl.cjs +9 -25
- package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.test-d.cjs +42 -0
- package/dist/cjs/localization/getLocalizedUrl.test-d.cjs.map +1 -0
- package/dist/cjs/localization/getPathWithoutLocale.cjs +2 -2
- package/dist/cjs/localization/getPathWithoutLocale.cjs.map +1 -1
- package/dist/cjs/localization/getPrefix.cjs +15 -1
- package/dist/cjs/localization/getPrefix.cjs.map +1 -1
- package/dist/cjs/localization/index.cjs +7 -1
- package/dist/cjs/localization/localeDetector.cjs +5 -3
- package/dist/cjs/localization/localeDetector.cjs.map +1 -1
- package/dist/cjs/localization/localeMapper.cjs.map +1 -1
- package/dist/cjs/localization/localeResolver.cjs.map +1 -1
- package/dist/cjs/localization/resolveBrowserLocale.cjs +63 -0
- package/dist/cjs/localization/resolveBrowserLocale.cjs.map +1 -0
- package/dist/cjs/localization/rewriteUtils.cjs +26 -14
- package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
- package/dist/cjs/localization/rewriteUtils.test-d.cjs +48 -0
- package/dist/cjs/localization/rewriteUtils.test-d.cjs.map +1 -0
- package/dist/cjs/markdown/constants.cjs +3 -0
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/markdown/index.cjs +1 -0
- package/dist/cjs/markdown/utils.cjs +23 -1
- package/dist/cjs/markdown/utils.cjs.map +1 -1
- package/dist/esm/dictionaryManipulator/index.mjs +2 -1
- package/dist/esm/dictionaryManipulator/plainDynamicLoader.mjs +70 -0
- package/dist/esm/dictionaryManipulator/plainDynamicLoader.mjs.map +1 -0
- package/dist/esm/dictionaryManipulator/preloadedDynamicLoader.mjs +27 -0
- package/dist/esm/dictionaryManipulator/preloadedDynamicLoader.mjs.map +1 -0
- package/dist/esm/dictionaryManipulator/qualifiedDynamicLoader.mjs +2 -8
- package/dist/esm/dictionaryManipulator/qualifiedDynamicLoader.mjs.map +1 -1
- package/dist/esm/index.mjs +7 -4
- package/dist/esm/localization/comparePaths.mjs +1 -1
- package/dist/esm/localization/comparePaths.mjs.map +1 -1
- package/dist/esm/localization/domainUtils.mjs.map +1 -1
- package/dist/esm/localization/getHTMLTextDir.mjs +11 -10
- package/dist/esm/localization/getHTMLTextDir.mjs.map +1 -1
- package/dist/esm/localization/getLocale.mjs.map +1 -1
- package/dist/esm/localization/getLocaleFromPath.mjs +4 -4
- package/dist/esm/localization/getLocaleFromPath.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedPath.mjs +73 -0
- package/dist/esm/localization/getLocalizedPath.mjs.map +1 -0
- package/dist/esm/localization/getLocalizedPath.test-d.mjs +83 -0
- package/dist/esm/localization/getLocalizedPath.test-d.mjs.map +1 -0
- package/dist/esm/localization/getLocalizedUrl.mjs +10 -26
- package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedUrl.test-d.mjs +42 -0
- package/dist/esm/localization/getLocalizedUrl.test-d.mjs.map +1 -0
- package/dist/esm/localization/getPathWithoutLocale.mjs +2 -2
- package/dist/esm/localization/getPathWithoutLocale.mjs.map +1 -1
- package/dist/esm/localization/getPrefix.mjs +15 -2
- package/dist/esm/localization/getPrefix.mjs.map +1 -1
- package/dist/esm/localization/index.mjs +5 -3
- package/dist/esm/localization/localeDetector.mjs +5 -3
- package/dist/esm/localization/localeDetector.mjs.map +1 -1
- package/dist/esm/localization/localeMapper.mjs.map +1 -1
- package/dist/esm/localization/localeResolver.mjs.map +1 -1
- package/dist/esm/localization/resolveBrowserLocale.mjs +61 -0
- package/dist/esm/localization/resolveBrowserLocale.mjs.map +1 -0
- package/dist/esm/localization/rewriteUtils.mjs +26 -14
- package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
- package/dist/esm/localization/rewriteUtils.test-d.mjs +48 -0
- package/dist/esm/localization/rewriteUtils.test-d.mjs.map +1 -0
- package/dist/esm/markdown/constants.mjs +3 -1
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/markdown/index.mjs +2 -2
- package/dist/esm/markdown/utils.mjs +24 -2
- package/dist/esm/markdown/utils.mjs.map +1 -1
- package/dist/types/dictionaryManipulator/index.d.ts +2 -1
- package/dist/types/dictionaryManipulator/plainDynamicLoader.d.ts +50 -0
- package/dist/types/dictionaryManipulator/plainDynamicLoader.d.ts.map +1 -0
- package/dist/types/dictionaryManipulator/preloadedDynamicLoader.d.ts +38 -0
- package/dist/types/dictionaryManipulator/preloadedDynamicLoader.d.ts.map +1 -0
- package/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts +1 -7
- package/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts.map +1 -1
- package/dist/types/index.d.ts +7 -4
- package/dist/types/localization/domainUtils.d.ts +2 -3
- package/dist/types/localization/domainUtils.d.ts.map +1 -1
- package/dist/types/localization/getHTMLTextDir.d.ts.map +1 -1
- package/dist/types/localization/getLocale.d.ts +2 -2
- package/dist/types/localization/getLocale.d.ts.map +1 -1
- package/dist/types/localization/getLocaleFromPath.d.ts +2 -2
- package/dist/types/localization/getLocaleFromPath.d.ts.map +1 -1
- package/dist/types/localization/getLocalizedPath.d.ts +47 -0
- package/dist/types/localization/getLocalizedPath.d.ts.map +1 -0
- package/dist/types/localization/getLocalizedPath.test-d.d.ts +1 -0
- package/dist/types/localization/getLocalizedUrl.d.ts +5 -1
- package/dist/types/localization/getLocalizedUrl.d.ts.map +1 -1
- package/dist/types/localization/getLocalizedUrl.test-d.d.ts +1 -0
- package/dist/types/localization/getPrefix.d.ts +20 -8
- package/dist/types/localization/getPrefix.d.ts.map +1 -1
- package/dist/types/localization/index.d.ts +5 -3
- package/dist/types/localization/localeDetector.d.ts +2 -1
- package/dist/types/localization/localeDetector.d.ts.map +1 -1
- package/dist/types/localization/localeMapper.d.ts +4 -5
- package/dist/types/localization/localeMapper.d.ts.map +1 -1
- package/dist/types/localization/localeResolver.d.ts +2 -3
- package/dist/types/localization/localeResolver.d.ts.map +1 -1
- package/dist/types/localization/resolveBrowserLocale.d.ts +35 -0
- package/dist/types/localization/resolveBrowserLocale.d.ts.map +1 -0
- package/dist/types/localization/rewriteUtils.d.ts +51 -11
- package/dist/types/localization/rewriteUtils.d.ts.map +1 -1
- package/dist/types/localization/rewriteUtils.test-d.d.ts +1 -0
- package/dist/types/markdown/constants.d.ts +3 -1
- package/dist/types/markdown/constants.d.ts.map +1 -1
- package/dist/types/markdown/index.d.ts +2 -2
- package/dist/types/markdown/utils.d.ts +6 -0
- package/dist/types/markdown/utils.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const require_localization_getLocalizedPath = require('./getLocalizedPath.cjs');
|
|
2
|
+
const require_localization_getLocalizedUrl = require('./getLocalizedUrl.cjs');
|
|
3
|
+
let vitest = require("vitest");
|
|
4
|
+
|
|
5
|
+
//#region src/localization/getLocalizedPath.test-d.ts
|
|
6
|
+
/**
|
|
7
|
+
* `getLocalizedPath` prefixes the rewritten path, so it reports the very type
|
|
8
|
+
* its sibling reports for a relative URL. This package declares neither rewrite
|
|
9
|
+
* rules nor a default locale, so the registry leaves both steps as no-ops.
|
|
10
|
+
*/
|
|
11
|
+
(0, vitest.describe)("getLocalizedPath", () => {
|
|
12
|
+
(0, vitest.it)("should report the same type as getLocalizedUrl", () => {
|
|
13
|
+
(0, vitest.expectTypeOf)(require_localization_getLocalizedPath.getLocalizedPath("/about", "fr")).toEqualTypeOf();
|
|
14
|
+
(0, vitest.expectTypeOf)(require_localization_getLocalizedPath.getLocalizedPath("/about", "fr")).toEqualTypeOf(require_localization_getLocalizedUrl.getLocalizedUrl("/about", "fr"));
|
|
15
|
+
});
|
|
16
|
+
(0, vitest.it)("should keep the literal path when nothing rewrites or prefixes it", () => {
|
|
17
|
+
(0, vitest.expectTypeOf)(require_localization_getLocalizedPath.getLocalizedPath("/about", "fr")).toEqualTypeOf();
|
|
18
|
+
});
|
|
19
|
+
(0, vitest.it)("should drop the origin of an absolute URL", () => {
|
|
20
|
+
(0, vitest.expectTypeOf)(require_localization_getLocalizedPath.getLocalizedPath("https://intlayer.org/about", "fr")).toEqualTypeOf();
|
|
21
|
+
});
|
|
22
|
+
(0, vitest.it)("should widen to string when the path is not a literal", () => {
|
|
23
|
+
(0, vitest.expectTypeOf)(require_localization_getLocalizedPath.getLocalizedPath("/about", "fr")).toEqualTypeOf();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* The resolution itself, exercised against explicit rules — the same shape the
|
|
28
|
+
* generated module augmentation feeds it as `__RoutingRegistry['rewrite']`.
|
|
29
|
+
*/
|
|
30
|
+
(0, vitest.describe)("LocalizedPath", () => {
|
|
31
|
+
(0, vitest.it)("should rewrite a static path", () => {
|
|
32
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
33
|
+
});
|
|
34
|
+
(0, vitest.it)("should keep a path no rule matches", () => {
|
|
35
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
36
|
+
});
|
|
37
|
+
(0, vitest.it)("should substitute a route parameter", () => {
|
|
38
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
39
|
+
});
|
|
40
|
+
(0, vitest.it)("should substitute several route parameters", () => {
|
|
41
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
42
|
+
});
|
|
43
|
+
(0, vitest.it)("should not match a parameter across a segment boundary", () => {
|
|
44
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
45
|
+
});
|
|
46
|
+
(0, vitest.it)("should keep the path when the locale declares no pattern", () => {
|
|
47
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
48
|
+
});
|
|
49
|
+
(0, vitest.it)("should distribute over a union of locales", () => {
|
|
50
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
51
|
+
});
|
|
52
|
+
(0, vitest.it)("should widen a variadic rule to string, but only for the paths it could match", () => {
|
|
53
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
54
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
55
|
+
});
|
|
56
|
+
(0, vitest.it)("should keep every path when the project declares no rule", () => {
|
|
57
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* The return type of `getLocalizedPath`, exercised against an explicit routing
|
|
62
|
+
* mode, default locale and locale set — this package declares none of them.
|
|
63
|
+
*/
|
|
64
|
+
(0, vitest.describe)("LocalizedPathname", () => {
|
|
65
|
+
(0, vitest.it)("should report the same type as LocalizedUrl for a relative path", () => {
|
|
66
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
67
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
68
|
+
});
|
|
69
|
+
(0, vitest.it)("should drop the origin of an absolute URL", () => {
|
|
70
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
71
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
72
|
+
});
|
|
73
|
+
(0, vitest.it)("should collapse an origin without a path to the root", () => {
|
|
74
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
75
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
76
|
+
});
|
|
77
|
+
(0, vitest.it)("should replace a locale segment carried by an absolute URL", () => {
|
|
78
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//# sourceMappingURL=getLocalizedPath.test-d.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLocalizedPath.test-d.cjs","names":["describe","getLocalizedPath","getLocalizedUrl"],"sources":["../../../src/localization/getLocalizedPath.test-d.ts"],"sourcesContent":["import type {\n LocalizedPath,\n LocalizedPathname,\n LocalizedUrl,\n} from '@intlayer/types/module_augmentation';\nimport { describe, expectTypeOf, it } from 'vitest';\nimport { getLocalizedPath } from './getLocalizedPath';\nimport { getLocalizedUrl } from './getLocalizedUrl';\n\n/**\n * `getLocalizedPath` prefixes the rewritten path, so it reports the very type\n * its sibling reports for a relative URL. This package declares neither rewrite\n * rules nor a default locale, so the registry leaves both steps as no-ops.\n */\ndescribe('getLocalizedPath', () => {\n it('should report the same type as getLocalizedUrl', () => {\n expectTypeOf(getLocalizedPath('/about', 'fr')).toEqualTypeOf<\n LocalizedUrl<'/about', 'fr'>\n >();\n expectTypeOf(getLocalizedPath('/about', 'fr')).toEqualTypeOf(\n getLocalizedUrl('/about', 'fr')\n );\n });\n\n it('should keep the literal path when nothing rewrites or prefixes it', () => {\n expectTypeOf(getLocalizedPath('/about', 'fr')).toEqualTypeOf<'/about'>();\n });\n\n it('should drop the origin of an absolute URL', () => {\n expectTypeOf(\n getLocalizedPath('https://intlayer.org/about', 'fr')\n ).toEqualTypeOf<'/about'>();\n });\n\n it('should widen to string when the path is not a literal', () => {\n const dynamicPath = '/about' as string;\n\n expectTypeOf(getLocalizedPath(dynamicPath, 'fr')).toEqualTypeOf<string>();\n });\n});\n\n/**\n * The resolution itself, exercised against explicit rules — the same shape the\n * generated module augmentation feeds it as `__RoutingRegistry['rewrite']`.\n */\ndescribe('LocalizedPath', () => {\n type Rules = {\n '/about': { en: '/about'; fr: '/a-propos' };\n '/product/:id': { en: '/product/:id'; fr: '/produit/:id' };\n '/shop/:category/:id': { fr: '/boutique/:category/:id' };\n '/docs/:path+': { fr: '/documentation/:path+' };\n };\n\n it('should rewrite a static path', () => {\n expectTypeOf<\n LocalizedPath<'/about', 'fr', Rules>\n >().toEqualTypeOf<'/a-propos'>();\n });\n\n it('should keep a path no rule matches', () => {\n expectTypeOf<\n LocalizedPath<'/contact', 'fr', Rules>\n >().toEqualTypeOf<'/contact'>();\n });\n\n it('should substitute a route parameter', () => {\n expectTypeOf<\n LocalizedPath<'/product/123', 'fr', Rules>\n >().toEqualTypeOf<'/produit/123'>();\n });\n\n it('should substitute several route parameters', () => {\n expectTypeOf<\n LocalizedPath<'/shop/shoes/123', 'fr', Rules>\n >().toEqualTypeOf<'/boutique/shoes/123'>();\n });\n\n it('should not match a parameter across a segment boundary', () => {\n expectTypeOf<\n LocalizedPath<'/product/123/reviews', 'fr', Rules>\n >().toEqualTypeOf<'/product/123/reviews'>();\n });\n\n it('should keep the path when the locale declares no pattern', () => {\n expectTypeOf<\n LocalizedPath<'/shop/shoes/123', 'en', Rules>\n >().toEqualTypeOf<'/shop/shoes/123'>();\n });\n\n it('should distribute over a union of locales', () => {\n expectTypeOf<LocalizedPath<'/about', 'en' | 'fr', Rules>>().toEqualTypeOf<\n '/about' | '/a-propos'\n >();\n });\n\n it('should widen a variadic rule to string, but only for the paths it could match', () => {\n expectTypeOf<\n LocalizedPath<'/docs/getting-started', 'fr', Rules>\n >().toEqualTypeOf<string>();\n expectTypeOf<\n LocalizedPath<'/about', 'fr', Rules>\n >().toEqualTypeOf<'/a-propos'>();\n });\n\n it('should keep every path when the project declares no rule', () => {\n expectTypeOf<LocalizedPath<'/about', 'fr', {}>>().toEqualTypeOf<'/about'>();\n });\n});\n\n/**\n * The return type of `getLocalizedPath`, exercised against an explicit routing\n * mode, default locale and locale set — this package declares none of them.\n */\ndescribe('LocalizedPathname', () => {\n type Locales = 'en' | 'fr' | 'es';\n type Path<P extends string, L extends Locales> = LocalizedPathname<\n P,\n L,\n 'prefix-no-default',\n 'en',\n Locales\n >;\n\n it('should report the same type as LocalizedUrl for a relative path', () => {\n expectTypeOf<Path<'/about', 'es'>>().toEqualTypeOf<\n LocalizedUrl<'/about', 'es', 'prefix-no-default', 'en', Locales>\n >();\n expectTypeOf<Path<'/about', 'es'>>().toEqualTypeOf<'/es/about'>();\n });\n\n it('should drop the origin of an absolute URL', () => {\n expectTypeOf<\n Path<'https://intlayer.org/about', 'es'>\n >().toEqualTypeOf<'/es/about'>();\n expectTypeOf<\n Path<'https://intlayer.org/about', 'en'>\n >().toEqualTypeOf<'/about'>();\n });\n\n it('should collapse an origin without a path to the root', () => {\n expectTypeOf<Path<'https://intlayer.org', 'en'>>().toEqualTypeOf<'/'>();\n expectTypeOf<Path<'https://intlayer.org/', 'es'>>().toEqualTypeOf<'/es'>();\n });\n\n it('should replace a locale segment carried by an absolute URL', () => {\n expectTypeOf<\n Path<'https://intlayer.org/fr/about', 'es'>\n >().toEqualTypeOf<'/es/about'>();\n });\n});\n"],"mappings":";;;;;;;;;;IAcAA,iBAAS,0BAA0B;CACjC,eAAG,wDAAwD;EACzD,yBAAaC,uDAAiB,UAAU,IAAI,CAAC,CAAC,CAAC,cAE7C;EACF,yBAAaA,uDAAiB,UAAU,IAAI,CAAC,CAAC,CAAC,cAC7CC,qDAAgB,UAAU,IAAI,CAChC;CACF,CAAC;CAED,eAAG,2EAA2E;EAC5E,yBAAaD,uDAAiB,UAAU,IAAI,CAAC,CAAC,CAAC,cAAwB;CACzE,CAAC;CAED,eAAG,mDAAmD;EACpD,yBACEA,uDAAiB,8BAA8B,IAAI,CACrD,CAAC,CAAC,cAAwB;CAC5B,CAAC;CAED,eAAG,+DAA+D;EAGhE,yBAAaA,uDAAiB,UAAa,IAAI,CAAC,CAAC,CAAC,cAAsB;CAC1E,CAAC;AACH,CAAC;;;;;IAMDD,iBAAS,uBAAuB;CAQ9B,eAAG,sCAAsC;EACvC,yBAEE,CAAC,CAAC,cAA2B;CACjC,CAAC;CAED,eAAG,4CAA4C;EAC7C,yBAEE,CAAC,CAAC,cAA0B;CAChC,CAAC;CAED,eAAG,6CAA6C;EAC9C,yBAEE,CAAC,CAAC,cAA8B;CACpC,CAAC;CAED,eAAG,oDAAoD;EACrD,yBAEE,CAAC,CAAC,cAAqC;CAC3C,CAAC;CAED,eAAG,gEAAgE;EACjE,yBAEE,CAAC,CAAC,cAAsC;CAC5C,CAAC;CAED,eAAG,kEAAkE;EACnE,yBAEE,CAAC,CAAC,cAAiC;CACvC,CAAC;CAED,eAAG,mDAAmD;EACpD,yBAA0D,CAAC,CAAC,cAE1D;CACJ,CAAC;CAED,eAAG,uFAAuF;EACxF,yBAEE,CAAC,CAAC,cAAsB;EAC1B,yBAEE,CAAC,CAAC,cAA2B;CACjC,CAAC;CAED,eAAG,kEAAkE;EACnE,yBAAgD,CAAC,CAAC,cAAwB;CAC5E,CAAC;AACH,CAAC;;;;;IAMDA,iBAAS,2BAA2B;CAUlC,eAAG,yEAAyE;EAC1E,yBAAmC,CAAC,CAAC,cAEnC;EACF,yBAAmC,CAAC,CAAC,cAA2B;CAClE,CAAC;CAED,eAAG,mDAAmD;EACpD,yBAEE,CAAC,CAAC,cAA2B;EAC/B,yBAEE,CAAC,CAAC,cAAwB;CAC9B,CAAC;CAED,eAAG,8DAA8D;EAC/D,yBAAiD,CAAC,CAAC,cAAmB;EACtE,yBAAkD,CAAC,CAAC,cAAqB;CAC3E,CAAC;CAED,eAAG,oEAAoE;EACrE,yBAEE,CAAC,CAAC,cAA2B;CACjC,CAAC;AACH,CAAC"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_checkIsURLAbsolute = require('../utils/checkIsURLAbsolute.cjs');
|
|
3
|
-
const require_localization_getPathWithoutLocale = require('./getPathWithoutLocale.cjs');
|
|
4
3
|
const require_localization_domainUtils = require('./domainUtils.cjs');
|
|
5
4
|
const require_localization_getPrefix = require('./getPrefix.cjs');
|
|
6
|
-
const
|
|
5
|
+
const require_localization_getLocalizedPath = require('./getLocalizedPath.cjs');
|
|
7
6
|
let _intlayer_config_built = require("@intlayer/config/built");
|
|
8
7
|
|
|
9
8
|
//#region src/localization/getLocalizedUrl.ts
|
|
@@ -13,6 +12,10 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
13
12
|
*
|
|
14
13
|
* This function gets the locales, default locale, and routing mode from the configuration if not provided.
|
|
15
14
|
*
|
|
15
|
+
* The path itself is localized by {@link getLocalizedPath}; this function only
|
|
16
|
+
* resolves the origin to put in front of it — the one of an absolute input, or
|
|
17
|
+
* the domain mapped to the target locale.
|
|
18
|
+
*
|
|
16
19
|
* Example:
|
|
17
20
|
*
|
|
18
21
|
* ```ts
|
|
@@ -52,33 +55,14 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
52
55
|
* not overridden via `options`.
|
|
53
56
|
*/
|
|
54
57
|
const getLocalizedUrl = (url, currentLocale = _intlayer_config_built.internationalization?.defaultLocale, options = {}) => {
|
|
55
|
-
const {
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
if (!(process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "no-prefix") && mode === "no-prefix") return require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(urlWithoutLocale, void 0, rewriteRules), currentLocale, rewriteRules).path;
|
|
59
|
-
const isAbsoluteUrl = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(urlWithoutLocale);
|
|
60
|
-
const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com");
|
|
61
|
-
const translatedPathname = require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(parsedUrl.pathname, void 0, rewriteRules), currentLocale, rewriteRules).path;
|
|
58
|
+
const { domains, currentDomain } = require_localization_getPrefix.resolveRoutingConfig(options);
|
|
59
|
+
const isAbsoluteUrl = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(url);
|
|
60
|
+
const parsedUrl = isAbsoluteUrl ? new URL(url) : new URL(url, "http://e.com");
|
|
62
61
|
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;
|
|
63
62
|
const localeDomain = process.env.INTLAYER_ROUTING_DOMAINS !== "false" ? domains?.[currentLocale] : void 0;
|
|
64
63
|
const localeDomainHostname = localeDomain ? require_localization_domainUtils.getDomainHostname(localeDomain) : null;
|
|
65
64
|
const normalizedDomain = localeDomainHostname !== null && (detectedCurrentHostname === null || localeDomainHostname !== detectedCurrentHostname) && localeDomain ? require_localization_domainUtils.getDomainOrigin(localeDomain) : null;
|
|
66
|
-
|
|
67
|
-
if (!(process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "search-params") && mode === "search-params") {
|
|
68
|
-
const searchParams = new URLSearchParams(parsedUrl.search);
|
|
69
|
-
searchParams.set("locale", currentLocale.toString());
|
|
70
|
-
const queryParams = searchParams.toString();
|
|
71
|
-
return `${baseUrl}${queryParams ? `${translatedPathname}?${queryParams}` : translatedPathname}${parsedUrl.hash}`;
|
|
72
|
-
}
|
|
73
|
-
const { prefix } = require_localization_getPrefix.getPrefix(currentLocale, {
|
|
74
|
-
defaultLocale,
|
|
75
|
-
mode,
|
|
76
|
-
locales,
|
|
77
|
-
domains
|
|
78
|
-
});
|
|
79
|
-
let localizedPath = `/${prefix}${translatedPathname}`.replace(/\/+/g, "/");
|
|
80
|
-
if (localizedPath.length > 1 && localizedPath.endsWith("/")) localizedPath = localizedPath.slice(0, -1);
|
|
81
|
-
return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;
|
|
65
|
+
return `${normalizedDomain ? normalizedDomain : isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : ""}${require_localization_getLocalizedPath.getLocalizedPath(`${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`, currentLocale, options)}`;
|
|
82
66
|
};
|
|
83
67
|
|
|
84
68
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedUrl.cjs","names":["internationalization","resolveRoutingConfig","
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.cjs","names":["internationalization","resolveRoutingConfig","checkIsURLAbsolute","getDomainHostname","getDomainOrigin","getLocalizedPath"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\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 { getLocalizedPath } from './getLocalizedPath';\nimport { type RoutingOptions, resolveRoutingConfig } from './getPrefix';\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 * The path itself is localized by {@link getLocalizedPath}; this function only\n * resolves the origin to put in front of it — the one of an absolute input, or\n * the domain mapped to the target locale.\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 { domains, currentDomain } = resolveRoutingConfig(options);\n\n const isAbsoluteUrl = checkIsURLAbsolute(url);\n const parsedUrl = isAbsoluteUrl ? new URL(url) : new URL(url, 'http://e.com');\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 const localizedPath = getLocalizedPath(\n `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`,\n currentLocale,\n options\n );\n\n return `${baseUrl}${localizedPath}` as LocalizedUrl<T, L>;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,MAAa,mBAIX,KACA,gBAAmBA,6CAAsB,eACzC,UAA0B,CAAC,MACJ;CACvB,MAAM,EAAE,SAAS,kBAAkBC,oDAAqB,OAAO;CAE/D,MAAM,gBAAgBC,oDAAmB,GAAG;CAC5C,MAAM,YAAY,gBAAgB,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,KAAK,cAAc;CAe5E,MAAM,0BACJ,QAAQ,IAAI,6BAA6B,UACrCC,mDACE,kBACG,gBAAgB,UAAU,WAAW,YACrC,OAAO,WAAW,cACf,QAAQ,UAAU,WAClB,WACJ,EACJ,KAAK,OACL;CAEN,MAAM,eACJ,QAAQ,IAAI,6BAA6B,UACrC,UAAU,iBACV;CAEN,MAAM,uBAAuB,eACzBA,mDAAkB,YAAY,IAC9B;CASJ,MAAM,mBAJJ,yBAAyB,SACxB,4BAA4B,QAC3B,yBAAyB,4BAGV,eAAeC,iDAAgB,YAAY,IAAI;CAelE,OAAO,GAbS,mBACZ,mBACA,gBACE,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC,KAGgBC,uDACpB,GAAG,UAAU,WAAW,UAAU,SAAS,UAAU,QACrD,eACA,OAG8B;AAClC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
let vitest = require("vitest");
|
|
2
|
+
|
|
3
|
+
//#region src/localization/getLocalizedUrl.test-d.ts
|
|
4
|
+
/**
|
|
5
|
+
* `LocalizedUrl` mirrors what `getLocalizedUrl` builds at runtime. The routing
|
|
6
|
+
* mode, default locale and declared locales are passed explicitly here — this
|
|
7
|
+
* package declares none of them, so the registry defaults would collapse every
|
|
8
|
+
* locale onto the default one.
|
|
9
|
+
*/
|
|
10
|
+
(0, vitest.describe)("LocalizedUrl", () => {
|
|
11
|
+
(0, vitest.it)("should prefix a path with a non-default locale", () => {
|
|
12
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
13
|
+
});
|
|
14
|
+
(0, vitest.it)("should collapse the root to a bare prefix, never a trailing slash", () => {
|
|
15
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
16
|
+
});
|
|
17
|
+
(0, vitest.it)("should leave the default locale unprefixed", () => {
|
|
18
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
19
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
20
|
+
});
|
|
21
|
+
(0, vitest.it)("should drop the trailing slash of a non-root path", () => {
|
|
22
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
23
|
+
});
|
|
24
|
+
(0, vitest.it)("should replace an existing locale segment", () => {
|
|
25
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
26
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
27
|
+
});
|
|
28
|
+
(0, vitest.it)("should prefix the pathname of an absolute URL, not its origin", () => {
|
|
29
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
30
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
31
|
+
});
|
|
32
|
+
(0, vitest.it)("should prefix every locale in prefix-all mode", () => {
|
|
33
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
34
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
35
|
+
});
|
|
36
|
+
(0, vitest.it)("should strip the locale in no-prefix mode", () => {
|
|
37
|
+
(0, vitest.expectTypeOf)().toEqualTypeOf();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
//# sourceMappingURL=getLocalizedUrl.test-d.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLocalizedUrl.test-d.cjs","names":["describe"],"sources":["../../../src/localization/getLocalizedUrl.test-d.ts"],"sourcesContent":["import type { LocalizedUrl } from '@intlayer/types/module_augmentation';\nimport { describe, expectTypeOf, it } from 'vitest';\n\n/**\n * `LocalizedUrl` mirrors what `getLocalizedUrl` builds at runtime. The routing\n * mode, default locale and declared locales are passed explicitly here — this\n * package declares none of them, so the registry defaults would collapse every\n * locale onto the default one.\n */\ndescribe('LocalizedUrl', () => {\n type Locales = 'en' | 'fr' | 'es';\n type Url<Path extends string, L extends Locales> = LocalizedUrl<\n Path,\n L,\n 'prefix-no-default',\n 'en',\n Locales\n >;\n\n it('should prefix a path with a non-default locale', () => {\n expectTypeOf<Url<'/about', 'es'>>().toEqualTypeOf<'/es/about'>();\n });\n\n it('should collapse the root to a bare prefix, never a trailing slash', () => {\n expectTypeOf<Url<'/', 'es'>>().toEqualTypeOf<'/es'>();\n });\n\n it('should leave the default locale unprefixed', () => {\n expectTypeOf<Url<'/about', 'en'>>().toEqualTypeOf<'/about'>();\n expectTypeOf<Url<'/', 'en'>>().toEqualTypeOf<'/'>();\n });\n\n it('should drop the trailing slash of a non-root path', () => {\n expectTypeOf<Url<'/about/', 'fr'>>().toEqualTypeOf<'/fr/about'>();\n });\n\n it('should replace an existing locale segment', () => {\n expectTypeOf<Url<'/en/about', 'fr'>>().toEqualTypeOf<'/fr/about'>();\n expectTypeOf<Url<'/fr', 'es'>>().toEqualTypeOf<'/es'>();\n });\n\n it('should prefix the pathname of an absolute URL, not its origin', () => {\n expectTypeOf<\n Url<'https://example.com/about', 'fr'>\n >().toEqualTypeOf<'https://example.com/fr/about'>();\n expectTypeOf<\n Url<'https://example.com/', 'fr'>\n >().toEqualTypeOf<'https://example.com/fr'>();\n });\n\n it('should prefix every locale in prefix-all mode', () => {\n expectTypeOf<\n LocalizedUrl<'/', 'en', 'prefix-all', 'en', Locales>\n >().toEqualTypeOf<'/en'>();\n expectTypeOf<\n LocalizedUrl<'/about', 'en', 'prefix-all', 'en', Locales>\n >().toEqualTypeOf<'/en/about'>();\n });\n\n it('should strip the locale in no-prefix mode', () => {\n expectTypeOf<\n LocalizedUrl<'/fr/about', 'fr', 'no-prefix', 'en', Locales>\n >().toEqualTypeOf<'/about'>();\n });\n});\n"],"mappings":";;;;;;;;;IASAA,iBAAS,sBAAsB;CAU7B,eAAG,wDAAwD;EACzD,yBAAkC,CAAC,CAAC,cAA2B;CACjE,CAAC;CAED,eAAG,2EAA2E;EAC5E,yBAA6B,CAAC,CAAC,cAAqB;CACtD,CAAC;CAED,eAAG,oDAAoD;EACrD,yBAAkC,CAAC,CAAC,cAAwB;EAC5D,yBAA6B,CAAC,CAAC,cAAmB;CACpD,CAAC;CAED,eAAG,2DAA2D;EAC5D,yBAAmC,CAAC,CAAC,cAA2B;CAClE,CAAC;CAED,eAAG,mDAAmD;EACpD,yBAAqC,CAAC,CAAC,cAA2B;EAClE,yBAA+B,CAAC,CAAC,cAAqB;CACxD,CAAC;CAED,eAAG,uEAAuE;EACxE,yBAEE,CAAC,CAAC,cAA8C;EAClD,yBAEE,CAAC,CAAC,cAAwC;CAC9C,CAAC;CAED,eAAG,uDAAuD;EACxD,yBAEE,CAAC,CAAC,cAAqB;EACzB,yBAEE,CAAC,CAAC,cAA2B;CACjC,CAAC;CAED,eAAG,mDAAmD;EACpD,yBAEE,CAAC,CAAC,cAAwB;CAC9B,CAAC;AACH,CAAC"}
|
|
@@ -45,7 +45,7 @@ const getPathWithoutLocale = (inputUrl, locales = _intlayer_config_built.interna
|
|
|
45
45
|
const isAbsoluteUrl = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(inputUrl);
|
|
46
46
|
let fixedInputUrl = inputUrl;
|
|
47
47
|
if (inputUrl?.endsWith("/")) fixedInputUrl = inputUrl.slice(0, -1);
|
|
48
|
-
const url = isAbsoluteUrl ? new URL(fixedInputUrl) : new URL(fixedInputUrl, "http://
|
|
48
|
+
const url = isAbsoluteUrl ? new URL(fixedInputUrl) : new URL(fixedInputUrl, "http://e.com");
|
|
49
49
|
const pathname = url.pathname;
|
|
50
50
|
if (!pathname.startsWith("/")) url.pathname = `/${pathname}`;
|
|
51
51
|
if (!TREE_SHAKE_PREFIX_MODES) {
|
|
@@ -64,7 +64,7 @@ const getPathWithoutLocale = (inputUrl, locales = _intlayer_config_built.interna
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
if (isAbsoluteUrl) return url.toString();
|
|
67
|
-
return url.toString().replace("http://
|
|
67
|
+
return url.toString().replace("http://e.com", "");
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPathWithoutLocale.cjs","names":["internationalization","checkIsURLAbsolute"],"sources":["../../../src/localization/getPathWithoutLocale.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\n/**\n * True when the build-time routing mode is known and is not a prefix-based\n * mode (neither 'prefix-all' nor 'prefix-no-default').\n */\nconst TREE_SHAKE_PREFIX_MODES =\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default';\n\n/**\n * True when the build-time routing mode is known and is NOT 'search-params'.\n */\nconst TREE_SHAKE_SEARCH_PARAMS =\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params';\n\nimport type {\n DeclaredLocales,\n LocalesValues,\n PathWithoutLocale,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\n\n/**\n * Removes the locale segment from the given URL or pathname if present.\n * Also removes locale from search parameters if present.\n *\n * This function get the locales from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * getPathWithoutLocale('/en/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('/fr/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('dashboard') // Returns 'dashboard'\n * getPathWithoutLocale('/dashboard?locale=fr') // Returns '/dashboard'\n * getPathWithoutLocale('https://example.com/en/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/fr/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/dashboard?locale=fr') // Returns 'https://example.com/dashboard'\n * ```\n *\n * @param inputUrl - The complete URL string or pathname to process.\n * @param locales - Optional array of supported locales. Defaults to `localesDefault`.\n * @returns The URL string or pathname without the locale segment or locale search parameter.\n */\n/**\n * The return type is narrowed to a template-literal type when both `inputUrl`\n * and `locales` are string literals known at compile time. Absolute URLs fall\n * back to `string`.\n */\nexport const getPathWithoutLocale = <\n const T extends string,\n const L extends LocalesValues = DeclaredLocales,\n>(\n inputUrl: T,\n locales: L[] = internationalization?.locales as L[]\n): PathWithoutLocale<T, L> => {\n // Determine if the original URL is absolute (includes protocol)\n const isAbsoluteUrl = checkIsURLAbsolute(inputUrl);\n\n let fixedInputUrl = inputUrl;\n\n if (inputUrl?.endsWith('/')) {\n fixedInputUrl = inputUrl.slice(0, -1);\n }\n\n // Initialize a URL object if the URL is absolute\n // For relative URLs, use a dummy base to leverage the URL API\n const url = isAbsoluteUrl\n ? new URL(fixedInputUrl)\n : new URL(fixedInputUrl, 'http://
|
|
1
|
+
{"version":3,"file":"getPathWithoutLocale.cjs","names":["internationalization","checkIsURLAbsolute"],"sources":["../../../src/localization/getPathWithoutLocale.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\n/**\n * True when the build-time routing mode is known and is not a prefix-based\n * mode (neither 'prefix-all' nor 'prefix-no-default').\n */\nconst TREE_SHAKE_PREFIX_MODES =\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default';\n\n/**\n * True when the build-time routing mode is known and is NOT 'search-params'.\n */\nconst TREE_SHAKE_SEARCH_PARAMS =\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params';\n\nimport type {\n DeclaredLocales,\n LocalesValues,\n PathWithoutLocale,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\n\n/**\n * Removes the locale segment from the given URL or pathname if present.\n * Also removes locale from search parameters if present.\n *\n * This function get the locales from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * getPathWithoutLocale('/en/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('/fr/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('/dashboard') // Returns '/dashboard'\n * getPathWithoutLocale('dashboard') // Returns 'dashboard'\n * getPathWithoutLocale('/dashboard?locale=fr') // Returns '/dashboard'\n * getPathWithoutLocale('https://example.com/en/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/fr/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/dashboard') // Returns 'https://example.com/dashboard'\n * getPathWithoutLocale('https://example.com/dashboard?locale=fr') // Returns 'https://example.com/dashboard'\n * ```\n *\n * @param inputUrl - The complete URL string or pathname to process.\n * @param locales - Optional array of supported locales. Defaults to `localesDefault`.\n * @returns The URL string or pathname without the locale segment or locale search parameter.\n */\n/**\n * The return type is narrowed to a template-literal type when both `inputUrl`\n * and `locales` are string literals known at compile time. Absolute URLs fall\n * back to `string`.\n */\nexport const getPathWithoutLocale = <\n const T extends string,\n const L extends LocalesValues = DeclaredLocales,\n>(\n inputUrl: T,\n locales: L[] = internationalization?.locales as L[]\n): PathWithoutLocale<T, L> => {\n // Determine if the original URL is absolute (includes protocol)\n const isAbsoluteUrl = checkIsURLAbsolute(inputUrl);\n\n let fixedInputUrl = inputUrl;\n\n if (inputUrl?.endsWith('/')) {\n fixedInputUrl = inputUrl.slice(0, -1);\n }\n\n // Initialize a URL object if the URL is absolute\n // For relative URLs, use a dummy base to leverage the URL API\n const url = isAbsoluteUrl\n ? new URL(fixedInputUrl)\n : new URL(fixedInputUrl, 'http://e.com');\n\n const pathname = url.pathname;\n\n // Ensure the pathname starts with '/'\n if (!pathname.startsWith('/')) {\n // If not, return the URL as is\n url.pathname = `/${pathname}`;\n }\n\n // Only strip locale path prefix in prefix-based routing modes\n if (!TREE_SHAKE_PREFIX_MODES) {\n // Split the pathname to extract the first segment\n const pathSegments = pathname.split('/');\n const firstSegment = pathSegments[1]; // The segment after the first '/'\n\n // Check if the first segment is a supported locale\n if (locales?.includes(firstSegment as L)) {\n // Remove the locale segment from the pathname\n pathSegments.splice(1, 1); // Remove the first segment\n\n // Reconstruct the pathname\n const newPathname = pathSegments.join('/') ?? '/';\n url.pathname = newPathname;\n }\n }\n\n // Only strip locale from search parameters in search-params routing mode\n if (!TREE_SHAKE_SEARCH_PARAMS) {\n const searchParams = new URLSearchParams(url.search);\n if (searchParams.has('locale')) {\n searchParams.delete('locale');\n url.search = searchParams.toString();\n }\n }\n\n if (isAbsoluteUrl) {\n return url.toString() as PathWithoutLocale<T, L>;\n }\n\n return url.toString().replace('http://e.com', '') as PathWithoutLocale<T, L>;\n};\n"],"mappings":";;;;;;;;;AAUA,MAAM,0BACJ,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B;;;;AAKxC,MAAM,2BACJ,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCxC,MAAa,wBAIX,UACA,UAAeA,6CAAsB,YACT;CAE5B,MAAM,gBAAgBC,oDAAmB,QAAQ;CAEjD,IAAI,gBAAgB;CAEpB,IAAI,UAAU,SAAS,GAAG,GACxB,gBAAgB,SAAS,MAAM,GAAG,EAAE;CAKtC,MAAM,MAAM,gBACR,IAAI,IAAI,aAAa,IACrB,IAAI,IAAI,eAAe,cAAc;CAEzC,MAAM,WAAW,IAAI;CAGrB,IAAI,CAAC,SAAS,WAAW,GAAG,GAE1B,IAAI,WAAW,IAAI;CAIrB,IAAI,CAAC,yBAAyB;EAE5B,MAAM,eAAe,SAAS,MAAM,GAAG;EACvC,MAAM,eAAe,aAAa;EAGlC,IAAI,SAAS,SAAS,YAAiB,GAAG;GAExC,aAAa,OAAO,GAAG,CAAC;GAIxB,IAAI,WADgB,aAAa,KAAK,GAAG,KAAK;EAEhD;CACF;CAGA,IAAI,CAAC,0BAA0B;EAC7B,MAAM,eAAe,IAAI,gBAAgB,IAAI,MAAM;EACnD,IAAI,aAAa,IAAI,QAAQ,GAAG;GAC9B,aAAa,OAAO,QAAQ;GAC5B,IAAI,SAAS,aAAa,SAAS;EACrC;CACF;CAEA,IAAI,eACF,OAAO,IAAI,SAAS;CAGtB,OAAO,IAAI,SAAS,CAAC,CAAC,QAAQ,gBAAgB,EAAE;AAClD"}
|
|
@@ -17,6 +17,19 @@ const resolveRoutingConfig = (options = {}) => ({
|
|
|
17
17
|
...options
|
|
18
18
|
});
|
|
19
19
|
/**
|
|
20
|
+
* Narrows an arbitrary string to a declared locale by membership test.
|
|
21
|
+
*
|
|
22
|
+
* `locales` is typed as `DeclaredLocales[]`, so a plain `includes` rejects the
|
|
23
|
+
* `string` values that actually need testing (a URL segment, a query param, a
|
|
24
|
+
* stored value). This keeps the check honest and hands back a narrowed type
|
|
25
|
+
* instead of forcing a cast at every call site.
|
|
26
|
+
*
|
|
27
|
+
* @param value - The candidate locale, from a URL segment / storage / header.
|
|
28
|
+
* @param locales - The locales declared by the configuration.
|
|
29
|
+
* @returns Whether `value` is one of the declared locales.
|
|
30
|
+
*/
|
|
31
|
+
const isDeclaredLocale = (value, locales) => !!value && (locales ?? _intlayer_config_built.internationalization.locales).includes(value);
|
|
32
|
+
/**
|
|
20
33
|
* Determines the URL prefix for a given locale based on the routing mode configuration.
|
|
21
34
|
*
|
|
22
35
|
* Example:
|
|
@@ -51,7 +64,7 @@ const resolveRoutingConfig = (options = {}) => ({
|
|
|
51
64
|
*/
|
|
52
65
|
const getPrefix = (locale, options = {}) => {
|
|
53
66
|
const { defaultLocale, mode, locales, domains } = resolveRoutingConfig(options);
|
|
54
|
-
if (process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "prefix-all" && process.env.INTLAYER_ROUTING_MODE !== "prefix-no-default" || !locale || !
|
|
67
|
+
if (process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "prefix-all" && process.env.INTLAYER_ROUTING_MODE !== "prefix-no-default" || !locale || !isDeclaredLocale(locale, locales)) return {
|
|
55
68
|
prefix: "",
|
|
56
69
|
localePrefix: void 0
|
|
57
70
|
};
|
|
@@ -71,5 +84,6 @@ const getPrefix = (locale, options = {}) => {
|
|
|
71
84
|
|
|
72
85
|
//#endregion
|
|
73
86
|
exports.getPrefix = getPrefix;
|
|
87
|
+
exports.isDeclaredLocale = isDeclaredLocale;
|
|
74
88
|
exports.resolveRoutingConfig = resolveRoutingConfig;
|
|
75
89
|
//# sourceMappingURL=getPrefix.cjs.map
|
|
@@ -1 +1 @@
|
|
|
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';\
|
|
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';\nimport type { RewriteRules, 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'] | RewriteRules;\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: DeclaredLocales;\n mode: RoutingConfig['mode'];\n locales: DeclaredLocales[];\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\n/**\n * Narrows an arbitrary string to a declared locale by membership test.\n *\n * `locales` is typed as `DeclaredLocales[]`, so a plain `includes` rejects the\n * `string` values that actually need testing (a URL segment, a query param, a\n * stored value). This keeps the check honest and hands back a narrowed type\n * instead of forcing a cast at every call site.\n *\n * @param value - The candidate locale, from a URL segment / storage / header.\n * @param locales - The locales declared by the configuration.\n * @returns Whether `value` is one of the declared locales.\n */\nexport const isDeclaredLocale = (\n value: LocalesValues | undefined | null,\n locales?: readonly LocalesValues[]\n): value is DeclaredLocales =>\n !!value && (locales ?? internationalization.locales).includes(value);\n\nexport type GetPrefixOptions = {\n defaultLocale?: ResolvedDefaultLocale;\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: DeclaredLocales | 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 !isDeclaredLocale(locale, locales)\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 DeclaredLocales,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;;;AA0CA,MAAa,wBACX,UAA0B,CAAC,OAKvB;CACJ,eAAeA,6CAAsB,iBAAiBC;CACtD,MAAMC,gCAAS,QAAQC;CACvB,SAASH,6CAAsB,WAAWI;CAC1C,SAASF,gCAAS;CAClB,SAASA,gCAAS;CAClB,GAAG;AACL;;;;;;;;;;;;;AAcA,MAAa,oBACX,OACA,YAEA,CAAC,CAAC,UAAU,WAAWF,4CAAqB,QAAO,CAAE,SAAS,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ErE,MAAa,aACX,QACA,UAA0B,CAAC,MACI;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,OAAO;CAE9B,IACG,QAAQ,IAAI,yBACX,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B,uBACxC,CAAC,UACD,CAAC,iBAAiB,QAAQ,OAAO,GAEjC,OAAO;EACL,QAAQ;EACR,cAAc;CAChB;CAKF,IACE,QAAQ,IAAI,6BAA6B,WACzCK,2DAA0B,QAAyB,OAAO,GAE1D,OAAO;EACL,QAAQ;EACR,cAAc;CAChB;CAQF,IAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,QAGnD,OAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;CAChB;CAGF,OAAO;EACL,QAAQ;EACR,cAAc;CAChB;AACF"}
|
|
@@ -4,6 +4,7 @@ const require_localization_comparePaths = require('./comparePaths.cjs');
|
|
|
4
4
|
const require_localization_domainUtils = require('./domainUtils.cjs');
|
|
5
5
|
const require_localization_getPrefix = require('./getPrefix.cjs');
|
|
6
6
|
const require_localization_rewriteUtils = require('./rewriteUtils.cjs');
|
|
7
|
+
const require_localization_getLocalizedPath = require('./getLocalizedPath.cjs');
|
|
7
8
|
const require_localization_getLocalizedUrl = require('./getLocalizedUrl.cjs');
|
|
8
9
|
const require_localization_getMultilingualUrls = require('./getMultilingualUrls.cjs');
|
|
9
10
|
const require_localization_generateSitemap = require('./generateSitemap.cjs');
|
|
@@ -17,6 +18,7 @@ const require_localization_getLocaleLang = require('./getLocaleLang.cjs');
|
|
|
17
18
|
const require_localization_getLocaleName = require('./getLocaleName.cjs');
|
|
18
19
|
const require_localization_localeMapper = require('./localeMapper.cjs');
|
|
19
20
|
const require_localization_proxyMode = require('./proxyMode.cjs');
|
|
21
|
+
const require_localization_resolveBrowserLocale = require('./resolveBrowserLocale.cjs');
|
|
20
22
|
const require_localization_validatePrefix = require('./validatePrefix.cjs');
|
|
21
23
|
|
|
22
24
|
exports.comparePaths = require_localization_comparePaths.comparePaths;
|
|
@@ -34,13 +36,15 @@ exports.getLocaleFromDomain = require_localization_domainUtils.getLocaleFromDoma
|
|
|
34
36
|
exports.getLocaleFromPath = require_localization_getLocaleFromPath.getLocaleFromPath;
|
|
35
37
|
exports.getLocaleLang = require_localization_getLocaleLang.getLocaleLang;
|
|
36
38
|
exports.getLocaleName = require_localization_getLocaleName.getLocaleName;
|
|
37
|
-
exports.getLocalizedPath =
|
|
39
|
+
exports.getLocalizedPath = require_localization_getLocalizedPath.getLocalizedPath;
|
|
38
40
|
exports.getLocalizedUrl = require_localization_getLocalizedUrl.getLocalizedUrl;
|
|
39
41
|
exports.getMultilingualUrls = require_localization_getMultilingualUrls.getMultilingualUrls;
|
|
40
42
|
exports.getPathWithoutLocale = require_localization_getPathWithoutLocale.getPathWithoutLocale;
|
|
41
43
|
exports.getPrefix = require_localization_getPrefix.getPrefix;
|
|
44
|
+
exports.getPreloadLocale = require_localization_resolveBrowserLocale.getPreloadLocale;
|
|
42
45
|
exports.getRewritePath = require_localization_rewriteUtils.getRewritePath;
|
|
43
46
|
exports.getRewriteRules = require_localization_rewriteUtils.getRewriteRules;
|
|
47
|
+
exports.isDeclaredLocale = require_localization_getPrefix.isDeclaredLocale;
|
|
44
48
|
exports.isLocaleExclusiveOnDomain = require_localization_domainUtils.isLocaleExclusiveOnDomain;
|
|
45
49
|
exports.isProxyStorageLocaleEnabled = require_localization_proxyMode.isProxyStorageLocaleEnabled;
|
|
46
50
|
exports.localeDetector = require_localization_localeDetector.localeDetector;
|
|
@@ -49,5 +53,7 @@ exports.localeMap = require_localization_localeMapper.localeMap;
|
|
|
49
53
|
exports.localeRecord = require_localization_localeMapper.localeRecord;
|
|
50
54
|
exports.localeResolver = require_localization_localeResolver.localeResolver;
|
|
51
55
|
exports.normalizePath = require_localization_comparePaths.normalizePath;
|
|
56
|
+
exports.resolveBrowserLocale = require_localization_resolveBrowserLocale.resolveBrowserLocale;
|
|
57
|
+
exports.resolveLocalizedPath = require_localization_rewriteUtils.resolveLocalizedPath;
|
|
52
58
|
exports.resolveProxyMode = require_localization_proxyMode.resolveProxyMode;
|
|
53
59
|
exports.validatePrefix = require_localization_validatePrefix.validatePrefix;
|
|
@@ -41,9 +41,11 @@ const parseAcceptLanguageHeader = (headerValue) => {
|
|
|
41
41
|
const rawTags = headerValue.split(",");
|
|
42
42
|
const preferences = [];
|
|
43
43
|
for (let index = 0; index < rawTags.length; index++) {
|
|
44
|
-
const tag = rawTags[index]
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const tag = rawTags[index]?.trim();
|
|
45
|
+
if (tag) {
|
|
46
|
+
const parsedLanguage = parseLanguageTag(tag, index);
|
|
47
|
+
if (parsedLanguage) preferences.push(parsedLanguage);
|
|
48
|
+
}
|
|
47
49
|
}
|
|
48
50
|
return preferences;
|
|
49
51
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeDetector.cjs","names":["localeResolver"],"sources":["../../../src/localization/localeDetector.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport { localeResolver } from './localeResolver';\n\n/**\n * Constants\n */\nconst LANGUAGE_FORMAT_REGULAR_EXPRESSION =\n /^\\s*([^\\s\\-;]+)(?:-([^\\s;]+))?\\s*(?:;(.*))?$/;\nconst DEFAULT_QUALITY_SCORE = 1;\n\n/**\n * Enumeration for specificity weights.\n * Higher values indicate a more precise match.\n */\nenum SpecificityWeight {\n None = 0,\n Broad = 1, // Matches prefix (e.g., 'en' matches 'en-US')\n Prefix = 2, // Matches prefix in reverse (e.g., 'en-US' matches 'en')\n Exact = 4, // Matches exact string (e.g., 'en-US' matches 'en-US')\n}\n\n/**\n * Represents a parsed language tag from the header.\n */\ntype LanguagePreference = {\n languageCode: string;\n regionCode?: string;\n fullLocale: string;\n qualityScore: number;\n originalIndex: number;\n};\n\n/**\n * Represents the result of matching a requested language against an available language.\n */\ntype MatchResult = {\n providedIndex: number;\n headerIndex: number;\n qualityScore: number;\n specificityScore: number;\n};\n\n/**\n * Parses a single language tag string from the Accept-Language header.\n * Example input: \"en-US;q=0.8\"\n */\nconst parseLanguageTag = (\n tagString: string,\n index: number\n): LanguagePreference | null => {\n const match = LANGUAGE_FORMAT_REGULAR_EXPRESSION.exec(tagString);\n if (!match) {\n return null;\n }\n\n const languageCode = match[1];\n const regionCode = match[2];\n const parameters = match[3];\n\n // Construct the full locale string (e.g., \"en-US\" or \"en\")\n const fullLocale = regionCode\n ? `${languageCode}-${regionCode}`\n : languageCode;\n\n let qualityScore = DEFAULT_QUALITY_SCORE;\n\n // Parse parameters to find the quality score (\"q\")\n if (parameters) {\n const parameterList = parameters.split(';');\n for (const parameter of parameterList) {\n const [key, value] = parameter.split('=');\n if (key === 'q') {\n qualityScore = parseFloat(value);\n }\n }\n }\n\n return {\n languageCode,\n regionCode,\n qualityScore,\n originalIndex: index,\n fullLocale,\n };\n};\n\n/**\n * Parses the entire Accept-Language header string into a list of preferences.\n */\nconst parseAcceptLanguageHeader = (\n headerValue: string\n): LanguagePreference[] => {\n const rawTags = headerValue.split(',');\n const preferences: LanguagePreference[] = [];\n\n for (let index = 0; index < rawTags.length; index++) {\n const tag = rawTags[index]
|
|
1
|
+
{"version":3,"file":"localeDetector.cjs","names":["localeResolver"],"sources":["../../../src/localization/localeDetector.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { DeclaredLocales } from '@intlayer/types/module_augmentation';\nimport { localeResolver } from './localeResolver';\n\n/**\n * Constants\n */\nconst LANGUAGE_FORMAT_REGULAR_EXPRESSION =\n /^\\s*([^\\s\\-;]+)(?:-([^\\s;]+))?\\s*(?:;(.*))?$/;\nconst DEFAULT_QUALITY_SCORE = 1;\n\n/**\n * Enumeration for specificity weights.\n * Higher values indicate a more precise match.\n */\nenum SpecificityWeight {\n None = 0,\n Broad = 1, // Matches prefix (e.g., 'en' matches 'en-US')\n Prefix = 2, // Matches prefix in reverse (e.g., 'en-US' matches 'en')\n Exact = 4, // Matches exact string (e.g., 'en-US' matches 'en-US')\n}\n\n/**\n * Represents a parsed language tag from the header.\n */\ntype LanguagePreference = {\n languageCode: string;\n regionCode?: string;\n fullLocale: string;\n qualityScore: number;\n originalIndex: number;\n};\n\n/**\n * Represents the result of matching a requested language against an available language.\n */\ntype MatchResult = {\n providedIndex: number;\n headerIndex: number;\n qualityScore: number;\n specificityScore: number;\n};\n\n/**\n * Parses a single language tag string from the Accept-Language header.\n * Example input: \"en-US;q=0.8\"\n */\nconst parseLanguageTag = (\n tagString: string,\n index: number\n): LanguagePreference | null => {\n const match = LANGUAGE_FORMAT_REGULAR_EXPRESSION.exec(tagString);\n if (!match) {\n return null;\n }\n\n const languageCode = match[1] as string;\n const regionCode = match[2];\n const parameters = match[3];\n\n // Construct the full locale string (e.g., \"en-US\" or \"en\")\n const fullLocale = regionCode\n ? `${languageCode}-${regionCode}`\n : languageCode;\n\n let qualityScore = DEFAULT_QUALITY_SCORE;\n\n // Parse parameters to find the quality score (\"q\")\n if (parameters) {\n const parameterList = parameters.split(';');\n\n for (const parameter of parameterList) {\n const [key, value] = parameter.split('=');\n\n if (key === 'q') {\n qualityScore = parseFloat(value as string);\n }\n }\n }\n\n return {\n languageCode,\n regionCode,\n qualityScore,\n originalIndex: index,\n fullLocale,\n };\n};\n\n/**\n * Parses the entire Accept-Language header string into a list of preferences.\n */\nconst parseAcceptLanguageHeader = (\n headerValue: string\n): LanguagePreference[] => {\n const rawTags = headerValue.split(',');\n const preferences: LanguagePreference[] = [];\n\n for (let index = 0; index < rawTags.length; index++) {\n const tag = rawTags[index]?.trim();\n\n if (tag) {\n const parsedLanguage = parseLanguageTag(tag, index);\n\n if (parsedLanguage) {\n preferences.push(parsedLanguage);\n }\n }\n }\n\n return preferences;\n};\n\n/**\n * Calculates the specificity of a match between a provided language and a requested preference.\n */\nconst calculateMatchSpecificity = (\n providedLanguage: string,\n preference: LanguagePreference,\n providedIndex: number\n): MatchResult | null => {\n const parsedProvided = parseLanguageTag(providedLanguage, providedIndex);\n if (!parsedProvided) {\n return null;\n }\n\n let specificityScore = SpecificityWeight.None;\n\n const preferenceFullLower = preference.fullLocale.toLowerCase();\n const preferencePrefixLower = preference.languageCode.toLowerCase();\n const providedFullLower = parsedProvided.fullLocale.toLowerCase();\n const providedPrefixLower = parsedProvided.languageCode.toLowerCase();\n\n if (preferenceFullLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Exact;\n } else if (preferencePrefixLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Prefix;\n } else if (preferenceFullLower === providedPrefixLower) {\n specificityScore |= SpecificityWeight.Broad;\n } else if (preference.fullLocale !== '*') {\n return null;\n }\n\n return {\n providedIndex,\n headerIndex: preference.originalIndex,\n qualityScore: preference.qualityScore,\n specificityScore,\n };\n};\n\n/**\n * Determines the best match for a specific available language against the list of user accepted languages.\n */\nconst getBestMatchForLanguage = (\n providedLanguage: string,\n acceptedPreferences: LanguagePreference[],\n providedIndex: number\n): MatchResult => {\n // Initialize with a non-match priority\n let bestMatch: MatchResult = {\n headerIndex: -1,\n qualityScore: 0,\n specificityScore: 0,\n providedIndex,\n };\n\n for (const preference of acceptedPreferences) {\n const matchSpec = calculateMatchSpecificity(\n providedLanguage,\n preference,\n providedIndex\n );\n\n if (matchSpec) {\n // Compare current best match with new match\n const scoreDifference =\n bestMatch.specificityScore - matchSpec.specificityScore ||\n bestMatch.qualityScore - matchSpec.qualityScore ||\n bestMatch.headerIndex - matchSpec.headerIndex;\n\n // If the new match is better (difference < 0), update priority\n if (scoreDifference < 0) {\n bestMatch = matchSpec;\n }\n }\n }\n\n return bestMatch;\n};\n\n/**\n * Comparator function to sort language matches.\n * Sorting order:\n * 1. Quality Score (Descending)\n * 2. Specificity Score (Descending)\n * 3. Order in Header (Ascending - lower index is better)\n * 4. Order in Provided List (Ascending)\n */\nconst compareMatchResults = (a: MatchResult, b: MatchResult): number => {\n return (\n b.qualityScore - a.qualityScore ||\n b.specificityScore - a.specificityScore ||\n a.headerIndex - b.headerIndex ||\n a.providedIndex - b.providedIndex ||\n 0\n );\n};\n\n/**\n * Derives the list of preferred languages based on the Accept-Language header\n * and an optional list of available languages.\n */\nexport const getPreferredLanguages = (\n acceptHeader: string | undefined,\n availableLanguages?: string[]\n): string[] => {\n // RFC 2616 sec 14.4: no header implies '*'\n const headerValue = acceptHeader === undefined ? '*' : acceptHeader || '';\n const acceptedPreferences = parseAcceptLanguageHeader(headerValue);\n\n // If no specific languages are provided to filter against, return the header languages sorted by quality\n if (!availableLanguages) {\n return acceptedPreferences\n .filter((preference) => preference.qualityScore > 0)\n .sort((a, b) => b.qualityScore - a.qualityScore) // Simple sort by quality\n .map((preference) => preference.fullLocale);\n }\n\n // Map available languages to their match priority against the header\n const matchResults = availableLanguages.map((language, index) =>\n getBestMatchForLanguage(language, acceptedPreferences, index)\n );\n\n return matchResults\n .filter((result) => result.qualityScore > 0)\n .sort(compareMatchResults)\n .map((result) => availableLanguages[result.providedIndex]) as string[];\n};\n\n/**\n * Detects the locale from the request headers.\n *\n * Headers are provided by the browser/client and can be used to determine the user's preferred language.\n * This function intersects the user's `Accept-Language` header with the application's available locales.\n */\nexport const localeDetector = (\n headers: Record<string, string | undefined>,\n availableLocales?: Locale[],\n defaultLocale?: Locale\n): DeclaredLocales => {\n const acceptLanguageHeader = headers['accept-language'];\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales as string[]\n );\n\n return localeResolver(\n preferredLocaleStrings as Locale[],\n availableLocales,\n defaultLocale\n );\n};\n"],"mappings":";;;;;;;AAOA,MAAM,qCACJ;AACF,MAAM,wBAAwB;;;;;AAsC9B,MAAM,oBACJ,WACA,UAC8B;CAC9B,MAAM,QAAQ,mCAAmC,KAAK,SAAS;CAC/D,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,eAAe,MAAM;CAC3B,MAAM,aAAa,MAAM;CACzB,MAAM,aAAa,MAAM;CAGzB,MAAM,aAAa,aACf,GAAG,aAAa,GAAG,eACnB;CAEJ,IAAI,eAAe;CAGnB,IAAI,YAAY;EACd,MAAM,gBAAgB,WAAW,MAAM,GAAG;EAE1C,KAAK,MAAM,aAAa,eAAe;GACrC,MAAM,CAAC,KAAK,SAAS,UAAU,MAAM,GAAG;GAExC,IAAI,QAAQ,KACV,eAAe,WAAW,KAAe;EAE7C;CACF;CAEA,OAAO;EACL;EACA;EACA;EACA,eAAe;EACf;CACF;AACF;;;;AAKA,MAAM,6BACJ,gBACyB;CACzB,MAAM,UAAU,YAAY,MAAM,GAAG;CACrC,MAAM,cAAoC,CAAC;CAE3C,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS;EACnD,MAAM,MAAM,QAAQ,MAAM,EAAE,KAAK;EAEjC,IAAI,KAAK;GACP,MAAM,iBAAiB,iBAAiB,KAAK,KAAK;GAElD,IAAI,gBACF,YAAY,KAAK,cAAc;EAEnC;CACF;CAEA,OAAO;AACT;;;;AAKA,MAAM,6BACJ,kBACA,YACA,kBACuB;CACvB,MAAM,iBAAiB,iBAAiB,kBAAkB,aAAa;CACvE,IAAI,CAAC,gBACH,OAAO;CAGT,IAAI;CAEJ,MAAM,sBAAsB,WAAW,WAAW,YAAY;CAC9D,MAAM,wBAAwB,WAAW,aAAa,YAAY;CAClE,MAAM,oBAAoB,eAAe,WAAW,YAAY;CAChE,MAAM,sBAAsB,eAAe,aAAa,YAAY;CAEpE,IAAI,wBAAwB,mBAC1B;MACK,IAAI,0BAA0B,mBACnC;MACK,IAAI,wBAAwB,qBACjC;MACK,IAAI,WAAW,eAAe,KACnC,OAAO;CAGT,OAAO;EACL;EACA,aAAa,WAAW;EACxB,cAAc,WAAW;EACzB;CACF;AACF;;;;AAKA,MAAM,2BACJ,kBACA,qBACA,kBACgB;CAEhB,IAAI,YAAyB;EAC3B,aAAa;EACb,cAAc;EACd,kBAAkB;EAClB;CACF;CAEA,KAAK,MAAM,cAAc,qBAAqB;EAC5C,MAAM,YAAY,0BAChB,kBACA,YACA,aACF;EAEA,IAAI,WAQF;QALE,UAAU,mBAAmB,UAAU,oBACvC,UAAU,eAAe,UAAU,gBACnC,UAAU,cAAc,UAAU,eAGd,GACpB,YAAY;EACd;CAEJ;CAEA,OAAO;AACT;;;;;;;;;AAUA,MAAM,uBAAuB,GAAgB,MAA2B;CACtE,OACE,EAAE,eAAe,EAAE,gBACnB,EAAE,mBAAmB,EAAE,oBACvB,EAAE,cAAc,EAAE,eAClB,EAAE,gBAAgB,EAAE,iBACpB;AAEJ;;;;;AAMA,MAAa,yBACX,cACA,uBACa;CAGb,MAAM,sBAAsB,0BADR,iBAAiB,SAAY,MAAM,gBAAgB,EACN;CAGjE,IAAI,CAAC,oBACH,OAAO,oBACJ,QAAQ,eAAe,WAAW,eAAe,CAAC,CAAC,CACnD,MAAM,GAAG,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,CAC/C,KAAK,eAAe,WAAW,UAAU;CAQ9C,OAJqB,mBAAmB,KAAK,UAAU,UACrD,wBAAwB,UAAU,qBAAqB,KAAK,CAG5C,CAAC,CAChB,QAAQ,WAAW,OAAO,eAAe,CAAC,CAAC,CAC3C,KAAK,mBAAmB,CAAC,CACzB,KAAK,WAAW,mBAAmB,OAAO,cAAc;AAC7D;;;;;;;AAQA,MAAa,kBACX,SACA,kBACA,kBACoB;CACpB,MAAM,uBAAuB,QAAQ;CAErC,MAAM,yBAAyB,sBAC7B,sBACA,gBACF;CAEA,OAAOA,mDACL,wBACA,kBACA,aACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeMapper.cjs","names":["internationalization","DEFAULT_LOCALE","routing","getPrefix"],"sources":["../../../src/localization/localeMapper.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport { DEFAULT_LOCALE } from '@intlayer/config/defaultValues';\nimport type {
|
|
1
|
+
{"version":3,"file":"localeMapper.cjs","names":["internationalization","DEFAULT_LOCALE","routing","getPrefix"],"sources":["../../../src/localization/localeMapper.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport { DEFAULT_LOCALE } from '@intlayer/config/defaultValues';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { getPrefix } from './getPrefix';\n\nexport type LocaleData = {\n locale: DeclaredLocales;\n defaultLocale: DeclaredLocales;\n isDefault: boolean;\n locales: DeclaredLocales[];\n urlPrefix: string;\n};\n\n/**\n * Map the locale data to an array of objects\n *\n * @example\n * ```ts\n * const routes = localeMap((localizedData) =>\n * ({\n * path: localizedData.urlPrefix,\n * name: localizedData.locale,\n * isDefault: localizedData.isDefault,\n * locales: localizedData.locales,\n * defaultLocale: localizedData.defaultLocale,\n * }),\n * );\n *\n * // Result\n * [\n * { path: '/', name: 'en', isDefault: true, locales: ['en'], defaultLocale: 'en', urlPrefix: '' },\n * { path: '/fr', name: 'fr', isDefault: false, locales: ['fr'], defaultLocale: 'en', urlPrefix: '/fr' },\n * { path: '/es', name: 'es', isDefault: false, locales: ['es'], defaultLocale: 'en', urlPrefix: '/es' },\n * ]\n * ```\n *\n * @param mapper - The mapper function that returns an object\n * @returns An array of objects\n */\nexport const localeMap = <T>(\n mapper: (locale: LocaleData) => T,\n locales: LocalesValues[] = internationalization.locales ?? [],\n defaultLocale: LocalesValues = internationalization.defaultLocale ??\n DEFAULT_LOCALE,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = routing?.mode ?? 'prefix-no-default'\n): T[] =>\n (locales ?? []).map((locale) =>\n mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: getPrefix(locale, { defaultLocale, mode, locales })\n .localePrefix\n ? `/${locale}`\n : '',\n } as LocaleData)\n );\n\n/**\n * Flatten the locale map into a single array of objects\n *\n * @example\n * ```ts\n * const routes = localeMap((localizedData) =>\n * [{\n * path: localizedData.urlPrefix,\n * name: localizedData.locale,\n * isDefault: localizedData.isDefault,\n * locales: localizedData.locales,\n * defaultLocale: localizedData.defaultLocale,\n * }],\n * );\n *\n * // Result\n * [\n * path: '/', name: 'en', isDefault: true, locales: ['en'], defaultLocale: 'en', urlPrefix: '' ,\n * path: '/fr', name: 'fr', isDefault: false, locales: ['fr'], defaultLocale: 'en', urlPrefix: '/fr' ,\n * path: '/es', name: 'es', isDefault: false, locales: ['es'], defaultLocale: 'en', urlPrefix: '/es' ,\n * ]\n * ```\n *\n * @param mapper - The mapper function that returns an array of objects\n * @returns An array of objects\n */\nexport const localeFlatMap = <T>(\n mapper: (locale: LocaleData) => T[],\n locales: LocalesValues[] = internationalization.locales ?? [],\n defaultLocale: LocalesValues = internationalization.defaultLocale ??\n DEFAULT_LOCALE,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = routing?.mode ?? 'prefix-no-default'\n): T[] =>\n locales.flatMap((locale) =>\n mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: getPrefix(locale, { defaultLocale, mode, locales })\n .localePrefix\n ? `/${locale}`\n : '',\n } as LocaleData)\n );\n\n/**\n * Creates a record object mapping locales to values transformed by the mapper function\n *\n * @example\n * ```ts\n * const translations = localeRecord(({ locale }) =>\n * require(`./translations/${locale}.json`)\n * );\n *\n * // Result\n *\n * en: ... , // Content of translations/en.json\n * fr: ... , // Content of translations/fr.json\n * es: ...\n *\n * ```\n *\n * @param mapper - Function that takes locale data and returns a value for that locale\n * @param locales - Array of locale codes to map over (defaults to configured locales)\n * @param defaultLocale - The default locale (defaults to configured default)\n * @param mode - URL routing mode for locale handling (defaults to configured value)\n * @returns Record mapping locale codes to mapped values\n */\nexport const localeRecord = <T>(\n mapper: (locale: LocaleData) => T,\n locales: LocalesValues[] = internationalization.locales ?? [],\n defaultLocale: LocalesValues = internationalization.defaultLocale ??\n DEFAULT_LOCALE,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = routing?.mode ?? 'prefix-no-default'\n): Record<LocalesValues, T> =>\n (locales ?? []).reduce(\n (acc, locale) => {\n acc[locale] = mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: getPrefix(locale, { defaultLocale, mode, locales })\n .localePrefix\n ? `/${locale}`\n : '',\n } as LocaleData);\n return acc;\n },\n {} as Record<LocalesValues, T>\n );\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,MAAa,aACX,QACA,UAA2BA,4CAAqB,WAAW,CAAC,GAC5D,gBAA+BA,4CAAqB,iBAClDC,+CACF,OAIsBC,gCAAS,QAAQ,yBAEtC,WAAW,CAAC,EAAC,CAAE,KAAK,WACnB,OAAO;CACL;CACA;CACA;CACA,WAAW,WAAW;CACtB,WAAWC,yCAAU,QAAQ;EAAE;EAAe;EAAM;CAAQ,CAAC,CAAC,CAC3D,eACC,IAAI,WACJ;AACN,CAAe,CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BF,MAAa,iBACX,QACA,UAA2BH,4CAAqB,WAAW,CAAC,GAC5D,gBAA+BA,4CAAqB,iBAClDC,+CACF,OAIsBC,gCAAS,QAAQ,wBAEvC,QAAQ,SAAS,WACf,OAAO;CACL;CACA;CACA;CACA,WAAW,WAAW;CACtB,WAAWC,yCAAU,QAAQ;EAAE;EAAe;EAAM;CAAQ,CAAC,CAAC,CAC3D,eACC,IAAI,WACJ;AACN,CAAe,CACjB;;;;;;;;;;;;;;;;;;;;;;;;AAyBF,MAAa,gBACX,QACA,UAA2BH,4CAAqB,WAAW,CAAC,GAC5D,gBAA+BA,4CAAqB,iBAClDC,+CACF,OAIsBC,gCAAS,QAAQ,yBAEtC,WAAW,CAAC,EAAC,CAAE,QACb,KAAK,WAAW;CACf,IAAI,UAAU,OAAO;EACnB;EACA;EACA;EACA,WAAW,WAAW;EACtB,WAAWC,yCAAU,QAAQ;GAAE;GAAe;GAAM;EAAQ,CAAC,CAAC,CAC3D,eACC,IAAI,WACJ;CACN,CAAe;CACf,OAAO;AACT,GACA,CAAC,CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeResolver.cjs","names":["internationalization"],"sources":["../../../src/localization/localeResolver.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type {
|
|
1
|
+
{"version":3,"file":"localeResolver.cjs","names":["internationalization"],"sources":["../../../src/localization/localeResolver.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Resolves the most specific locale from a user-provided list,\n * or falls back to the default locale if no match is found.\n */\nexport const localeResolver = (\n selectedLocale: LocalesValues | LocalesValues[],\n locales: LocalesValues[] = internationalization?.locales,\n defaultLocale: LocalesValues = internationalization?.defaultLocale\n): DeclaredLocales => {\n // Ensure we can handle both a single locale or an array of locales uniformly\n const requestedLocales = [selectedLocale].flat();\n\n // Simple helper to normalize locale strings (e.g. \"en-US\" => \"en-us\")\n const normalize = (locale: string): string => locale.trim().toLowerCase();\n\n try {\n // Check each requested locale in order\n for (const requested of requestedLocales) {\n const normalizedRequested = normalize(requested);\n\n // Attempt exact match\n const exactMatch = locales.find(\n (locale) => normalize(locale) === normalizedRequested\n );\n if (exactMatch) {\n return exactMatch as DeclaredLocales;\n }\n\n // Attempt partial match on language subtag\n // e.g. if requested is \"en-US\" and not found,\n // see if \"en\" is available among locales\n const [requestedLang] = normalizedRequested.split('-');\n const partialMatch = locales.find(\n (locale) => normalize(locale).split('-')[0] === requestedLang\n );\n if (partialMatch) {\n return partialMatch as DeclaredLocales;\n }\n }\n } catch {\n // If anything unexpected happened, fall back to default\n }\n\n // If no match was found, return the default\n return defaultLocale as DeclaredLocales;\n};\n"],"mappings":";;;;;;;;AAUA,MAAa,kBACX,gBACA,UAA2BA,6CAAsB,SACjD,gBAA+BA,6CAAsB,kBACjC;CAEpB,MAAM,mBAAmB,CAAC,cAAc,CAAC,CAAC,KAAK;CAG/C,MAAM,aAAa,WAA2B,OAAO,KAAK,CAAC,CAAC,YAAY;CAExE,IAAI;EAEF,KAAK,MAAM,aAAa,kBAAkB;GACxC,MAAM,sBAAsB,UAAU,SAAS;GAG/C,MAAM,aAAa,QAAQ,MACxB,WAAW,UAAU,MAAM,MAAM,mBACpC;GACA,IAAI,YACF,OAAO;GAMT,MAAM,CAAC,iBAAiB,oBAAoB,MAAM,GAAG;GACrD,MAAM,eAAe,QAAQ,MAC1B,WAAW,UAAU,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,aAClD;GACA,IAAI,cACF,OAAO;EAEX;CACF,QAAQ,CAER;CAGA,OAAO;AACT"}
|