@prosopo/locale 3.6.2 → 3.8.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.
Files changed (106) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +3 -6
  2. package/.turbo/turbo-build$colon$tsc.log +6 -9
  3. package/.turbo/turbo-build.log +5 -11
  4. package/CHANGELOG.md +43 -0
  5. package/LICENSE +201 -0
  6. package/dist/cjs/locales/en/translation.cjs +24 -2
  7. package/dist/locales/ar/translation.json +24 -2
  8. package/dist/locales/az/translation.json +24 -2
  9. package/dist/locales/cs/translation.json +24 -2
  10. package/dist/locales/de/translation.json +24 -2
  11. package/dist/locales/el/translation.json +24 -2
  12. package/dist/locales/en/translation.js +24 -2
  13. package/dist/locales/en/translation.json +24 -2
  14. package/dist/locales/es/translation.json +24 -2
  15. package/dist/locales/fi/translation.json +24 -2
  16. package/dist/locales/fr/translation.json +24 -2
  17. package/dist/locales/hi/translation.json +24 -2
  18. package/dist/locales/hu/translation.json +24 -2
  19. package/dist/locales/id/translation.json +24 -2
  20. package/dist/locales/it/translation.json +24 -2
  21. package/dist/locales/ja/translation.json +24 -2
  22. package/dist/locales/jv/translation.json +24 -2
  23. package/dist/locales/ko/translation.json +24 -2
  24. package/dist/locales/ml/translation.json +24 -2
  25. package/dist/locales/ms/translation.json +24 -2
  26. package/dist/locales/nl/translation.json +24 -2
  27. package/dist/locales/no/translation.json +24 -2
  28. package/dist/locales/pl/translation.json +24 -2
  29. package/dist/locales/pt/translation.json +24 -2
  30. package/dist/locales/pt-BR/translation.json +24 -2
  31. package/dist/locales/ro/translation.json +24 -2
  32. package/dist/locales/ru/translation.json +24 -2
  33. package/dist/locales/sr/translation.json +24 -2
  34. package/dist/locales/sv/translation.json +24 -2
  35. package/dist/locales/th/translation.json +24 -2
  36. package/dist/locales/tr/translation.json +24 -2
  37. package/dist/locales/uk/translation.json +24 -2
  38. package/dist/locales/vi/translation.json +24 -2
  39. package/dist/locales/zh-CN/translation.json +24 -2
  40. package/package.json +65 -66
  41. package/src/direction.ts +0 -36
  42. package/src/errorMessage.ts +0 -37
  43. package/src/i18SharedOptions.ts +0 -29
  44. package/src/i18nBackend.ts +0 -69
  45. package/src/i18nFrontend.ts +0 -267
  46. package/src/i18nMiddleware.ts +0 -35
  47. package/src/index.ts +0 -33
  48. package/src/loadI18next.ts +0 -136
  49. package/src/locales/ar/translation.json +0 -493
  50. package/src/locales/az/translation.json +0 -493
  51. package/src/locales/cs/translation.json +0 -493
  52. package/src/locales/de/translation.json +0 -493
  53. package/src/locales/el/translation.json +0 -493
  54. package/src/locales/en/translation.json +0 -493
  55. package/src/locales/es/translation.json +0 -493
  56. package/src/locales/fi/translation.json +0 -493
  57. package/src/locales/fr/translation.json +0 -493
  58. package/src/locales/hi/translation.json +0 -493
  59. package/src/locales/hu/translation.json +0 -493
  60. package/src/locales/id/translation.json +0 -493
  61. package/src/locales/it/translation.json +0 -493
  62. package/src/locales/ja/translation.json +0 -493
  63. package/src/locales/jv/translation.json +0 -493
  64. package/src/locales/ko/translation.json +0 -493
  65. package/src/locales/ml/translation.json +0 -493
  66. package/src/locales/ms/translation.json +0 -493
  67. package/src/locales/nl/translation.json +0 -493
  68. package/src/locales/no/translation.json +0 -493
  69. package/src/locales/pl/translation.json +0 -493
  70. package/src/locales/pt/translation.json +0 -493
  71. package/src/locales/pt-BR/translation.json +0 -493
  72. package/src/locales/ro/translation.json +0 -493
  73. package/src/locales/ru/translation.json +0 -493
  74. package/src/locales/sr/translation.json +0 -493
  75. package/src/locales/sv/translation.json +0 -493
  76. package/src/locales/th/translation.json +0 -493
  77. package/src/locales/tr/translation.json +0 -493
  78. package/src/locales/uk/translation.json +0 -493
  79. package/src/locales/vi/translation.json +0 -493
  80. package/src/locales/zh-CN/translation.json +0 -493
  81. package/src/process.ts +0 -29
  82. package/src/tests/direction.unit.test.ts +0 -52
  83. package/src/tests/errorMessage.unit.test.ts +0 -84
  84. package/src/tests/i18SharedOptions.unit.test.ts +0 -139
  85. package/src/tests/i18nBackend.unit.test.ts +0 -241
  86. package/src/tests/i18nFrontend.unit.test.ts +0 -404
  87. package/src/tests/i18nMiddleware.unit.test.ts +0 -159
  88. package/src/tests/loadI18next.unit.test.ts +0 -443
  89. package/src/tests/locale.test-d.ts +0 -184
  90. package/src/tests/localePlaceholders.unit.test.ts +0 -81
  91. package/src/tests/locales.unit.test.ts +0 -79
  92. package/src/tests/process.unit.test.ts +0 -33
  93. package/src/tests/thrownErrorKeys.unit.test.ts +0 -91
  94. package/src/tests/translationKey.unit.test.ts +0 -155
  95. package/src/tests/translations.unit.test.ts +0 -97
  96. package/src/tests/translator.unit.test.ts +0 -213
  97. package/src/tests/util.unit.test.ts +0 -102
  98. package/src/translationKey.ts +0 -73
  99. package/src/translations.ts +0 -55
  100. package/src/translator.ts +0 -69
  101. package/src/types.ts +0 -47
  102. package/src/util.ts +0 -25
  103. package/tsconfig.cjs.json +0 -21
  104. package/tsconfig.json +0 -22
  105. package/tsconfig.tsbuildinfo +0 -1
  106. package/tsconfig.types.json +0 -9
@@ -1,213 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import type { i18n } from "i18next";
16
- import { afterEach, describe, expect, test, vi } from "vitest";
17
- import type { Translator } from "../translator.js";
18
-
19
- // The translator is a thin wrapper: it forces the package's own i18next
20
- // instance in rather than letting a host app's provider decide, and exposes the
21
- // three events that used to drive a React re-render. i18next itself is mocked
22
- // so the tests observe the wiring rather than i18next's own behaviour.
23
-
24
- interface FakeI18n {
25
- readonly instance: i18n;
26
- readonly handlers: Map<string, Set<() => void>>;
27
- isInitialized: boolean;
28
- loadedNamespaces: string[];
29
- translations: Record<string, string>;
30
- }
31
-
32
- const fakeI18n = (): FakeI18n => {
33
- const handlers = new Map<string, Set<() => void>>();
34
- const fake: FakeI18n = {
35
- handlers,
36
- isInitialized: true,
37
- loadedNamespaces: ["translation"],
38
- translations: {},
39
- instance: {
40
- t: (key: string): string => fake.translations[key] ?? key,
41
- get isInitialized(): boolean {
42
- return fake.isInitialized;
43
- },
44
- hasLoadedNamespace: (namespace: string): boolean =>
45
- fake.loadedNamespaces.includes(namespace),
46
- on: (event: string, listener: () => void): void => {
47
- const existing = handlers.get(event) ?? new Set<() => void>();
48
- existing.add(listener);
49
- handlers.set(event, existing);
50
- },
51
- off: (event: string, listener: () => void): void => {
52
- handlers.get(event)?.delete(listener);
53
- },
54
- } as unknown as i18n,
55
- };
56
- return fake;
57
- };
58
-
59
- const emit = (fake: FakeI18n, event: string): void => {
60
- for (const listener of fake.handlers.get(event) ?? []) {
61
- listener();
62
- }
63
- };
64
-
65
- const load = async (): Promise<{
66
- createTranslator: (existing?: i18n) => Translator;
67
- packageInstance: i18n;
68
- initCount: () => number;
69
- }> => {
70
- vi.resetModules();
71
-
72
- const packageInstance = fakeI18n().instance;
73
- let initCalls = 0;
74
-
75
- vi.doMock("../i18nFrontend.js", () => ({
76
- default: (): i18n => {
77
- initCalls += 1;
78
- return packageInstance;
79
- },
80
- }));
81
-
82
- const imported = await import("../translator.js");
83
- return {
84
- createTranslator: imported.createTranslator,
85
- packageInstance,
86
- initCount: (): number => initCalls,
87
- };
88
- };
89
-
90
- afterEach(() => {
91
- vi.resetModules();
92
- vi.doUnmock("../i18nFrontend.js");
93
- });
94
-
95
- describe("which i18next instance the translator talks to", () => {
96
- test("initialises the package's own instance when given none", async () => {
97
- // Without this, a host application running its own i18next would capture
98
- // the widget's translations and render its keys instead.
99
- const { createTranslator, packageInstance, initCount } = await load();
100
-
101
- const translator = createTranslator();
102
-
103
- expect(translator.i18n).toBe(packageInstance);
104
- expect(initCount()).toBe(1);
105
- });
106
-
107
- test("adopts an instance the caller already has", async () => {
108
- // The bundle loads i18next once and hands the same instance to every
109
- // widget on the page, so a second init would be wasted work.
110
- const { createTranslator, initCount } = await load();
111
- const existing = fakeI18n().instance;
112
-
113
- const translator = createTranslator(existing);
114
-
115
- expect(translator.i18n).toBe(existing);
116
- expect(initCount()).toBe(0);
117
- });
118
- });
119
-
120
- describe("translating", () => {
121
- test("delegates to the instance", async () => {
122
- const { createTranslator } = await load();
123
- const fake = fakeI18n();
124
- fake.translations = { "WIDGET.SUBMIT": "Submit" };
125
-
126
- expect(createTranslator(fake.instance).t("WIDGET.SUBMIT")).toBe("Submit");
127
- });
128
-
129
- test("reads the instance at call time, not at creation time", async () => {
130
- // A language switch mutates the instance in place; a translator that
131
- // cached `t` would keep serving the previous language.
132
- const { createTranslator } = await load();
133
- const fake = fakeI18n();
134
- const translator = createTranslator(fake.instance);
135
-
136
- fake.translations = { "WIDGET.SUBMIT": "Envoyer" };
137
-
138
- expect(translator.t("WIDGET.SUBMIT")).toBe("Envoyer");
139
- });
140
- });
141
-
142
- describe("readiness", () => {
143
- test("is ready once the instance has loaded the translation namespace", async () => {
144
- const { createTranslator } = await load();
145
- const fake = fakeI18n();
146
-
147
- expect(createTranslator(fake.instance).isReady()).toBe(true);
148
- });
149
-
150
- test("is not ready before initialisation", async () => {
151
- const { createTranslator } = await load();
152
- const fake = fakeI18n();
153
- fake.isInitialized = false;
154
-
155
- expect(createTranslator(fake.instance).isReady()).toBe(false);
156
- });
157
-
158
- test("is not ready while the namespace is still loading", async () => {
159
- // Widgets render an empty label until this flips, rather than flashing a
160
- // raw translation key at the user.
161
- const { createTranslator } = await load();
162
- const fake = fakeI18n();
163
- fake.loadedNamespaces = [];
164
-
165
- expect(createTranslator(fake.instance).isReady()).toBe(false);
166
- });
167
- });
168
-
169
- describe("subscribing", () => {
170
- test.each(["initialized", "loaded", "languageChanged"])(
171
- "notifies the listener on %s",
172
- async (event: string) => {
173
- const { createTranslator } = await load();
174
- const fake = fakeI18n();
175
- const listener = vi.fn<() => void>();
176
-
177
- createTranslator(fake.instance).subscribe(listener);
178
- emit(fake, event);
179
-
180
- expect(listener).toHaveBeenCalledTimes(1);
181
- },
182
- );
183
-
184
- test("stops notifying once unsubscribed", async () => {
185
- // Widgets unsubscribe on destroy; a leaked listener would keep a torn-down
186
- // widget alive for the lifetime of the page.
187
- const { createTranslator } = await load();
188
- const fake = fakeI18n();
189
- const listener = vi.fn<() => void>();
190
-
191
- const unsubscribe = createTranslator(fake.instance).subscribe(listener);
192
- unsubscribe();
193
- emit(fake, "languageChanged");
194
-
195
- expect(listener).not.toHaveBeenCalled();
196
- });
197
-
198
- test("keeps independent subscriptions apart", async () => {
199
- const { createTranslator } = await load();
200
- const fake = fakeI18n();
201
- const first = vi.fn<() => void>();
202
- const second = vi.fn<() => void>();
203
- const translator = createTranslator(fake.instance);
204
-
205
- const unsubscribeFirst = translator.subscribe(first);
206
- translator.subscribe(second);
207
- unsubscribeFirst();
208
- emit(fake, "loaded");
209
-
210
- expect(first).not.toHaveBeenCalled();
211
- expect(second).toHaveBeenCalledTimes(1);
212
- });
213
- });
@@ -1,102 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import { afterEach, describe, expect, test } from "vitest";
16
- import { isClientSide, isServerSide } from "../util.js";
17
-
18
- // The detection reads `window` off the global object, so each test installs a
19
- // fake and the teardown removes it. Reflect.deleteProperty rather than
20
- // `delete globalThis.window` keeps TypeScript happy about an optional global.
21
- type FakeWindow = {
22
- document?: { createElement?: unknown };
23
- };
24
-
25
- const setWindow = (value: FakeWindow | undefined): void => {
26
- if (value === undefined) {
27
- Reflect.deleteProperty(globalThis, "window");
28
- return;
29
- }
30
- Object.defineProperty(globalThis, "window", {
31
- value,
32
- configurable: true,
33
- writable: true,
34
- });
35
- };
36
-
37
- afterEach(() => {
38
- setWindow(undefined);
39
- });
40
-
41
- describe("isClientSide", () => {
42
- test("is false under plain node, where there is no window at all", () => {
43
- expect(isClientSide()).toBe(false);
44
- });
45
-
46
- test("is true when window exposes document.createElement", () => {
47
- setWindow({ document: { createElement: (): void => {} } });
48
- expect(isClientSide()).toBe(true);
49
- });
50
-
51
- // The three guards are checked in order and each one has to be able to
52
- // veto on its own, otherwise a half-built environment (jsdom teardown, a
53
- // server-side-rendering shim that stubs `window` but not `document`) would
54
- // be misread as a browser and the frontend i18n path would be selected on
55
- // a server.
56
- test("is false when window exists but has no document", () => {
57
- setWindow({});
58
- expect(isClientSide()).toBe(false);
59
- });
60
-
61
- test("is false when document exists but has no createElement", () => {
62
- setWindow({ document: {} });
63
- expect(isClientSide()).toBe(false);
64
- });
65
-
66
- test("is false when createElement is present but undefined", () => {
67
- setWindow({ document: { createElement: undefined } });
68
- expect(isClientSide()).toBe(false);
69
- });
70
-
71
- test("returns a real boolean, not the truthy function itself", () => {
72
- const createElement = (): void => {};
73
- setWindow({ document: { createElement } });
74
- const result: boolean = isClientSide();
75
- expect(result).toBe(true);
76
- expect(typeof result).toBe("boolean");
77
- });
78
- });
79
-
80
- describe("isServerSide", () => {
81
- test("is true under plain node", () => {
82
- expect(isServerSide()).toBe(true);
83
- });
84
-
85
- test("is false in a browser-like environment", () => {
86
- setWindow({ document: { createElement: (): void => {} } });
87
- expect(isServerSide()).toBe(false);
88
- });
89
-
90
- test("is always the exact negation of isClientSide", () => {
91
- const environments: (FakeWindow | undefined)[] = [
92
- undefined,
93
- {},
94
- { document: {} },
95
- { document: { createElement: (): void => {} } },
96
- ];
97
- for (const environment of environments) {
98
- setWindow(environment);
99
- expect(isServerSide()).toBe(!isClientSide());
100
- }
101
- });
102
- });
@@ -1,73 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import translationEn from "./locales/en/translation.json" with { type: "json" };
16
-
17
- export type TranslationNode =
18
- | {
19
- [key: string]: TranslationNode | string;
20
- }
21
- | string;
22
-
23
- // Exported so the traversal can be exercised directly against shapes the
24
- // bundled English translation happens not to contain (deep nesting, empty
25
- // objects, explicitly-undefined values).
26
- export function getLeafFieldPath(obj: TranslationNode): string[] {
27
- if (typeof obj === "string") {
28
- return [];
29
- }
30
-
31
- return Object.keys(obj).reduce((arr, key) => {
32
- const value = obj[key];
33
- if (value === undefined) {
34
- throw new Error(`Undefined value for key ${key}`);
35
- }
36
-
37
- // A string value IS the leaf, so the path ends here. Recursing into it
38
- // returns [] and the `children.map` below then contributes nothing,
39
- // which is how this function used to return an empty array for every
40
- // input — leaving `translationKeys` empty. That list is spread into
41
- // three mongoose `reason` fields (types-database provider.ts), and
42
- // mongoose registers its enum validator even for an empty list, so
43
- // every non-null reason failed validation.
44
- if (typeof value === "string") {
45
- return arr.concat(key);
46
- }
47
-
48
- const children = getLeafFieldPath(value);
49
-
50
- return arr.concat(
51
- children.map((child) => {
52
- return `${key}.${child}`;
53
- }),
54
- );
55
- }, [] as string[]);
56
- }
57
-
58
- export const translationKeys: string[] = getLeafFieldPath(translationEn);
59
-
60
- type LeafPath<Node> = {
61
- [Key in keyof Node & string]: Node[Key] extends string
62
- ? Key
63
- : `${Key}.${LeafPath<Node[Key]>}`;
64
- }[keyof Node & string];
65
-
66
- /** A leaf path in the English catalogue, so a mistyped key fails to compile. */
67
- export type TranslationKey = LeafPath<typeof translationEn>;
68
-
69
- const translationKeySet: ReadonlySet<string> = new Set(translationKeys);
70
-
71
- /** For keys that only exist at runtime, e.g. an error message. */
72
- export const isTranslationKey = (value: string): value is TranslationKey =>
73
- translationKeySet.has(value);
@@ -1,55 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- export const Languages = {
16
- arabic: "ar",
17
- azerbaijani: "az",
18
- czech: "cs",
19
- german: "de",
20
- greek: "el",
21
- english: "en",
22
- spanish: "es",
23
- finnish: "fi",
24
- french: "fr",
25
- hindi: "hi",
26
- hungarian: "hu",
27
- indonesian: "id",
28
- italian: "it",
29
- japanese: "ja",
30
- javanese: "jv",
31
- korean: "ko",
32
- malayalam: "ml",
33
- malay: "ms",
34
- dutch: "nl",
35
- norwegian: "no",
36
- polish: "pl",
37
- portugeseBrazil: "pt-BR",
38
- portuguese: "pt",
39
- romanian: "ro",
40
- russian: "ru",
41
- serbian: "sr",
42
- swedish: "sv",
43
- thai: "th",
44
- turkish: "tr",
45
- ukrainian: "uk",
46
- vietnamese: "vi",
47
- chinese: "zh-CN",
48
- } as const;
49
-
50
- export type Language = (typeof Languages)[keyof typeof Languages];
51
-
52
- export const LanguageCodes: readonly string[] = Object.values(Languages);
53
-
54
- export const isLanguage = (value: string): value is Language =>
55
- LanguageCodes.includes(value);
package/src/translator.ts DELETED
@@ -1,69 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import initializeI18n from "./i18nFrontend.js";
16
- import type { TranslationKey } from "./translationKey.js";
17
- import type { Ti18n, TranslateOptions } from "./types.js";
18
-
19
- const NAMESPACE = "translation";
20
-
21
- export interface Translator {
22
- /**
23
- * Translate a key against the current language. `options` carries
24
- * interpolation values and the `defaultValue` a widget falls back to when
25
- * its key has not been added to the bundled catalogues yet.
26
- */
27
- t(key: TranslationKey, options?: TranslateOptions): string;
28
- /**
29
- * Whether the namespace for the active language has finished loading.
30
- * Mirrors `ready` from the old react-i18next hook: widgets render an empty
31
- * label until it flips, rather than flashing a raw translation key.
32
- */
33
- isReady(): boolean;
34
- /**
35
- * Notified when the translation output could have changed — initialisation,
36
- * a namespace load, or a language switch. Returns an unsubscribe function.
37
- */
38
- subscribe(listener: () => void): () => void;
39
- readonly i18n: Ti18n;
40
- }
41
-
42
- /**
43
- * Vanilla replacement for the `useTranslation` hook: the instance's `t` plus
44
- * the three events that used to trigger a React re-render.
45
- */
46
- export const createTranslator = (existing?: Ti18n): Translator => {
47
- const i18n: Ti18n = existing ?? initializeI18n();
48
-
49
- const isReady = (): boolean =>
50
- i18n.isInitialized && i18n.hasLoadedNamespace(NAMESPACE);
51
-
52
- return {
53
- t: (key: TranslationKey, options?: TranslateOptions): string =>
54
- i18n.t(key, options),
55
- isReady,
56
- i18n,
57
- subscribe: (listener: () => void): (() => void) => {
58
- const events = ["initialized", "loaded", "languageChanged"] as const;
59
- for (const event of events) {
60
- i18n.on(event, listener);
61
- }
62
- return () => {
63
- for (const event of events) {
64
- i18n.off(event, listener);
65
- }
66
- };
67
- },
68
- };
69
- };
package/src/types.ts DELETED
@@ -1,47 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import type { TranslationKey } from "./translationKey.js";
16
-
17
- /**
18
- * Interpolation values, plus the `defaultValue` a caller falls back to when its
19
- * key is not in the catalogue. Values are substituted into `{{name}}`
20
- * placeholders.
21
- */
22
- export interface TranslateOptions {
23
- defaultValue?: string;
24
- [value: string]: unknown;
25
- }
26
-
27
- export type TranslateFn = (
28
- key: TranslationKey,
29
- options?: TranslateOptions,
30
- ) => string;
31
-
32
- export type I18nEvent = "initialized" | "loaded" | "languageChanged";
33
-
34
- /**
35
- * The slice of an i18n instance this repository uses. Both implementations
36
- * satisfy it: the browser one in `i18nFrontend.ts`, and i18next itself on the
37
- * server, where `i18next-http-middleware` needs the real thing.
38
- */
39
- export interface Ti18n {
40
- readonly language: string;
41
- readonly isInitialized: boolean;
42
- t: TranslateFn;
43
- changeLanguage(language: string): Promise<unknown>;
44
- hasLoadedNamespace(namespace: string): boolean;
45
- on(event: I18nEvent, listener: () => void): void;
46
- off(event: I18nEvent, listener: () => void): void;
47
- }
package/src/util.ts DELETED
@@ -1,25 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- export const isClientSide = (): boolean => {
16
- return !!(
17
- typeof window !== "undefined" &&
18
- window.document &&
19
- window.document.createElement
20
- );
21
- };
22
-
23
- export const isServerSide = (): boolean => {
24
- return !isClientSide();
25
- };
package/tsconfig.cjs.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.cjs.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist/cjs"
6
- },
7
- "include": [
8
- "./src/**/*.ts",
9
- "./src/**/*.json",
10
- "./src/**/*.d.ts",
11
- "./src/**/*.tsx"
12
- ],
13
- "references": [
14
- {
15
- "path": "../../dev/config/tsconfig.cjs.json"
16
- },
17
- {
18
- "path": "../util/tsconfig.cjs.json"
19
- }
20
- ]
21
- }
package/tsconfig.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.esm.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist"
6
- },
7
- "include": [
8
- "src",
9
- "src/**/*.json",
10
- "src/**/*.ts",
11
- "src/**/*.tsx",
12
- "src/**/*.d.ts"
13
- ],
14
- "references": [
15
- {
16
- "path": "../../dev/config/tsconfig.json"
17
- },
18
- {
19
- "path": "../util"
20
- }
21
- ]
22
- }