i18n-keyless-node 1.12.3 → 1.12.5
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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/package.json +2 -2
- package/dist/service.d.ts +26 -7
- package/dist/service.js +124 -76
- package/dist/types.d.ts +2 -5
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { init,
|
|
1
|
+
export { init, getAllTranslationsForAllLanguages, awaitForTranslation } from "./service";
|
|
2
2
|
export type { Translations, I18nKeylessNodeConfig, I18nKeylessNodeStore, TranslationOptions, I18nKeylessRequestBody, I18nKeylessAllTranslationsResponse, } from "./types";
|
|
3
3
|
export { type Lang, type PrimaryLang, type I18nKeylessResponse, queue } from "i18n-keyless-core";
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { init,
|
|
1
|
+
export { init, getAllTranslationsForAllLanguages, awaitForTranslation } from "./service";
|
|
2
2
|
export { queue } from "i18n-keyless-core";
|
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18n-keyless-node",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.12.
|
|
4
|
+
"version": "1.12.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"postpublish": "rm -rf ./dist && rm *.tgz"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"i18n-keyless-core": "1.12.
|
|
18
|
+
"i18n-keyless-core": "1.12.5"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@eslint/js": "^9.9.0",
|
package/dist/service.d.ts
CHANGED
|
@@ -1,18 +1,37 @@
|
|
|
1
1
|
import { type Lang, type TranslationOptions, I18nKeylessAllTranslationsResponse } from "i18n-keyless-core";
|
|
2
|
-
import { I18nKeylessNodeConfig
|
|
2
|
+
import { I18nKeylessNodeConfig } from "types";
|
|
3
3
|
/**
|
|
4
4
|
* Fetches all translations
|
|
5
5
|
* @param store - The translation store
|
|
6
6
|
* @returns Promise resolving to the translation response or void if failed
|
|
7
7
|
*/
|
|
8
|
-
export declare function getAllTranslationsForAllLanguages(
|
|
8
|
+
export declare function getAllTranslationsForAllLanguages(): Promise<I18nKeylessAllTranslationsResponse | void>;
|
|
9
9
|
export declare function init(newConfig: I18nKeylessNodeConfig): Promise<I18nKeylessNodeConfig>;
|
|
10
|
-
export declare function getTranslation(key: string, currentLanguage: Lang, options?: TranslationOptions): string;
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
11
|
+
* Core logic for fetching/retrieving a translation asynchronously.
|
|
13
12
|
* @param key - The text to translate
|
|
14
|
-
* @param
|
|
13
|
+
* @param currentLanguage - The language to translate to
|
|
14
|
+
* @param options - Optional parameters for the translation process
|
|
15
|
+
* @returns Promise resolving to the translated string or the original key
|
|
16
|
+
*/
|
|
17
|
+
declare function awaitForTranslationFn(key: string, currentLanguage: Lang, options?: TranslationOptions): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* **MANDATORY AWAIT / PROMISE HANDLING REQUIRED IN NODE.JS**
|
|
20
|
+
*
|
|
21
|
+
* Asynchronously retrieves a translation for a key, fetching from the backend if necessary.
|
|
22
|
+
* In a Node.js environment, failure to `await` this function inside a `try...catch` block
|
|
23
|
+
* or attach a `.catch()` handler WILL lead to an unhandled promise rejection if an error
|
|
24
|
+
* occurs during translation (e.g., network error, API error). This unhandled rejection
|
|
25
|
+
* is designed to cause a **FATAL ERROR** and **CRASH** the Node.js process to prevent
|
|
26
|
+
* silent failures. Ensure all calls are properly handled.
|
|
27
|
+
*
|
|
28
|
+
* **Recommendation:** Use the `@typescript-eslint/no-floating-promises` lint rule.
|
|
29
|
+
*
|
|
30
|
+
* @param key - The text to translate
|
|
31
|
+
* @param currentLanguage - The language to translate to
|
|
15
32
|
* @param options - Optional parameters for the translation process
|
|
16
|
-
* @
|
|
33
|
+
* @returns A Promise resolving to the translated string or the original key if not found/on error *after handling*.
|
|
34
|
+
* @throws Re-throws any internal error if the promise rejection is not handled by the caller.
|
|
17
35
|
*/
|
|
18
|
-
export declare const awaitForTranslation:
|
|
36
|
+
export declare const awaitForTranslation: typeof awaitForTranslationFn;
|
|
37
|
+
export {};
|
package/dist/service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { queue,
|
|
1
|
+
import { queue, api, } from "i18n-keyless-core";
|
|
2
2
|
import packageJson from "./package.json";
|
|
3
3
|
const store = {
|
|
4
4
|
translations: {
|
|
@@ -34,7 +34,7 @@ const store = {
|
|
|
34
34
|
* @param store - The translation store
|
|
35
35
|
* @returns Promise resolving to the translation response or void if failed
|
|
36
36
|
*/
|
|
37
|
-
export async function getAllTranslationsForAllLanguages(
|
|
37
|
+
export async function getAllTranslationsForAllLanguages() {
|
|
38
38
|
const config = store.config;
|
|
39
39
|
const lastRefresh = store.lastRefresh;
|
|
40
40
|
const uniqueId = store.uniqueId;
|
|
@@ -73,7 +73,7 @@ export async function getAllTranslationsForAllLanguages(store) {
|
|
|
73
73
|
}
|
|
74
74
|
queue.on("empty", () => {
|
|
75
75
|
// when each word is translated, fetch the translations for the current language
|
|
76
|
-
getAllTranslationsForAllLanguages(
|
|
76
|
+
getAllTranslationsForAllLanguages().then((res) => {
|
|
77
77
|
if (res?.ok) {
|
|
78
78
|
store.translations = res.data.translations;
|
|
79
79
|
}
|
|
@@ -96,110 +96,158 @@ export async function init(newConfig) {
|
|
|
96
96
|
newConfig.addMissingTranslations = true;
|
|
97
97
|
store.config = newConfig;
|
|
98
98
|
store.config.onInit?.(newConfig.languages.primary);
|
|
99
|
-
const response = await getAllTranslationsForAllLanguages(
|
|
99
|
+
const response = await getAllTranslationsForAllLanguages();
|
|
100
100
|
if (response?.ok) {
|
|
101
101
|
store.translations = response.data.translations;
|
|
102
102
|
}
|
|
103
103
|
return newConfig;
|
|
104
104
|
}
|
|
105
|
-
export function getTranslation(key, currentLanguage, options) {
|
|
106
|
-
if (options?.debug) {
|
|
107
|
-
console.log("getTranslation", key, currentLanguage, store.translations);
|
|
108
|
-
}
|
|
109
|
-
return getTranslationCore(key, {
|
|
110
|
-
...store,
|
|
111
|
-
config: store.config,
|
|
112
|
-
currentLanguage,
|
|
113
|
-
translations: store.translations[currentLanguage],
|
|
114
|
-
}, options);
|
|
115
|
-
}
|
|
116
105
|
/**
|
|
117
|
-
*
|
|
106
|
+
* Core logic for fetching/retrieving a translation asynchronously.
|
|
118
107
|
* @param key - The text to translate
|
|
119
|
-
* @param
|
|
108
|
+
* @param currentLanguage - The language to translate to
|
|
120
109
|
* @param options - Optional parameters for the translation process
|
|
121
|
-
* @
|
|
110
|
+
* @returns Promise resolving to the translated string or the original key
|
|
122
111
|
*/
|
|
123
|
-
|
|
112
|
+
async function awaitForTranslationFn(key, currentLanguage, options) {
|
|
113
|
+
const config = store.config;
|
|
114
|
+
const translations = store.translations;
|
|
115
|
+
const uniqueId = store.uniqueId;
|
|
116
|
+
const context = options?.context;
|
|
117
|
+
const debug = options?.debug;
|
|
124
118
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (!config.API_KEY) {
|
|
129
|
-
throw new Error("i18n-keyless: config is not initialized");
|
|
119
|
+
// Ensure config is initialized enough for either API call or custom handler
|
|
120
|
+
if (!config.API_KEY && !config.handleTranslate) {
|
|
121
|
+
throw new Error("i18n-keyless: config lacks API_KEY and handleTranslate. Cannot proceed.");
|
|
130
122
|
}
|
|
131
|
-
const context = options?.context;
|
|
132
|
-
const debug = options?.debug;
|
|
133
|
-
// if (key.length > 280) {
|
|
134
|
-
// console.error("i18n-keyless: Key length exceeds 280 characters limit:", key);
|
|
135
|
-
// return;
|
|
136
|
-
// }
|
|
137
123
|
if (!key) {
|
|
138
124
|
return "";
|
|
139
125
|
}
|
|
140
126
|
if (debug) {
|
|
141
|
-
console.log("
|
|
127
|
+
console.log("i18n-keyless: awaitForTranslationFn called with:", { key, currentLanguage, context, options });
|
|
142
128
|
}
|
|
143
129
|
const forceTemporaryLang = options?.forceTemporary?.[currentLanguage];
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
130
|
+
const translationKey = context ? `${key}__${context}` : key;
|
|
131
|
+
// Safe navigation for potentially undefined language store
|
|
132
|
+
const translation = translations[currentLanguage]?.[translationKey];
|
|
133
|
+
// Return existing translation if found and not forced temporary
|
|
147
134
|
if (translation && !forceTemporaryLang) {
|
|
148
135
|
if (debug) {
|
|
149
|
-
console.log(
|
|
136
|
+
console.log(`i18n-keyless: Translation found in store for key: "${translationKey}"`);
|
|
150
137
|
}
|
|
151
138
|
return translation;
|
|
152
139
|
}
|
|
140
|
+
// Use custom handler if provided
|
|
153
141
|
if (config.handleTranslate) {
|
|
154
|
-
await config.handleTranslate?.(key);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
const body = {
|
|
158
|
-
key,
|
|
159
|
-
context,
|
|
160
|
-
forceTemporary: options?.forceTemporary,
|
|
161
|
-
languages: config.languages.supported,
|
|
162
|
-
primaryLanguage: config.languages.primary,
|
|
163
|
-
};
|
|
164
|
-
const apiUrl = config.API_URL || "https://api.i18n-keyless.com";
|
|
165
|
-
const url = `${apiUrl}/translate?return_translation=true`;
|
|
166
142
|
if (debug) {
|
|
167
|
-
console.log(
|
|
143
|
+
console.log(`i18n-keyless: Using handleTranslate for key: "${key}"`);
|
|
168
144
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
body: JSON.stringify(body),
|
|
179
|
-
})
|
|
180
|
-
.then((res) => res);
|
|
181
|
-
if (debug) {
|
|
182
|
-
console.log("response", response);
|
|
145
|
+
// Expect handleTranslate to manage its own errors/state updates
|
|
146
|
+
await config.handleTranslate(key); // Pass only the key
|
|
147
|
+
// Re-check store after custom handler, maybe it populated the translation
|
|
148
|
+
const updatedTranslation = translations[currentLanguage]?.[translationKey];
|
|
149
|
+
if (updatedTranslation) {
|
|
150
|
+
if (debug) {
|
|
151
|
+
console.log(`i18n-keyless: Translation found for key "${translationKey}" after handleTranslate`);
|
|
152
|
+
}
|
|
153
|
+
return updatedTranslation;
|
|
183
154
|
}
|
|
184
|
-
|
|
185
|
-
|
|
155
|
+
// If still not found after custom handler, return original key
|
|
156
|
+
if (debug) {
|
|
157
|
+
console.warn(`i18n-keyless: Translation for key "${translationKey}" still not found after handleTranslate.`);
|
|
186
158
|
}
|
|
187
|
-
return
|
|
159
|
+
return key;
|
|
188
160
|
}
|
|
161
|
+
// Proceed with API call if no custom handler
|
|
162
|
+
if (!config.API_KEY) {
|
|
163
|
+
// This should technically be caught earlier, but belt-and-suspenders
|
|
164
|
+
throw new Error("i18n-keyless: API_KEY is required for API translation but missing.");
|
|
165
|
+
}
|
|
166
|
+
const body = {
|
|
167
|
+
key,
|
|
168
|
+
context,
|
|
169
|
+
forceTemporary: options?.forceTemporary,
|
|
170
|
+
languages: config.languages.supported,
|
|
171
|
+
primaryLanguage: config.languages.primary,
|
|
172
|
+
};
|
|
173
|
+
const apiUrl = config.API_URL || "https://api.i18n-keyless.com";
|
|
174
|
+
const url = `${apiUrl}/translate`;
|
|
175
|
+
if (debug) {
|
|
176
|
+
console.log("i18n-keyless: Fetching translation from API:", { url, body });
|
|
177
|
+
}
|
|
178
|
+
const response = await api
|
|
179
|
+
.fetchTranslation(url, {
|
|
180
|
+
method: "POST",
|
|
181
|
+
headers: {
|
|
182
|
+
"Content-Type": "application/json",
|
|
183
|
+
Authorization: `Bearer ${config.API_KEY}`,
|
|
184
|
+
unique_id: uniqueId || "",
|
|
185
|
+
Version: packageJson.version,
|
|
186
|
+
},
|
|
187
|
+
body: JSON.stringify(body),
|
|
188
|
+
})
|
|
189
|
+
.then((res) => res);
|
|
190
|
+
if (debug) {
|
|
191
|
+
console.log("i18n-keyless: API response received:", response);
|
|
192
|
+
}
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
// Throw an error if the API response indicates failure
|
|
195
|
+
throw new Error(response.error || `i18n-keyless: API request failed for key "${key}"`);
|
|
196
|
+
}
|
|
197
|
+
if (response.message) {
|
|
198
|
+
// Log any informational messages from the API
|
|
199
|
+
console.warn("i18n-keyless: API message:", response.message);
|
|
200
|
+
}
|
|
201
|
+
// Return the fetched translation or the original key if not available for the current language
|
|
202
|
+
const fetchedTranslation = response.data?.translation?.[currentLanguage];
|
|
203
|
+
if (debug && !fetchedTranslation) {
|
|
204
|
+
console.log(`i18n-keyless: Translation for lang "${currentLanguage}" not found in API response for key "${key}". Returning original key.`);
|
|
205
|
+
}
|
|
206
|
+
return fetchedTranslation || key;
|
|
189
207
|
}
|
|
190
208
|
catch (error) {
|
|
191
|
-
|
|
209
|
+
// Log the specific error during translation attempt
|
|
210
|
+
console.error(`i18n-keyless: Error during awaitForTranslationFn for key "${key}":`, error);
|
|
211
|
+
// Re-throw the error to ensure the promise returned by this async function rejects
|
|
212
|
+
throw error;
|
|
192
213
|
}
|
|
193
|
-
|
|
194
|
-
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* **MANDATORY AWAIT / PROMISE HANDLING REQUIRED IN NODE.JS**
|
|
217
|
+
*
|
|
218
|
+
* Asynchronously retrieves a translation for a key, fetching from the backend if necessary.
|
|
219
|
+
* In a Node.js environment, failure to `await` this function inside a `try...catch` block
|
|
220
|
+
* or attach a `.catch()` handler WILL lead to an unhandled promise rejection if an error
|
|
221
|
+
* occurs during translation (e.g., network error, API error). This unhandled rejection
|
|
222
|
+
* is designed to cause a **FATAL ERROR** and **CRASH** the Node.js process to prevent
|
|
223
|
+
* silent failures. Ensure all calls are properly handled.
|
|
224
|
+
*
|
|
225
|
+
* **Recommendation:** Use the `@typescript-eslint/no-floating-promises` lint rule.
|
|
226
|
+
*
|
|
227
|
+
* @param key - The text to translate
|
|
228
|
+
* @param currentLanguage - The language to translate to
|
|
229
|
+
* @param options - Optional parameters for the translation process
|
|
230
|
+
* @returns A Promise resolving to the translated string or the original key if not found/on error *after handling*.
|
|
231
|
+
* @throws Re-throws any internal error if the promise rejection is not handled by the caller.
|
|
232
|
+
*/
|
|
233
|
+
export const awaitForTranslation = new Proxy(awaitForTranslationFn, // Target the named async function
|
|
234
|
+
{
|
|
195
235
|
apply(target, thisArg, args) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
236
|
+
// Call the actual async function
|
|
237
|
+
const promise = Reflect.apply(target, thisArg, args);
|
|
238
|
+
// Attach a catch handler. This runs ONLY if the promise REJECTS.
|
|
239
|
+
promise.catch((error) => {
|
|
240
|
+
// Log a specific error message indicating an unhandled rejection.
|
|
241
|
+
console.error(`i18n-keyless: FATAL: Unhandled rejection in awaitForTranslation! ` +
|
|
242
|
+
`The promise for key "${String(args[0])}" was rejected and not caught. ` +
|
|
243
|
+
`Ensure the call is wrapped in try/catch and awaited, or attach a .catch() handler. ` +
|
|
244
|
+
`Original error:`, error);
|
|
245
|
+
// Re-throw the error. In Node.js, an uncaught promise rejection
|
|
246
|
+
// will typically terminate the process (depending on Node version and handlers).
|
|
247
|
+
// This enforces handling of translation errors.
|
|
248
|
+
throw error;
|
|
249
|
+
});
|
|
250
|
+
// Return the original promise to the caller
|
|
251
|
+
return promise;
|
|
204
252
|
},
|
|
205
253
|
});
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Lang, PrimaryLang } from "i18n-keyless-core";
|
|
1
|
+
import { HandleTranslateFunction, Lang, PrimaryLang } from "i18n-keyless-core";
|
|
2
2
|
export type Translations = Record<string, string>;
|
|
3
3
|
export interface I18nKeylessNodeConfig {
|
|
4
4
|
/**
|
|
@@ -54,10 +54,7 @@ export interface I18nKeylessNodeConfig {
|
|
|
54
54
|
* - not use this `handleTranslate` function, and use the built in API call with API_KEY filled
|
|
55
55
|
* - not use this `handleTranslate` function nor API_KEY key, and provide your own API_URL
|
|
56
56
|
*/
|
|
57
|
-
handleTranslate?:
|
|
58
|
-
ok: boolean;
|
|
59
|
-
message: string;
|
|
60
|
-
}>;
|
|
57
|
+
handleTranslate?: HandleTranslateFunction;
|
|
61
58
|
/**
|
|
62
59
|
* if this function exists, it will be called instead of the API call
|
|
63
60
|
* if this function doesn't exist, the default behavior is to call the API, with the API_KEY
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18n-keyless-node",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.12.
|
|
4
|
+
"version": "1.12.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"postpublish": "rm -rf ./dist && rm *.tgz"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"i18n-keyless-core": "1.12.
|
|
18
|
+
"i18n-keyless-core": "1.12.5"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@eslint/js": "^9.9.0",
|