@prosopo/locale 3.2.8 → 3.3.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/.turbo/turbo-build$colon$cjs.log +10 -9
- package/.turbo/turbo-build$colon$tsc.log +5 -5
- package/.turbo/turbo-build.log +11 -10
- package/CHANGELOG.md +36 -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/locales/en/translation.cjs +1 -0
- 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/locales/ar/translation.json +1 -0
- package/dist/locales/az/translation.json +1 -0
- package/dist/locales/cs/translation.json +1 -0
- package/dist/locales/de/translation.json +1 -0
- package/dist/locales/el/translation.json +1 -0
- package/dist/locales/en/translation.js +1 -0
- package/dist/locales/en/translation.json +1 -0
- package/dist/locales/es/translation.json +1 -0
- package/dist/locales/fi/translation.json +1 -0
- package/dist/locales/fr/translation.json +1 -0
- package/dist/locales/hi/translation.json +1 -0
- package/dist/locales/hu/translation.json +1 -0
- package/dist/locales/id/translation.json +1 -0
- package/dist/locales/it/translation.json +1 -0
- package/dist/locales/ja/translation.json +1 -0
- package/dist/locales/jv/translation.json +1 -0
- package/dist/locales/ko/translation.json +1 -0
- package/dist/locales/ml/translation.json +1 -0
- package/dist/locales/ms/translation.json +1 -0
- package/dist/locales/nl/translation.json +1 -0
- package/dist/locales/no/translation.json +1 -0
- package/dist/locales/pl/translation.json +1 -0
- package/dist/locales/pt/translation.json +1 -0
- package/dist/locales/pt-BR/translation.json +1 -0
- package/dist/locales/ro/translation.json +1 -0
- package/dist/locales/ru/translation.json +1 -0
- package/dist/locales/sr/translation.json +1 -0
- package/dist/locales/sv/translation.json +1 -0
- package/dist/locales/th/translation.json +1 -0
- package/dist/locales/tr/translation.json +1 -0
- package/dist/locales/uk/translation.json +1 -0
- package/dist/locales/vi/translation.json +1 -0
- package/dist/locales/zh-CN/translation.json +1 -0
- 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 +2 -2
- 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/locales/ar/translation.json +1 -0
- package/src/locales/az/translation.json +1 -0
- package/src/locales/cs/translation.json +1 -0
- package/src/locales/de/translation.json +1 -0
- package/src/locales/el/translation.json +1 -0
- package/src/locales/en/translation.json +1 -0
- package/src/locales/es/translation.json +1 -0
- package/src/locales/fi/translation.json +1 -0
- package/src/locales/fr/translation.json +1 -0
- package/src/locales/hi/translation.json +1 -0
- package/src/locales/hu/translation.json +1 -0
- package/src/locales/id/translation.json +1 -0
- package/src/locales/it/translation.json +1 -0
- package/src/locales/ja/translation.json +1 -0
- package/src/locales/jv/translation.json +1 -0
- package/src/locales/ko/translation.json +1 -0
- package/src/locales/ml/translation.json +1 -0
- package/src/locales/ms/translation.json +1 -0
- package/src/locales/nl/translation.json +1 -0
- package/src/locales/no/translation.json +1 -0
- package/src/locales/pl/translation.json +1 -0
- package/src/locales/pt/translation.json +1 -0
- package/src/locales/pt-BR/translation.json +1 -0
- package/src/locales/ro/translation.json +1 -0
- package/src/locales/ru/translation.json +1 -0
- package/src/locales/sr/translation.json +1 -0
- package/src/locales/sv/translation.json +1 -0
- package/src/locales/th/translation.json +1 -0
- package/src/locales/tr/translation.json +1 -0
- package/src/locales/uk/translation.json +1 -0
- package/src/locales/vi/translation.json +1 -0
- package/src/locales/zh-CN/translation.json +1 -0
- 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,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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTranslation.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/useTranslation.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
const asI18n = (value) => value;
|
|
3
|
+
const load = async () => {
|
|
4
|
+
vi.resetModules();
|
|
5
|
+
const instance = asI18n({ name: "package instance" });
|
|
6
|
+
const calls = [];
|
|
7
|
+
let initCalls = 0;
|
|
8
|
+
vi.doMock("../i18nFrontend.js", () => ({
|
|
9
|
+
default: () => {
|
|
10
|
+
initCalls += 1;
|
|
11
|
+
return instance;
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
vi.doMock("react-i18next", () => ({
|
|
15
|
+
useTranslation: (namespace, options) => {
|
|
16
|
+
calls.push([namespace, options]);
|
|
17
|
+
return { t: (key) => key, i18n: options.i18n };
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
const imported = await import("../useTranslation.js");
|
|
21
|
+
return {
|
|
22
|
+
useTranslation: imported.default,
|
|
23
|
+
instance,
|
|
24
|
+
calls,
|
|
25
|
+
initCount: () => initCalls,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
vi.resetModules();
|
|
30
|
+
vi.doUnmock("../i18nFrontend.js");
|
|
31
|
+
vi.doUnmock("react-i18next");
|
|
32
|
+
});
|
|
33
|
+
describe("useTranslation", () => {
|
|
34
|
+
test("always asks for the translation namespace", async () => {
|
|
35
|
+
const { useTranslation, calls } = await load();
|
|
36
|
+
useTranslation();
|
|
37
|
+
expect(calls[0]?.[0]).toBe("translation");
|
|
38
|
+
});
|
|
39
|
+
test("injects the package's own i18next instance", async () => {
|
|
40
|
+
const { useTranslation, calls, instance } = await load();
|
|
41
|
+
useTranslation();
|
|
42
|
+
expect(calls[0]?.[1].i18n).toBe(instance);
|
|
43
|
+
});
|
|
44
|
+
test("initialises the frontend instance on use", async () => {
|
|
45
|
+
const { useTranslation, initCount } = await load();
|
|
46
|
+
useTranslation();
|
|
47
|
+
expect(initCount()).toBe(1);
|
|
48
|
+
});
|
|
49
|
+
test("works with no options at all", async () => {
|
|
50
|
+
const { useTranslation, calls } = await load();
|
|
51
|
+
useTranslation();
|
|
52
|
+
expect(calls[0]?.[1]).toEqual({ i18n: expect.anything() });
|
|
53
|
+
});
|
|
54
|
+
test("passes caller options through", async () => {
|
|
55
|
+
const { useTranslation, calls } = await load();
|
|
56
|
+
useTranslation({ nsMode: "fallback", useSuspense: false });
|
|
57
|
+
expect(calls[0]?.[1]).toMatchObject({
|
|
58
|
+
nsMode: "fallback",
|
|
59
|
+
useSuspense: false,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
test("lets the caller override the instance, since options spread last", async () => {
|
|
63
|
+
const { useTranslation, calls, instance } = await load();
|
|
64
|
+
const other = asI18n({ name: "caller instance" });
|
|
65
|
+
useTranslation({ i18n: other });
|
|
66
|
+
expect(calls[0]?.[1].i18n).toBe(other);
|
|
67
|
+
expect(calls[0]?.[1].i18n).not.toBe(instance);
|
|
68
|
+
});
|
|
69
|
+
test("returns whatever react-i18next returns", async () => {
|
|
70
|
+
const { useTranslation } = await load();
|
|
71
|
+
const result = useTranslation();
|
|
72
|
+
expect(result.t("WIDGET.SUBMIT")).toBe("WIDGET.SUBMIT");
|
|
73
|
+
});
|
|
74
|
+
test("re-initialises on every call, matching hook semantics", async () => {
|
|
75
|
+
const { useTranslation, initCount } = await load();
|
|
76
|
+
useTranslation();
|
|
77
|
+
useTranslation();
|
|
78
|
+
expect(initCount()).toBe(2);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=useTranslation.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTranslation.unit.test.js","sourceRoot":"","sources":["../../src/tests/useTranslation.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/util.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { isClientSide, isServerSide } from "../util.js";
|
|
3
|
+
const setWindow = (value) => {
|
|
4
|
+
if (value === undefined) {
|
|
5
|
+
Reflect.deleteProperty(globalThis, "window");
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(globalThis, "window", {
|
|
9
|
+
value,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
setWindow(undefined);
|
|
16
|
+
});
|
|
17
|
+
describe("isClientSide", () => {
|
|
18
|
+
test("is false under plain node, where there is no window at all", () => {
|
|
19
|
+
expect(isClientSide()).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
test("is true when window exposes document.createElement", () => {
|
|
22
|
+
setWindow({ document: { createElement: () => { } } });
|
|
23
|
+
expect(isClientSide()).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
test("is false when window exists but has no document", () => {
|
|
26
|
+
setWindow({});
|
|
27
|
+
expect(isClientSide()).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
test("is false when document exists but has no createElement", () => {
|
|
30
|
+
setWindow({ document: {} });
|
|
31
|
+
expect(isClientSide()).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
test("is false when createElement is present but undefined", () => {
|
|
34
|
+
setWindow({ document: { createElement: undefined } });
|
|
35
|
+
expect(isClientSide()).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
test("returns a real boolean, not the truthy function itself", () => {
|
|
38
|
+
const createElement = () => { };
|
|
39
|
+
setWindow({ document: { createElement } });
|
|
40
|
+
const result = isClientSide();
|
|
41
|
+
expect(result).toBe(true);
|
|
42
|
+
expect(typeof result).toBe("boolean");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("isServerSide", () => {
|
|
46
|
+
test("is true under plain node", () => {
|
|
47
|
+
expect(isServerSide()).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
test("is false in a browser-like environment", () => {
|
|
50
|
+
setWindow({ document: { createElement: () => { } } });
|
|
51
|
+
expect(isServerSide()).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
test("is always the exact negation of isClientSide", () => {
|
|
54
|
+
const environments = [
|
|
55
|
+
undefined,
|
|
56
|
+
{},
|
|
57
|
+
{ document: {} },
|
|
58
|
+
{ document: { createElement: () => { } } },
|
|
59
|
+
];
|
|
60
|
+
for (const environment of environments) {
|
|
61
|
+
setWindow(environment);
|
|
62
|
+
expect(isServerSide()).toBe(!isClientSide());
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=util.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.unit.test.js","sourceRoot":"","sources":["../../src/tests/util.unit.test.ts"],"names":[],"mappings":"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"}
|
package/dist/translationKey.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
export type TranslationNode = {
|
|
3
|
+
[key: string]: TranslationNode | string;
|
|
4
|
+
} | string;
|
|
5
|
+
export declare function getLeafFieldPath(obj: TranslationNode): string[];
|
|
2
6
|
export declare const TranslationKeysSchema: z.ZodEnum<[string, ...string[]]>;
|
|
3
7
|
export type TranslationKey = z.infer<typeof TranslationKeysSchema>;
|
|
4
8
|
//# sourceMappingURL=translationKey.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translationKey.d.ts","sourceRoot":"","sources":["../src/translationKey.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"translationKey.d.ts","sourceRoot":"","sources":["../src/translationKey.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,MAAM,eAAe,GACxB;IACA,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,MAAM,CAAC;CACvC,GACD,MAAM,CAAC;AAKV,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,EAAE,CA8B/D;AAED,eAAO,MAAM,qBAAqB,kCAEjC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
package/dist/translationKey.js
CHANGED
|
@@ -6,6 +6,7 @@ function getLeafFieldPath(obj) {
|
|
|
6
6
|
return Object.keys(obj).reduce((arr, key) => {
|
|
7
7
|
const value = obj[key];
|
|
8
8
|
if (value === void 0) throw new Error(`Undefined value for key ${key}`);
|
|
9
|
+
if (typeof value === "string") return arr.concat(key);
|
|
9
10
|
const children = getLeafFieldPath(value);
|
|
10
11
|
return arr.concat(children.map((child) => {
|
|
11
12
|
return `${key}.${child}`;
|
|
@@ -14,4 +15,4 @@ function getLeafFieldPath(obj) {
|
|
|
14
15
|
}
|
|
15
16
|
var TranslationKeysSchema = z$1.enum(getLeafFieldPath(translation_default));
|
|
16
17
|
//#endregion
|
|
17
|
-
export { TranslationKeysSchema };
|
|
18
|
+
export { TranslationKeysSchema, getLeafFieldPath };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translationKey.js","sourceRoot":"","sources":["../src/translationKey.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,aAAa,MAAM,+BAA+B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"translationKey.js","sourceRoot":"","sources":["../src/translationKey.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,aAAa,MAAM,+BAA+B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAWhF,MAAM,UAAU,gBAAgB,CAAC,GAAoB;IACpD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACX,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;QACnD,CAAC;QASD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAEzC,OAAO,GAAG,CAAC,MAAM,CAChB,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACtB,OAAO,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,CAAC,CAAC,CACF,CAAC;IACH,CAAC,EAAE,EAAc,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,IAAI,CAC1C,gBAAgB,CAAC,aAAa,CAA0B,CACxD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/locale",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Prosopo locale library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"zod": "3.23.8"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@prosopo/config": "3.3.
|
|
46
|
+
"@prosopo/config": "3.3.7",
|
|
47
47
|
"@types/node": "22.10.2",
|
|
48
48
|
"@vitest/coverage-v8": "4.1.10",
|
|
49
49
|
"concurrently": "9.0.1",
|
package/src/i18SharedOptions.ts
CHANGED
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
+
import { getProcess } from "./process.js";
|
|
14
15
|
import { LanguageSchema, Languages } from "./translations.js";
|
|
15
16
|
|
|
16
|
-
//
|
|
17
|
-
// runtime where `process` is undefined. Without
|
|
17
|
+
// Read through getProcess() so the module stays loadable in a plain browser
|
|
18
|
+
// runtime where `process` is undefined. Without that guard, any side-effectful
|
|
18
19
|
// runtime import of `@prosopo/types` (which transitively reaches here via
|
|
19
20
|
// `LanguageSchema`) crashes the page in Vite's dev/preview mode.
|
|
20
|
-
const logLevel =
|
|
21
|
-
typeof process !== "undefined" ? process.env?.PROSOPO_LOG_LEVEL : undefined;
|
|
21
|
+
const logLevel = getProcess()?.env?.PROSOPO_LOG_LEVEL;
|
|
22
22
|
|
|
23
23
|
export const i18nSharedOptions = {
|
|
24
24
|
debug: logLevel === "debug",
|
package/src/i18nBackend.ts
CHANGED
|
@@ -43,9 +43,25 @@ export function initializeI18n(
|
|
|
43
43
|
loadPath,
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
|
+
// "loaded" fires once per namespace, and again after changeLanguage(),
|
|
47
|
+
// so the raw event is not the one-shot signal the callback expects.
|
|
48
|
+
// Latch it here as well as in loadI18next: this callback is public and
|
|
49
|
+
// a caller could reasonably use it to run a side effect.
|
|
50
|
+
let notified = false;
|
|
46
51
|
i18n.on("loaded", () => {
|
|
52
|
+
if (notified) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
notified = true;
|
|
47
56
|
i18nLoadedCallback?.(i18n);
|
|
48
57
|
});
|
|
58
|
+
} else {
|
|
59
|
+
// Nothing to initialise — either i18next is already up (a frontend
|
|
60
|
+
// consumer got there first) or we are not on the server. The `loaded`
|
|
61
|
+
// handler above is only registered inside the init branch, so without
|
|
62
|
+
// this the callback would never fire and loadI18next() would stay
|
|
63
|
+
// pending forever instead of handing back the instance we already have.
|
|
64
|
+
i18nLoadedCallback?.(i18n);
|
|
49
65
|
}
|
|
50
66
|
return i18n;
|
|
51
67
|
}
|