intor-translator 1.1.5 → 1.2.1
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 +34 -142
- package/dist/index.cjs +206 -85
- package/dist/index.d.cts +92 -81
- package/dist/index.d.ts +92 -81
- package/dist/index.js +207 -85
- package/package.json +15 -23
package/dist/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { rura } from 'rura';
|
|
2
|
+
|
|
3
|
+
// src/pipeline/hooks/find-message.ts
|
|
4
|
+
|
|
5
|
+
// src/translators/shared/utils/find-message-in-locales.ts
|
|
2
6
|
var findMessageInLocales = ({
|
|
3
7
|
messages,
|
|
4
8
|
candidateLocales,
|
|
@@ -21,28 +25,50 @@ var findMessageInLocales = ({
|
|
|
21
25
|
}
|
|
22
26
|
};
|
|
23
27
|
|
|
24
|
-
// src/
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// src/pipeline/hooks/find-message.ts
|
|
29
|
+
var findMessage = rura.createHook(
|
|
30
|
+
"findMessage",
|
|
31
|
+
(ctx) => {
|
|
32
|
+
ctx.rawMessage = findMessageInLocales({
|
|
33
|
+
messages: ctx.messages,
|
|
34
|
+
candidateLocales: ctx.candidateLocales,
|
|
35
|
+
key: ctx.key
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
200
|
|
39
|
+
);
|
|
30
40
|
|
|
31
|
-
// src/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
// src/pipeline/utils/make-handler-context.ts
|
|
42
|
+
function makeHandlerContext(ctx) {
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
locale: ctx.locale,
|
|
45
|
+
key: ctx.key,
|
|
46
|
+
replacements: ctx.replacements,
|
|
47
|
+
messages: ctx.messages,
|
|
48
|
+
candidateLocales: ctx.candidateLocales,
|
|
49
|
+
config: ctx.config,
|
|
50
|
+
isLoading: ctx.isLoading,
|
|
51
|
+
rawMessage: ctx.rawMessage,
|
|
52
|
+
formattedMessage: ctx.formattedMessage,
|
|
53
|
+
meta: ctx.meta
|
|
54
|
+
});
|
|
55
|
+
}
|
|
44
56
|
|
|
45
|
-
// src/
|
|
57
|
+
// src/pipeline/hooks/format.ts
|
|
58
|
+
var format = rura.createHook(
|
|
59
|
+
"format",
|
|
60
|
+
(ctx) => {
|
|
61
|
+
const { config, rawMessage } = ctx;
|
|
62
|
+
const { formatHandler } = config.handlers || {};
|
|
63
|
+
if (!formatHandler || rawMessage === void 0) return;
|
|
64
|
+
ctx.formattedMessage = formatHandler(
|
|
65
|
+
makeHandlerContext(ctx)
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
500
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// src/translators/shared/utils/replace-values.ts
|
|
46
72
|
var replaceValues = (message, params) => {
|
|
47
73
|
if (!params || typeof params !== "object" || Object.keys(params).length === 0) {
|
|
48
74
|
return message;
|
|
@@ -61,63 +87,113 @@ var replaceValues = (message, params) => {
|
|
|
61
87
|
return replaced;
|
|
62
88
|
};
|
|
63
89
|
|
|
64
|
-
// src/
|
|
65
|
-
var
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
// src/pipeline/hooks/interpolate.ts
|
|
91
|
+
var interpolate = rura.createHook(
|
|
92
|
+
"interpolate",
|
|
93
|
+
(ctx) => {
|
|
94
|
+
const { rawMessage, formattedMessage, replacements } = ctx;
|
|
95
|
+
const message = formattedMessage ?? rawMessage;
|
|
96
|
+
if (typeof message !== "string" || !replacements) {
|
|
97
|
+
ctx.finalMessage = message;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
ctx.finalMessage = replaceValues(message, replacements);
|
|
101
|
+
},
|
|
102
|
+
600
|
|
103
|
+
);
|
|
104
|
+
var loading = rura.createHook(
|
|
105
|
+
"loading",
|
|
106
|
+
(ctx) => {
|
|
107
|
+
const { config, isLoading } = ctx;
|
|
108
|
+
if (!isLoading) return;
|
|
109
|
+
const { loadingHandler } = config.handlers || {};
|
|
110
|
+
if (loadingHandler) {
|
|
111
|
+
return {
|
|
112
|
+
early: true,
|
|
113
|
+
output: loadingHandler(makeHandlerContext(ctx))
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const { loadingMessage } = config;
|
|
117
|
+
if (loadingMessage) {
|
|
118
|
+
return { early: true, output: loadingMessage };
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
300
|
|
122
|
+
);
|
|
123
|
+
var missing = rura.createHook(
|
|
124
|
+
"missing",
|
|
125
|
+
(ctx) => {
|
|
126
|
+
const { config, key, rawMessage } = ctx;
|
|
127
|
+
if (rawMessage !== void 0) return;
|
|
128
|
+
const { missingHandler } = config.handlers || {};
|
|
129
|
+
if (missingHandler) {
|
|
130
|
+
return {
|
|
131
|
+
early: true,
|
|
132
|
+
output: missingHandler(makeHandlerContext(ctx))
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const { placeholder } = config;
|
|
136
|
+
if (placeholder) {
|
|
137
|
+
return { early: true, output: placeholder };
|
|
138
|
+
}
|
|
139
|
+
return { early: true, output: key };
|
|
140
|
+
},
|
|
141
|
+
400
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// src/translators/shared/utils/resolve-candidate-locales.ts
|
|
145
|
+
var resolveCandidateLocales = (locale, fallbackLocalesMap) => {
|
|
146
|
+
const fallbacks = fallbackLocalesMap?.[locale] || [];
|
|
147
|
+
const filteredFallbacks = fallbacks.filter((l) => l !== locale);
|
|
148
|
+
return [locale, ...filteredFallbacks];
|
|
95
149
|
};
|
|
96
150
|
|
|
151
|
+
// src/pipeline/hooks/resolve-locales.ts
|
|
152
|
+
var resolveLocales = rura.createHook(
|
|
153
|
+
"resolveLocales",
|
|
154
|
+
(ctx) => {
|
|
155
|
+
ctx.candidateLocales = resolveCandidateLocales(
|
|
156
|
+
ctx.locale,
|
|
157
|
+
ctx.config.fallbackLocales
|
|
158
|
+
);
|
|
159
|
+
},
|
|
160
|
+
100
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// src/pipeline/index.ts
|
|
164
|
+
var DEFAULT_HOOKS = [
|
|
165
|
+
resolveLocales,
|
|
166
|
+
findMessage,
|
|
167
|
+
loading,
|
|
168
|
+
missing,
|
|
169
|
+
format,
|
|
170
|
+
interpolate
|
|
171
|
+
];
|
|
172
|
+
|
|
97
173
|
// src/translators/base-translator/base-translator.ts
|
|
98
174
|
var BaseTranslator = class {
|
|
99
175
|
/** Current messages for translation */
|
|
100
|
-
|
|
176
|
+
_messages;
|
|
101
177
|
/** Current active locale */
|
|
102
|
-
|
|
178
|
+
_locale;
|
|
103
179
|
/** Current loading state */
|
|
104
|
-
|
|
180
|
+
_isLoading;
|
|
105
181
|
constructor(options) {
|
|
106
|
-
this.
|
|
107
|
-
this.
|
|
108
|
-
this.
|
|
182
|
+
this._messages = options.messages ?? {};
|
|
183
|
+
this._locale = options.locale;
|
|
184
|
+
this._isLoading = options.isLoading ?? false;
|
|
109
185
|
}
|
|
110
186
|
/** Get messages. */
|
|
111
187
|
get messages() {
|
|
112
|
-
return this.
|
|
188
|
+
return this._messages;
|
|
113
189
|
}
|
|
114
190
|
/** Get the current active locale. */
|
|
115
191
|
get locale() {
|
|
116
|
-
return this.
|
|
192
|
+
return this._locale;
|
|
117
193
|
}
|
|
118
194
|
/** Get the current loading state. */
|
|
119
195
|
get isLoading() {
|
|
120
|
-
return this.
|
|
196
|
+
return this._isLoading;
|
|
121
197
|
}
|
|
122
198
|
/**
|
|
123
199
|
* Replace messages with new ones.
|
|
@@ -126,7 +202,7 @@ var BaseTranslator = class {
|
|
|
126
202
|
* The type cast bypasses TypeScript restrictions on dynamic messages.
|
|
127
203
|
*/
|
|
128
204
|
setMessages(messages) {
|
|
129
|
-
this.
|
|
205
|
+
this._messages = messages;
|
|
130
206
|
}
|
|
131
207
|
/**
|
|
132
208
|
* Set the active locale.
|
|
@@ -134,30 +210,74 @@ var BaseTranslator = class {
|
|
|
134
210
|
* - Note: Unlike `setMessages`, the locale structure cannot be changed at runtime.
|
|
135
211
|
*/
|
|
136
212
|
setLocale(newLocale) {
|
|
137
|
-
this.
|
|
213
|
+
this._locale = newLocale;
|
|
138
214
|
}
|
|
139
215
|
/** Set the loading state. */
|
|
140
216
|
setLoading(state) {
|
|
141
|
-
this.
|
|
217
|
+
this._isLoading = state;
|
|
142
218
|
}
|
|
143
219
|
};
|
|
144
220
|
|
|
221
|
+
// src/translators/shared/has-key.ts
|
|
222
|
+
var hasKey = ({
|
|
223
|
+
messages,
|
|
224
|
+
locale,
|
|
225
|
+
key,
|
|
226
|
+
targetLocale
|
|
227
|
+
}) => {
|
|
228
|
+
const candidateLocales = resolveCandidateLocales(targetLocale || locale);
|
|
229
|
+
const message = findMessageInLocales({
|
|
230
|
+
messages,
|
|
231
|
+
candidateLocales,
|
|
232
|
+
key
|
|
233
|
+
});
|
|
234
|
+
return !!message;
|
|
235
|
+
};
|
|
236
|
+
function translate(options) {
|
|
237
|
+
const context = {
|
|
238
|
+
...options,
|
|
239
|
+
config: options.translateConfig,
|
|
240
|
+
candidateLocales: [],
|
|
241
|
+
meta: {}
|
|
242
|
+
};
|
|
243
|
+
const { early, ctx, output } = rura.run(context, options.hooks);
|
|
244
|
+
if (early === true) return output;
|
|
245
|
+
return ctx.finalMessage;
|
|
246
|
+
}
|
|
247
|
+
|
|
145
248
|
// src/translators/core-translator/core-translator.ts
|
|
146
249
|
var CoreTranslator = class extends BaseTranslator {
|
|
147
|
-
options
|
|
250
|
+
/** User-provided options including messages, locale, and config. */
|
|
251
|
+
translateConfig;
|
|
252
|
+
/** Active pipeline hooks applied during translation. */
|
|
253
|
+
hooks = [...DEFAULT_HOOKS];
|
|
148
254
|
constructor(options) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
255
|
+
const { locale, messages, isLoading, plugins, ...translateConfig } = options;
|
|
256
|
+
super({ locale, messages, isLoading });
|
|
257
|
+
this.translateConfig = translateConfig;
|
|
258
|
+
if (plugins) {
|
|
259
|
+
for (const plugin of plugins) this.use(plugin);
|
|
260
|
+
}
|
|
261
|
+
this.sortHooks();
|
|
262
|
+
}
|
|
263
|
+
/** Sort hooks by order value (lower runs earlier). */
|
|
264
|
+
sortHooks() {
|
|
265
|
+
this.hooks.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
266
|
+
}
|
|
267
|
+
/** Register a plugin or a raw pipeline hook. */
|
|
268
|
+
use(plugin) {
|
|
269
|
+
if ("run" in plugin) this.hooks.push(plugin);
|
|
270
|
+
else if ("hook" in plugin && plugin.hook) {
|
|
271
|
+
const hooks = Array.isArray(plugin.hook) ? plugin.hook : [plugin.hook];
|
|
272
|
+
this.hooks.push(...hooks);
|
|
273
|
+
}
|
|
274
|
+
this.sortHooks();
|
|
155
275
|
}
|
|
156
276
|
/** Check if a key exists in the specified locale or current locale. */
|
|
157
277
|
hasKey = (key, targetLocale) => {
|
|
158
278
|
return hasKey({
|
|
159
|
-
|
|
160
|
-
|
|
279
|
+
messages: this._messages,
|
|
280
|
+
locale: this._locale,
|
|
161
281
|
key,
|
|
162
282
|
targetLocale
|
|
163
283
|
});
|
|
@@ -165,17 +285,18 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
165
285
|
/** Get the translated message for a key, with optional replacements. */
|
|
166
286
|
t = (key, replacements) => {
|
|
167
287
|
return translate({
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
288
|
+
hooks: this.hooks,
|
|
289
|
+
messages: this._messages,
|
|
290
|
+
locale: this._locale,
|
|
291
|
+
isLoading: this._isLoading,
|
|
292
|
+
translateConfig: this.translateConfig,
|
|
172
293
|
key,
|
|
173
294
|
replacements
|
|
174
295
|
});
|
|
175
296
|
};
|
|
176
297
|
};
|
|
177
298
|
|
|
178
|
-
// src/utils/get-full-key.ts
|
|
299
|
+
// src/translators/scope-translator/utils/get-full-key.ts
|
|
179
300
|
var getFullKey = (preKey = "", key = "") => {
|
|
180
301
|
if (!preKey) return key;
|
|
181
302
|
if (!key) return preKey;
|
|
@@ -193,8 +314,8 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
193
314
|
hasKey: (key, targetLocale) => {
|
|
194
315
|
const fullKey = getFullKey(preKey, key);
|
|
195
316
|
return hasKey({
|
|
196
|
-
|
|
197
|
-
|
|
317
|
+
messages: this._messages,
|
|
318
|
+
locale: this._locale,
|
|
198
319
|
key: fullKey,
|
|
199
320
|
targetLocale
|
|
200
321
|
});
|
|
@@ -202,10 +323,11 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
202
323
|
t: (key, replacements) => {
|
|
203
324
|
const fullKey = getFullKey(preKey, key);
|
|
204
325
|
return translate({
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
326
|
+
hooks: this.hooks,
|
|
327
|
+
messages: this._messages,
|
|
328
|
+
locale: this._locale,
|
|
329
|
+
isLoading: this._isLoading,
|
|
330
|
+
translateConfig: this.translateConfig,
|
|
209
331
|
key: fullKey,
|
|
210
332
|
replacements
|
|
211
333
|
});
|
|
@@ -214,4 +336,4 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
214
336
|
}
|
|
215
337
|
};
|
|
216
338
|
|
|
217
|
-
export { ScopeTranslator
|
|
339
|
+
export { ScopeTranslator as Translator };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intor-translator",
|
|
3
|
-
"version": "1.1
|
|
4
|
-
"description": "A type
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "🤖 A modern, type-safe i18n engine.",
|
|
5
5
|
"author": "Yiming Liao",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/yiming-liao/intor-translator#readme",
|
|
@@ -17,21 +17,9 @@
|
|
|
17
17
|
"internationalization",
|
|
18
18
|
"translation",
|
|
19
19
|
"typescript",
|
|
20
|
-
"node",
|
|
21
|
-
"nextjs",
|
|
22
|
-
"react",
|
|
23
|
-
"translator",
|
|
24
|
-
"i18n core",
|
|
25
|
-
"custom messages",
|
|
26
|
-
"rich replacements",
|
|
27
|
-
"async loading",
|
|
28
|
-
"type safe",
|
|
29
20
|
"type-safe",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"type-safe i18n",
|
|
33
|
-
"type-safe translation",
|
|
34
|
-
"type-safe core"
|
|
21
|
+
"i18n engine",
|
|
22
|
+
"translator"
|
|
35
23
|
],
|
|
36
24
|
"exports": {
|
|
37
25
|
".": {
|
|
@@ -56,12 +44,19 @@
|
|
|
56
44
|
"type": "tsc --noEmit",
|
|
57
45
|
"lint": "eslint",
|
|
58
46
|
"lint:debug": "eslint --debug",
|
|
59
|
-
"knip": "knip --config .config/knip.config.ts"
|
|
47
|
+
"knip": "knip --config .config/knip.config.ts",
|
|
48
|
+
"examples:html": "vite --config examples/html/vite.config.ts"
|
|
49
|
+
},
|
|
50
|
+
"sideEffects": false,
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=16.0.0"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"rura": "1.0.7"
|
|
60
56
|
},
|
|
61
|
-
"dependencies": {},
|
|
62
57
|
"devDependencies": {
|
|
63
58
|
"@types/node": "^24.10.1",
|
|
64
|
-
"@vitest/coverage-v8": "4.0.
|
|
59
|
+
"@vitest/coverage-v8": "4.0.15",
|
|
65
60
|
"eslint": "^9.39.1",
|
|
66
61
|
"eslint-config-prettier": "^10.1.8",
|
|
67
62
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
@@ -77,10 +72,7 @@
|
|
|
77
72
|
"tsup": "^8.4.0",
|
|
78
73
|
"typescript": "^5.8.3",
|
|
79
74
|
"typescript-eslint": "^8.46.4",
|
|
75
|
+
"vite": "^7.2.6",
|
|
80
76
|
"vitest": "^4.0.9"
|
|
81
|
-
},
|
|
82
|
-
"sideEffects": false,
|
|
83
|
-
"engines": {
|
|
84
|
-
"node": ">=16.0.0"
|
|
85
77
|
}
|
|
86
78
|
}
|