@aidc-toolkit/core 0.9.6-beta → 0.9.8-beta

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/README.md CHANGED
@@ -5,29 +5,81 @@ any of the functionality of the AIDC Toolkit. It is a required dependency for al
5
5
 
6
6
  All AIDC Toolkit packages require localization. The localization functionality in this package simplifies initialization
7
7
  and allows packages to share a common internationalization engine, whose initialization is the responsibility of the
8
- client application. Packages install their resources as follows in `i18n.ts` or similar:
8
+ client application. Each package requires its own internationalization object and each is responsible for initializing
9
+ those of its dependencies.
10
+
11
+ Packages install their resources as follows in `i18n.ts` or similar:
9
12
 
10
13
  ```typescript
11
- import { i18nAddResourceBundle, i18next } from "@aidc-toolkit/core";
12
- import { localeStrings as enLocaleStrings } from "./en/locale_strings.js";
14
+ import { i18nAssertValidResources, i18nCoreInit, type I18NEnvironment } from "@aidc-toolkit/core";
15
+ import { i18nDependency1Init, dependency1Resources } from "@aidc-toolkit/dependency1";
16
+ import { i18nDependency2Init, dependency2Resources } from "@aidc-toolkit/dependency2";
17
+ import i18next from "i18next";
18
+ import { localeStrings as enLocaleStrings } from "./en/locale-strings.js";
19
+ import { localeStrings as frLocaleStrings } from "./fr/locale-strings.js";
13
20
 
14
21
  export const packageNS = "aidct_package";
15
22
 
16
- i18nAddResourceBundle("en", packageNS, enLocaleStrings);
23
+ /**
24
+ * Locale strings type is extracted from the English locale strings object.
25
+ */
26
+ export type PackageLocaleStrings = typeof enLocaleStrings;
27
+
28
+ i18nAssertValidResources(enLocaleStrings, "fr", frLocaleStrings);
29
+
30
+ /**
31
+ * Package resources.
32
+ */
33
+ export const packageResources = {
34
+ en: {
35
+ aidct_package: enLocaleStrings
36
+ },
37
+ fr: {
38
+ aidct_package: frLocaleStrings
39
+ }
40
+ };
41
+
42
+ export const i18nextPackage = i18next.createInstance();
17
43
 
18
- export default i18next;
44
+ /**
45
+ * Initialize internationalization.
46
+ *
47
+ * @param environment
48
+ * Environment in which the application is running.
49
+ *
50
+ * @param debug
51
+ * Debug setting.
52
+ *
53
+ * @returns
54
+ * Void promise.
55
+ */
56
+ export async function i18nPackageInit(environment: I18NEnvironment, debug = false): Promise<void> {
57
+ await i18nDependency1Init(environment, debug);
58
+ await i18nDependency2Init(environment, debug);
59
+ await i18nCoreInit(i18nextPackage, environment, debug, packageNS, dependency1Resources, dependency2Resources, packageResources);
60
+ }
19
61
  ```
20
62
 
21
63
  The resource types are declared in `i18next.d.ts` or similar:
22
64
 
23
65
  ```typescript
24
- import type { localeStrings } from "./en/locale_strings.js";
66
+ import type { Dependency1LocaleStrings } from "@aidc-toolkit/dependency1";
67
+ import type { Dependency2LocaleStrings } from "@aidc-toolkit/dependency2";
68
+ import type { PackageLocaleStrings } from "./i18n.js";
25
69
 
70
+ /**
71
+ * Internationalization module.
72
+ */
26
73
  declare module "i18next" {
74
+ /**
75
+ * Custom type options for this package.
76
+ */
27
77
  interface CustomTypeOptions {
78
+ defaultNS: "aidct_package";
28
79
  resources: {
29
- // Extract the type from the English locale strings object.
30
- aidct_package: typeof localeStrings;
80
+ aidct_dependency1: Dependency1LocaleStrings;
81
+ aidct_dependency2: Dependency2LocaleStrings;
82
+ aidct_package: PackageLocaleStrings;
31
83
  };
32
84
  }
33
85
  }
package/dist/index.cjs CHANGED
@@ -31,68 +31,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  I18NEnvironment: () => I18NEnvironment,
34
- i18nAddResourceBundle: () => i18nAddResourceBundle,
35
34
  i18nAssertValidResources: () => i18nAssertValidResources,
36
- i18nInit: () => i18nInit,
37
- i18next: () => i18n_default
35
+ i18nCoreInit: () => i18nCoreInit
38
36
  });
39
37
  module.exports = __toCommonJS(src_exports);
40
38
 
41
39
  // src/locale/i18n.ts
42
- var import_i18next = __toESM(require("i18next"), 1);
43
40
  var import_i18next_browser_languagedetector = __toESM(require("i18next-browser-languagedetector"), 1);
44
41
  var import_i18next_cli_language_detector = __toESM(require("i18next-cli-language-detector"), 1);
45
- var i18n_default = import_i18next.default;
46
- var pendingResourceBundles = [];
47
42
  var I18NEnvironment = /* @__PURE__ */ ((I18NEnvironment2) => {
48
43
  I18NEnvironment2[I18NEnvironment2["CLI"] = 0] = "CLI";
49
44
  I18NEnvironment2[I18NEnvironment2["Server"] = 1] = "Server";
50
45
  I18NEnvironment2[I18NEnvironment2["Browser"] = 2] = "Browser";
51
46
  return I18NEnvironment2;
52
47
  })(I18NEnvironment || {});
53
- async function i18nInit(environment, debug = false) {
54
- let initialized;
55
- if (pendingResourceBundles !== void 0) {
56
- initialized = true;
57
- let module2;
58
- switch (environment) {
59
- case 0 /* CLI */:
60
- module2 = import_i18next_cli_language_detector.default;
61
- break;
62
- case 2 /* Browser */:
63
- module2 = import_i18next_browser_languagedetector.default;
64
- break;
65
- default:
66
- throw new Error("Not supported");
67
- }
68
- const initResourceBundles = pendingResourceBundles;
69
- pendingResourceBundles = void 0;
70
- await import_i18next.default.use(module2).init({
71
- fallbackLng: "en",
72
- debug,
73
- resources: {}
74
- }).then(() => {
75
- import_i18next.default.services.formatter?.add("toLowerCase", (value) => typeof value === "string" ? value.toLowerCase() : String(value));
76
- for (const initResourceBundle of initResourceBundles) {
77
- i18nAddResourceBundle(initResourceBundle.lng, initResourceBundle.ns, initResourceBundle.resources);
78
- }
79
- });
80
- } else {
81
- initialized = false;
82
- }
83
- return initialized;
84
- }
85
- function i18nAddResourceBundle(lng, ns, resources) {
86
- if (pendingResourceBundles !== void 0) {
87
- pendingResourceBundles.push({
88
- lng,
89
- ns,
90
- resources
91
- });
92
- } else {
93
- import_i18next.default.addResourceBundle(lng, ns, resources);
94
- }
95
- }
96
48
  function i18nAssertValidResources(enResources, lng, lngResources, parent) {
97
49
  const enResourcesMap = new Map(Object.entries(enResources));
98
50
  const lngResourcesMap = new Map(Object.entries(lngResources));
@@ -118,11 +70,47 @@ function i18nAssertValidResources(enResources, lng, lngResources, parent) {
118
70
  }
119
71
  }
120
72
  }
73
+ function toLowerCase(s) {
74
+ return s.split(" ").map((word) => /[a-z]/.test(word) ? word.toLowerCase() : word).join(" ");
75
+ }
76
+ async function i18nCoreInit(i18next, environment, debug, defaultNS, ...resources) {
77
+ if (!i18next.isInitialized) {
78
+ const mergedResource = {};
79
+ for (const resource of resources) {
80
+ for (const [language, resourceLanguage] of Object.entries(resource)) {
81
+ if (!(language in mergedResource)) {
82
+ mergedResource[language] = {};
83
+ }
84
+ const mergedResourceLanguage = mergedResource[language];
85
+ for (const [namespace, resourceKey] of Object.entries(resourceLanguage)) {
86
+ mergedResourceLanguage[namespace] = resourceKey;
87
+ }
88
+ }
89
+ }
90
+ let module2;
91
+ switch (environment) {
92
+ case 0 /* CLI */:
93
+ module2 = import_i18next_cli_language_detector.default;
94
+ break;
95
+ case 2 /* Browser */:
96
+ module2 = import_i18next_browser_languagedetector.default;
97
+ break;
98
+ default:
99
+ throw new Error("Not supported");
100
+ }
101
+ await i18next.use(module2).init({
102
+ debug,
103
+ resources: mergedResource,
104
+ fallbackLng: "en",
105
+ defaultNS
106
+ }).then(() => {
107
+ i18next.services.formatter?.add("toLowerCase", (value) => typeof value === "string" ? toLowerCase(value) : String(value));
108
+ });
109
+ }
110
+ }
121
111
  // Annotate the CommonJS export names for ESM import in node:
122
112
  0 && (module.exports = {
123
113
  I18NEnvironment,
124
- i18nAddResourceBundle,
125
114
  i18nAssertValidResources,
126
- i18nInit,
127
- i18next
115
+ i18nCoreInit
128
116
  });
package/dist/index.d.cts CHANGED
@@ -1,5 +1,4 @@
1
- import i18next from 'i18next';
2
- export { default as i18next } from 'i18next';
1
+ import { i18n, Resource } from 'i18next';
3
2
 
4
3
  /**
5
4
  * Internationalization operating environment.
@@ -18,32 +17,6 @@ declare enum I18NEnvironment {
18
17
  */
19
18
  Browser = 2
20
19
  }
21
- /**
22
- * Initialize internationalization.
23
- *
24
- * @param environment
25
- * Environment in which the application is running.
26
- *
27
- * @param debug
28
- * Debug setting.
29
- *
30
- * @returns
31
- * True if initialization was completed, false if skipped (already initialized).
32
- */
33
- declare function i18nInit(environment: I18NEnvironment, debug?: boolean): Promise<boolean>;
34
- /**
35
- * Add a resource bundle.
36
- *
37
- * @param lng
38
- * Language.
39
- *
40
- * @param ns
41
- * Namespace.
42
- *
43
- * @param resources
44
- * Resources.
45
- */
46
- declare function i18nAddResourceBundle(lng: string, ns: string, resources: object): void;
47
20
  /**
48
21
  * Assert that language resources are a type match for English (default) resources.
49
22
  *
@@ -60,5 +33,28 @@ declare function i18nAddResourceBundle(lng: string, ns: string, resources: objec
60
33
  * Parent key name (set recursively).
61
34
  */
62
35
  declare function i18nAssertValidResources(enResources: object, lng: string, lngResources: object, parent?: string): void;
36
+ /**
37
+ * Initialize internationalization.
38
+ *
39
+ * @param i18next
40
+ * Internationalization object. As multiple objects exists, this parameter represents the one for the module for which
41
+ * internationalization is being initialized.
42
+ *
43
+ * @param environment
44
+ * Environment in which the application is running.
45
+ *
46
+ * @param debug
47
+ * Debug setting.
48
+ *
49
+ * @param defaultNS
50
+ * Default namespace.
51
+ *
52
+ * @param resources
53
+ * Resources.
54
+ *
55
+ * @returns
56
+ * Void promise.
57
+ */
58
+ declare function i18nCoreInit(i18next: i18n, environment: I18NEnvironment, debug: boolean, defaultNS: string, ...resources: Resource[]): Promise<void>;
63
59
 
64
- export { I18NEnvironment, i18nAddResourceBundle, i18nAssertValidResources, i18nInit };
60
+ export { I18NEnvironment, i18nAssertValidResources, i18nCoreInit };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import i18next from 'i18next';
2
- export { default as i18next } from 'i18next';
1
+ import { i18n, Resource } from 'i18next';
3
2
 
4
3
  /**
5
4
  * Internationalization operating environment.
@@ -18,32 +17,6 @@ declare enum I18NEnvironment {
18
17
  */
19
18
  Browser = 2
20
19
  }
21
- /**
22
- * Initialize internationalization.
23
- *
24
- * @param environment
25
- * Environment in which the application is running.
26
- *
27
- * @param debug
28
- * Debug setting.
29
- *
30
- * @returns
31
- * True if initialization was completed, false if skipped (already initialized).
32
- */
33
- declare function i18nInit(environment: I18NEnvironment, debug?: boolean): Promise<boolean>;
34
- /**
35
- * Add a resource bundle.
36
- *
37
- * @param lng
38
- * Language.
39
- *
40
- * @param ns
41
- * Namespace.
42
- *
43
- * @param resources
44
- * Resources.
45
- */
46
- declare function i18nAddResourceBundle(lng: string, ns: string, resources: object): void;
47
20
  /**
48
21
  * Assert that language resources are a type match for English (default) resources.
49
22
  *
@@ -60,5 +33,28 @@ declare function i18nAddResourceBundle(lng: string, ns: string, resources: objec
60
33
  * Parent key name (set recursively).
61
34
  */
62
35
  declare function i18nAssertValidResources(enResources: object, lng: string, lngResources: object, parent?: string): void;
36
+ /**
37
+ * Initialize internationalization.
38
+ *
39
+ * @param i18next
40
+ * Internationalization object. As multiple objects exists, this parameter represents the one for the module for which
41
+ * internationalization is being initialized.
42
+ *
43
+ * @param environment
44
+ * Environment in which the application is running.
45
+ *
46
+ * @param debug
47
+ * Debug setting.
48
+ *
49
+ * @param defaultNS
50
+ * Default namespace.
51
+ *
52
+ * @param resources
53
+ * Resources.
54
+ *
55
+ * @returns
56
+ * Void promise.
57
+ */
58
+ declare function i18nCoreInit(i18next: i18n, environment: I18NEnvironment, debug: boolean, defaultNS: string, ...resources: Resource[]): Promise<void>;
63
59
 
64
- export { I18NEnvironment, i18nAddResourceBundle, i18nAssertValidResources, i18nInit };
60
+ export { I18NEnvironment, i18nAssertValidResources, i18nCoreInit };
package/dist/index.js CHANGED
@@ -1,58 +1,12 @@
1
1
  // src/locale/i18n.ts
2
- import i18next from "i18next";
3
2
  import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
4
3
  import I18nextCLILanguageDetector from "i18next-cli-language-detector";
5
- var i18n_default = i18next;
6
- var pendingResourceBundles = [];
7
4
  var I18NEnvironment = /* @__PURE__ */ ((I18NEnvironment2) => {
8
5
  I18NEnvironment2[I18NEnvironment2["CLI"] = 0] = "CLI";
9
6
  I18NEnvironment2[I18NEnvironment2["Server"] = 1] = "Server";
10
7
  I18NEnvironment2[I18NEnvironment2["Browser"] = 2] = "Browser";
11
8
  return I18NEnvironment2;
12
9
  })(I18NEnvironment || {});
13
- async function i18nInit(environment, debug = false) {
14
- let initialized;
15
- if (pendingResourceBundles !== void 0) {
16
- initialized = true;
17
- let module;
18
- switch (environment) {
19
- case 0 /* CLI */:
20
- module = I18nextCLILanguageDetector;
21
- break;
22
- case 2 /* Browser */:
23
- module = I18nextBrowserLanguageDetector;
24
- break;
25
- default:
26
- throw new Error("Not supported");
27
- }
28
- const initResourceBundles = pendingResourceBundles;
29
- pendingResourceBundles = void 0;
30
- await i18next.use(module).init({
31
- fallbackLng: "en",
32
- debug,
33
- resources: {}
34
- }).then(() => {
35
- i18next.services.formatter?.add("toLowerCase", (value) => typeof value === "string" ? value.toLowerCase() : String(value));
36
- for (const initResourceBundle of initResourceBundles) {
37
- i18nAddResourceBundle(initResourceBundle.lng, initResourceBundle.ns, initResourceBundle.resources);
38
- }
39
- });
40
- } else {
41
- initialized = false;
42
- }
43
- return initialized;
44
- }
45
- function i18nAddResourceBundle(lng, ns, resources) {
46
- if (pendingResourceBundles !== void 0) {
47
- pendingResourceBundles.push({
48
- lng,
49
- ns,
50
- resources
51
- });
52
- } else {
53
- i18next.addResourceBundle(lng, ns, resources);
54
- }
55
- }
56
10
  function i18nAssertValidResources(enResources, lng, lngResources, parent) {
57
11
  const enResourcesMap = new Map(Object.entries(enResources));
58
12
  const lngResourcesMap = new Map(Object.entries(lngResources));
@@ -78,10 +32,46 @@ function i18nAssertValidResources(enResources, lng, lngResources, parent) {
78
32
  }
79
33
  }
80
34
  }
35
+ function toLowerCase(s) {
36
+ return s.split(" ").map((word) => /[a-z]/.test(word) ? word.toLowerCase() : word).join(" ");
37
+ }
38
+ async function i18nCoreInit(i18next, environment, debug, defaultNS, ...resources) {
39
+ if (!i18next.isInitialized) {
40
+ const mergedResource = {};
41
+ for (const resource of resources) {
42
+ for (const [language, resourceLanguage] of Object.entries(resource)) {
43
+ if (!(language in mergedResource)) {
44
+ mergedResource[language] = {};
45
+ }
46
+ const mergedResourceLanguage = mergedResource[language];
47
+ for (const [namespace, resourceKey] of Object.entries(resourceLanguage)) {
48
+ mergedResourceLanguage[namespace] = resourceKey;
49
+ }
50
+ }
51
+ }
52
+ let module;
53
+ switch (environment) {
54
+ case 0 /* CLI */:
55
+ module = I18nextCLILanguageDetector;
56
+ break;
57
+ case 2 /* Browser */:
58
+ module = I18nextBrowserLanguageDetector;
59
+ break;
60
+ default:
61
+ throw new Error("Not supported");
62
+ }
63
+ await i18next.use(module).init({
64
+ debug,
65
+ resources: mergedResource,
66
+ fallbackLng: "en",
67
+ defaultNS
68
+ }).then(() => {
69
+ i18next.services.formatter?.add("toLowerCase", (value) => typeof value === "string" ? toLowerCase(value) : String(value));
70
+ });
71
+ }
72
+ }
81
73
  export {
82
74
  I18NEnvironment,
83
- i18nAddResourceBundle,
84
75
  i18nAssertValidResources,
85
- i18nInit,
86
- i18n_default as i18next
76
+ i18nCoreInit
87
77
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/core",
3
- "version": "0.9.6-beta",
3
+ "version": "0.9.8-beta",
4
4
  "description": "Core functionality for AIDC Toolkit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,16 +24,16 @@
24
24
  "build-doc": "npm run build && tsc src/index.ts --outDir dist --target esnext --moduleResolution nodenext --module nodenext --emitDeclarationOnly --declaration --declarationMap"
25
25
  },
26
26
  "devDependencies": {
27
- "@aidc-toolkit/dev": "^0.9.6-beta",
27
+ "@aidc-toolkit/dev": "^0.9.8-beta",
28
28
  "eslint": "^9.16.0",
29
29
  "ts-node": "^10.9.2",
30
30
  "tsup": "^8.3.5",
31
31
  "typescript": "^5.7.2"
32
32
  },
33
33
  "dependencies": {
34
- "@rollup/rollup-linux-x64-gnu": "^4.28.0",
35
- "i18next": "^24.0.5",
36
- "i18next-browser-languagedetector": "^8.0.0",
34
+ "@rollup/rollup-linux-x64-gnu": "^4.28.1",
35
+ "i18next": "^24.1.0",
36
+ "i18next-browser-languagedetector": "^8.0.2",
37
37
  "i18next-cli-language-detector": "^1.1.8"
38
38
  }
39
39
  }
package/src/index.ts CHANGED
@@ -1,2 +1 @@
1
1
  export * from "./locale/i18n.js";
2
- export { default as i18next } from "./locale/i18n.js";
@@ -1,23 +1,7 @@
1
- import i18next, { type LanguageDetectorModule } from "i18next";
1
+ import type { i18n, LanguageDetectorModule, Resource } from "i18next";
2
2
  import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
3
3
  import I18nextCLILanguageDetector from "i18next-cli-language-detector";
4
4
 
5
- export default i18next;
6
-
7
- /**
8
- * Internal type to maintain resource bundles added before initialization.
9
- */
10
- interface ResourceBundle {
11
- lng: string;
12
- ns: string;
13
- resources: object;
14
- }
15
-
16
- /**
17
- * Internal array to maintain resource bundles added before initialization.
18
- */
19
- let pendingResourceBundles: ResourceBundle[] | undefined = [];
20
-
21
5
  /**
22
6
  * Internationalization operating environment.
23
7
  */
@@ -38,91 +22,6 @@ export enum I18NEnvironment {
38
22
  Browser
39
23
  }
40
24
 
41
- /**
42
- * Initialize internationalization.
43
- *
44
- * @param environment
45
- * Environment in which the application is running.
46
- *
47
- * @param debug
48
- * Debug setting.
49
- *
50
- * @returns
51
- * True if initialization was completed, false if skipped (already initialized).
52
- */
53
- export async function i18nInit(environment: I18NEnvironment, debug = false): Promise<boolean> {
54
- let initialized: boolean;
55
-
56
- // Skip if initialization is not pending.
57
- if (pendingResourceBundles !== undefined) {
58
- initialized = true;
59
-
60
- let module: Parameters<typeof i18next.use>[0];
61
-
62
- switch (environment) {
63
- case I18NEnvironment.CLI:
64
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Pending resolution of https://github.com/neet/i18next-cli-language-detector/issues/281.
65
- module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;
66
- break;
67
-
68
- case I18NEnvironment.Browser:
69
- module = I18nextBrowserLanguageDetector;
70
- break;
71
-
72
- default:
73
- throw new Error("Not supported");
74
- }
75
-
76
- const initResourceBundles = pendingResourceBundles;
77
-
78
- // No need to manage pending resource bundles past this point.
79
- pendingResourceBundles = undefined;
80
-
81
- await i18next.use(module).init({
82
- fallbackLng: "en",
83
- debug,
84
- resources: {}
85
- }).then(() => {
86
- // Add toLowerCase function.
87
- i18next.services.formatter?.add("toLowerCase", value => typeof value === "string" ? value.toLowerCase() : String(value));
88
-
89
- // Add pending resource bundles.
90
- for (const initResourceBundle of initResourceBundles) {
91
- i18nAddResourceBundle(initResourceBundle.lng, initResourceBundle.ns, initResourceBundle.resources);
92
- }
93
- });
94
- } else {
95
- initialized = false;
96
- }
97
-
98
- return initialized;
99
- }
100
-
101
- /**
102
- * Add a resource bundle.
103
- *
104
- * @param lng
105
- * Language.
106
- *
107
- * @param ns
108
- * Namespace.
109
- *
110
- * @param resources
111
- * Resources.
112
- */
113
- export function i18nAddResourceBundle(lng: string, ns: string, resources: object): void {
114
- if (pendingResourceBundles !== undefined) {
115
- pendingResourceBundles.push({
116
- lng,
117
- ns,
118
- resources
119
- });
120
- } else {
121
- // Already initialized; add resource bundle directly.
122
- i18next.addResourceBundle(lng, ns, resources);
123
- }
124
- }
125
-
126
25
  /**
127
26
  * Assert that language resources are a type match for English (default) resources.
128
27
  *
@@ -158,7 +57,7 @@ export function i18nAssertValidResources(enResources: object, lng: string, lngRe
158
57
  if (enValueType === "object") {
159
58
  i18nAssertValidResources(enValue, lng, lngValue, `${parent === undefined ? "" : `${parent}.`}${enKey}`);
160
59
  }
161
- // Locale falls back to raw language so ignore if missing.
60
+ // Locale falls back to raw language so ignore if missing.
162
61
  } else if (!isLocale) {
163
62
  throw new Error(`Missing key ${parent === undefined ? "" : `${parent}.`}${enKey} from ${lng} resources`);
164
63
  }
@@ -170,3 +69,90 @@ export function i18nAssertValidResources(enResources: object, lng: string, lngRe
170
69
  }
171
70
  }
172
71
  }
72
+
73
+ /**
74
+ * Convert a string to lower case, skipping words that are all upper case.
75
+ *
76
+ * @param s
77
+ * String.
78
+ *
79
+ * @returns
80
+ * Lower case string.
81
+ */
82
+ function toLowerCase(s: string): string {
83
+ // Words with no lower case letters are preserved as they are likely mnemonics.
84
+ return s.split(" ").map(word => /[a-z]/.test(word) ? word.toLowerCase() : word).join(" ");
85
+ }
86
+
87
+ /**
88
+ * Initialize internationalization.
89
+ *
90
+ * @param i18next
91
+ * Internationalization object. As multiple objects exists, this parameter represents the one for the module for which
92
+ * internationalization is being initialized.
93
+ *
94
+ * @param environment
95
+ * Environment in which the application is running.
96
+ *
97
+ * @param debug
98
+ * Debug setting.
99
+ *
100
+ * @param defaultNS
101
+ * Default namespace.
102
+ *
103
+ * @param resources
104
+ * Resources.
105
+ *
106
+ * @returns
107
+ * Void promise.
108
+ */
109
+ export async function i18nCoreInit(i18next: i18n, environment: I18NEnvironment, debug: boolean, defaultNS: string, ...resources: Resource[]): Promise<void> {
110
+ // Initialization may be called more than once.
111
+ if (!i18next.isInitialized) {
112
+ const mergedResource: Resource = {};
113
+
114
+ // Merge resources.
115
+ for (const resource of resources) {
116
+ // Merge languages.
117
+ for (const [language, resourceLanguage] of Object.entries(resource)) {
118
+ if (!(language in mergedResource)) {
119
+ mergedResource[language] = {};
120
+ }
121
+
122
+ const mergedResourceLanguage = mergedResource[language];
123
+
124
+ // Merge namespaces.
125
+ for (const [namespace, resourceKey] of Object.entries(resourceLanguage)) {
126
+ mergedResourceLanguage[namespace] = resourceKey;
127
+ }
128
+ }
129
+ }
130
+
131
+ let module: Parameters<typeof i18next.use>[0];
132
+
133
+ switch (environment) {
134
+ case I18NEnvironment.CLI:
135
+ // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
136
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
137
+ module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;
138
+ break;
139
+
140
+ case I18NEnvironment.Browser:
141
+ module = I18nextBrowserLanguageDetector;
142
+ break;
143
+
144
+ default:
145
+ throw new Error("Not supported");
146
+ }
147
+
148
+ await i18next.use(module).init({
149
+ debug,
150
+ resources: mergedResource,
151
+ fallbackLng: "en",
152
+ defaultNS
153
+ }).then(() => {
154
+ // Add toLowerCase function.
155
+ i18next.services.formatter?.add("toLowerCase", value => typeof value === "string" ? toLowerCase(value) : String(value));
156
+ });
157
+ }
158
+ }
File without changes