@inlang/paraglide-js 2.0.0-beta.15 → 2.0.0-beta.17
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/dist/bundler-plugins/unplugin.d.ts.map +1 -1
- package/dist/bundler-plugins/unplugin.js +10 -3
- package/dist/cli/steps/run-compiler.js +1 -1
- package/dist/compiler/compile-bundle.d.ts.map +1 -1
- package/dist/compiler/compile-bundle.js +9 -4
- package/dist/compiler/compile-bundle.test.js +11 -0
- package/dist/compiler/compile-message.d.ts +0 -3
- package/dist/compiler/compile-message.d.ts.map +1 -1
- package/dist/compiler/compile-message.js +14 -9
- package/dist/compiler/compile-message.test.js +25 -3
- package/dist/compiler/compile-project.d.ts.map +1 -1
- package/dist/compiler/compile-project.js +0 -3
- package/dist/compiler/compile-project.test.js +59 -66
- package/dist/compiler/compile.d.ts +41 -2
- package/dist/compiler/compile.d.ts.map +1 -1
- package/dist/compiler/compile.js +12 -4
- package/dist/compiler/compile.test.js +29 -7
- package/dist/compiler/jsdoc-types.d.ts +9 -3
- package/dist/compiler/jsdoc-types.d.ts.map +1 -1
- package/dist/compiler/jsdoc-types.js +15 -11
- package/dist/compiler/output-structure/locale-modules.d.ts.map +1 -1
- package/dist/compiler/output-structure/locale-modules.js +5 -8
- package/dist/compiler/runtime/assert-is-locale.js +1 -1
- package/dist/compiler/runtime/create-runtime.d.ts +3 -4
- package/dist/compiler/runtime/create-runtime.d.ts.map +1 -1
- package/dist/compiler/runtime/create-runtime.js +28 -11
- package/dist/compiler/runtime/de-localize-path.d.ts +2 -2
- package/dist/compiler/runtime/de-localize-path.d.ts.map +1 -1
- package/dist/compiler/runtime/de-localize-path.js +25 -6
- package/dist/compiler/runtime/de-localize-path.test.js +83 -21
- package/dist/compiler/runtime/de-localized-path.d.ts +27 -0
- package/dist/compiler/runtime/de-localized-path.d.ts.map +1 -0
- package/dist/compiler/runtime/de-localized-path.js +32 -0
- package/dist/compiler/runtime/de-localized-path.test.d.ts +2 -0
- package/dist/compiler/runtime/de-localized-path.test.d.ts.map +1 -0
- package/dist/compiler/runtime/de-localized-path.test.js +48 -0
- package/dist/compiler/runtime/detect-locale-from-request.d.ts +22 -0
- package/dist/compiler/runtime/detect-locale-from-request.d.ts.map +1 -0
- package/dist/compiler/runtime/detect-locale-from-request.js +44 -0
- package/dist/compiler/runtime/e2e.test.d.ts +2 -0
- package/dist/compiler/runtime/e2e.test.d.ts.map +1 -0
- package/dist/compiler/runtime/e2e.test.js +33 -0
- package/dist/compiler/runtime/extract-locale-from-cookie.js +1 -1
- package/dist/compiler/runtime/extract-locale-from-pathname.d.ts.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-pathname.js +19 -3
- package/dist/compiler/runtime/extract-locale-from-pathname.test.js +83 -0
- package/dist/compiler/runtime/extract-locale-from-request.d.ts.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-request.js +2 -4
- package/dist/compiler/runtime/extract-locale-from-request.test.js +5 -0
- package/dist/compiler/runtime/get-locale-from-path.d.ts +13 -0
- package/dist/compiler/runtime/get-locale-from-path.d.ts.map +1 -0
- package/dist/compiler/runtime/get-locale-from-path.js +17 -0
- package/dist/compiler/runtime/get-locale-from-path.test.d.ts +2 -0
- package/dist/compiler/runtime/get-locale-from-path.test.d.ts.map +1 -0
- package/dist/compiler/runtime/get-locale-from-path.test.js +22 -0
- package/dist/compiler/runtime/get-locale.d.ts.map +1 -1
- package/dist/compiler/runtime/get-locale.js +7 -5
- package/dist/compiler/runtime/get-locale.test.js +2 -2
- package/dist/compiler/runtime/is-locale.js +1 -1
- package/dist/compiler/runtime/jsdoc-runtime.d.ts +2 -0
- package/dist/compiler/runtime/jsdoc-runtime.d.ts.map +1 -0
- package/dist/compiler/runtime/jsdoc-runtime.js +131 -0
- package/dist/compiler/runtime/locale-in-path.d.ts +13 -0
- package/dist/compiler/runtime/locale-in-path.d.ts.map +1 -0
- package/dist/compiler/runtime/locale-in-path.js +17 -0
- package/dist/compiler/runtime/locale-in-path.test.d.ts +2 -0
- package/dist/compiler/runtime/locale-in-path.test.d.ts.map +1 -0
- package/dist/compiler/runtime/locale-in-path.test.js +22 -0
- package/dist/compiler/runtime/localize-path.d.ts +2 -2
- package/dist/compiler/runtime/localize-path.d.ts.map +1 -1
- package/dist/compiler/runtime/localize-path.js +61 -13
- package/dist/compiler/runtime/localize-path.test.js +192 -20
- package/dist/compiler/runtime/localized-path.d.ts +32 -0
- package/dist/compiler/runtime/localized-path.d.ts.map +1 -0
- package/dist/compiler/runtime/localized-path.js +44 -0
- package/dist/compiler/runtime/localized-path.test.d.ts +2 -0
- package/dist/compiler/runtime/localized-path.test.d.ts.map +1 -0
- package/dist/compiler/runtime/localized-path.test.js +42 -0
- package/dist/compiler/runtime/mock-runtime.d.ts +6 -0
- package/dist/compiler/runtime/mock-runtime.d.ts.map +1 -0
- package/dist/compiler/runtime/mock-runtime.js +31 -0
- package/dist/compiler/runtime/path-to-regexp.d.ts +2 -0
- package/dist/compiler/runtime/path-to-regexp.d.ts.map +1 -0
- package/dist/compiler/runtime/path-to-regexp.js +1 -0
- package/dist/compiler/runtime/pathname-pattern.d.ts +30 -0
- package/dist/compiler/runtime/pathname-pattern.d.ts.map +1 -0
- package/dist/compiler/runtime/pathname-pattern.js +99 -0
- package/dist/compiler/runtime/pathname-pattern.test.d.ts +2 -0
- package/dist/compiler/runtime/pathname-pattern.test.d.ts.map +1 -0
- package/dist/compiler/runtime/pathname-pattern.test.js +103 -0
- package/dist/compiler/runtime/set-locale.d.ts.map +1 -1
- package/dist/compiler/runtime/set-locale.js +5 -5
- package/dist/compiler/runtime/set-locale.test.js +1 -1
- package/dist/compiler/runtime/ts-runtime.d.ts +2 -0
- package/dist/compiler/runtime/ts-runtime.d.ts.map +1 -0
- package/dist/compiler/runtime/ts-runtime.js +119 -0
- package/dist/compiler/runtime/type.d.ts +2 -2
- package/dist/compiler/runtime/type.d.ts.map +1 -1
- package/dist/compiler/runtime/type.test.js +48 -11
- package/dist/compiler/runtime/variables.d.ts +46 -0
- package/dist/compiler/runtime/variables.d.ts.map +1 -0
- package/dist/compiler/runtime/variables.js +45 -0
- package/dist/compiler/strategy.d.ts +13 -0
- package/dist/compiler/strategy.d.ts.map +1 -0
- package/dist/compiler/strategy.js +12 -0
- package/dist/compiler/strategy.test.d.ts +2 -0
- package/dist/compiler/strategy.test.d.ts.map +1 -0
- package/dist/compiler/strategy.test.js +9 -0
- package/dist/path-to-regexp/index.d.ts +12 -0
- package/dist/path-to-regexp/index.d.ts.map +1 -0
- package/dist/path-to-regexp/index.js +11 -0
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/file-handling/write-output.d.ts +6 -1
- package/dist/services/file-handling/write-output.d.ts.map +1 -1
- package/dist/services/file-handling/write-output.js +33 -19
- package/dist/services/file-handling/write-output.test.js +60 -11
- package/dist/urlpattern-polyfill/index.d.ts +2 -0
- package/dist/urlpattern-polyfill/index.d.ts.map +1 -0
- package/dist/urlpattern-polyfill/index.js +1 -0
- package/package.json +12 -8
|
@@ -1,48 +1,220 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
1
|
+
import { test, expect, describe } from "vitest";
|
|
2
2
|
import { createRuntimeForTesting } from "./create-runtime.js";
|
|
3
|
+
test("matches root path and paths", async () => {
|
|
4
|
+
const runtime = await createRuntimeForTesting({
|
|
5
|
+
baseLocale: "en",
|
|
6
|
+
locales: ["en", "de"],
|
|
7
|
+
compilerOptions: {
|
|
8
|
+
pathnames: {
|
|
9
|
+
"/{*path}": {
|
|
10
|
+
de: "/de{/*path}",
|
|
11
|
+
en: "/en{/*path}",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
expect(runtime.localizePath("/", { locale: "en" })).toBe("/en");
|
|
17
|
+
expect(runtime.localizePath("/something", { locale: "en" })).toBe("/en/something");
|
|
18
|
+
});
|
|
3
19
|
test("localizes the path based on the return value of getLocale()", async () => {
|
|
4
20
|
const runtime = await createRuntimeForTesting({
|
|
5
21
|
baseLocale: "en",
|
|
6
22
|
locales: ["en", "de"],
|
|
23
|
+
compilerOptions: {
|
|
24
|
+
pathnames: {
|
|
25
|
+
"/{*path}": {
|
|
26
|
+
en: "/en{/*path}",
|
|
27
|
+
de: "/de{/*path}",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
7
31
|
});
|
|
8
32
|
runtime.setLocale("de");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
expect(
|
|
33
|
+
expect(runtime.localizePath("/about")).toBe("/de/about");
|
|
34
|
+
runtime.setLocale("en");
|
|
35
|
+
expect(runtime.localizePath("/about")).toBe("/en/about");
|
|
36
|
+
});
|
|
37
|
+
test("trailing slashes are kept as is", async () => {
|
|
38
|
+
const runtime = await createRuntimeForTesting({
|
|
39
|
+
baseLocale: "en",
|
|
40
|
+
locales: ["en", "de"],
|
|
41
|
+
compilerOptions: {
|
|
42
|
+
pathnames: {
|
|
43
|
+
"*path": {
|
|
44
|
+
en: "*path",
|
|
45
|
+
de: "/de*path",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
expect(runtime.localizePath("/about/", { locale: "de" })).toBe("/de/about/");
|
|
51
|
+
});
|
|
52
|
+
test("root path stays root path", async () => {
|
|
53
|
+
const runtime = await createRuntimeForTesting({
|
|
54
|
+
baseLocale: "en",
|
|
55
|
+
locales: ["en", "de"],
|
|
56
|
+
compilerOptions: {
|
|
57
|
+
pathnames: {
|
|
58
|
+
"/{*path}": {
|
|
59
|
+
de: "/de{/*path}",
|
|
60
|
+
en: "/{*path}",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
expect(runtime.localizePath("/", { locale: "en" })).toBe("/");
|
|
66
|
+
expect(runtime.localizePath("/", { locale: "de" })).toBe("/de");
|
|
12
67
|
});
|
|
13
|
-
test("
|
|
68
|
+
test("catchall pathname pattern", async () => {
|
|
14
69
|
const runtime = await createRuntimeForTesting({
|
|
15
70
|
baseLocale: "en",
|
|
16
71
|
locales: ["en", "de"],
|
|
72
|
+
compilerOptions: {
|
|
73
|
+
pathnames: {
|
|
74
|
+
"/{*path}": {
|
|
75
|
+
en: "/en{/*path}",
|
|
76
|
+
de: "/de{/*path}",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
17
80
|
});
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
expect(
|
|
81
|
+
expect(runtime.localizePath("/about", { locale: "en" })).toBe("/en/about");
|
|
82
|
+
expect(runtime.localizePath("/about", { locale: "de" })).toBe("/de/about");
|
|
83
|
+
expect(runtime.localizePath("/blog/123/suffix", { locale: "en" })).toBe("/en/blog/123/suffix");
|
|
84
|
+
expect(runtime.localizePath("/blog/123/suffix", { locale: "de" })).toBe("/de/blog/123/suffix");
|
|
21
85
|
});
|
|
22
|
-
test("
|
|
86
|
+
test("path parameters", async () => {
|
|
23
87
|
const runtime = await createRuntimeForTesting({
|
|
24
88
|
baseLocale: "en",
|
|
25
89
|
locales: ["en", "de"],
|
|
90
|
+
compilerOptions: {
|
|
91
|
+
strategy: ["pathname"],
|
|
92
|
+
pathnames: {
|
|
93
|
+
"/blog/:post/suffix": {
|
|
94
|
+
en: "/en/blog/:post/suffix",
|
|
95
|
+
de: "/de/artikel/:post/anhang",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
26
99
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(l10nPath).toBe("/de");
|
|
100
|
+
expect(runtime.localizePath("/blog/532/suffix", { locale: "en" })).toBe("/en/blog/532/suffix");
|
|
101
|
+
expect(runtime.localizePath("/blog/12/suffix", { locale: "de" })).toBe("/de/artikel/12/anhang");
|
|
30
102
|
});
|
|
31
|
-
test("
|
|
103
|
+
test("order of defining pathnames matters", async () => {
|
|
32
104
|
const runtime = await createRuntimeForTesting({
|
|
33
105
|
baseLocale: "en",
|
|
34
106
|
locales: ["en", "de"],
|
|
107
|
+
compilerOptions: {
|
|
108
|
+
strategy: ["pathname"],
|
|
109
|
+
pathnames: {
|
|
110
|
+
// the catch all has precedence over the parameter pattern
|
|
111
|
+
// because it is defined first
|
|
112
|
+
"/{*path}": {
|
|
113
|
+
en: "/en{/*path}",
|
|
114
|
+
de: "/de{/*path}",
|
|
115
|
+
},
|
|
116
|
+
"/about": {
|
|
117
|
+
en: "/en/about",
|
|
118
|
+
de: "/de/uber-uns",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
35
122
|
});
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
123
|
+
const runtime2 = await createRuntimeForTesting({
|
|
124
|
+
baseLocale: "en",
|
|
125
|
+
locales: ["en", "de"],
|
|
126
|
+
compilerOptions: {
|
|
127
|
+
strategy: ["pathname"],
|
|
128
|
+
pathnames: {
|
|
129
|
+
// the catch all has precedence over the parameter pattern
|
|
130
|
+
// because it is defined first
|
|
131
|
+
"/about": {
|
|
132
|
+
en: "/en/about",
|
|
133
|
+
de: "/de/uber-uns",
|
|
134
|
+
},
|
|
135
|
+
"/{*path}": {
|
|
136
|
+
en: "/en{/*path}",
|
|
137
|
+
de: "/de{/*path}",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
expect(runtime.localizePath("/about", { locale: "en" })).toBe("/en/about");
|
|
143
|
+
expect(runtime.localizePath("/about", { locale: "de" })).toBe("/de/about");
|
|
144
|
+
expect(runtime2.localizePath("/about", { locale: "en" })).toBe("/en/about");
|
|
145
|
+
expect(runtime2.localizePath("/about", { locale: "de" })).toBe("/de/uber-uns");
|
|
146
|
+
});
|
|
147
|
+
test("handles query parameters", async () => {
|
|
148
|
+
const runtime = await createRuntimeForTesting({
|
|
149
|
+
baseLocale: "en",
|
|
150
|
+
locales: ["en", "de"],
|
|
151
|
+
compilerOptions: {
|
|
152
|
+
pathnames: {
|
|
153
|
+
"/{*path}": {
|
|
154
|
+
en: "/en{/*path}",
|
|
155
|
+
de: "/de{/*path}",
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
expect(runtime.localizePath("/about?query=1", { locale: "en" })).toBe("/en/about?query=1");
|
|
39
161
|
});
|
|
40
|
-
test("does not
|
|
162
|
+
test("does not double localize already localized paths", async () => {
|
|
41
163
|
const runtime = await createRuntimeForTesting({
|
|
42
164
|
baseLocale: "en",
|
|
43
165
|
locales: ["en", "de"],
|
|
166
|
+
compilerOptions: {
|
|
167
|
+
pathnames: {
|
|
168
|
+
"/{*path}": {
|
|
169
|
+
en: "/en{/*path}",
|
|
170
|
+
de: "/de{/*path}",
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
// path is already localized
|
|
176
|
+
expect(runtime.localizePath("/en/about", { locale: "en" })).toBe("/en/about");
|
|
177
|
+
});
|
|
178
|
+
test("handles TREE_SHAKE_DEFAULT_PATHNAMES", async () => {
|
|
179
|
+
const runtime = await createRuntimeForTesting({
|
|
180
|
+
baseLocale: "en",
|
|
181
|
+
locales: ["en", "de"],
|
|
182
|
+
compilerOptions: {
|
|
183
|
+
// auto creates default pathnames for all locales
|
|
184
|
+
pathnames: undefined,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
expect(runtime.localizePath("/about", { locale: "en" })).toBe("/about");
|
|
188
|
+
expect(runtime.localizePath("/about", { locale: "de" })).toBe("/de/about");
|
|
189
|
+
expect(runtime.localizePath("/about/", { locale: "de" })).toBe("/de/about/");
|
|
190
|
+
expect(runtime.localizePath("/de/about", { locale: "de" })).toBe("/de/about");
|
|
191
|
+
// switching locale
|
|
192
|
+
expect(runtime.localizePath("/de/about", { locale: "en" })).toBe("/about");
|
|
193
|
+
});
|
|
194
|
+
// https://github.com/opral/inlang-paraglide-js/issues/362
|
|
195
|
+
describe.each([
|
|
196
|
+
{ pathnameBase: "/base" },
|
|
197
|
+
{
|
|
198
|
+
pathnameBase: "/base",
|
|
199
|
+
pathnames: {
|
|
200
|
+
"/{*path}": {
|
|
201
|
+
de: "/de{/*path}",
|
|
202
|
+
en: "/{*path}",
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
])("handles pathnameBase", (compilerOptions) => {
|
|
207
|
+
test(`pathnames: ${compilerOptions.pathnames}`, async () => {
|
|
208
|
+
const runtime = await createRuntimeForTesting({
|
|
209
|
+
baseLocale: "en",
|
|
210
|
+
locales: ["en", "de"],
|
|
211
|
+
compilerOptions,
|
|
212
|
+
});
|
|
213
|
+
expect(runtime.localizePath("/about", { locale: "en" })).toBe("/base/about");
|
|
214
|
+
expect(runtime.localizePath("/base", { locale: "de" })).toBe("/base/de");
|
|
215
|
+
expect(runtime.localizePath("/base/de", { locale: "en" })).toBe("/base");
|
|
216
|
+
expect(runtime.localizePath("/base/about", { locale: "en" })).toBe("/base/about");
|
|
217
|
+
expect(runtime.localizePath("/about", { locale: "de" })).toBe("/base/de/about");
|
|
218
|
+
expect(runtime.localizePath("/base/de/about", { locale: "de" })).toBe("/base/de/about");
|
|
44
219
|
});
|
|
45
|
-
const path = "/de";
|
|
46
|
-
const l10nPath = runtime.localizePath(path, { locale: "de" });
|
|
47
|
-
expect(l10nPath).toBe("/de");
|
|
48
220
|
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Localizes the given path.
|
|
3
|
+
*
|
|
4
|
+
* This function is useful if you use localized (i18n) routing
|
|
5
|
+
* in your application.
|
|
6
|
+
*
|
|
7
|
+
* Defaults to `getLocale()` if no locale is provided.
|
|
8
|
+
*
|
|
9
|
+
* @tip
|
|
10
|
+
* Use `deLocalizedPath()` for the inverse operation.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // getLocale() = 'en'
|
|
14
|
+
* localizedPath('/home'));
|
|
15
|
+
* // '/de/home'
|
|
16
|
+
*
|
|
17
|
+
* // enforcing a specific locale
|
|
18
|
+
* localizedPath('/home', { locale: 'fr' });
|
|
19
|
+
* // '/fr/home'
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* <a href={localizedPath('/home')}>Home</a>
|
|
23
|
+
*
|
|
24
|
+
* @param {string} path
|
|
25
|
+
* @param {Object} [options] - Optional parameters.
|
|
26
|
+
* @param {Locale} [options.locale] - The locale to use for the path.
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function localizedPath(path: string, options?: {
|
|
30
|
+
locale?: Locale;
|
|
31
|
+
}): string;
|
|
32
|
+
//# sourceMappingURL=localized-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localized-path.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/localized-path.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,oCALW,MAAM,YAEd;IAAyB,MAAM,GAAvB,MAAM;CACd,GAAU,MAAM,CAgBlB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Localizes the given path.
|
|
3
|
+
*
|
|
4
|
+
* This function is useful if you use localized (i18n) routing
|
|
5
|
+
* in your application.
|
|
6
|
+
*
|
|
7
|
+
* Defaults to `getLocale()` if no locale is provided.
|
|
8
|
+
*
|
|
9
|
+
* @tip
|
|
10
|
+
* Use `deLocalizedPath()` for the inverse operation.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // getLocale() = 'en'
|
|
14
|
+
* localizedPath('/home'));
|
|
15
|
+
* // '/de/home'
|
|
16
|
+
*
|
|
17
|
+
* // enforcing a specific locale
|
|
18
|
+
* localizedPath('/home', { locale: 'fr' });
|
|
19
|
+
* // '/fr/home'
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* <a href={localizedPath('/home')}>Home</a>
|
|
23
|
+
*
|
|
24
|
+
* @param {string} path
|
|
25
|
+
* @param {Object} [options] - Optional parameters.
|
|
26
|
+
* @param {Locale} [options.locale] - The locale to use for the path.
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function localizedPath(path, options) {
|
|
30
|
+
const locale = options?.locale ?? getLocale();
|
|
31
|
+
const hasLocale = getLocaleFromPath(path);
|
|
32
|
+
const pathWithoutLocale = hasLocale
|
|
33
|
+
? "/" + path.split("/").slice(2).join("/")
|
|
34
|
+
: path;
|
|
35
|
+
if (locale === baseLocale) {
|
|
36
|
+
return pathWithoutLocale;
|
|
37
|
+
}
|
|
38
|
+
else if (path === "/" || pathWithoutLocale === "/") {
|
|
39
|
+
return `/${locale}`;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return `/${locale}${pathWithoutLocale}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localized-path.test.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/localized-path.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { test, vi, beforeEach, expect, describe } from "vitest";
|
|
2
|
+
import { localizedPath } from "./localized-path.js";
|
|
3
|
+
import { mockRuntime } from "./mock-runtime.js";
|
|
4
|
+
// sequential to avoid global variable conflicts
|
|
5
|
+
describe.sequential("", () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.resetAllMocks();
|
|
8
|
+
});
|
|
9
|
+
mockRuntime({
|
|
10
|
+
baseLocale: "en",
|
|
11
|
+
locales: ["en", "de"],
|
|
12
|
+
});
|
|
13
|
+
test("localizes the path based on the getLocale definition", () => {
|
|
14
|
+
// @ts-expect-error - global variable definition
|
|
15
|
+
globalThis.getLocale = vi.fn().mockReturnValue("de");
|
|
16
|
+
const path = "/about";
|
|
17
|
+
const l10nPath = localizedPath(path);
|
|
18
|
+
expect(l10nPath).toBe("/de/about");
|
|
19
|
+
});
|
|
20
|
+
test("keeps trailing slashes if provided", () => {
|
|
21
|
+
const path = "/about/";
|
|
22
|
+
const l10nPath = localizedPath(path, { locale: "de" });
|
|
23
|
+
expect(l10nPath).toBe("/de/about/");
|
|
24
|
+
});
|
|
25
|
+
test("adds no trailing slash for the root path", () => {
|
|
26
|
+
const path = "/";
|
|
27
|
+
const l10nPath = localizedPath(path, { locale: "de" });
|
|
28
|
+
expect(l10nPath).toBe("/de");
|
|
29
|
+
});
|
|
30
|
+
test("removes the base locale from the path", () => {
|
|
31
|
+
// @ts-expect-error - global variable definition
|
|
32
|
+
globalThis.baseLocale = "en";
|
|
33
|
+
const path = "/de/about";
|
|
34
|
+
const l10nPath = localizedPath(path, { locale: "en" });
|
|
35
|
+
expect(l10nPath).toBe("/about");
|
|
36
|
+
});
|
|
37
|
+
test("does not add a slash suffix if it's the root path that is already localized", () => {
|
|
38
|
+
const path = "/de";
|
|
39
|
+
const l10nPath = localizedPath(path, { locale: "de" });
|
|
40
|
+
expect(l10nPath).toBe("/de");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-runtime.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/mock-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,wBAAgB,WAAW,CAAC,EAAE,UAAiB,EAAE,OAAsB,EAAE;;;CAAA,WAwBxE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { localeInPath } from "./locale-in-path.js";
|
|
2
|
+
import { localizePath } from "./localize-path.js";
|
|
3
|
+
import { isLocale } from "./is-locale.js";
|
|
4
|
+
import { deLocalizePath } from "./de-localize-path.js";
|
|
5
|
+
import { assertIsLocale } from "./assert-is-locale.js";
|
|
6
|
+
import { detectLocaleFromRequest } from "./detect-locale-from-request.js";
|
|
7
|
+
import { defaultCompilerOptions } from "../compile.js";
|
|
8
|
+
export function mockRuntime({ baseLocale = "en", locales = ["en", "de"] }) {
|
|
9
|
+
let locale = baseLocale;
|
|
10
|
+
const runtime = {
|
|
11
|
+
baseLocale,
|
|
12
|
+
locales,
|
|
13
|
+
cookieName: defaultCompilerOptions.cookieName,
|
|
14
|
+
strategy: defaultCompilerOptions.strategy,
|
|
15
|
+
isLocale,
|
|
16
|
+
assertIsLocale,
|
|
17
|
+
localeInPath,
|
|
18
|
+
localizePath,
|
|
19
|
+
deLocalizePath,
|
|
20
|
+
detectLocaleFromRequest,
|
|
21
|
+
defineGetLocale: (fn) => (runtime.getLocale = fn),
|
|
22
|
+
defineSetLocale: (fn) => (runtime.setLocale = fn),
|
|
23
|
+
setLocale: (newLocale) => (locale = newLocale),
|
|
24
|
+
getLocale: () => locale,
|
|
25
|
+
};
|
|
26
|
+
for (const [key, value] of Object.entries(runtime)) {
|
|
27
|
+
// @ts-expect-error - global variable definition
|
|
28
|
+
globalThis[key] = value;
|
|
29
|
+
}
|
|
30
|
+
return runtime;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-to-regexp.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/path-to-regexp.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {any} pattern
|
|
4
|
+
* @param {any} pathname
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export function matchPathnamePattern2(pattern: any, pathname: any): {
|
|
8
|
+
params: {
|
|
9
|
+
[key: string]: string | undefined;
|
|
10
|
+
};
|
|
11
|
+
} | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Matches a pathname against a pattern with named parameters, wildcards, and optional segments.
|
|
14
|
+
* Supports path-to-regexp v8 syntax (`/:param`, `/*wildcard`, `/de{/*path}`).
|
|
15
|
+
*
|
|
16
|
+
* @param {string} pattern - The pattern to match.
|
|
17
|
+
* @param {string} pathname - The actual pathname.
|
|
18
|
+
* @returns {object | undefined} - Matched parameters or `undefined` if no match.
|
|
19
|
+
*/
|
|
20
|
+
export function matchPathnamePattern(pattern: string, pathname: string): object | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Generates a pathname from a pattern and parameters.
|
|
23
|
+
* Supports named parameters (`:param`), optional segments (`{}`), and wildcards (`*param`).
|
|
24
|
+
*
|
|
25
|
+
* @param {string} pattern - The pattern to generate the path from.
|
|
26
|
+
* @param {Record<string, string | string[]>} params - Parameters to replace in the pattern.
|
|
27
|
+
* @returns {string} - The generated pathname.
|
|
28
|
+
*/
|
|
29
|
+
export function compilePathnamePattern(pattern: string, params: Record<string, string | string[]>): string;
|
|
30
|
+
//# sourceMappingURL=pathname-pattern.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathname-pattern.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/pathname-pattern.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,+CAJW,GAAG,YACH,GAAG;;;;cAsBb;AAED;;;;;;;GAOG;AACH,8CAJW,MAAM,YACN,MAAM,GACJ,MAAM,GAAG,SAAS,CAuC9B;AAED;;;;;;;GAOG;AACH,gDAJW,MAAM,UACN,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAC/B,MAAM,CA8BlB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { URLPattern } from "urlpattern-polyfill/urlpattern";
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @param {any} pattern
|
|
5
|
+
* @param {any} pathname
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function matchPathnamePattern2(pattern, pathname) {
|
|
9
|
+
const matcher = new URLPattern({
|
|
10
|
+
baseURL: "https://example.com",
|
|
11
|
+
pathname: pattern,
|
|
12
|
+
});
|
|
13
|
+
const match = matcher.exec(new URL(pathname, "https://example.com"));
|
|
14
|
+
if (!match)
|
|
15
|
+
return undefined;
|
|
16
|
+
const params = match.pathname.groups ?? {};
|
|
17
|
+
for (const key in params) {
|
|
18
|
+
if (params[key] === undefined) {
|
|
19
|
+
delete params[key];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { params };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Matches a pathname against a pattern with named parameters, wildcards, and optional segments.
|
|
26
|
+
* Supports path-to-regexp v8 syntax (`/:param`, `/*wildcard`, `/de{/*path}`).
|
|
27
|
+
*
|
|
28
|
+
* @param {string} pattern - The pattern to match.
|
|
29
|
+
* @param {string} pathname - The actual pathname.
|
|
30
|
+
* @returns {object | undefined} - Matched parameters or `undefined` if no match.
|
|
31
|
+
*/
|
|
32
|
+
export function matchPathnamePattern(pattern, pathname) {
|
|
33
|
+
// Ensure pathname doesn't have trailing slashes (unless root `/`)
|
|
34
|
+
if (pathname !== "/" && pathname.endsWith("/")) {
|
|
35
|
+
pathname = pathname.slice(0, -1);
|
|
36
|
+
}
|
|
37
|
+
// Convert `{*param}` to a named capture group `(?<param>.+)`
|
|
38
|
+
let regexPattern = pattern
|
|
39
|
+
.replace(/\{\*([^}]+)\}/g, (_, param) => `(?<${param}>.+)`) // ✅ Wildcards `{*param}`
|
|
40
|
+
.replace(/\{\/\*([^}]+)\}/g, (_, param) => `(?:/(?<${param}>.*?))?`) // ✅ Optional wildcards `{/*param}`
|
|
41
|
+
.replace(/\{\/:([^}]+)\}/g, (_, param) => `(?:/(?<${param}>[^/]+))?`) // ✅ Optional parameters `{/:param}`
|
|
42
|
+
.replace(/\/:([^/]+)/g, (_, param) => `/(?<${param}>[^/]+)`) // ✅ Named parameters
|
|
43
|
+
.replace(/\*([^/]+)/g, (_, param) => `(?<${param}>.+)`); // ✅ Normal wildcards `*param`
|
|
44
|
+
// Create a RegExp object from the modified pattern
|
|
45
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
46
|
+
// Attempt to match the pathname
|
|
47
|
+
const match = pathname.match(regex);
|
|
48
|
+
if (!match)
|
|
49
|
+
return undefined;
|
|
50
|
+
// Extract named parameters
|
|
51
|
+
/** @type {Record<string, string | string[]>} */
|
|
52
|
+
const params = match.groups ? { ...match.groups } : {};
|
|
53
|
+
for (const key in params) {
|
|
54
|
+
// ✅ Convert wildcard (`*param`) values to arrays to match `path-to-regexp` behavior
|
|
55
|
+
if (pattern.includes(`*${key}`) && typeof params[key] === "string") {
|
|
56
|
+
params[key] = params[key] ? params[key].split("/") : [];
|
|
57
|
+
}
|
|
58
|
+
// ✅ Remove undefined params (optional parameters)
|
|
59
|
+
else if (params[key] === undefined) {
|
|
60
|
+
delete params[key];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return { params };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generates a pathname from a pattern and parameters.
|
|
67
|
+
* Supports named parameters (`:param`), optional segments (`{}`), and wildcards (`*param`).
|
|
68
|
+
*
|
|
69
|
+
* @param {string} pattern - The pattern to generate the path from.
|
|
70
|
+
* @param {Record<string, string | string[]>} params - Parameters to replace in the pattern.
|
|
71
|
+
* @returns {string} - The generated pathname.
|
|
72
|
+
*/
|
|
73
|
+
export function compilePathnamePattern(pattern, params) {
|
|
74
|
+
return (pattern
|
|
75
|
+
// Replace optional segments `{/:param}`
|
|
76
|
+
.replace(/\{(\/:[^}]+)\}/g, (_, segment) => {
|
|
77
|
+
const paramKey = segment.slice(2); // Extract `param` from `/:param`
|
|
78
|
+
return params[paramKey] ? `/${params[paramKey]}` : "";
|
|
79
|
+
})
|
|
80
|
+
// Replace named parameters `/:param`
|
|
81
|
+
.replace(/\/:([^/]+)/g, (_, paramKey) => {
|
|
82
|
+
if (params[paramKey] === undefined) {
|
|
83
|
+
throw new Error(`Missing value for parameter ":${paramKey}"`);
|
|
84
|
+
}
|
|
85
|
+
return `/${params[paramKey]}`;
|
|
86
|
+
})
|
|
87
|
+
// Replace wildcards `/*param`
|
|
88
|
+
.replace(/\*([^/]+)/g, (_, paramKey) => {
|
|
89
|
+
if (!Array.isArray(params[paramKey])) {
|
|
90
|
+
throw new Error(`Wildcard parameter "*${paramKey}" must be an array`);
|
|
91
|
+
}
|
|
92
|
+
return params[paramKey].length > 0
|
|
93
|
+
? `/${params[paramKey].join("/")}`
|
|
94
|
+
: "";
|
|
95
|
+
})
|
|
96
|
+
// Ensure the resulting path is correctly formatted
|
|
97
|
+
.replace(/\/+/g, "/") // Prevent double slashes
|
|
98
|
+
.replace(/\/$/, "")); // Remove trailing slash unless it's the root `/`
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathname-pattern.test.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/pathname-pattern.test.ts"],"names":[],"mappings":""}
|