@aidc-toolkit/core 1.0.38-beta → 1.0.39-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
@@ -32,7 +32,9 @@ All AIDC Toolkit packages require internationalization. The localization functio
32
32
  >
33
33
  > For a complete example, including how to use application-specific resource bundles, see the AIDC Toolkit [demo source](https://github.com/aidc-toolkit/demo/tree/main/src/locale).
34
34
 
35
- Packages install their resources as follows in `i18n.ts` or similar. Note that "dependency1" and "dependency2" are placeholders for the names of the packages on which the package depends, and "package" is the package itself.
35
+ ### Initialization
36
+
37
+ Packages initialize their resources as follows in `i18n.ts` or similar. Note that "dependency1" and "dependency2" are placeholders for the names of the packages on which the package depends, and "package" is the package itself.
36
38
 
37
39
  ```typescript
38
40
  import { i18nCoreInit, type I18nEnvironment, i18nInit } from "@aidc-toolkit/core";
@@ -110,7 +112,9 @@ declare module "i18next" {
110
112
 
111
113
  The declaration in `i18next.d.ts` exposes the resources of the dependencies to the package. The initialization process merges all the resources into a single resource bundle matching the declaration.
112
114
 
113
- Support is available for the following environments:
115
+ ### Environment-Specific Language Detection
116
+
117
+ Language detection is available for the following environments:
114
118
 
115
119
  - [Command-line interface](#command-line-interface)
116
120
  - Unit tests
@@ -118,7 +122,19 @@ Support is available for the following environments:
118
122
  - Web server - **NOT YET IMPLEMENTED**
119
123
  - [Web browser](#web-browser)
120
124
 
121
- ### Command-Line Interface
125
+ When a package's `i18next` object is initialized:
126
+
127
+ Language detection starts with the full locale as provided by the environment then falls back as follows:
128
+
129
+ - the full locale minus the regional variant if any;
130
+ - the full locale minus the regional variant and the region if any; and
131
+ - the first locale as defined in the default resource bundle.
132
+
133
+ Caching (typically via the `i18nextLng` attribute in some form of storage) is disabled. Depending on the detector, this may still allow reading from a cache (e.g., the browser detector from local storage or session storage) but not writing. This leaves it to the application to decide how and when to persist the language setting.
134
+
135
+ #### Command-Line Interface
136
+
137
+ Language detection is implemented using [I18nextCLILanguageDetector](https://github.com/neet/i18next-cli-language-detector).
122
138
 
123
139
  Initializing internationalization for a command-line interface application is straightforward:
124
140
 
@@ -126,7 +142,9 @@ Initializing internationalization for a command-line interface application is st
126
142
  await i18nPackageInit(I18nEnvironment.CLI);
127
143
  ```
128
144
 
129
- ### Web Browser
145
+ #### Web Browser
146
+
147
+ Language detection is implemented using [I18nextBrowserLanguageDetector](https://github.com/i18next/i18next-browser-languageDetector).
130
148
 
131
149
  Initializing internationalization for a web browser requires awaiting the fulfillment of the `Promise` returned by the call to the initialization function before rendering any content. For example, in the React framework, this would be done before creating the root:
132
150
 
@@ -167,7 +185,7 @@ Parts of the AIDC Toolkit require persistent application data management, but th
167
185
 
168
186
  The application data management functionality in this package provides a simple and consistent mechanism for managing application data. While not suitable for high-volumne or transactional data, it's sufficient for most applications that require simple key-value storage.
169
187
 
170
- The [`AppData`](https://aidc-toolkit.com/api/Core/type-aliases/AppData.html) type alias is a simple constrained type of `string`, `number`, `boolean`, or `object`. An object type must be one of:
188
+ The [`AppData`](https://aidc-toolkit.com/v1.0/api/Core/type-aliases/AppData.html) type alias is a simple constrained type of `string`, `number`, `boolean`, or `object`. An object type must be one of:
171
189
 
172
190
  - `Date`;
173
191
  - `Uint8Array`;
@@ -181,13 +199,13 @@ Two functions `encodeAppData()` and `decodeAppData()` are provided to convert be
181
199
  - encoding `Date` objects as ISO 8601 strings preceded by the string "dateTime:"; and
182
200
  - encoding `Uint8Array` objects as [Base64](https://developer.mozilla.org/en-US/docs/Glossary/Base64) strings preceded by the string "binary:".
183
201
 
184
- The functions are generally not called directly. Rather, they are called automatically by the [`ReadOnlyAppDataStorage`](https://aidc-toolkit.com/api/Core/classes/ReadOnlyAppDataStorage.html) and [`AppDataStorage`](https://aidc-toolkit.com/api/Core/classes/AppDataStorage.html) classes, which are used to manage application data in the AIDC Toolkit packages.
202
+ The functions are generally not called directly. Rather, they are called automatically by the [`ReadOnlyAppDataStorage`](https://aidc-toolkit.com/v1.0/api/Core/classes/ReadOnlyAppDataStorage.html) and [`AppDataStorage`](https://aidc-toolkit.com/v1.0/api/Core/classes/AppDataStorage.html) classes, which are used to manage application data in the AIDC Toolkit packages.
185
203
 
186
204
  Internally, each storage provider defines whether it supports binary data natively. If so, a request to read binary data will return raw content as `Uint8Array` from the underlying storage mechanism and a request to write binary data will write the `Uint8Array` as-is. This applies only to top-level read and write operations, not to `Uint8Array` values stored in nested objects.
187
205
 
188
206
  All storage providers take a path argument, which defines an implementation-specific location for the data. The following storage providers are provided by default:
189
207
 
190
- - [`LocalAppDataStorage`](https://aidc-toolkit.com/api/Core/variables/LocalAppDataStorage.html)
208
+ - [`LocalAppDataStorage`](https://aidc-toolkit.com/v1.0/api/Core/variables/LocalAppDataStorage.html)
191
209
  - Not a class, but rather a `Promise` of a constructor to one of the following implementations:
192
210
  - File-based storage
193
211
  - Supports binary data.
@@ -195,11 +213,11 @@ All storage providers take a path argument, which defines an implementation-spec
195
213
  - Browser-based storage
196
214
  - Does not support binary data.
197
215
  - Maps the path by prepending it plus `/` to the key for use in [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).
198
- - [`RemoteAppDataStorage`](https://aidc-toolkit.com/api/Core/classes/RemoteAppDataStorage.html)
216
+ - [`RemoteAppDataStorage`](https://aidc-toolkit.com/v1.0/api/Core/classes/RemoteAppDataStorage.html)
199
217
  - Read-only.
200
218
  - Supports binary data.
201
219
  - Maps the path to a base URL.
202
220
 
203
221
  ## Caching
204
222
 
205
- The [`Cache`](https://aidc-toolkit.com/api/Core/classes/Cache.html) class provides a simple cache that can be used to maintain synchronization with an external source.
223
+ The [`Cache`](https://aidc-toolkit.com/v1.0/api/Core/classes/Cache.html) class provides a simple cache that can be used to maintain synchronization with an external source.
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/locale/i18n.ts"],"names":[],"mappings":"AAAA,OAAgB,EACZ,KAAK,IAAI,EAKT,KAAK,QAAQ,EAChB,MAAM,SAAS,CAAC;AAGjB,OAAO,iBAAiB,MAAM,0BAA0B,CAAC;AAGzD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,MAAM,CAAC;CAC3C;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;IACzB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CAEG,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;AAgB1E,eAAO,MAAM,MAAM,eAAe,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,iBAAiB,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAOhC,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,IAA+B,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,qBAAqB,EAAE,QAAQ,EAAE,GAAG,mBAAmB,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiErQ;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEjG"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/locale/i18n.ts"],"names":[],"mappings":"AAAA,OAAgB,EACZ,KAAK,IAAI,EAKT,KAAK,QAAQ,EAChB,MAAM,SAAS,CAAC;AAGjB,OAAO,iBAAiB,MAAM,0BAA0B,CAAC;AAGzD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,MAAM,CAAC;CAC3C;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;IACzB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CAEG,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;AAkB1E,eAAO,MAAM,MAAM,eAAe,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,iBAAiB,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAOhC,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,IAA+B,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,qBAAqB,EAAE,QAAQ,EAAE,GAAG,mBAAmB,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4ErQ;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,eAAe,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEjG"}
@@ -23,15 +23,17 @@ export const I18nEnvironments = {
23
23
  /**
24
24
  * Convert a string to lower case, skipping words that are all upper case.
25
25
  *
26
- * @param s
27
- * String.
26
+ * @param value
27
+ * Value.
28
28
  *
29
29
  * @returns
30
- * Lower case string.
30
+ * Lower case string if value is a string. If not, value is returned as a string but not converted to lower case.
31
31
  */
32
- function toLowerCase(s) {
33
- // Words with no lower case letters are preserved as they are likely mnemonics.
34
- return s.split(" ").map(word => /[a-z]/u.test(word) ? word.toLowerCase() : word).join(" ");
32
+ function toLowerCase(value) {
33
+ return typeof value === "string" ?
34
+ // Words with no lower case letters are preserved as they are likely mnemonics.
35
+ value.split(" ").map(word => /[a-z]/u.test(word) ? word.toLowerCase() : word).join(" ") :
36
+ String(value);
35
37
  }
36
38
  export const coreNS = "aidct_core";
37
39
  /**
@@ -91,35 +93,48 @@ export async function i18nInit(i18next, environment, debug, defaultNS, defaultRe
91
93
  const mergedLanguageResourceBundle = mergedResourceBundle[language];
92
94
  // Merge namespaces.
93
95
  for (const [namespace, resourceKey] of Object.entries(languageResourceBundle)) {
96
+ if (namespace in mergedLanguageResourceBundle) {
97
+ // Error prior to internationalization initialization; no localization possible.
98
+ throw new Error(`Duplicate namespace ${namespace} in merged resource bundle for language ${language}`);
99
+ }
94
100
  mergedLanguageResourceBundle[namespace] = resourceKey;
95
101
  }
96
102
  }
97
103
  }
98
104
  mergeResourceBundle(defaultResourceBundle);
99
105
  // Initialize dependencies and merge their resource bundles.
100
- await Promise.all(i18nDependencyInits.map(async (i18nDependencyInit) => i18nDependencyInit(environment, debug).then(mergeResourceBundle))).then(() => {
101
- let module;
102
- switch (environment) {
103
- case I18nEnvironments.CLI:
104
- // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
105
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
106
- module = I18nextCLILanguageDetector;
107
- break;
108
- case I18nEnvironments.Browser:
109
- module = I18nextBrowserLanguageDetector;
110
- break;
111
- default:
112
- throw new Error("Not supported");
113
- }
114
- return module;
115
- }).then(async (module) => i18next.use(module).init({
106
+ for (const i18nDependencyInit of i18nDependencyInits) {
107
+ // eslint-disable-next-line no-await-in-loop -- Dependencies must initialized first.
108
+ await i18nDependencyInit(environment, debug).then(mergeResourceBundle);
109
+ }
110
+ let module;
111
+ switch (environment) {
112
+ case I18nEnvironments.CLI:
113
+ // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
114
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
115
+ module = I18nextCLILanguageDetector;
116
+ break;
117
+ case I18nEnvironments.Browser:
118
+ module = I18nextBrowserLanguageDetector;
119
+ break;
120
+ default:
121
+ throw new Error("Not supported");
122
+ }
123
+ await i18next.use(module).init({
116
124
  debug,
125
+ defaultNS,
117
126
  resources: mergedResourceBundle,
118
- fallbackLng: "en",
119
- defaultNS
120
- })).then(() => {
121
- // Add toLowerCase function.
122
- i18next.services.formatter?.add("toLowerCase", value => typeof value === "string" ? toLowerCase(value) : String(value));
127
+ // Allow fallback by removing variant code then country code until match is found.
128
+ nonExplicitSupportedLngs: true,
129
+ // Fallback to first language defined.
130
+ fallbackLng: Object.keys(mergedResourceBundle)[0],
131
+ detection: {
132
+ // Disabling cache allows read but requires explicit saving of i18nextLng attribute (e.g., via UI).
133
+ caches: []
134
+ }
135
+ }).then(() => {
136
+ // Add toLowerCase formatter.
137
+ i18next.services.formatter?.add("toLowerCase", toLowerCase);
123
138
  });
124
139
  }
125
140
  return defaultResourceBundle;
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/locale/i18n.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/locale/i18n.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/core",
3
- "version": "1.0.38-beta",
3
+ "version": "1.0.39-beta",
4
4
  "description": "Core functionality for AIDC Toolkit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "build:doc": "npm run build:non-prod"
29
29
  },
30
30
  "devDependencies": {
31
- "@aidc-toolkit/dev": "1.0.37-beta"
31
+ "@aidc-toolkit/dev": "1.0.38-beta"
32
32
  },
33
33
  "dependencies": {
34
34
  "base64-js": "^1.5.1",
@@ -51,15 +51,17 @@ export type I18nEnvironment = typeof I18nEnvironments[I18nEnvironmentKey];
51
51
  /**
52
52
  * Convert a string to lower case, skipping words that are all upper case.
53
53
  *
54
- * @param s
55
- * String.
54
+ * @param value
55
+ * Value.
56
56
  *
57
57
  * @returns
58
- * Lower case string.
58
+ * Lower case string if value is a string. If not, value is returned as a string but not converted to lower case.
59
59
  */
60
- function toLowerCase(s: string): string {
61
- // Words with no lower case letters are preserved as they are likely mnemonics.
62
- return s.split(" ").map(word => /[a-z]/u.test(word) ? word.toLowerCase() : word).join(" ");
60
+ function toLowerCase(value: unknown): string {
61
+ return typeof value === "string" ?
62
+ // Words with no lower case letters are preserved as they are likely mnemonics.
63
+ value.split(" ").map(word => /[a-z]/u.test(word) ? word.toLowerCase() : word).join(" ") :
64
+ String(value);
63
65
  }
64
66
 
65
67
  export const coreNS = "aidct_core";
@@ -131,6 +133,11 @@ export async function i18nInit(i18next: i18n, environment: I18nEnvironment, debu
131
133
 
132
134
  // Merge namespaces.
133
135
  for (const [namespace, resourceKey] of Object.entries(languageResourceBundle)) {
136
+ if (namespace in mergedLanguageResourceBundle) {
137
+ // Error prior to internationalization initialization; no localization possible.
138
+ throw new Error(`Duplicate namespace ${namespace} in merged resource bundle for language ${language}`);
139
+ }
140
+
134
141
  mergedLanguageResourceBundle[namespace] = resourceKey;
135
142
  }
136
143
  }
@@ -139,37 +146,43 @@ export async function i18nInit(i18next: i18n, environment: I18nEnvironment, debu
139
146
  mergeResourceBundle(defaultResourceBundle);
140
147
 
141
148
  // Initialize dependencies and merge their resource bundles.
142
- await Promise.all(i18nDependencyInits.map(async i18nDependencyInit =>
143
- i18nDependencyInit(environment, debug).then(mergeResourceBundle))
144
- ).then(() => {
145
- let module: Module | Newable<Module> | NewableModule<Module>;
146
-
147
- switch (environment) {
148
- case I18nEnvironments.CLI:
149
- // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
150
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
151
- module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;
152
- break;
153
-
154
- case I18nEnvironments.Browser:
155
- module = I18nextBrowserLanguageDetector;
156
- break;
157
-
158
- default:
159
- throw new Error("Not supported");
160
- }
149
+ for (const i18nDependencyInit of i18nDependencyInits) {
150
+ // eslint-disable-next-line no-await-in-loop -- Dependencies must initialized first.
151
+ await i18nDependencyInit(environment, debug).then(mergeResourceBundle);
152
+ }
153
+
154
+ let module: Module | Newable<Module> | NewableModule<Module>;
155
+
156
+ switch (environment) {
157
+ case I18nEnvironments.CLI:
158
+ // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
159
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
160
+ module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;
161
+ break;
161
162
 
162
- return module;
163
- }).then(async module =>
164
- i18next.use(module).init({
165
- debug,
166
- resources: mergedResourceBundle,
167
- fallbackLng: "en",
168
- defaultNS
169
- })
170
- ).then(() => {
171
- // Add toLowerCase function.
172
- i18next.services.formatter?.add("toLowerCase", value => typeof value === "string" ? toLowerCase(value) : String(value));
163
+ case I18nEnvironments.Browser:
164
+ module = I18nextBrowserLanguageDetector;
165
+ break;
166
+
167
+ default:
168
+ throw new Error("Not supported");
169
+ }
170
+
171
+ await i18next.use(module).init({
172
+ debug,
173
+ defaultNS,
174
+ resources: mergedResourceBundle,
175
+ // Allow fallback by removing variant code then country code until match is found.
176
+ nonExplicitSupportedLngs: true,
177
+ // Fallback to first language defined.
178
+ fallbackLng: Object.keys(mergedResourceBundle)[0],
179
+ detection: {
180
+ // Disabling cache allows read but requires explicit saving of i18nextLng attribute (e.g., via UI).
181
+ caches: []
182
+ }
183
+ }).then(() => {
184
+ // Add toLowerCase formatter.
185
+ i18next.services.formatter?.add("toLowerCase", toLowerCase);
173
186
  });
174
187
  }
175
188