@inlang/paraglide-js 2.0.12 → 2.1.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/dist/cli/steps/initialize-inlang-project.d.ts.map +1 -1
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/compiler/compile-bundle.d.ts +2 -1
- package/dist/compiler/compile-bundle.d.ts.map +1 -1
- package/dist/compiler/compile-bundle.js +4 -3
- package/dist/compiler/compile-bundle.test.js +64 -0
- package/dist/compiler/compile-message.d.ts.map +1 -1
- package/dist/compiler/compile-pattern.d.ts.map +1 -1
- package/dist/compiler/compile-project.d.ts.map +1 -1
- package/dist/compiler/compile-project.js +1 -0
- package/dist/compiler/compiler-options.d.ts +2 -0
- package/dist/compiler/compiler-options.d.ts.map +1 -1
- package/dist/compiler/runtime/create-runtime.d.ts.map +1 -1
- package/dist/compiler/runtime/create-runtime.js +6 -0
- package/dist/compiler/runtime/extract-locale-from-cookie.d.ts +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.d.ts +2 -0
- package/dist/compiler/runtime/extract-locale-from-header.d.ts.map +1 -0
- package/dist/compiler/runtime/extract-locale-from-header.js +43 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.d.ts +2 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.d.ts.map +1 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.js +51 -0
- package/dist/compiler/runtime/extract-locale-from-navigator.d.ts +2 -0
- package/dist/compiler/runtime/extract-locale-from-navigator.d.ts.map +1 -0
- package/dist/compiler/runtime/extract-locale-from-navigator.js +31 -0
- package/dist/compiler/runtime/extract-locale-from-navigator.test.d.ts +2 -0
- package/dist/compiler/runtime/extract-locale-from-navigator.test.d.ts.map +1 -0
- package/dist/compiler/runtime/extract-locale-from-navigator.test.js +29 -0
- package/dist/compiler/runtime/extract-locale-from-request.d.ts.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-request.js +8 -36
- package/dist/compiler/runtime/extract-locale-from-request.test.js +83 -2
- package/dist/compiler/runtime/extract-locale-from-url.d.ts.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-url.js +35 -13
- package/dist/compiler/runtime/get-locale.d.ts.map +1 -1
- package/dist/compiler/runtime/get-locale.js +8 -26
- package/dist/compiler/runtime/get-locale.test.js +153 -0
- package/dist/compiler/runtime/localize-href.d.ts.map +1 -1
- package/dist/compiler/runtime/localize-href.js +7 -4
- package/dist/compiler/runtime/set-locale.d.ts.map +1 -1
- package/dist/compiler/runtime/set-locale.js +6 -1
- package/dist/compiler/runtime/set-locale.test.js +140 -0
- package/dist/compiler/runtime/strategy.d.ts +60 -0
- package/dist/compiler/runtime/strategy.d.ts.map +1 -0
- package/dist/compiler/runtime/strategy.js +62 -0
- package/dist/compiler/runtime/strategy.test.d.ts +2 -0
- package/dist/compiler/runtime/strategy.test.d.ts.map +1 -0
- package/dist/compiler/runtime/strategy.test.js +94 -0
- package/dist/compiler/runtime/type.d.ts +4 -0
- package/dist/compiler/runtime/type.d.ts.map +1 -1
- package/dist/compiler/runtime/variables.d.ts +2 -2
- package/dist/compiler/runtime/variables.d.ts.map +1 -1
- package/dist/compiler/runtime/variables.js +1 -1
- package/dist/compiler/server/middleware.d.ts +4 -2
- package/dist/compiler/server/middleware.d.ts.map +1 -1
- package/dist/compiler/server/middleware.js +17 -3
- package/dist/compiler/server/middleware.test.js +151 -0
- package/dist/services/codegen/quotes.d.ts.map +1 -1
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/telemetry/capture.d.ts.map +1 -1
- package/dist/utilities/detect-json-formatting.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach } from "vitest";
|
|
2
|
+
import { newProject } from "@inlang/sdk";
|
|
3
|
+
import { defineCustomServerStrategy, defineCustomClientStrategy, isCustomStrategy, } from "./strategy.js";
|
|
4
|
+
import { createParaglide } from "../create-paraglide.js";
|
|
5
|
+
describe("isCustomStrategy", () => {
|
|
6
|
+
test("returns true for valid custom strategy patterns", () => {
|
|
7
|
+
expect(isCustomStrategy("custom-header")).toBe(true);
|
|
8
|
+
expect(isCustomStrategy("custom-auth123")).toBe(true);
|
|
9
|
+
expect(isCustomStrategy("custom-API")).toBe(true);
|
|
10
|
+
expect(isCustomStrategy("custom-sessionStorage")).toBe(true);
|
|
11
|
+
expect(isCustomStrategy("custom-oAuth2")).toBe(true);
|
|
12
|
+
expect(isCustomStrategy("custom-a")).toBe(true);
|
|
13
|
+
expect(isCustomStrategy("custom-1")).toBe(true);
|
|
14
|
+
expect(isCustomStrategy("custom-Z")).toBe(true);
|
|
15
|
+
expect(isCustomStrategy("custom-9")).toBe(true);
|
|
16
|
+
expect(isCustomStrategy("custom-aZ19")).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
test("returns false for invalid custom strategy patterns", () => {
|
|
19
|
+
expect(isCustomStrategy("")).toBe(false);
|
|
20
|
+
expect(isCustomStrategy("custom_")).toBe(false);
|
|
21
|
+
expect(isCustomStrategy("custom-")).toBe(false);
|
|
22
|
+
expect(isCustomStrategy("header")).toBe(false);
|
|
23
|
+
expect(isCustomStrategy("custom")).toBe(false);
|
|
24
|
+
expect(isCustomStrategy("custom-invalid-name")).toBe(false);
|
|
25
|
+
expect(isCustomStrategy("custom-invalid_name")).toBe(false);
|
|
26
|
+
expect(isCustomStrategy("custom-invalid name")).toBe(false);
|
|
27
|
+
expect(isCustomStrategy("custom-invalid@")).toBe(false);
|
|
28
|
+
expect(isCustomStrategy("Custom-header")).toBe(false);
|
|
29
|
+
expect(isCustomStrategy("CUSTOM-header")).toBe(false);
|
|
30
|
+
expect(isCustomStrategy(null)).toBe(false);
|
|
31
|
+
expect(isCustomStrategy(undefined)).toBe(false);
|
|
32
|
+
expect(isCustomStrategy(123)).toBe(false);
|
|
33
|
+
expect(isCustomStrategy({})).toBe(false);
|
|
34
|
+
expect(isCustomStrategy([])).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
test("returns false for built-in strategy names", () => {
|
|
37
|
+
expect(isCustomStrategy("cookie")).toBe(false);
|
|
38
|
+
expect(isCustomStrategy("baseLocale")).toBe(false);
|
|
39
|
+
expect(isCustomStrategy("globalVariable")).toBe(false);
|
|
40
|
+
expect(isCustomStrategy("url")).toBe(false);
|
|
41
|
+
expect(isCustomStrategy("preferredLanguage")).toBe(false);
|
|
42
|
+
expect(isCustomStrategy("localStorage")).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe.each([
|
|
46
|
+
["defineCustomServerStrategy", defineCustomServerStrategy],
|
|
47
|
+
["defineCustomClientStrategy", defineCustomClientStrategy],
|
|
48
|
+
])("%s", (strategyName, defineStrategy) => {
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
// Reset global variables before each test
|
|
51
|
+
if (typeof globalThis !== "undefined") {
|
|
52
|
+
// @ts-expect-error - Testing environment cleanup
|
|
53
|
+
delete globalThis.document;
|
|
54
|
+
// @ts-expect-error - Testing environment cleanup
|
|
55
|
+
delete globalThis.window;
|
|
56
|
+
// @ts-expect-error - Testing environment cleanup
|
|
57
|
+
delete globalThis.localStorage;
|
|
58
|
+
// @ts-expect-error - Testing environment cleanup
|
|
59
|
+
delete globalThis.navigator;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const defaultHandler = { getLocale: () => "en", setLocale: () => { } };
|
|
63
|
+
const invalidInputs = [
|
|
64
|
+
["", "empty name"],
|
|
65
|
+
["invalid-name", "names with hyphens"],
|
|
66
|
+
["invalid_name", "names with underscores"],
|
|
67
|
+
["@invalid", "names with special characters (@)"],
|
|
68
|
+
["invalid!", "names with special characters (!)"],
|
|
69
|
+
["inva lid", "names with spaces"],
|
|
70
|
+
];
|
|
71
|
+
test.each(invalidInputs)(`${strategyName} throws error for %s (%s)`, (input) => {
|
|
72
|
+
expect(() => defineStrategy(input, defaultHandler)).toThrow(`Invalid custom strategy: "${input}". Must be a custom strategy following the pattern custom-<name> where <name> contains only alphanumeric characters.`);
|
|
73
|
+
});
|
|
74
|
+
test(`${strategyName} should compile with custom strategies in strategy array`, async () => {
|
|
75
|
+
// Test that compile accepts custom strategies
|
|
76
|
+
const runtime = await createParaglide({
|
|
77
|
+
blob: await newProject({
|
|
78
|
+
settings: {
|
|
79
|
+
baseLocale: "en",
|
|
80
|
+
locales: ["en", "de", "fr"],
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
strategy: ["custom-auth", "custom-header", "cookie", "baseLocale"],
|
|
84
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
85
|
+
});
|
|
86
|
+
// Verify the runtime contains the strategy array
|
|
87
|
+
expect(runtime.strategy).toEqual([
|
|
88
|
+
"custom-auth",
|
|
89
|
+
"custom-header",
|
|
90
|
+
"cookie",
|
|
91
|
+
"baseLocale",
|
|
92
|
+
]);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -28,7 +28,11 @@ export type Runtime = {
|
|
|
28
28
|
extractLocaleFromUrl: typeof import("./extract-locale-from-url.js").extractLocaleFromUrl;
|
|
29
29
|
extractLocaleFromRequest: typeof import("./extract-locale-from-request.js").extractLocaleFromRequest;
|
|
30
30
|
extractLocaleFromCookie: typeof import("./extract-locale-from-cookie.js").extractLocaleFromCookie;
|
|
31
|
+
extractLocaleFromHeader: typeof import("./extract-locale-from-header.js").extractLocaleFromHeader;
|
|
32
|
+
extractLocaleFromNavigator: typeof import("./extract-locale-from-navigator.js").extractLocaleFromNavigator;
|
|
31
33
|
generateStaticLocalizedUrls: typeof import("./generate-static-localized-urls.js").generateStaticLocalizedUrls;
|
|
32
34
|
trackMessageCall: typeof import("./track-message-call.js").trackMessageCall;
|
|
35
|
+
defineCustomServerStrategy: typeof import("./strategy.js").defineCustomServerStrategy;
|
|
36
|
+
defineCustomClientStrategy: typeof import("./strategy.js").defineCustomClientStrategy;
|
|
33
37
|
};
|
|
34
38
|
//# sourceMappingURL=type.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/type.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACrB,UAAU,EAAE,cAAc,gBAAgB,EAAE,UAAU,CAAC;IACvD,OAAO,EAAE,cAAc,gBAAgB,EAAE,OAAO,CAAC;IACjD,QAAQ,EAAE,cAAc,gBAAgB,EAAE,QAAQ,CAAC;IACnD,UAAU,EAAE,cAAc,gBAAgB,EAAE,UAAU,CAAC;IACvD,YAAY,EAAE,cAAc,gBAAgB,EAAE,YAAY,CAAC;IAC3D,WAAW,EAAE,cAAc,gBAAgB,EAAE,WAAW,CAAC;IACzD,wBAAwB,EAAE,cAAc,gBAAgB,EAAE,wBAAwB,CAAC;IACnF,uBAAuB,EAAE,cAAc,gBAAgB,EAAE,uBAAuB,CAAC;IACjF,qCAAqC,EAAE,cAAc,gBAAgB,EAAE,qCAAqC,CAAC;IAC7G,QAAQ,EAAE,cAAc,gBAAgB,EAAE,QAAQ,CAAC;IACnD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAC;IACtD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAC;IACtD,YAAY,EAAE,cAAc,qBAAqB,EAAE,YAAY,CAAC;IAChE,kBAAkB,EAAE,cAAc,iBAAiB,EAAE,kBAAkB,CAAC;IACxE,kBAAkB,EAAE,cAAc,iBAAiB,EAAE,kBAAkB,CAAC;IACxE,qBAAqB,EAAE,cAAc,qBAAqB,EAAE,qBAAqB,CAAC;IAClF,gCAAgC,EAAE,cAAc,gBAAgB,EAAE,gCAAgC,CAAC;IACnG,cAAc,EAAE,cAAc,uBAAuB,EAAE,cAAc,CAAC;IACtE,QAAQ,EAAE,cAAc,gBAAgB,EAAE,QAAQ,CAAC;IACnD,YAAY,EAAE,cAAc,oBAAoB,EAAE,YAAY,CAAC;IAC/D,cAAc,EAAE,cAAc,oBAAoB,EAAE,cAAc,CAAC;IACnE,WAAW,EAAE,cAAc,mBAAmB,EAAE,WAAW,CAAC;IAC5D,aAAa,EAAE,cAAc,mBAAmB,EAAE,aAAa,CAAC;IAChE,oBAAoB,EAAE,cAAc,8BAA8B,EAAE,oBAAoB,CAAC;IACzF,wBAAwB,EAAE,cAAc,kCAAkC,EAAE,wBAAwB,CAAC;IACrG,uBAAuB,EAAE,cAAc,iCAAiC,EAAE,uBAAuB,CAAC;IAClG,2BAA2B,EAAE,cAAc,qCAAqC,EAAE,2BAA2B,CAAC;IAC9G,gBAAgB,EAAE,cAAc,yBAAyB,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/type.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACrB,UAAU,EAAE,cAAc,gBAAgB,EAAE,UAAU,CAAC;IACvD,OAAO,EAAE,cAAc,gBAAgB,EAAE,OAAO,CAAC;IACjD,QAAQ,EAAE,cAAc,gBAAgB,EAAE,QAAQ,CAAC;IACnD,UAAU,EAAE,cAAc,gBAAgB,EAAE,UAAU,CAAC;IACvD,YAAY,EAAE,cAAc,gBAAgB,EAAE,YAAY,CAAC;IAC3D,WAAW,EAAE,cAAc,gBAAgB,EAAE,WAAW,CAAC;IACzD,wBAAwB,EAAE,cAAc,gBAAgB,EAAE,wBAAwB,CAAC;IACnF,uBAAuB,EAAE,cAAc,gBAAgB,EAAE,uBAAuB,CAAC;IACjF,qCAAqC,EAAE,cAAc,gBAAgB,EAAE,qCAAqC,CAAC;IAC7G,QAAQ,EAAE,cAAc,gBAAgB,EAAE,QAAQ,CAAC;IACnD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAC;IACtD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAC;IACtD,YAAY,EAAE,cAAc,qBAAqB,EAAE,YAAY,CAAC;IAChE,kBAAkB,EAAE,cAAc,iBAAiB,EAAE,kBAAkB,CAAC;IACxE,kBAAkB,EAAE,cAAc,iBAAiB,EAAE,kBAAkB,CAAC;IACxE,qBAAqB,EAAE,cAAc,qBAAqB,EAAE,qBAAqB,CAAC;IAClF,gCAAgC,EAAE,cAAc,gBAAgB,EAAE,gCAAgC,CAAC;IACnG,cAAc,EAAE,cAAc,uBAAuB,EAAE,cAAc,CAAC;IACtE,QAAQ,EAAE,cAAc,gBAAgB,EAAE,QAAQ,CAAC;IACnD,YAAY,EAAE,cAAc,oBAAoB,EAAE,YAAY,CAAC;IAC/D,cAAc,EAAE,cAAc,oBAAoB,EAAE,cAAc,CAAC;IACnE,WAAW,EAAE,cAAc,mBAAmB,EAAE,WAAW,CAAC;IAC5D,aAAa,EAAE,cAAc,mBAAmB,EAAE,aAAa,CAAC;IAChE,oBAAoB,EAAE,cAAc,8BAA8B,EAAE,oBAAoB,CAAC;IACzF,wBAAwB,EAAE,cAAc,kCAAkC,EAAE,wBAAwB,CAAC;IACrG,uBAAuB,EAAE,cAAc,iCAAiC,EAAE,uBAAuB,CAAC;IAClG,uBAAuB,EAAE,cAAc,iCAAiC,EAAE,uBAAuB,CAAC;IAClG,0BAA0B,EAAE,cAAc,oCAAoC,EAAE,0BAA0B,CAAC;IAC3G,2BAA2B,EAAE,cAAc,qCAAqC,EAAE,2BAA2B,CAAC;IAC9G,gBAAgB,EAAE,cAAc,yBAAyB,EAAE,gBAAgB,CAAC;IAC5E,0BAA0B,EAAE,cAAc,eAAe,EAAE,0BAA0B,CAAC;IACtF,0BAA0B,EAAE,cAAc,eAAe,EAAE,0BAA0B,CAAC;CACtF,CAAC"}
|
|
@@ -36,9 +36,9 @@ export const cookieDomain: string;
|
|
|
36
36
|
/** @type {string} */
|
|
37
37
|
export const localStorageKey: string;
|
|
38
38
|
/**
|
|
39
|
-
* @type {Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage"
|
|
39
|
+
* @type {Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage" | `custom-${string}`>}
|
|
40
40
|
*/
|
|
41
|
-
export const strategy: Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage"
|
|
41
|
+
export const strategy: Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage" | `custom-${string}`>;
|
|
42
42
|
/**
|
|
43
43
|
* The used URL patterns.
|
|
44
44
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/variables.js"],"names":[],"mappings":"AAwEA;;;;;;;;;GASG;AACH,wDAFW,0BAA0B,GAAG,SAAS,QAIhD;AApFD;;;;;;;GAOG;AACH,yBAA0B,IAAI,CAAC;AAE/B;;;;;;;GAOG;AACH,4CAA2D;AAE3D,qBAAqB;AACrB,yBADW,MAAM,CACyB;AAE1C,qBAAqB;AACrB,2BADW,MAAM,CAC8B;AAE/C,qBAAqB;AACrB,2BADW,MAAM,CAC6B;AAE9C,qBAAqB;AACrB,8BADW,MAAM,CACiC;AAElD;;GAEG;AACH,uBAFU,KAAK,CAAC,QAAQ,GAAG,YAAY,GAAG,gBAAgB,GAAG,KAAK,GAAG,mBAAmB,GAAG,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/variables.js"],"names":[],"mappings":"AAwEA;;;;;;;;;GASG;AACH,wDAFW,0BAA0B,GAAG,SAAS,QAIhD;AApFD;;;;;;;GAOG;AACH,yBAA0B,IAAI,CAAC;AAE/B;;;;;;;GAOG;AACH,4CAA2D;AAE3D,qBAAqB;AACrB,yBADW,MAAM,CACyB;AAE1C,qBAAqB;AACrB,2BADW,MAAM,CAC8B;AAE/C,qBAAqB;AACrB,2BADW,MAAM,CAC6B;AAE9C,qBAAqB;AACrB,8BADW,MAAM,CACiC;AAElD;;GAEG;AACH,uBAFU,KAAK,CAAC,QAAQ,GAAG,YAAY,GAAG,gBAAgB,GAAG,KAAK,GAAG,mBAAmB,GAAG,cAAc,GAAG,UAAU,MAAM,EAAE,CAAC,CAEpF;AAE3C;;;;GAIG;AACH,0BAFU,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CAAC,CAE1C;AAE9B;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,oCAFU,0BAA0B,GAAG,SAAS,CAED;AAE/C,uCAAwC,KAAK,CAAC;AAE9C,oDAAqD,KAAK,CAAC;AAE3D,+BAAsD;AAgBtD,8CAA+C,KAAK,CAAC;AAErD,2CAA4C,KAAK,CAAC;AAElD,uDAAwD,KAAK,CAAC;AAE9D,0DAA2D,KAAK,CAAC;AAEjE,kDAAmD,KAAK,CAAC;AAEzD,qDAAsD,KAAK,CAAC;yCAnD/C;IACR,QAAQ,IAAI;QACV,MAAM,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;KACzB,GAAG,SAAS,CAAC;IACf,GAAG,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;KAAC,EAC3E,EAAE,EAAE,GAAG,KAAK,GAAG,CAAA;CACjB"}
|
|
@@ -25,7 +25,7 @@ export const cookieDomain = "<cookie-domain>";
|
|
|
25
25
|
/** @type {string} */
|
|
26
26
|
export const localStorageKey = "PARAGLIDE_LOCALE";
|
|
27
27
|
/**
|
|
28
|
-
* @type {Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage"
|
|
28
|
+
* @type {Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage" | `custom-${string}`>}
|
|
29
29
|
*/
|
|
30
30
|
export const strategy = ["globalVariable"];
|
|
31
31
|
/**
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @param {Request} request - The incoming request object
|
|
19
19
|
* @param {(args: { request: Request, locale: import("./runtime.js").Locale }) => T | Promise<T>} resolve - Function to handle the request
|
|
20
|
-
*
|
|
20
|
+
* @param {{ onRedirect:(response: Response) => void }} [callbacks] - Callbacks to handle events from middleware
|
|
21
21
|
* @returns {Promise<Response>}
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
@@ -62,5 +62,7 @@
|
|
|
62
62
|
export function paraglideMiddleware<T>(request: Request, resolve: (args: {
|
|
63
63
|
request: Request;
|
|
64
64
|
locale: import("./runtime.js").Locale;
|
|
65
|
-
}) => T | Promise<T
|
|
65
|
+
}) => T | Promise<T>, callbacks?: {
|
|
66
|
+
onRedirect: (response: Response) => void;
|
|
67
|
+
}): Promise<Response>;
|
|
66
68
|
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/compiler/server/middleware.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,oCA9Ca,CAAC,WAEH,OAAO,WACP,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAA;CAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/compiler/server/middleware.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,oCA9Ca,CAAC,WAEH,OAAO,WACP,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAA;CAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,cACrF;IAAE,UAAU,EAAC,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;CAAE,GACzC,OAAO,CAAC,QAAQ,CAAC,CA0I7B"}
|
|
@@ -18,7 +18,7 @@ import * as runtime from "./runtime.js";
|
|
|
18
18
|
*
|
|
19
19
|
* @param {Request} request - The incoming request object
|
|
20
20
|
* @param {(args: { request: Request, locale: import("./runtime.js").Locale }) => T | Promise<T>} resolve - Function to handle the request
|
|
21
|
-
*
|
|
21
|
+
* @param {{ onRedirect:(response: Response) => void }} [callbacks] - Callbacks to handle events from middleware
|
|
22
22
|
* @returns {Promise<Response>}
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
@@ -60,7 +60,7 @@ import * as runtime from "./runtime.js";
|
|
|
60
60
|
* };
|
|
61
61
|
* ```
|
|
62
62
|
*/
|
|
63
|
-
export async function paraglideMiddleware(request, resolve) {
|
|
63
|
+
export async function paraglideMiddleware(request, resolve, callbacks) {
|
|
64
64
|
if (!runtime.disableAsyncLocalStorage && !runtime.serverAsyncLocalStorage) {
|
|
65
65
|
const { AsyncLocalStorage } = await import("async_hooks");
|
|
66
66
|
runtime.overwriteServerAsyncLocalStorage(new AsyncLocalStorage());
|
|
@@ -76,7 +76,21 @@ export async function paraglideMiddleware(request, resolve) {
|
|
|
76
76
|
runtime.strategy.includes("url")) {
|
|
77
77
|
const localizedUrl = runtime.localizeUrl(request.url, { locale });
|
|
78
78
|
if (normalizeURL(localizedUrl.href) !== normalizeURL(request.url)) {
|
|
79
|
-
|
|
79
|
+
// Create headers object with Vary header if preferredLanguage strategy is used
|
|
80
|
+
/** @type {Record<string, string>} */
|
|
81
|
+
const headers = {};
|
|
82
|
+
if (runtime.strategy.includes("preferredLanguage")) {
|
|
83
|
+
headers["Vary"] = "Accept-Language";
|
|
84
|
+
}
|
|
85
|
+
const response = new Response(null, {
|
|
86
|
+
status: 307,
|
|
87
|
+
headers: {
|
|
88
|
+
Location: localizedUrl.href,
|
|
89
|
+
...headers,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
callbacks?.onRedirect(response);
|
|
93
|
+
return response;
|
|
80
94
|
}
|
|
81
95
|
}
|
|
82
96
|
// If the strategy includes "url", we need to de-localize the URL
|
|
@@ -109,6 +109,157 @@ test("redirects to localized URL when non-URL strategy determines locale", async
|
|
|
109
109
|
expect(response.status).toBe(307); // Redirect status code
|
|
110
110
|
expect(response.headers.get("Location")).toBe("https://example.com/fr/some-path");
|
|
111
111
|
});
|
|
112
|
+
test("call onRedirect callback when redirecting to new url", async () => {
|
|
113
|
+
const runtime = await createParaglide({
|
|
114
|
+
blob: await newProject({
|
|
115
|
+
settings: {
|
|
116
|
+
baseLocale: "en",
|
|
117
|
+
locales: ["en", "fr"],
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
strategy: ["cookie", "url"],
|
|
121
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
122
|
+
urlPatterns: [
|
|
123
|
+
{
|
|
124
|
+
pattern: "https://example.com/:path(.*)?",
|
|
125
|
+
localized: [
|
|
126
|
+
["en", "https://example.com/en/:path(.*)?"],
|
|
127
|
+
["fr", "https://example.com/fr/:path(.*)?"],
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
// Request to URL in en with cookie specifying French
|
|
133
|
+
const request = new Request("https://example.com/en/some-path", {
|
|
134
|
+
headers: {
|
|
135
|
+
cookie: `PARAGLIDE_LOCALE=fr`,
|
|
136
|
+
"Sec-Fetch-Dest": "document",
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
let response;
|
|
140
|
+
await runtime.paraglideMiddleware(request, () => {
|
|
141
|
+
// This shouldn't be called since we should redirect
|
|
142
|
+
throw new Error("Should not reach here");
|
|
143
|
+
}, {
|
|
144
|
+
onRedirect: (res) => {
|
|
145
|
+
response = res;
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
expect(response instanceof Response).toBe(true);
|
|
149
|
+
// needs to be 307 status code https://github.com/opral/inlang-paraglide-js/issues/416
|
|
150
|
+
expect(response.status).toBe(307); // Redirect status code
|
|
151
|
+
expect(response.headers.get("Location")).toBe("https://example.com/fr/some-path");
|
|
152
|
+
});
|
|
153
|
+
test("sets Vary: Accept-Language header when preferredLanguage strategy is used and redirect occurs", async () => {
|
|
154
|
+
const runtime = await createParaglide({
|
|
155
|
+
blob: await newProject({
|
|
156
|
+
settings: {
|
|
157
|
+
baseLocale: "en",
|
|
158
|
+
locales: ["en", "fr"],
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
strategy: ["preferredLanguage", "url"],
|
|
162
|
+
urlPatterns: [
|
|
163
|
+
{
|
|
164
|
+
pattern: "https://example.com/:path(.*)?",
|
|
165
|
+
localized: [
|
|
166
|
+
["en", "https://example.com/en/:path(.*)?"],
|
|
167
|
+
["fr", "https://example.com/fr/:path(.*)?"],
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
// Request with Accept-Language header preferring French
|
|
173
|
+
const request = new Request("https://example.com/en/some-path", {
|
|
174
|
+
headers: {
|
|
175
|
+
"Accept-Language": "fr,en;q=0.8",
|
|
176
|
+
"Sec-Fetch-Dest": "document",
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
const response = await runtime.paraglideMiddleware(request, () => {
|
|
180
|
+
// This shouldn't be called since we should redirect
|
|
181
|
+
throw new Error("Should not reach here");
|
|
182
|
+
});
|
|
183
|
+
expect(response instanceof Response).toBe(true);
|
|
184
|
+
expect(response.status).toBe(307); // Redirect status code
|
|
185
|
+
expect(response.headers.get("Location")).toBe("https://example.com/fr/some-path");
|
|
186
|
+
// Should have Vary header when preferredLanguage strategy is used
|
|
187
|
+
expect(response.headers.get("Vary")).toBe("Accept-Language");
|
|
188
|
+
});
|
|
189
|
+
test("does not set Vary header when preferredLanguage strategy is not used", async () => {
|
|
190
|
+
const runtime = await createParaglide({
|
|
191
|
+
blob: await newProject({
|
|
192
|
+
settings: {
|
|
193
|
+
baseLocale: "en",
|
|
194
|
+
locales: ["en", "fr"],
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
197
|
+
strategy: ["cookie", "url"],
|
|
198
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
199
|
+
urlPatterns: [
|
|
200
|
+
{
|
|
201
|
+
pattern: "https://example.com/:path(.*)?",
|
|
202
|
+
localized: [
|
|
203
|
+
["en", "https://example.com/en/:path(.*)?"],
|
|
204
|
+
["fr", "https://example.com/fr/:path(.*)?"],
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
});
|
|
209
|
+
// Request with cookie specifying French
|
|
210
|
+
const request = new Request("https://example.com/en/some-path", {
|
|
211
|
+
headers: {
|
|
212
|
+
cookie: `PARAGLIDE_LOCALE=fr`,
|
|
213
|
+
"Sec-Fetch-Dest": "document",
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
const response = await runtime.paraglideMiddleware(request, () => {
|
|
217
|
+
// This shouldn't be called since we should redirect
|
|
218
|
+
throw new Error("Should not reach here");
|
|
219
|
+
});
|
|
220
|
+
expect(response instanceof Response).toBe(true);
|
|
221
|
+
expect(response.status).toBe(307); // Redirect status code
|
|
222
|
+
expect(response.headers.get("Location")).toBe("https://example.com/fr/some-path");
|
|
223
|
+
// Should NOT have Vary header when preferredLanguage strategy is not used
|
|
224
|
+
expect(response.headers.get("Vary")).toBe(null);
|
|
225
|
+
});
|
|
226
|
+
test("does not call onRedirect callback when there is no redirecting", async () => {
|
|
227
|
+
const runtime = await createParaglide({
|
|
228
|
+
blob: await newProject({
|
|
229
|
+
settings: {
|
|
230
|
+
baseLocale: "en",
|
|
231
|
+
locales: ["en", "fr"],
|
|
232
|
+
},
|
|
233
|
+
}),
|
|
234
|
+
strategy: ["cookie", "url"],
|
|
235
|
+
cookieName: "PARAGLIDE_LOCALE",
|
|
236
|
+
urlPatterns: [
|
|
237
|
+
{
|
|
238
|
+
pattern: "https://example.com/:path(.*)?",
|
|
239
|
+
localized: [
|
|
240
|
+
["en", "https://example.com/en/:path(.*)?"],
|
|
241
|
+
["fr", "https://example.com/fr/:path(.*)?"],
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
});
|
|
246
|
+
// Request to URL in en with cookie specifying French
|
|
247
|
+
const request = new Request("https://example.com/fr/some-path", {
|
|
248
|
+
headers: {
|
|
249
|
+
cookie: `PARAGLIDE_LOCALE=fr`,
|
|
250
|
+
"Sec-Fetch-Dest": "document",
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
let response = null;
|
|
254
|
+
await runtime.paraglideMiddleware(request, () => {
|
|
255
|
+
return new Response("Hello World");
|
|
256
|
+
}, {
|
|
257
|
+
onRedirect: (res) => {
|
|
258
|
+
response = res;
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
expect(response).toBe(null);
|
|
262
|
+
});
|
|
112
263
|
test("does not redirect if URL already matches determined locale", async () => {
|
|
113
264
|
const runtime = await createParaglide({
|
|
114
265
|
blob: await newProject({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../../../src/services/codegen/quotes.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../../../src/services/codegen/quotes.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,WAAoC,CAAC;AAC5E,yCAAyC;AACzC,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,WAAiB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../../src/services/telemetry/capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD;;;;GAIG;AACH,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../../src/services/telemetry/capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD;;;;GAIG;AACH,eAAO,MAAM,OAAO,GACnB,OAAO,+BAA+B,EACtC,MAAM;IACL,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;CAC7C,kBA8BD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-json-formatting.d.ts","sourceRoot":"","sources":["../../src/utilities/detect-json-formatting.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"detect-json-formatting.d.ts","sourceRoot":"","sources":["../../src/utilities/detect-json-formatting.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,MAAM,KACV,CAAC,CACH,KAAK,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAC3C,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAE3C,MAAM,CAOV,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/paraglide-js",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"json5": "2.2.3",
|
|
32
32
|
"unplugin": "^2.1.2",
|
|
33
33
|
"urlpattern-polyfill": "^10.0.0",
|
|
34
|
-
"@inlang/sdk": "2.4.
|
|
34
|
+
"@inlang/sdk": "2.4.9",
|
|
35
35
|
"@inlang/recommend-sherlock": "0.2.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
"memfs": "4.17.0",
|
|
45
45
|
"prettier": "^3.4.2",
|
|
46
46
|
"rolldown": "1.0.0-beta.1",
|
|
47
|
-
"typedoc": "
|
|
48
|
-
"typedoc-plugin-markdown": "^4.
|
|
49
|
-
"typedoc-plugin-missing-exports": "
|
|
47
|
+
"typedoc": "0.28.3",
|
|
48
|
+
"typedoc-plugin-markdown": "^4.6.0",
|
|
49
|
+
"typedoc-plugin-missing-exports": "4.0.0",
|
|
50
50
|
"typescript": "^5.7.3",
|
|
51
51
|
"typescript-eslint": "^8.20.0",
|
|
52
52
|
"vitest": "2.1.8",
|
|
53
|
-
"@inlang/paraglide-js": "2.0
|
|
53
|
+
"@inlang/paraglide-js": "2.1.0",
|
|
54
54
|
"@inlang/plugin-message-format": "4.0.0",
|
|
55
55
|
"@opral/tsconfig": "1.1.0"
|
|
56
56
|
},
|