@prosopo/locale 3.2.9 → 3.3.1
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/.turbo/turbo-build$colon$cjs.log +10 -9
- package/.turbo/turbo-build$colon$tsc.log +5 -5
- package/.turbo/turbo-build.log +17 -16
- package/CHANGELOG.md +29 -0
- package/dist/cjs/i18SharedOptions.cjs +1 -1
- package/dist/cjs/i18nBackend.cjs +4 -1
- package/dist/cjs/i18nFrontend.cjs +4 -1
- package/dist/cjs/loadI18next.cjs +41 -14
- package/dist/cjs/process.cjs +17 -0
- package/dist/cjs/translationKey.cjs +2 -0
- package/dist/i18SharedOptions.js +2 -1
- package/dist/i18SharedOptions.js.map +1 -1
- package/dist/i18nBackend.d.ts.map +1 -1
- package/dist/i18nBackend.js +4 -1
- package/dist/i18nBackend.js.map +1 -1
- package/dist/i18nFrontend.d.ts.map +1 -1
- package/dist/i18nFrontend.js +4 -1
- package/dist/i18nFrontend.js.map +1 -1
- package/dist/loadI18next.d.ts +1 -0
- package/dist/loadI18next.d.ts.map +1 -1
- package/dist/loadI18next.js +41 -15
- package/dist/loadI18next.js.map +1 -1
- package/dist/process.d.ts +2 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +17 -0
- package/dist/process.js.map +1 -0
- package/dist/tests/i18SharedOptions.unit.test.d.ts +2 -0
- package/dist/tests/i18SharedOptions.unit.test.d.ts.map +1 -0
- package/dist/tests/i18SharedOptions.unit.test.js +91 -0
- package/dist/tests/i18SharedOptions.unit.test.js.map +1 -0
- package/dist/tests/i18nBackend.unit.test.d.ts +2 -0
- package/dist/tests/i18nBackend.unit.test.d.ts.map +1 -0
- package/dist/tests/i18nBackend.unit.test.js +153 -0
- package/dist/tests/i18nBackend.unit.test.js.map +1 -0
- package/dist/tests/i18nFrontend.unit.test.d.ts +2 -0
- package/dist/tests/i18nFrontend.unit.test.d.ts.map +1 -0
- package/dist/tests/i18nFrontend.unit.test.js +199 -0
- package/dist/tests/i18nFrontend.unit.test.js.map +1 -0
- package/dist/tests/i18nMiddleware.unit.test.d.ts +2 -0
- package/dist/tests/i18nMiddleware.unit.test.d.ts.map +1 -0
- package/dist/tests/i18nMiddleware.unit.test.js +80 -0
- package/dist/tests/i18nMiddleware.unit.test.js.map +1 -0
- package/dist/tests/loadI18next.unit.test.d.ts +2 -0
- package/dist/tests/loadI18next.unit.test.d.ts.map +1 -0
- package/dist/tests/loadI18next.unit.test.js +270 -0
- package/dist/tests/loadI18next.unit.test.js.map +1 -0
- package/dist/tests/locale.test-d.d.ts +2 -0
- package/dist/tests/locale.test-d.d.ts.map +1 -0
- package/dist/tests/locale.test-d.js +88 -0
- package/dist/tests/locale.test-d.js.map +1 -0
- package/dist/tests/process.unit.test.d.ts +2 -0
- package/dist/tests/process.unit.test.d.ts.map +1 -0
- package/dist/tests/process.unit.test.js +14 -0
- package/dist/tests/process.unit.test.js.map +1 -0
- package/dist/tests/translationKey.unit.test.d.ts +2 -0
- package/dist/tests/translationKey.unit.test.d.ts.map +1 -0
- package/dist/tests/translationKey.unit.test.js +108 -0
- package/dist/tests/translationKey.unit.test.js.map +1 -0
- package/dist/tests/translations.unit.test.d.ts +2 -0
- package/dist/tests/translations.unit.test.d.ts.map +1 -0
- package/dist/tests/translations.unit.test.js +74 -0
- package/dist/tests/translations.unit.test.js.map +1 -0
- package/dist/tests/useTranslation.unit.test.d.ts +2 -0
- package/dist/tests/useTranslation.unit.test.d.ts.map +1 -0
- package/dist/tests/useTranslation.unit.test.js +81 -0
- package/dist/tests/useTranslation.unit.test.js.map +1 -0
- package/dist/tests/util.unit.test.d.ts +2 -0
- package/dist/tests/util.unit.test.d.ts.map +1 -0
- package/dist/tests/util.unit.test.js +66 -0
- package/dist/tests/util.unit.test.js.map +1 -0
- package/dist/translationKey.d.ts +4 -0
- package/dist/translationKey.d.ts.map +1 -1
- package/dist/translationKey.js +2 -1
- package/dist/translationKey.js.map +1 -1
- package/package.json +6 -6
- package/src/i18SharedOptions.ts +4 -4
- package/src/i18nBackend.ts +16 -0
- package/src/i18nFrontend.ts +16 -0
- package/src/loadI18next.ts +83 -15
- package/src/process.ts +29 -0
- package/src/tests/i18SharedOptions.unit.test.ts +139 -0
- package/src/tests/i18nBackend.unit.test.ts +241 -0
- package/src/tests/i18nFrontend.unit.test.ts +302 -0
- package/src/tests/i18nMiddleware.unit.test.ts +140 -0
- package/src/tests/loadI18next.unit.test.ts +443 -0
- package/src/tests/locale.test-d.ts +156 -0
- package/src/tests/process.unit.test.ts +33 -0
- package/src/tests/translationKey.unit.test.ts +166 -0
- package/src/tests/translations.unit.test.ts +110 -0
- package/src/tests/useTranslation.unit.test.ts +134 -0
- package/src/tests/util.unit.test.ts +102 -0
- package/src/translationKey.ts +18 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
const asI18n = (fake) => fake;
|
|
3
|
+
const install = (module, options = {}) => {
|
|
4
|
+
const instance = {
|
|
5
|
+
language: options.language ?? "en",
|
|
6
|
+
changeLanguage: options.changeLanguage ??
|
|
7
|
+
(async (lng) => {
|
|
8
|
+
instance.language = lng;
|
|
9
|
+
return undefined;
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
const initialize = vi.fn((callback) => {
|
|
13
|
+
const fire = options.fire ?? "async";
|
|
14
|
+
if (fire === "sync") {
|
|
15
|
+
callback?.(asI18n(instance));
|
|
16
|
+
}
|
|
17
|
+
else if (fire === "async") {
|
|
18
|
+
queueMicrotask(() => callback?.(asI18n(instance)));
|
|
19
|
+
}
|
|
20
|
+
return asI18n(instance);
|
|
21
|
+
});
|
|
22
|
+
vi.doMock(module, () => ({ default: initialize }));
|
|
23
|
+
return { instance, initialize };
|
|
24
|
+
};
|
|
25
|
+
const loadModule = async () => {
|
|
26
|
+
const imported = await import("../loadI18next.js");
|
|
27
|
+
return imported.default;
|
|
28
|
+
};
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
vi.useRealTimers();
|
|
31
|
+
vi.resetModules();
|
|
32
|
+
vi.doUnmock("../i18nBackend.js");
|
|
33
|
+
vi.doUnmock("../i18nFrontend.js");
|
|
34
|
+
vi.restoreAllMocks();
|
|
35
|
+
});
|
|
36
|
+
describe("loadI18next, backend", () => {
|
|
37
|
+
test("initialises once and resolves with the instance", async () => {
|
|
38
|
+
const { instance, initialize } = install("../i18nBackend.js");
|
|
39
|
+
const loadI18next = await loadModule();
|
|
40
|
+
const resolved = await loadI18next(true);
|
|
41
|
+
expect(initialize).toHaveBeenCalledTimes(1);
|
|
42
|
+
expect(resolved).toBe(asI18n(instance));
|
|
43
|
+
});
|
|
44
|
+
test("resolves from the callback, not from the return value", async () => {
|
|
45
|
+
const { initialize } = install("../i18nBackend.js", { fire: "never" });
|
|
46
|
+
const loadI18next = await loadModule();
|
|
47
|
+
let settled = false;
|
|
48
|
+
void loadI18next(true).then(() => {
|
|
49
|
+
settled = true;
|
|
50
|
+
});
|
|
51
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
52
|
+
expect(initialize).toHaveBeenCalledTimes(1);
|
|
53
|
+
expect(settled).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
test("reuses the singleton on a second call without re-initialising", async () => {
|
|
56
|
+
const { instance, initialize } = install("../i18nBackend.js");
|
|
57
|
+
const loadI18next = await loadModule();
|
|
58
|
+
const first = await loadI18next(true);
|
|
59
|
+
const second = await loadI18next(true);
|
|
60
|
+
expect(initialize).toHaveBeenCalledTimes(1);
|
|
61
|
+
expect(second).toBe(first);
|
|
62
|
+
expect(second).toBe(asI18n(instance));
|
|
63
|
+
});
|
|
64
|
+
test("ignores lng on the backend path — the server detects per request", async () => {
|
|
65
|
+
const { instance, initialize } = install("../i18nBackend.js", {
|
|
66
|
+
language: "en",
|
|
67
|
+
});
|
|
68
|
+
const loadI18next = await loadModule();
|
|
69
|
+
await loadI18next(true, "fr");
|
|
70
|
+
expect(initialize.mock.calls[0]?.[1]).toBeUndefined();
|
|
71
|
+
expect(instance.language).toBe("en");
|
|
72
|
+
});
|
|
73
|
+
test("rejects, rather than hanging, when the module fails to load", async () => {
|
|
74
|
+
vi.doMock("../i18nBackend.js", () => {
|
|
75
|
+
throw new Error("backend module blew up");
|
|
76
|
+
});
|
|
77
|
+
const loadI18next = await loadModule();
|
|
78
|
+
await expect(loadI18next(true)).rejects.toThrow();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe("loadI18next, frontend", () => {
|
|
82
|
+
test("initialises once and resolves with the instance", async () => {
|
|
83
|
+
const { instance, initialize } = install("../i18nFrontend.js");
|
|
84
|
+
const loadI18next = await loadModule();
|
|
85
|
+
const resolved = await loadI18next(false);
|
|
86
|
+
expect(initialize).toHaveBeenCalledTimes(1);
|
|
87
|
+
expect(resolved).toBe(asI18n(instance));
|
|
88
|
+
});
|
|
89
|
+
test("passes lng straight into init so browser detection is skipped", async () => {
|
|
90
|
+
const { initialize } = install("../i18nFrontend.js", { language: "fr" });
|
|
91
|
+
const loadI18next = await loadModule();
|
|
92
|
+
await loadI18next(false, "fr");
|
|
93
|
+
expect(initialize.mock.calls[0]?.[1]).toBe("fr");
|
|
94
|
+
});
|
|
95
|
+
test("does not call changeLanguage when init already produced the target", async () => {
|
|
96
|
+
const changeLanguage = vi.fn(async () => undefined);
|
|
97
|
+
install("../i18nFrontend.js", { language: "fr", changeLanguage });
|
|
98
|
+
const loadI18next = await loadModule();
|
|
99
|
+
await loadI18next(false, "fr");
|
|
100
|
+
expect(changeLanguage).not.toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
test("does not call changeLanguage when no language was requested", async () => {
|
|
103
|
+
const changeLanguage = vi.fn(async () => undefined);
|
|
104
|
+
install("../i18nFrontend.js", { language: "de", changeLanguage });
|
|
105
|
+
const loadI18next = await loadModule();
|
|
106
|
+
await loadI18next(false);
|
|
107
|
+
expect(changeLanguage).not.toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
test("reconciles when init settled on a different language", async () => {
|
|
110
|
+
const changeLanguage = vi.fn(async () => undefined);
|
|
111
|
+
install("../i18nFrontend.js", { language: "en", changeLanguage });
|
|
112
|
+
const loadI18next = await loadModule();
|
|
113
|
+
await loadI18next(false, "fr");
|
|
114
|
+
expect(changeLanguage).toHaveBeenCalledWith("fr");
|
|
115
|
+
});
|
|
116
|
+
test("reconciles a pre-existing singleton before resolving", async () => {
|
|
117
|
+
const { instance, initialize } = install("../i18nFrontend.js", {
|
|
118
|
+
language: "en",
|
|
119
|
+
});
|
|
120
|
+
const loadI18next = await loadModule();
|
|
121
|
+
await loadI18next(false);
|
|
122
|
+
const second = await loadI18next(false, "fr");
|
|
123
|
+
expect(initialize).toHaveBeenCalledTimes(1);
|
|
124
|
+
expect(instance.language).toBe("fr");
|
|
125
|
+
expect(second).toBe(asI18n(instance));
|
|
126
|
+
});
|
|
127
|
+
test("resolves the cached singleton unchanged when lng is omitted", async () => {
|
|
128
|
+
const changeLanguage = vi.fn(async () => undefined);
|
|
129
|
+
install("../i18nFrontend.js", { language: "de", changeLanguage });
|
|
130
|
+
const loadI18next = await loadModule();
|
|
131
|
+
await loadI18next(false);
|
|
132
|
+
await loadI18next(false);
|
|
133
|
+
expect(changeLanguage).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
test("rejects, rather than hanging, when the module fails to load", async () => {
|
|
136
|
+
vi.doMock("../i18nFrontend.js", () => {
|
|
137
|
+
throw new Error("frontend module blew up");
|
|
138
|
+
});
|
|
139
|
+
const loadI18next = await loadModule();
|
|
140
|
+
await expect(loadI18next(false)).rejects.toThrow();
|
|
141
|
+
});
|
|
142
|
+
test("rejects when changeLanguage fails during first-load reconciliation", async () => {
|
|
143
|
+
install("../i18nFrontend.js", {
|
|
144
|
+
language: "en",
|
|
145
|
+
changeLanguage: async () => {
|
|
146
|
+
throw new Error("resource fetch failed");
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
const loadI18next = await loadModule();
|
|
150
|
+
await expect(loadI18next(false, "fr")).rejects.toThrow("resource fetch failed");
|
|
151
|
+
});
|
|
152
|
+
test("rejects when changeLanguage fails while reconciling the singleton", async () => {
|
|
153
|
+
let failing = false;
|
|
154
|
+
install("../i18nFrontend.js", {
|
|
155
|
+
language: "en",
|
|
156
|
+
changeLanguage: async () => {
|
|
157
|
+
if (failing) {
|
|
158
|
+
throw new Error("resource fetch failed");
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
const loadI18next = await loadModule();
|
|
164
|
+
await loadI18next(false);
|
|
165
|
+
failing = true;
|
|
166
|
+
await expect(loadI18next(false, "fr")).rejects.toThrow("resource fetch failed");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe("loadI18next, timeout", () => {
|
|
170
|
+
test("resolves with the degraded instance when `loaded` never fires", async () => {
|
|
171
|
+
vi.useFakeTimers();
|
|
172
|
+
const { instance } = install("../i18nBackend.js", { fire: "never" });
|
|
173
|
+
const loadI18next = await loadModule();
|
|
174
|
+
const { I18N_LOAD_TIMEOUT_MS } = await import("../loadI18next.js");
|
|
175
|
+
const pending = loadI18next(true);
|
|
176
|
+
await vi.advanceTimersByTimeAsync(I18N_LOAD_TIMEOUT_MS);
|
|
177
|
+
await expect(pending).resolves.toBe(asI18n(instance));
|
|
178
|
+
});
|
|
179
|
+
test("does not fire early — the instance is not handed back before the deadline", async () => {
|
|
180
|
+
vi.useFakeTimers();
|
|
181
|
+
install("../i18nBackend.js", { fire: "never" });
|
|
182
|
+
const loadI18next = await loadModule();
|
|
183
|
+
const { I18N_LOAD_TIMEOUT_MS } = await import("../loadI18next.js");
|
|
184
|
+
let settled = false;
|
|
185
|
+
void loadI18next(true).then(() => {
|
|
186
|
+
settled = true;
|
|
187
|
+
});
|
|
188
|
+
await vi.advanceTimersByTimeAsync(I18N_LOAD_TIMEOUT_MS - 1);
|
|
189
|
+
expect(settled).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
test("rejects on timeout when no instance was ever created", async () => {
|
|
192
|
+
vi.useFakeTimers();
|
|
193
|
+
vi.doMock("../i18nBackend.js", () => new Promise(() => undefined));
|
|
194
|
+
const loadI18next = await loadModule();
|
|
195
|
+
const { I18N_LOAD_TIMEOUT_MS } = await import("../loadI18next.js");
|
|
196
|
+
const assertion = expect(loadI18next(true)).rejects.toThrow(/did not load within/);
|
|
197
|
+
await vi.advanceTimersByTimeAsync(I18N_LOAD_TIMEOUT_MS);
|
|
198
|
+
await assertion;
|
|
199
|
+
});
|
|
200
|
+
test("a normal load clears the timer, so a late event cannot re-settle it", async () => {
|
|
201
|
+
vi.useFakeTimers();
|
|
202
|
+
let fire;
|
|
203
|
+
const instance = {
|
|
204
|
+
language: "en",
|
|
205
|
+
changeLanguage: async () => undefined,
|
|
206
|
+
};
|
|
207
|
+
const initialize = vi.fn((callback) => {
|
|
208
|
+
fire = callback;
|
|
209
|
+
return asI18n(instance);
|
|
210
|
+
});
|
|
211
|
+
vi.doMock("../i18nBackend.js", () => ({ default: initialize }));
|
|
212
|
+
const loadI18next = await loadModule();
|
|
213
|
+
const { I18N_LOAD_TIMEOUT_MS } = await import("../loadI18next.js");
|
|
214
|
+
const pending = loadI18next(true);
|
|
215
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
216
|
+
fire?.(asI18n(instance));
|
|
217
|
+
await expect(pending).resolves.toBe(asI18n(instance));
|
|
218
|
+
fire?.(asI18n(instance));
|
|
219
|
+
await vi.advanceTimersByTimeAsync(I18N_LOAD_TIMEOUT_MS * 2);
|
|
220
|
+
await expect(pending).resolves.toBe(asI18n(instance));
|
|
221
|
+
});
|
|
222
|
+
test("a failure arriving after the timeout cannot turn a resolved promise into a rejection", async () => {
|
|
223
|
+
vi.useFakeTimers();
|
|
224
|
+
let fire;
|
|
225
|
+
const instance = {
|
|
226
|
+
language: "en",
|
|
227
|
+
changeLanguage: async () => {
|
|
228
|
+
throw new Error("resource fetch failed");
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
const initialize = vi.fn((callback) => {
|
|
232
|
+
fire = callback;
|
|
233
|
+
return asI18n(instance);
|
|
234
|
+
});
|
|
235
|
+
vi.doMock("../i18nFrontend.js", () => ({ default: initialize }));
|
|
236
|
+
const loadI18next = await loadModule();
|
|
237
|
+
const { I18N_LOAD_TIMEOUT_MS } = await import("../loadI18next.js");
|
|
238
|
+
const pending = loadI18next(false, "fr");
|
|
239
|
+
await vi.advanceTimersByTimeAsync(I18N_LOAD_TIMEOUT_MS);
|
|
240
|
+
await expect(pending).resolves.toBe(asI18n(instance));
|
|
241
|
+
fire?.(asI18n(instance));
|
|
242
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
243
|
+
await expect(pending).resolves.toBe(asI18n(instance));
|
|
244
|
+
});
|
|
245
|
+
test("the deadline is long enough not to trip a healthy cold start", async () => {
|
|
246
|
+
const { I18N_LOAD_TIMEOUT_MS } = await import("../loadI18next.js");
|
|
247
|
+
expect(I18N_LOAD_TIMEOUT_MS).toBeGreaterThanOrEqual(5_000);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
describe("loadI18next, singleton shared across both paths", () => {
|
|
251
|
+
test("a frontend call after a backend call reuses the backend instance", async () => {
|
|
252
|
+
const backend = install("../i18nBackend.js", { language: "en" });
|
|
253
|
+
const frontend = install("../i18nFrontend.js", { language: "de" });
|
|
254
|
+
const loadI18next = await loadModule();
|
|
255
|
+
const first = await loadI18next(true);
|
|
256
|
+
const second = await loadI18next(false);
|
|
257
|
+
expect(backend.initialize).toHaveBeenCalledTimes(1);
|
|
258
|
+
expect(frontend.initialize).not.toHaveBeenCalled();
|
|
259
|
+
expect(second).toBe(first);
|
|
260
|
+
});
|
|
261
|
+
test("the later caller's language still wins via reconciliation", async () => {
|
|
262
|
+
const backend = install("../i18nBackend.js", { language: "en" });
|
|
263
|
+
install("../i18nFrontend.js");
|
|
264
|
+
const loadI18next = await loadModule();
|
|
265
|
+
await loadI18next(true);
|
|
266
|
+
await loadI18next(false, "fr");
|
|
267
|
+
expect(backend.instance.language).toBe("fr");
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=loadI18next.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadI18next.unit.test.js","sourceRoot":"","sources":["../../src/tests/loadI18next.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locale.test-d.d.ts","sourceRoot":"","sources":["../../src/tests/locale.test-d.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { assertType, describe, expectTypeOf, it } from "vitest";
|
|
2
|
+
import { LanguageSchema, Languages, TranslationKeysSchema, i18nMiddleware, isClientSide, loadI18next, useTranslation, } from "../index.js";
|
|
3
|
+
describe("Languages", () => {
|
|
4
|
+
it("is a frozen const map of name to code, not a widened record", () => {
|
|
5
|
+
expectTypeOf(Languages.english).toEqualTypeOf();
|
|
6
|
+
expectTypeOf(Languages.chinese).toEqualTypeOf();
|
|
7
|
+
});
|
|
8
|
+
it("rejects assignment to a code", () => {
|
|
9
|
+
Languages.english = "fr";
|
|
10
|
+
});
|
|
11
|
+
it("has no member for a language that is not shipped", () => {
|
|
12
|
+
Languages.klingon;
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe("LanguageSchema", () => {
|
|
16
|
+
it("parses to a string", () => {
|
|
17
|
+
expectTypeOf(LanguageSchema.parse("en")).toEqualTypeOf();
|
|
18
|
+
});
|
|
19
|
+
it("exposes .enum as a lookup of codes", () => {
|
|
20
|
+
expectTypeOf(LanguageSchema.enum).toExtend();
|
|
21
|
+
});
|
|
22
|
+
it("accepts unknown input at the parse boundary", () => {
|
|
23
|
+
expectTypeOf(LanguageSchema.parse).toBeCallableWith("anything");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe("TranslationKey", () => {
|
|
27
|
+
it("is inferred from the schema", () => {
|
|
28
|
+
expectTypeOf().toEqualTypeOf();
|
|
29
|
+
});
|
|
30
|
+
it("accepts a key literal, so error call sites need no cast", () => {
|
|
31
|
+
assertType("API.UNKNOWN");
|
|
32
|
+
});
|
|
33
|
+
it("exposes the derived keys as an array of options", () => {
|
|
34
|
+
expectTypeOf(TranslationKeysSchema.options).toExtend();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe("isClientSide", () => {
|
|
38
|
+
it("takes no arguments and returns a boolean", () => {
|
|
39
|
+
expectTypeOf(isClientSide).parameters.toEqualTypeOf();
|
|
40
|
+
expectTypeOf(isClientSide).returns.toEqualTypeOf();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe("loadI18next", () => {
|
|
44
|
+
it("requires the backend flag", () => {
|
|
45
|
+
expectTypeOf(loadI18next).toBeCallableWith(true);
|
|
46
|
+
expectTypeOf(loadI18next).toBeCallableWith(false, "fr");
|
|
47
|
+
});
|
|
48
|
+
it("rejects a call with no arguments", () => {
|
|
49
|
+
loadI18next();
|
|
50
|
+
});
|
|
51
|
+
it("rejects a non-boolean first argument", () => {
|
|
52
|
+
loadI18next("fr");
|
|
53
|
+
});
|
|
54
|
+
it("resolves to the i18next instance type the package re-exports", () => {
|
|
55
|
+
expectTypeOf(loadI18next).returns.toEqualTypeOf();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("Ti18n", () => {
|
|
59
|
+
it("carries the i18next surface consumers need", () => {
|
|
60
|
+
expectTypeOf().toHaveProperty("t");
|
|
61
|
+
expectTypeOf().toHaveProperty("language");
|
|
62
|
+
expectTypeOf().toHaveProperty("changeLanguage");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe("i18nMiddleware", () => {
|
|
66
|
+
it("takes handler options and resolves to an express handler", () => {
|
|
67
|
+
expectTypeOf(i18nMiddleware).toBeCallableWith({});
|
|
68
|
+
expectTypeOf(i18nMiddleware).returns.toExtend();
|
|
69
|
+
});
|
|
70
|
+
it("rejects an unknown option", () => {
|
|
71
|
+
i18nMiddleware({ notAnOption: true });
|
|
72
|
+
});
|
|
73
|
+
it("rejects being called with no options", () => {
|
|
74
|
+
i18nMiddleware();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("useTranslation", () => {
|
|
78
|
+
it("is callable with no options", () => {
|
|
79
|
+
expectTypeOf(useTranslation).toBeCallableWith();
|
|
80
|
+
});
|
|
81
|
+
it("returns a t function", () => {
|
|
82
|
+
expectTypeOf(useTranslation).returns.toHaveProperty("t");
|
|
83
|
+
});
|
|
84
|
+
it("rejects an unknown option", () => {
|
|
85
|
+
useTranslation({ notAnOption: 1 });
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=locale.test-d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locale.test-d.js","sourceRoot":"","sources":["../../src/tests/locale.test-d.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/process.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { getProcess } from "../process.js";
|
|
3
|
+
describe("getProcess", () => {
|
|
4
|
+
test("returns the process global when one exists", () => {
|
|
5
|
+
expect(getProcess()).toBe(process);
|
|
6
|
+
});
|
|
7
|
+
test("exposes env, which is the only member consumers use", () => {
|
|
8
|
+
expect(getProcess()?.env).toBe(process.env);
|
|
9
|
+
});
|
|
10
|
+
test("is stable across calls rather than returning a copy", () => {
|
|
11
|
+
expect(getProcess()).toBe(getProcess());
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=process.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.unit.test.js","sourceRoot":"","sources":["../../src/tests/process.unit.test.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAI3B,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translationKey.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/translationKey.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import translationEn from "../locales/en/translation.json" with {
|
|
3
|
+
type: "json"
|
|
4
|
+
};
|
|
5
|
+
import { TranslationKeysSchema, getLeafFieldPath, } from "../translationKey.js";
|
|
6
|
+
describe("getLeafFieldPath", () => {
|
|
7
|
+
test("returns no paths for a bare string, which is a leaf and not a container", () => {
|
|
8
|
+
expect(getLeafFieldPath("a string")).toEqual([]);
|
|
9
|
+
});
|
|
10
|
+
test("returns no paths for the empty string", () => {
|
|
11
|
+
expect(getLeafFieldPath("")).toEqual([]);
|
|
12
|
+
});
|
|
13
|
+
test("emits a top-level string value under its own key", () => {
|
|
14
|
+
expect(getLeafFieldPath({ topLevel: "value" })).toEqual(["topLevel"]);
|
|
15
|
+
});
|
|
16
|
+
test("emits section.key for a one-level-deep section", () => {
|
|
17
|
+
expect(getLeafFieldPath({ section: { key: "value" } })).toEqual([
|
|
18
|
+
"section.key",
|
|
19
|
+
]);
|
|
20
|
+
});
|
|
21
|
+
test("emits every key of a section, in insertion order", () => {
|
|
22
|
+
expect(getLeafFieldPath({ section: { first: "1", second: "2", third: "3" } })).toEqual(["section.first", "section.second", "section.third"]);
|
|
23
|
+
});
|
|
24
|
+
test("recurses to arbitrary depth, joining each level with a dot", () => {
|
|
25
|
+
expect(getLeafFieldPath({ a: { b: { c: { d: "leaf" } } } })).toEqual([
|
|
26
|
+
"a.b.c.d",
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
test("handles sibling branches of differing depth", () => {
|
|
30
|
+
expect(getLeafFieldPath({
|
|
31
|
+
shallow: { key: "v" },
|
|
32
|
+
deep: { nested: { key: "v" } },
|
|
33
|
+
})).toEqual(["shallow.key", "deep.nested.key"]);
|
|
34
|
+
});
|
|
35
|
+
test("returns no paths for an empty object", () => {
|
|
36
|
+
expect(getLeafFieldPath({})).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
test("drops an empty nested section rather than erroring", () => {
|
|
39
|
+
expect(getLeafFieldPath({ section: {} })).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
test("keeps populated siblings when one section is empty", () => {
|
|
42
|
+
expect(getLeafFieldPath({ empty: {}, full: { key: "v" } })).toEqual([
|
|
43
|
+
"full.key",
|
|
44
|
+
]);
|
|
45
|
+
});
|
|
46
|
+
test("throws on an explicitly undefined value, naming the offending key", () => {
|
|
47
|
+
const node = {
|
|
48
|
+
section: { broken: undefined },
|
|
49
|
+
};
|
|
50
|
+
expect(() => getLeafFieldPath(node)).toThrow("Undefined value for key broken");
|
|
51
|
+
});
|
|
52
|
+
test("throws before emitting any of the sibling keys of the broken one", () => {
|
|
53
|
+
const node = {
|
|
54
|
+
section: { ok: "v", broken: undefined },
|
|
55
|
+
};
|
|
56
|
+
expect(() => getLeafFieldPath(node)).toThrow(/Undefined value/);
|
|
57
|
+
});
|
|
58
|
+
test("does not mutate the input", () => {
|
|
59
|
+
const node = { section: { key: "value" } };
|
|
60
|
+
const snapshot = JSON.stringify(node);
|
|
61
|
+
getLeafFieldPath(node);
|
|
62
|
+
expect(JSON.stringify(node)).toBe(snapshot);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe("TranslationKeysSchema", () => {
|
|
66
|
+
const keys = getLeafFieldPath(translationEn);
|
|
67
|
+
test("is non-empty — an empty z.enum would throw at module load", () => {
|
|
68
|
+
expect(keys.length).toBeGreaterThan(0);
|
|
69
|
+
});
|
|
70
|
+
test("accepts every key derived from the English translation", () => {
|
|
71
|
+
for (const key of keys) {
|
|
72
|
+
expect(TranslationKeysSchema.parse(key)).toBe(key);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
test("rejects a key that is not in the English translation", () => {
|
|
76
|
+
expect(() => TranslationKeysSchema.parse("no.such.key")).toThrow();
|
|
77
|
+
});
|
|
78
|
+
test("rejects the empty string", () => {
|
|
79
|
+
expect(() => TranslationKeysSchema.parse("")).toThrow();
|
|
80
|
+
});
|
|
81
|
+
test("rejects a section name on its own — only leaves are valid keys", () => {
|
|
82
|
+
const [firstKey] = keys;
|
|
83
|
+
expect(firstKey).toBeDefined();
|
|
84
|
+
const section = String(firstKey).split(".")[0];
|
|
85
|
+
expect(() => TranslationKeysSchema.parse(section)).toThrow();
|
|
86
|
+
});
|
|
87
|
+
test("rejects non-string input", () => {
|
|
88
|
+
expect(() => TranslationKeysSchema.parse(42)).toThrow();
|
|
89
|
+
expect(() => TranslationKeysSchema.parse(null)).toThrow();
|
|
90
|
+
expect(() => TranslationKeysSchema.parse(undefined)).toThrow();
|
|
91
|
+
});
|
|
92
|
+
test("safeParse reports failure without throwing", () => {
|
|
93
|
+
const result = TranslationKeysSchema.safeParse("no.such.key");
|
|
94
|
+
expect(result.success).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
test("is case sensitive", () => {
|
|
97
|
+
const [firstKey] = keys;
|
|
98
|
+
expect(firstKey).toBeDefined();
|
|
99
|
+
const upper = String(firstKey).toUpperCase();
|
|
100
|
+
if (upper !== firstKey) {
|
|
101
|
+
expect(() => TranslationKeysSchema.parse(upper)).toThrow();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
test("exposes exactly the derived keys as enum options", () => {
|
|
105
|
+
expect(new Set(TranslationKeysSchema.options)).toEqual(new Set(keys));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=translationKey.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translationKey.unit.test.js","sourceRoot":"","sources":["../../src/tests/translationKey.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/translations.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { describe, expect, test } from "vitest";
|
|
4
|
+
import { LanguageSchema, Languages } from "../translations.js";
|
|
5
|
+
const codes = Object.values(Languages);
|
|
6
|
+
describe("Languages", () => {
|
|
7
|
+
test("is non-empty", () => {
|
|
8
|
+
expect(codes.length).toBeGreaterThan(0);
|
|
9
|
+
});
|
|
10
|
+
test("maps English language names to BCP 47 codes", () => {
|
|
11
|
+
expect(Languages.english).toBe("en");
|
|
12
|
+
expect(Languages.chinese).toBe("zh-CN");
|
|
13
|
+
expect(Languages.portugeseBrazil).toBe("pt-BR");
|
|
14
|
+
});
|
|
15
|
+
test("includes the fallback language", () => {
|
|
16
|
+
expect(codes).toContain("en");
|
|
17
|
+
});
|
|
18
|
+
test("has no duplicate codes", () => {
|
|
19
|
+
expect(new Set(codes).size).toBe(codes.length);
|
|
20
|
+
});
|
|
21
|
+
test("every code is a well-formed, lowercase-primary language tag", () => {
|
|
22
|
+
for (const code of codes) {
|
|
23
|
+
expect(code).toMatch(/^[a-z]{2}(-[A-Z]{2})?$/);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
test("every code has a locales directory containing translation.json", () => {
|
|
27
|
+
for (const code of codes) {
|
|
28
|
+
const file = path.resolve(`./src/locales/${code}/translation.json`);
|
|
29
|
+
expect(fs.existsSync(file), `missing ${code}`).toBe(true);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
test("every locales directory is claimed by a code — no orphans", () => {
|
|
33
|
+
const dirs = fs.readdirSync(path.resolve("./src/locales"));
|
|
34
|
+
for (const dir of dirs) {
|
|
35
|
+
expect(codes, `orphan locale directory ${dir}`).toContain(dir);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("LanguageSchema", () => {
|
|
40
|
+
test("accepts every declared code", () => {
|
|
41
|
+
for (const code of codes) {
|
|
42
|
+
expect(LanguageSchema.parse(code)).toBe(code);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
test("exposes each code on .enum for use as a constant", () => {
|
|
46
|
+
expect(LanguageSchema.enum.en).toBe("en");
|
|
47
|
+
});
|
|
48
|
+
test("rejects an undeclared language code", () => {
|
|
49
|
+
expect(() => LanguageSchema.parse("xx")).toThrow();
|
|
50
|
+
});
|
|
51
|
+
test("rejects the empty string", () => {
|
|
52
|
+
expect(() => LanguageSchema.parse("")).toThrow();
|
|
53
|
+
});
|
|
54
|
+
test("rejects a regional variant of a supported language", () => {
|
|
55
|
+
expect(() => LanguageSchema.parse("en-GB")).toThrow();
|
|
56
|
+
});
|
|
57
|
+
test("is case sensitive — `EN` is not `en`", () => {
|
|
58
|
+
expect(() => LanguageSchema.parse("EN")).toThrow();
|
|
59
|
+
});
|
|
60
|
+
test("rejects non-string input", () => {
|
|
61
|
+
expect(() => LanguageSchema.parse(1)).toThrow();
|
|
62
|
+
expect(() => LanguageSchema.parse(null)).toThrow();
|
|
63
|
+
expect(() => LanguageSchema.parse(undefined)).toThrow();
|
|
64
|
+
expect(() => LanguageSchema.parse(["en"])).toThrow();
|
|
65
|
+
});
|
|
66
|
+
test("safeParse reports failure without throwing", () => {
|
|
67
|
+
expect(LanguageSchema.safeParse("xx").success).toBe(false);
|
|
68
|
+
expect(LanguageSchema.safeParse("en").success).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
test("its options are exactly the declared codes", () => {
|
|
71
|
+
expect(new Set(LanguageSchema.options)).toEqual(new Set(codes));
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=translations.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.unit.test.js","sourceRoot":"","sources":["../../src/tests/translations.unit.test.ts"],"names":[],"mappings":"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"}
|