intor-translator 1.4.5 → 1.4.7
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.cjs +21 -59
- package/dist/index.d.cts +131 -139
- package/dist/index.d.ts +131 -139
- package/dist/index.js +21 -59
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
var rura = require('rura');
|
|
4
4
|
|
|
5
5
|
// src/translators/core-translator/core-translator.ts
|
|
6
|
+
function runTranslate(options) {
|
|
7
|
+
const context = {
|
|
8
|
+
...options,
|
|
9
|
+
config: options.translateConfig,
|
|
10
|
+
candidateLocales: [],
|
|
11
|
+
meta: {}
|
|
12
|
+
};
|
|
13
|
+
return rura.rura.run(context, options.hooks);
|
|
14
|
+
}
|
|
6
15
|
|
|
7
16
|
// src/shared/utils/find-message-in-locales.ts
|
|
8
17
|
var findMessageInLocales = ({
|
|
@@ -31,15 +40,11 @@ var findMessageInLocales = ({
|
|
|
31
40
|
var findMessage = rura.rura.createHook(
|
|
32
41
|
"findMessage",
|
|
33
42
|
(ctx) => {
|
|
34
|
-
ctx.
|
|
35
|
-
ctx.rawString = void 0;
|
|
36
|
-
const message = findMessageInLocales({
|
|
43
|
+
ctx.rawMessage = findMessageInLocales({
|
|
37
44
|
messages: ctx.messages,
|
|
38
45
|
candidateLocales: ctx.candidateLocales,
|
|
39
46
|
key: ctx.key
|
|
40
47
|
});
|
|
41
|
-
ctx.rawValue = message;
|
|
42
|
-
if (typeof message === "string") ctx.rawString = message;
|
|
43
48
|
},
|
|
44
49
|
200
|
|
45
50
|
);
|
|
@@ -54,8 +59,7 @@ function makeHandlerContext(ctx) {
|
|
|
54
59
|
key: ctx.key,
|
|
55
60
|
replacements: ctx.replacements,
|
|
56
61
|
candidateLocales: ctx.candidateLocales,
|
|
57
|
-
|
|
58
|
-
rawString: ctx.rawString,
|
|
62
|
+
rawMessage: ctx.rawMessage,
|
|
59
63
|
formattedMessage: ctx.formattedMessage,
|
|
60
64
|
meta: ctx.meta
|
|
61
65
|
});
|
|
@@ -65,9 +69,9 @@ function makeHandlerContext(ctx) {
|
|
|
65
69
|
var format = rura.rura.createHook(
|
|
66
70
|
"format",
|
|
67
71
|
(ctx) => {
|
|
68
|
-
const { config,
|
|
72
|
+
const { config, rawMessage } = ctx;
|
|
69
73
|
const { formatHandler } = config.handlers || {};
|
|
70
|
-
if (!formatHandler ||
|
|
74
|
+
if (!formatHandler || rawMessage === void 0) return;
|
|
71
75
|
ctx.formattedMessage = formatHandler(
|
|
72
76
|
makeHandlerContext(ctx)
|
|
73
77
|
);
|
|
@@ -98,8 +102,8 @@ var replaceValues = (message, params) => {
|
|
|
98
102
|
var interpolate = rura.rura.createHook(
|
|
99
103
|
"interpolate",
|
|
100
104
|
(ctx) => {
|
|
101
|
-
const {
|
|
102
|
-
const message = formattedMessage ??
|
|
105
|
+
const { rawMessage, formattedMessage, replacements } = ctx;
|
|
106
|
+
const message = formattedMessage ?? rawMessage;
|
|
103
107
|
if (typeof message !== "string" || !replacements) {
|
|
104
108
|
ctx.finalMessage = message;
|
|
105
109
|
return;
|
|
@@ -130,8 +134,8 @@ var loading = rura.rura.createHook(
|
|
|
130
134
|
var missing = rura.rura.createHook(
|
|
131
135
|
"missing",
|
|
132
136
|
(ctx) => {
|
|
133
|
-
const { config, key,
|
|
134
|
-
if (
|
|
137
|
+
const { config, key, rawMessage } = ctx;
|
|
138
|
+
if (rawMessage !== void 0) return;
|
|
135
139
|
const { missingHandler } = config.handlers || {};
|
|
136
140
|
if (missingHandler) {
|
|
137
141
|
return {
|
|
@@ -236,15 +240,6 @@ var hasKey = ({
|
|
|
236
240
|
const message = findMessageInLocales({ messages, candidateLocales, key });
|
|
237
241
|
return message !== void 0;
|
|
238
242
|
};
|
|
239
|
-
function runTranslate(options) {
|
|
240
|
-
const context = {
|
|
241
|
-
...options,
|
|
242
|
-
config: options.translateConfig,
|
|
243
|
-
candidateLocales: [],
|
|
244
|
-
meta: {}
|
|
245
|
-
};
|
|
246
|
-
return rura.rura.run(context, options.hooks);
|
|
247
|
-
}
|
|
248
243
|
|
|
249
244
|
// src/translators/methods/translate.ts
|
|
250
245
|
function translate(options) {
|
|
@@ -256,15 +251,6 @@ function translate(options) {
|
|
|
256
251
|
return ctx.finalMessage;
|
|
257
252
|
}
|
|
258
253
|
|
|
259
|
-
// src/translators/methods/translate-raw.ts
|
|
260
|
-
function translateRaw(options) {
|
|
261
|
-
const { ctx } = runTranslate(options);
|
|
262
|
-
if (ctx.rawValue === void 0) {
|
|
263
|
-
throw new Error("Invariant violated: missing hook did not produce output");
|
|
264
|
-
}
|
|
265
|
-
return ctx.rawValue;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
254
|
// src/translators/core-translator/core-translator.ts
|
|
269
255
|
var CoreTranslator = class extends BaseTranslator {
|
|
270
256
|
/** User-provided options including messages, locale, and config. */
|
|
@@ -309,7 +295,7 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
309
295
|
});
|
|
310
296
|
};
|
|
311
297
|
/** Get the translated message for a key, with optional replacements. */
|
|
312
|
-
t = (key,
|
|
298
|
+
t = (key, ...replacementArgs) => {
|
|
313
299
|
return translate({
|
|
314
300
|
hooks: this.hooks,
|
|
315
301
|
messages: this._messages,
|
|
@@ -317,19 +303,7 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
317
303
|
isLoading: this._isLoading,
|
|
318
304
|
translateConfig: this.translateConfig,
|
|
319
305
|
key,
|
|
320
|
-
replacements
|
|
321
|
-
});
|
|
322
|
-
};
|
|
323
|
-
/** Get the raw message value for a key without formatting or interpolation. */
|
|
324
|
-
tRaw = (key, replacements) => {
|
|
325
|
-
return translateRaw({
|
|
326
|
-
hooks: this.hooks,
|
|
327
|
-
messages: this._messages,
|
|
328
|
-
locale: this._locale,
|
|
329
|
-
isLoading: this._isLoading,
|
|
330
|
-
translateConfig: this.translateConfig,
|
|
331
|
-
key,
|
|
332
|
-
replacements
|
|
306
|
+
replacements: replacementArgs[0]
|
|
333
307
|
});
|
|
334
308
|
};
|
|
335
309
|
};
|
|
@@ -358,7 +332,7 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
358
332
|
targetLocale
|
|
359
333
|
});
|
|
360
334
|
},
|
|
361
|
-
t: (key,
|
|
335
|
+
t: (key, ...args) => {
|
|
362
336
|
const fullKey = getFullKey(preKey, key);
|
|
363
337
|
return translate({
|
|
364
338
|
hooks: this.hooks,
|
|
@@ -367,19 +341,7 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
367
341
|
isLoading: this._isLoading,
|
|
368
342
|
translateConfig: this.translateConfig,
|
|
369
343
|
key: fullKey,
|
|
370
|
-
replacements
|
|
371
|
-
});
|
|
372
|
-
},
|
|
373
|
-
tRaw: (key, replacements) => {
|
|
374
|
-
const fullKey = getFullKey(preKey, key);
|
|
375
|
-
return translateRaw({
|
|
376
|
-
hooks: this.hooks,
|
|
377
|
-
messages: this._messages,
|
|
378
|
-
locale: this._locale,
|
|
379
|
-
isLoading: this._isLoading,
|
|
380
|
-
translateConfig: this.translateConfig,
|
|
381
|
-
key: fullKey,
|
|
382
|
-
replacements
|
|
344
|
+
replacements: args[0]
|
|
383
345
|
});
|
|
384
346
|
}
|
|
385
347
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -42,30 +42,6 @@ type MessageLeaf = MessagePrimitive | MessageArray;
|
|
|
42
42
|
* ```
|
|
43
43
|
*/
|
|
44
44
|
type LocaleMessages = Record<string, MessageObject>;
|
|
45
|
-
/**
|
|
46
|
-
* Merges messages from all locales into a single unified structure,
|
|
47
|
-
* or extracts messages for a specific locale if `L` is provided.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```ts
|
|
51
|
-
* const messages = {
|
|
52
|
-
* en: { greeting: { morning: "morning" } },
|
|
53
|
-
* zh: { greeting: { evening: "晚上好" } },
|
|
54
|
-
* };
|
|
55
|
-
*
|
|
56
|
-
* // 1. Union of all locales
|
|
57
|
-
* UnionLocaleMessages<typeof messages>;
|
|
58
|
-
* // → { greeting: { morning: string; }; } | { greeting: { evening: string; }; }
|
|
59
|
-
*
|
|
60
|
-
* // 2. Messages for a specified locale
|
|
61
|
-
* UnionLocaleMessages<typeof messages, "en">; // → { greeting: { morning: string; }; }
|
|
62
|
-
* UnionLocaleMessages<typeof messages, "zh">; // → { greeting: { evening: string; }; }
|
|
63
|
-
*
|
|
64
|
-
* // 3. Fallback if M is not LocaleMessages
|
|
65
|
-
* UnionLocaleMessages // → unknown
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
type LocalizedMessagesUnion<M = unknown, L extends keyof M | "union" = "union"> = M extends LocaleMessages ? L extends "union" ? M[Locale<M>] : M[L & keyof M] : unknown;
|
|
69
45
|
|
|
70
46
|
/**
|
|
71
47
|
* Extracts locale keys only when M is a valid messages object.
|
|
@@ -106,25 +82,6 @@ type Locale<M = unknown> = M extends LocaleMessages ? keyof M & string : string;
|
|
|
106
82
|
*/
|
|
107
83
|
type FallbackLocalesMap<L extends string = string> = Partial<Record<L, L[]>>;
|
|
108
84
|
|
|
109
|
-
/**
|
|
110
|
-
* Represents a recursive replacement object used for interpolating values in message templates.
|
|
111
|
-
*
|
|
112
|
-
* - Each key can be any value (`string`, `number`, `boolean`, `Date`, `function`, nested object, etc.).
|
|
113
|
-
* - Supports nested structures for complex interpolation.
|
|
114
|
-
* - Can be used directly with `intl-messageformat` or custom format handlers.
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* const replacements: Replacement = {
|
|
118
|
-
* name: "Alice",
|
|
119
|
-
* count: 5,
|
|
120
|
-
* nested: {
|
|
121
|
-
* score: 100
|
|
122
|
-
* },
|
|
123
|
-
* formatter: (value: unknown) => `<b>${value}</b>`
|
|
124
|
-
* };
|
|
125
|
-
*/
|
|
126
|
-
type Replacement = Record<string, unknown>;
|
|
127
|
-
|
|
128
85
|
/**
|
|
129
86
|
* Default maximum recursive depth for nested key type computations,
|
|
130
87
|
* balancing type safety and compiler performance.
|
|
@@ -164,6 +121,19 @@ type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never
|
|
|
164
121
|
* ```
|
|
165
122
|
*/
|
|
166
123
|
type LeafValue<M, K extends string> = K extends `${infer Seg}.${infer Rest}` ? Seg extends keyof M ? LeafValue<M[Seg], Rest> : never : K extends keyof M ? M[K] : never;
|
|
124
|
+
/**
|
|
125
|
+
* Resolves the type located at a dot-separated path.
|
|
126
|
+
*
|
|
127
|
+
* The resolved type may be a subtree or a leaf value.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const messages = { a: { b: { c: "1" }, z: "2" } };
|
|
132
|
+
* AtPath<typeof messages, "a">; // → { b: { c: string }; z: string };
|
|
133
|
+
* AtPath<typeof messages, "a.b">; // → { c: string };
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
type AtPath<MessageSchema, PK extends string> = PK extends `${infer Head}.${infer Tail}` ? Head extends keyof MessageSchema ? AtPath<MessageSchema[Head], Tail> : never : PK extends keyof MessageSchema ? MessageSchema[PK] : never;
|
|
167
137
|
|
|
168
138
|
/**
|
|
169
139
|
* Extracts all **node keys** from the messages
|
|
@@ -187,7 +157,7 @@ type LeafValue<M, K extends string> = K extends `${infer Seg}.${infer Rest}` ? S
|
|
|
187
157
|
* LocalizedNodeKeys // → string
|
|
188
158
|
* ```
|
|
189
159
|
*/
|
|
190
|
-
type LocalizedNodeKeys<M = unknown,
|
|
160
|
+
type LocalizedNodeKeys<M = unknown, D extends number = DefaultDepth> = M extends LocaleMessages ? NodeKeys<M[keyof M], D> : string;
|
|
191
161
|
/**
|
|
192
162
|
* Extracts all **leaf keys** from the messages
|
|
193
163
|
* of a specified locale (or union of locales).
|
|
@@ -210,32 +180,15 @@ type LocalizedNodeKeys<M = unknown, L extends keyof M | "union" = "union", D ext
|
|
|
210
180
|
* LocalizedLeafKeys // → string
|
|
211
181
|
* ```
|
|
212
182
|
*/
|
|
213
|
-
type LocalizedLeafKeys<M = unknown,
|
|
183
|
+
type LocalizedLeafKeys<M = unknown, D extends number = DefaultDepth> = M extends LocaleMessages ? LeafKeys<M[keyof M], D> : string;
|
|
214
184
|
/**
|
|
215
185
|
* Resolves the value type of a **localized leaf key**
|
|
216
186
|
* from the messages of a specified locale (or union of locales).
|
|
217
187
|
*
|
|
218
188
|
* - Fallback to `MessageValue` if M is not LocaleMessages
|
|
219
189
|
*/
|
|
220
|
-
type LocalizedLeafValue<M = unknown, K extends string = string
|
|
190
|
+
type LocalizedLeafValue<M = unknown, K extends string = string> = M extends LocaleMessages ? LeafValue<M[keyof M], K> : MessageValue;
|
|
221
191
|
|
|
222
|
-
/**
|
|
223
|
-
* Resolves the type at a dot-separated key in a nested object.
|
|
224
|
-
*
|
|
225
|
-
* @example
|
|
226
|
-
* ```ts
|
|
227
|
-
* const structure = {
|
|
228
|
-
* a: {
|
|
229
|
-
* b: { c: "hello" },
|
|
230
|
-
* z: "world",
|
|
231
|
-
* },
|
|
232
|
-
* };
|
|
233
|
-
*
|
|
234
|
-
* MessagesAtPreKey<typeof structure, "a"> // → { b: { c: string; }; z: string;}
|
|
235
|
-
* MessagesAtPreKey<typeof structure, "a.b"> // → { c: string; };
|
|
236
|
-
* ```
|
|
237
|
-
*/
|
|
238
|
-
type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? MessagesAtPreKey<T[Head], Tail> : never : PK extends keyof T ? T[PK] : never;
|
|
239
192
|
/**
|
|
240
193
|
* Extracts all **leaf keys** under a scoped path (`PK`) from the messages
|
|
241
194
|
* of a specified locale (`L`) (or union of locales).
|
|
@@ -252,7 +205,7 @@ type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer
|
|
|
252
205
|
* ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
|
|
253
206
|
* ```
|
|
254
207
|
*/
|
|
255
|
-
type ScopedLeafKeys<M, PK extends string,
|
|
208
|
+
type ScopedLeafKeys<M, PK extends string, D extends number = DefaultDepth> = M extends LocaleMessages ? M[Locale<M>] extends infer Messages ? Messages extends MessageValue ? AtPath<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafKeys<Scoped, D> : never : never : never : never : string;
|
|
256
209
|
/**
|
|
257
210
|
* Resolves the value type of a scoped leaf key (`K`)
|
|
258
211
|
* under a prefix path (`PK`) from localized messages.
|
|
@@ -267,7 +220,108 @@ type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union",
|
|
|
267
220
|
* ScopedLeafValue<typeof messages, "a.b", "c">; // string
|
|
268
221
|
* ```
|
|
269
222
|
*/
|
|
270
|
-
type ScopedLeafValue<M, PK extends string, K extends string
|
|
223
|
+
type ScopedLeafValue<M, PK extends string, K extends string> = M extends LocaleMessages ? M[Locale<M>] extends infer Messages ? Messages extends MessageValue ? AtPath<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafValue<Scoped, K> : never : never : never : never : MessageValue;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Represents a replacement map used for interpolating values
|
|
227
|
+
* in message templates.
|
|
228
|
+
*
|
|
229
|
+
* Replacement values are treated as plain data and interpreted
|
|
230
|
+
* by the message formatter at runtime.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* const replacements: Replacement = {
|
|
234
|
+
* name: "Alice",
|
|
235
|
+
* count: 5,
|
|
236
|
+
* nested: {
|
|
237
|
+
* score: 100,
|
|
238
|
+
* },
|
|
239
|
+
* };
|
|
240
|
+
*/
|
|
241
|
+
type Replacement = Record<string, unknown>;
|
|
242
|
+
/**
|
|
243
|
+
* Resolves the expected replacement type for a localized message key.
|
|
244
|
+
*
|
|
245
|
+
* Uses the canonical (default-locale) replacement schema when available,
|
|
246
|
+
* otherwise falls back to `Replacement`.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* type RMap = {
|
|
251
|
+
* "{locale}": {
|
|
252
|
+
* welcome: { name: MessageValue };
|
|
253
|
+
* total: { count: MessageValue };
|
|
254
|
+
* };
|
|
255
|
+
* };
|
|
256
|
+
*
|
|
257
|
+
* type WelcomeReplacement = LocalizedReplacement<RMap, "welcome">;
|
|
258
|
+
* // => { name: MessageValue }
|
|
259
|
+
*
|
|
260
|
+
* type UnknownReplacement = LocalizedReplacement<RMap, "unknown">;
|
|
261
|
+
* // => Replacement
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
type LocalizedReplacement<ReplacementSchema, K extends string> = ReplacementSchema extends {
|
|
265
|
+
"{locale}": infer LM;
|
|
266
|
+
} ? AtPath<LM, K> extends infer R ? R extends MessageObject ? R : Replacement : Replacement : Replacement;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Options for initializing a translator
|
|
270
|
+
*
|
|
271
|
+
* @template M - type of messages object
|
|
272
|
+
*/
|
|
273
|
+
interface BaseTranslatorOptions<M = unknown> {
|
|
274
|
+
/**
|
|
275
|
+
* Messages object for translations.
|
|
276
|
+
* - Use `LocaleMessages` type to enable key inference for `hasKey` and `t`.
|
|
277
|
+
*/
|
|
278
|
+
messages?: Readonly<M>;
|
|
279
|
+
/**
|
|
280
|
+
* Current locale key.
|
|
281
|
+
* - If `messages` is typed as `LocaleMessages`, this can be inferred automatically.
|
|
282
|
+
*/
|
|
283
|
+
locale: Locale<M>;
|
|
284
|
+
/**
|
|
285
|
+
* Indicates whether the translator is in a loading state.
|
|
286
|
+
*/
|
|
287
|
+
isLoading?: boolean;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* The minimal, shared foundation for all translators.
|
|
292
|
+
*
|
|
293
|
+
* @template M - Shape of the messages object.
|
|
294
|
+
*/
|
|
295
|
+
declare class BaseTranslator<M extends LocaleMessages | unknown = unknown> {
|
|
296
|
+
/** Current messages for translation */
|
|
297
|
+
protected _messages: Readonly<M>;
|
|
298
|
+
/** Current active locale */
|
|
299
|
+
protected _locale: Locale<M>;
|
|
300
|
+
/** Current loading state */
|
|
301
|
+
protected _isLoading: boolean;
|
|
302
|
+
constructor(options: BaseTranslatorOptions<M>);
|
|
303
|
+
/** Get messages. */
|
|
304
|
+
get messages(): M;
|
|
305
|
+
/** Get the current active locale. */
|
|
306
|
+
get locale(): Locale<M>;
|
|
307
|
+
/** Get the current loading state. */
|
|
308
|
+
get isLoading(): boolean;
|
|
309
|
+
/**
|
|
310
|
+
* Replace messages with new ones.
|
|
311
|
+
*
|
|
312
|
+
* - Note: This allows runtime setting of messages even if `M` is inferred as `never`.
|
|
313
|
+
* The type cast bypasses TypeScript restrictions on dynamic messages.
|
|
314
|
+
*/
|
|
315
|
+
setMessages<N extends LocaleMessages>(messages: N): void;
|
|
316
|
+
/**
|
|
317
|
+
* Set the active locale.
|
|
318
|
+
*
|
|
319
|
+
* - Note: Unlike `setMessages`, the locale structure cannot be changed at runtime.
|
|
320
|
+
*/
|
|
321
|
+
setLocale(newLocale: Locale<M>): void;
|
|
322
|
+
/** Set the loading state. */
|
|
323
|
+
setLoading(state: boolean): void;
|
|
324
|
+
}
|
|
271
325
|
|
|
272
326
|
/**
|
|
273
327
|
* Configuration options for translation behavior.
|
|
@@ -299,7 +353,7 @@ type LoadingHandler = (ctx: HandlerContext) => MessageValue;
|
|
|
299
353
|
type MissingHandler = (ctx: HandlerContext) => MessageValue;
|
|
300
354
|
/** Function to format a resolved message. */
|
|
301
355
|
type FormatHandler = (ctx: HandlerContext & {
|
|
302
|
-
|
|
356
|
+
rawMessage: string;
|
|
303
357
|
}) => MessageValue;
|
|
304
358
|
/**
|
|
305
359
|
* Snapshot of the translate pipeline context exposed to handlers.
|
|
@@ -330,9 +384,7 @@ interface TranslateContext {
|
|
|
330
384
|
/** Ordered list of locales to try, including fallbacks */
|
|
331
385
|
candidateLocales: string[];
|
|
332
386
|
/** Raw message value resolved from the message tree. */
|
|
333
|
-
|
|
334
|
-
/** Raw string message before formatting. */
|
|
335
|
-
rawString?: string;
|
|
387
|
+
rawMessage?: MessageValue;
|
|
336
388
|
/** Message after formatting (e.g. ICU, custom formatters) */
|
|
337
389
|
formattedMessage?: MessageValue;
|
|
338
390
|
/** Final value produced by the pipeline */
|
|
@@ -345,64 +397,6 @@ interface TranslateContext {
|
|
|
345
397
|
*/
|
|
346
398
|
type TranslateHook = RuraHook<TranslateContext, MessageValue>;
|
|
347
399
|
|
|
348
|
-
/**
|
|
349
|
-
* Options for initializing a translator
|
|
350
|
-
*
|
|
351
|
-
* @template M - type of messages object
|
|
352
|
-
*/
|
|
353
|
-
interface BaseTranslatorOptions<M = unknown> {
|
|
354
|
-
/**
|
|
355
|
-
* Messages object for translations.
|
|
356
|
-
* - Use `LocaleMessages` type to enable key inference for `hasKey` and `t`.
|
|
357
|
-
*/
|
|
358
|
-
messages?: Readonly<M>;
|
|
359
|
-
/**
|
|
360
|
-
* Current locale key.
|
|
361
|
-
* - If `messages` is typed as `LocaleMessages`, this can be inferred automatically.
|
|
362
|
-
*/
|
|
363
|
-
locale: Locale<M>;
|
|
364
|
-
/**
|
|
365
|
-
* Indicates whether the translator is in a loading state.
|
|
366
|
-
*/
|
|
367
|
-
isLoading?: boolean;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* The minimal, shared foundation for all translators.
|
|
372
|
-
*
|
|
373
|
-
* @template M - Shape of the messages object.
|
|
374
|
-
*/
|
|
375
|
-
declare class BaseTranslator<M extends LocaleMessages | unknown = unknown> {
|
|
376
|
-
/** Current messages for translation */
|
|
377
|
-
protected _messages: Readonly<M>;
|
|
378
|
-
/** Current active locale */
|
|
379
|
-
protected _locale: Locale<M>;
|
|
380
|
-
/** Current loading state */
|
|
381
|
-
protected _isLoading: boolean;
|
|
382
|
-
constructor(options: BaseTranslatorOptions<M>);
|
|
383
|
-
/** Get messages. */
|
|
384
|
-
get messages(): M;
|
|
385
|
-
/** Get the current active locale. */
|
|
386
|
-
get locale(): Locale<M>;
|
|
387
|
-
/** Get the current loading state. */
|
|
388
|
-
get isLoading(): boolean;
|
|
389
|
-
/**
|
|
390
|
-
* Replace messages with new ones.
|
|
391
|
-
*
|
|
392
|
-
* - Note: This allows runtime setting of messages even if `M` is inferred as `never`.
|
|
393
|
-
* The type cast bypasses TypeScript restrictions on dynamic messages.
|
|
394
|
-
*/
|
|
395
|
-
setMessages<N extends LocaleMessages>(messages: N): void;
|
|
396
|
-
/**
|
|
397
|
-
* Set the active locale.
|
|
398
|
-
*
|
|
399
|
-
* - Note: Unlike `setMessages`, the locale structure cannot be changed at runtime.
|
|
400
|
-
*/
|
|
401
|
-
setLocale(newLocale: Locale<M>): void;
|
|
402
|
-
/** Set the loading state. */
|
|
403
|
-
setLoading(state: boolean): void;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
400
|
interface CoreTranslatorOptions<M> extends BaseTranslatorOptions<M>, TranslateConfig<M> {
|
|
407
401
|
/** Optional plugins or raw hooks to extend the translation pipeline */
|
|
408
402
|
plugins?: Array<TranslatorPlugin | TranslateHook>;
|
|
@@ -419,9 +413,8 @@ interface TranslatorPlugin {
|
|
|
419
413
|
* using the pipeline engine and built-in hooks.
|
|
420
414
|
*
|
|
421
415
|
* @template M - Shape of the messages object.
|
|
422
|
-
* @template L - Locale selection strategy ("union" or specific locale keys).
|
|
423
416
|
*/
|
|
424
|
-
declare class CoreTranslator<M extends LocaleMessages | unknown = unknown,
|
|
417
|
+
declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, ReplacementSchema = unknown> extends BaseTranslator<M> {
|
|
425
418
|
/** User-provided options including messages, locale, and config. */
|
|
426
419
|
protected translateConfig: TranslateConfig<M>;
|
|
427
420
|
/** Active pipeline hooks applied during translation. */
|
|
@@ -434,24 +427,23 @@ declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, L ext
|
|
|
434
427
|
/** Outputs a debug overview of the active pipeline. */
|
|
435
428
|
debugHooks(): void;
|
|
436
429
|
/** Check if a key exists in the specified locale or current locale. */
|
|
437
|
-
hasKey: <K extends LocalizedLeafKeys<M
|
|
430
|
+
hasKey: <K extends LocalizedLeafKeys<M>>(key: K, targetLocale?: Locale<M>) => boolean;
|
|
438
431
|
/** Get the translated message for a key, with optional replacements. */
|
|
439
|
-
t: <K extends LocalizedLeafKeys<M
|
|
440
|
-
/** Get the raw message value for a key without formatting or interpolation. */
|
|
441
|
-
tRaw: <K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => LocalizedLeafValue<M, K, L>;
|
|
432
|
+
t: <K extends LocalizedLeafKeys<M> = LocalizedLeafKeys<M>>(key: K, ...replacementArgs: [LocalizedReplacement<ReplacementSchema, K>?]) => LocalizedLeafValue<M, K>;
|
|
442
433
|
}
|
|
443
434
|
|
|
444
435
|
type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
|
|
445
|
-
type ScopeTranslatorMethods<M extends LocaleMessages | unknown = unknown,
|
|
436
|
+
type ScopeTranslatorMethods<M extends LocaleMessages | unknown = unknown, ReplacementSchema = unknown, PK extends string | undefined = undefined, K extends string = PK extends string ? ScopedLeafKeys<M, PK> : LocalizedLeafKeys<M>> = {
|
|
446
437
|
hasKey: (key?: K, targetLocale?: Locale<M>) => boolean;
|
|
447
|
-
t: <Key extends K>(key?: Key,
|
|
448
|
-
|
|
438
|
+
t: <Key extends K>(key?: Key, ...replacementArgs: [
|
|
439
|
+
LocalizedReplacement<ReplacementSchema, PK extends string ? `${PK}.${Key & string}` : Key>?
|
|
440
|
+
]) => PK extends string ? ScopedLeafValue<M, PK, Key> : LocalizedLeafValue<M, Key>;
|
|
449
441
|
};
|
|
450
442
|
|
|
451
|
-
declare class ScopeTranslator<M extends LocaleMessages | unknown = unknown,
|
|
443
|
+
declare class ScopeTranslator<M extends LocaleMessages | unknown = unknown, ReplacementSchema = unknown> extends CoreTranslator<M, ReplacementSchema> {
|
|
452
444
|
constructor(options: ScopeTranslatorOptions<M>);
|
|
453
445
|
/** Create a scoped translator with a prefix key for resolving nested message paths. */
|
|
454
|
-
scoped<PK extends LocalizedNodeKeys<M
|
|
446
|
+
scoped<PK extends LocalizedNodeKeys<M> | undefined = undefined>(preKey?: PK): PK extends string ? ScopeTranslatorMethods<M, ReplacementSchema, PK> : ScopeTranslatorMethods<M, ReplacementSchema>;
|
|
455
447
|
}
|
|
456
448
|
|
|
457
449
|
/** Semantic tag attributes map. */
|
|
@@ -526,4 +518,4 @@ interface Renderer<Output> {
|
|
|
526
518
|
*/
|
|
527
519
|
declare function renderRichMessage<Output>(message: MessageValue, renderer: Renderer<Output>): Output[];
|
|
528
520
|
|
|
529
|
-
export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LeafValue, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedLeafValue, type
|
|
521
|
+
export { type ASTNode, type AtPath, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LeafValue, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedLeafValue, type LocalizedNodeKeys, type LocalizedReplacement, type MessageObject, type MessageValue, type MissingHandler, type NodeKeys, type Renderer, type Replacement, type ScopedLeafKeys, type ScopedLeafValue, type TranslateConfig, type TranslateContext, type TranslateHandlers, type TranslateHook, ScopeTranslator as Translator, type ScopeTranslatorMethods as TranslatorMethods, type ScopeTranslatorOptions as TranslatorOptions, type TranslatorPlugin, parseRichMessage, renderRichMessage };
|
package/dist/index.d.ts
CHANGED
|
@@ -42,30 +42,6 @@ type MessageLeaf = MessagePrimitive | MessageArray;
|
|
|
42
42
|
* ```
|
|
43
43
|
*/
|
|
44
44
|
type LocaleMessages = Record<string, MessageObject>;
|
|
45
|
-
/**
|
|
46
|
-
* Merges messages from all locales into a single unified structure,
|
|
47
|
-
* or extracts messages for a specific locale if `L` is provided.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```ts
|
|
51
|
-
* const messages = {
|
|
52
|
-
* en: { greeting: { morning: "morning" } },
|
|
53
|
-
* zh: { greeting: { evening: "晚上好" } },
|
|
54
|
-
* };
|
|
55
|
-
*
|
|
56
|
-
* // 1. Union of all locales
|
|
57
|
-
* UnionLocaleMessages<typeof messages>;
|
|
58
|
-
* // → { greeting: { morning: string; }; } | { greeting: { evening: string; }; }
|
|
59
|
-
*
|
|
60
|
-
* // 2. Messages for a specified locale
|
|
61
|
-
* UnionLocaleMessages<typeof messages, "en">; // → { greeting: { morning: string; }; }
|
|
62
|
-
* UnionLocaleMessages<typeof messages, "zh">; // → { greeting: { evening: string; }; }
|
|
63
|
-
*
|
|
64
|
-
* // 3. Fallback if M is not LocaleMessages
|
|
65
|
-
* UnionLocaleMessages // → unknown
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
type LocalizedMessagesUnion<M = unknown, L extends keyof M | "union" = "union"> = M extends LocaleMessages ? L extends "union" ? M[Locale<M>] : M[L & keyof M] : unknown;
|
|
69
45
|
|
|
70
46
|
/**
|
|
71
47
|
* Extracts locale keys only when M is a valid messages object.
|
|
@@ -106,25 +82,6 @@ type Locale<M = unknown> = M extends LocaleMessages ? keyof M & string : string;
|
|
|
106
82
|
*/
|
|
107
83
|
type FallbackLocalesMap<L extends string = string> = Partial<Record<L, L[]>>;
|
|
108
84
|
|
|
109
|
-
/**
|
|
110
|
-
* Represents a recursive replacement object used for interpolating values in message templates.
|
|
111
|
-
*
|
|
112
|
-
* - Each key can be any value (`string`, `number`, `boolean`, `Date`, `function`, nested object, etc.).
|
|
113
|
-
* - Supports nested structures for complex interpolation.
|
|
114
|
-
* - Can be used directly with `intl-messageformat` or custom format handlers.
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* const replacements: Replacement = {
|
|
118
|
-
* name: "Alice",
|
|
119
|
-
* count: 5,
|
|
120
|
-
* nested: {
|
|
121
|
-
* score: 100
|
|
122
|
-
* },
|
|
123
|
-
* formatter: (value: unknown) => `<b>${value}</b>`
|
|
124
|
-
* };
|
|
125
|
-
*/
|
|
126
|
-
type Replacement = Record<string, unknown>;
|
|
127
|
-
|
|
128
85
|
/**
|
|
129
86
|
* Default maximum recursive depth for nested key type computations,
|
|
130
87
|
* balancing type safety and compiler performance.
|
|
@@ -164,6 +121,19 @@ type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never
|
|
|
164
121
|
* ```
|
|
165
122
|
*/
|
|
166
123
|
type LeafValue<M, K extends string> = K extends `${infer Seg}.${infer Rest}` ? Seg extends keyof M ? LeafValue<M[Seg], Rest> : never : K extends keyof M ? M[K] : never;
|
|
124
|
+
/**
|
|
125
|
+
* Resolves the type located at a dot-separated path.
|
|
126
|
+
*
|
|
127
|
+
* The resolved type may be a subtree or a leaf value.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const messages = { a: { b: { c: "1" }, z: "2" } };
|
|
132
|
+
* AtPath<typeof messages, "a">; // → { b: { c: string }; z: string };
|
|
133
|
+
* AtPath<typeof messages, "a.b">; // → { c: string };
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
type AtPath<MessageSchema, PK extends string> = PK extends `${infer Head}.${infer Tail}` ? Head extends keyof MessageSchema ? AtPath<MessageSchema[Head], Tail> : never : PK extends keyof MessageSchema ? MessageSchema[PK] : never;
|
|
167
137
|
|
|
168
138
|
/**
|
|
169
139
|
* Extracts all **node keys** from the messages
|
|
@@ -187,7 +157,7 @@ type LeafValue<M, K extends string> = K extends `${infer Seg}.${infer Rest}` ? S
|
|
|
187
157
|
* LocalizedNodeKeys // → string
|
|
188
158
|
* ```
|
|
189
159
|
*/
|
|
190
|
-
type LocalizedNodeKeys<M = unknown,
|
|
160
|
+
type LocalizedNodeKeys<M = unknown, D extends number = DefaultDepth> = M extends LocaleMessages ? NodeKeys<M[keyof M], D> : string;
|
|
191
161
|
/**
|
|
192
162
|
* Extracts all **leaf keys** from the messages
|
|
193
163
|
* of a specified locale (or union of locales).
|
|
@@ -210,32 +180,15 @@ type LocalizedNodeKeys<M = unknown, L extends keyof M | "union" = "union", D ext
|
|
|
210
180
|
* LocalizedLeafKeys // → string
|
|
211
181
|
* ```
|
|
212
182
|
*/
|
|
213
|
-
type LocalizedLeafKeys<M = unknown,
|
|
183
|
+
type LocalizedLeafKeys<M = unknown, D extends number = DefaultDepth> = M extends LocaleMessages ? LeafKeys<M[keyof M], D> : string;
|
|
214
184
|
/**
|
|
215
185
|
* Resolves the value type of a **localized leaf key**
|
|
216
186
|
* from the messages of a specified locale (or union of locales).
|
|
217
187
|
*
|
|
218
188
|
* - Fallback to `MessageValue` if M is not LocaleMessages
|
|
219
189
|
*/
|
|
220
|
-
type LocalizedLeafValue<M = unknown, K extends string = string
|
|
190
|
+
type LocalizedLeafValue<M = unknown, K extends string = string> = M extends LocaleMessages ? LeafValue<M[keyof M], K> : MessageValue;
|
|
221
191
|
|
|
222
|
-
/**
|
|
223
|
-
* Resolves the type at a dot-separated key in a nested object.
|
|
224
|
-
*
|
|
225
|
-
* @example
|
|
226
|
-
* ```ts
|
|
227
|
-
* const structure = {
|
|
228
|
-
* a: {
|
|
229
|
-
* b: { c: "hello" },
|
|
230
|
-
* z: "world",
|
|
231
|
-
* },
|
|
232
|
-
* };
|
|
233
|
-
*
|
|
234
|
-
* MessagesAtPreKey<typeof structure, "a"> // → { b: { c: string; }; z: string;}
|
|
235
|
-
* MessagesAtPreKey<typeof structure, "a.b"> // → { c: string; };
|
|
236
|
-
* ```
|
|
237
|
-
*/
|
|
238
|
-
type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? MessagesAtPreKey<T[Head], Tail> : never : PK extends keyof T ? T[PK] : never;
|
|
239
192
|
/**
|
|
240
193
|
* Extracts all **leaf keys** under a scoped path (`PK`) from the messages
|
|
241
194
|
* of a specified locale (`L`) (or union of locales).
|
|
@@ -252,7 +205,7 @@ type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer
|
|
|
252
205
|
* ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
|
|
253
206
|
* ```
|
|
254
207
|
*/
|
|
255
|
-
type ScopedLeafKeys<M, PK extends string,
|
|
208
|
+
type ScopedLeafKeys<M, PK extends string, D extends number = DefaultDepth> = M extends LocaleMessages ? M[Locale<M>] extends infer Messages ? Messages extends MessageValue ? AtPath<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafKeys<Scoped, D> : never : never : never : never : string;
|
|
256
209
|
/**
|
|
257
210
|
* Resolves the value type of a scoped leaf key (`K`)
|
|
258
211
|
* under a prefix path (`PK`) from localized messages.
|
|
@@ -267,7 +220,108 @@ type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union",
|
|
|
267
220
|
* ScopedLeafValue<typeof messages, "a.b", "c">; // string
|
|
268
221
|
* ```
|
|
269
222
|
*/
|
|
270
|
-
type ScopedLeafValue<M, PK extends string, K extends string
|
|
223
|
+
type ScopedLeafValue<M, PK extends string, K extends string> = M extends LocaleMessages ? M[Locale<M>] extends infer Messages ? Messages extends MessageValue ? AtPath<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafValue<Scoped, K> : never : never : never : never : MessageValue;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Represents a replacement map used for interpolating values
|
|
227
|
+
* in message templates.
|
|
228
|
+
*
|
|
229
|
+
* Replacement values are treated as plain data and interpreted
|
|
230
|
+
* by the message formatter at runtime.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* const replacements: Replacement = {
|
|
234
|
+
* name: "Alice",
|
|
235
|
+
* count: 5,
|
|
236
|
+
* nested: {
|
|
237
|
+
* score: 100,
|
|
238
|
+
* },
|
|
239
|
+
* };
|
|
240
|
+
*/
|
|
241
|
+
type Replacement = Record<string, unknown>;
|
|
242
|
+
/**
|
|
243
|
+
* Resolves the expected replacement type for a localized message key.
|
|
244
|
+
*
|
|
245
|
+
* Uses the canonical (default-locale) replacement schema when available,
|
|
246
|
+
* otherwise falls back to `Replacement`.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* type RMap = {
|
|
251
|
+
* "{locale}": {
|
|
252
|
+
* welcome: { name: MessageValue };
|
|
253
|
+
* total: { count: MessageValue };
|
|
254
|
+
* };
|
|
255
|
+
* };
|
|
256
|
+
*
|
|
257
|
+
* type WelcomeReplacement = LocalizedReplacement<RMap, "welcome">;
|
|
258
|
+
* // => { name: MessageValue }
|
|
259
|
+
*
|
|
260
|
+
* type UnknownReplacement = LocalizedReplacement<RMap, "unknown">;
|
|
261
|
+
* // => Replacement
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
type LocalizedReplacement<ReplacementSchema, K extends string> = ReplacementSchema extends {
|
|
265
|
+
"{locale}": infer LM;
|
|
266
|
+
} ? AtPath<LM, K> extends infer R ? R extends MessageObject ? R : Replacement : Replacement : Replacement;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Options for initializing a translator
|
|
270
|
+
*
|
|
271
|
+
* @template M - type of messages object
|
|
272
|
+
*/
|
|
273
|
+
interface BaseTranslatorOptions<M = unknown> {
|
|
274
|
+
/**
|
|
275
|
+
* Messages object for translations.
|
|
276
|
+
* - Use `LocaleMessages` type to enable key inference for `hasKey` and `t`.
|
|
277
|
+
*/
|
|
278
|
+
messages?: Readonly<M>;
|
|
279
|
+
/**
|
|
280
|
+
* Current locale key.
|
|
281
|
+
* - If `messages` is typed as `LocaleMessages`, this can be inferred automatically.
|
|
282
|
+
*/
|
|
283
|
+
locale: Locale<M>;
|
|
284
|
+
/**
|
|
285
|
+
* Indicates whether the translator is in a loading state.
|
|
286
|
+
*/
|
|
287
|
+
isLoading?: boolean;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* The minimal, shared foundation for all translators.
|
|
292
|
+
*
|
|
293
|
+
* @template M - Shape of the messages object.
|
|
294
|
+
*/
|
|
295
|
+
declare class BaseTranslator<M extends LocaleMessages | unknown = unknown> {
|
|
296
|
+
/** Current messages for translation */
|
|
297
|
+
protected _messages: Readonly<M>;
|
|
298
|
+
/** Current active locale */
|
|
299
|
+
protected _locale: Locale<M>;
|
|
300
|
+
/** Current loading state */
|
|
301
|
+
protected _isLoading: boolean;
|
|
302
|
+
constructor(options: BaseTranslatorOptions<M>);
|
|
303
|
+
/** Get messages. */
|
|
304
|
+
get messages(): M;
|
|
305
|
+
/** Get the current active locale. */
|
|
306
|
+
get locale(): Locale<M>;
|
|
307
|
+
/** Get the current loading state. */
|
|
308
|
+
get isLoading(): boolean;
|
|
309
|
+
/**
|
|
310
|
+
* Replace messages with new ones.
|
|
311
|
+
*
|
|
312
|
+
* - Note: This allows runtime setting of messages even if `M` is inferred as `never`.
|
|
313
|
+
* The type cast bypasses TypeScript restrictions on dynamic messages.
|
|
314
|
+
*/
|
|
315
|
+
setMessages<N extends LocaleMessages>(messages: N): void;
|
|
316
|
+
/**
|
|
317
|
+
* Set the active locale.
|
|
318
|
+
*
|
|
319
|
+
* - Note: Unlike `setMessages`, the locale structure cannot be changed at runtime.
|
|
320
|
+
*/
|
|
321
|
+
setLocale(newLocale: Locale<M>): void;
|
|
322
|
+
/** Set the loading state. */
|
|
323
|
+
setLoading(state: boolean): void;
|
|
324
|
+
}
|
|
271
325
|
|
|
272
326
|
/**
|
|
273
327
|
* Configuration options for translation behavior.
|
|
@@ -299,7 +353,7 @@ type LoadingHandler = (ctx: HandlerContext) => MessageValue;
|
|
|
299
353
|
type MissingHandler = (ctx: HandlerContext) => MessageValue;
|
|
300
354
|
/** Function to format a resolved message. */
|
|
301
355
|
type FormatHandler = (ctx: HandlerContext & {
|
|
302
|
-
|
|
356
|
+
rawMessage: string;
|
|
303
357
|
}) => MessageValue;
|
|
304
358
|
/**
|
|
305
359
|
* Snapshot of the translate pipeline context exposed to handlers.
|
|
@@ -330,9 +384,7 @@ interface TranslateContext {
|
|
|
330
384
|
/** Ordered list of locales to try, including fallbacks */
|
|
331
385
|
candidateLocales: string[];
|
|
332
386
|
/** Raw message value resolved from the message tree. */
|
|
333
|
-
|
|
334
|
-
/** Raw string message before formatting. */
|
|
335
|
-
rawString?: string;
|
|
387
|
+
rawMessage?: MessageValue;
|
|
336
388
|
/** Message after formatting (e.g. ICU, custom formatters) */
|
|
337
389
|
formattedMessage?: MessageValue;
|
|
338
390
|
/** Final value produced by the pipeline */
|
|
@@ -345,64 +397,6 @@ interface TranslateContext {
|
|
|
345
397
|
*/
|
|
346
398
|
type TranslateHook = RuraHook<TranslateContext, MessageValue>;
|
|
347
399
|
|
|
348
|
-
/**
|
|
349
|
-
* Options for initializing a translator
|
|
350
|
-
*
|
|
351
|
-
* @template M - type of messages object
|
|
352
|
-
*/
|
|
353
|
-
interface BaseTranslatorOptions<M = unknown> {
|
|
354
|
-
/**
|
|
355
|
-
* Messages object for translations.
|
|
356
|
-
* - Use `LocaleMessages` type to enable key inference for `hasKey` and `t`.
|
|
357
|
-
*/
|
|
358
|
-
messages?: Readonly<M>;
|
|
359
|
-
/**
|
|
360
|
-
* Current locale key.
|
|
361
|
-
* - If `messages` is typed as `LocaleMessages`, this can be inferred automatically.
|
|
362
|
-
*/
|
|
363
|
-
locale: Locale<M>;
|
|
364
|
-
/**
|
|
365
|
-
* Indicates whether the translator is in a loading state.
|
|
366
|
-
*/
|
|
367
|
-
isLoading?: boolean;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* The minimal, shared foundation for all translators.
|
|
372
|
-
*
|
|
373
|
-
* @template M - Shape of the messages object.
|
|
374
|
-
*/
|
|
375
|
-
declare class BaseTranslator<M extends LocaleMessages | unknown = unknown> {
|
|
376
|
-
/** Current messages for translation */
|
|
377
|
-
protected _messages: Readonly<M>;
|
|
378
|
-
/** Current active locale */
|
|
379
|
-
protected _locale: Locale<M>;
|
|
380
|
-
/** Current loading state */
|
|
381
|
-
protected _isLoading: boolean;
|
|
382
|
-
constructor(options: BaseTranslatorOptions<M>);
|
|
383
|
-
/** Get messages. */
|
|
384
|
-
get messages(): M;
|
|
385
|
-
/** Get the current active locale. */
|
|
386
|
-
get locale(): Locale<M>;
|
|
387
|
-
/** Get the current loading state. */
|
|
388
|
-
get isLoading(): boolean;
|
|
389
|
-
/**
|
|
390
|
-
* Replace messages with new ones.
|
|
391
|
-
*
|
|
392
|
-
* - Note: This allows runtime setting of messages even if `M` is inferred as `never`.
|
|
393
|
-
* The type cast bypasses TypeScript restrictions on dynamic messages.
|
|
394
|
-
*/
|
|
395
|
-
setMessages<N extends LocaleMessages>(messages: N): void;
|
|
396
|
-
/**
|
|
397
|
-
* Set the active locale.
|
|
398
|
-
*
|
|
399
|
-
* - Note: Unlike `setMessages`, the locale structure cannot be changed at runtime.
|
|
400
|
-
*/
|
|
401
|
-
setLocale(newLocale: Locale<M>): void;
|
|
402
|
-
/** Set the loading state. */
|
|
403
|
-
setLoading(state: boolean): void;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
400
|
interface CoreTranslatorOptions<M> extends BaseTranslatorOptions<M>, TranslateConfig<M> {
|
|
407
401
|
/** Optional plugins or raw hooks to extend the translation pipeline */
|
|
408
402
|
plugins?: Array<TranslatorPlugin | TranslateHook>;
|
|
@@ -419,9 +413,8 @@ interface TranslatorPlugin {
|
|
|
419
413
|
* using the pipeline engine and built-in hooks.
|
|
420
414
|
*
|
|
421
415
|
* @template M - Shape of the messages object.
|
|
422
|
-
* @template L - Locale selection strategy ("union" or specific locale keys).
|
|
423
416
|
*/
|
|
424
|
-
declare class CoreTranslator<M extends LocaleMessages | unknown = unknown,
|
|
417
|
+
declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, ReplacementSchema = unknown> extends BaseTranslator<M> {
|
|
425
418
|
/** User-provided options including messages, locale, and config. */
|
|
426
419
|
protected translateConfig: TranslateConfig<M>;
|
|
427
420
|
/** Active pipeline hooks applied during translation. */
|
|
@@ -434,24 +427,23 @@ declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, L ext
|
|
|
434
427
|
/** Outputs a debug overview of the active pipeline. */
|
|
435
428
|
debugHooks(): void;
|
|
436
429
|
/** Check if a key exists in the specified locale or current locale. */
|
|
437
|
-
hasKey: <K extends LocalizedLeafKeys<M
|
|
430
|
+
hasKey: <K extends LocalizedLeafKeys<M>>(key: K, targetLocale?: Locale<M>) => boolean;
|
|
438
431
|
/** Get the translated message for a key, with optional replacements. */
|
|
439
|
-
t: <K extends LocalizedLeafKeys<M
|
|
440
|
-
/** Get the raw message value for a key without formatting or interpolation. */
|
|
441
|
-
tRaw: <K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => LocalizedLeafValue<M, K, L>;
|
|
432
|
+
t: <K extends LocalizedLeafKeys<M> = LocalizedLeafKeys<M>>(key: K, ...replacementArgs: [LocalizedReplacement<ReplacementSchema, K>?]) => LocalizedLeafValue<M, K>;
|
|
442
433
|
}
|
|
443
434
|
|
|
444
435
|
type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
|
|
445
|
-
type ScopeTranslatorMethods<M extends LocaleMessages | unknown = unknown,
|
|
436
|
+
type ScopeTranslatorMethods<M extends LocaleMessages | unknown = unknown, ReplacementSchema = unknown, PK extends string | undefined = undefined, K extends string = PK extends string ? ScopedLeafKeys<M, PK> : LocalizedLeafKeys<M>> = {
|
|
446
437
|
hasKey: (key?: K, targetLocale?: Locale<M>) => boolean;
|
|
447
|
-
t: <Key extends K>(key?: Key,
|
|
448
|
-
|
|
438
|
+
t: <Key extends K>(key?: Key, ...replacementArgs: [
|
|
439
|
+
LocalizedReplacement<ReplacementSchema, PK extends string ? `${PK}.${Key & string}` : Key>?
|
|
440
|
+
]) => PK extends string ? ScopedLeafValue<M, PK, Key> : LocalizedLeafValue<M, Key>;
|
|
449
441
|
};
|
|
450
442
|
|
|
451
|
-
declare class ScopeTranslator<M extends LocaleMessages | unknown = unknown,
|
|
443
|
+
declare class ScopeTranslator<M extends LocaleMessages | unknown = unknown, ReplacementSchema = unknown> extends CoreTranslator<M, ReplacementSchema> {
|
|
452
444
|
constructor(options: ScopeTranslatorOptions<M>);
|
|
453
445
|
/** Create a scoped translator with a prefix key for resolving nested message paths. */
|
|
454
|
-
scoped<PK extends LocalizedNodeKeys<M
|
|
446
|
+
scoped<PK extends LocalizedNodeKeys<M> | undefined = undefined>(preKey?: PK): PK extends string ? ScopeTranslatorMethods<M, ReplacementSchema, PK> : ScopeTranslatorMethods<M, ReplacementSchema>;
|
|
455
447
|
}
|
|
456
448
|
|
|
457
449
|
/** Semantic tag attributes map. */
|
|
@@ -526,4 +518,4 @@ interface Renderer<Output> {
|
|
|
526
518
|
*/
|
|
527
519
|
declare function renderRichMessage<Output>(message: MessageValue, renderer: Renderer<Output>): Output[];
|
|
528
520
|
|
|
529
|
-
export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LeafValue, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedLeafValue, type
|
|
521
|
+
export { type ASTNode, type AtPath, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LeafValue, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedLeafValue, type LocalizedNodeKeys, type LocalizedReplacement, type MessageObject, type MessageValue, type MissingHandler, type NodeKeys, type Renderer, type Replacement, type ScopedLeafKeys, type ScopedLeafValue, type TranslateConfig, type TranslateContext, type TranslateHandlers, type TranslateHook, ScopeTranslator as Translator, type ScopeTranslatorMethods as TranslatorMethods, type ScopeTranslatorOptions as TranslatorOptions, type TranslatorPlugin, parseRichMessage, renderRichMessage };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { rura } from 'rura';
|
|
2
2
|
|
|
3
3
|
// src/translators/core-translator/core-translator.ts
|
|
4
|
+
function runTranslate(options) {
|
|
5
|
+
const context = {
|
|
6
|
+
...options,
|
|
7
|
+
config: options.translateConfig,
|
|
8
|
+
candidateLocales: [],
|
|
9
|
+
meta: {}
|
|
10
|
+
};
|
|
11
|
+
return rura.run(context, options.hooks);
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
// src/shared/utils/find-message-in-locales.ts
|
|
6
15
|
var findMessageInLocales = ({
|
|
@@ -29,15 +38,11 @@ var findMessageInLocales = ({
|
|
|
29
38
|
var findMessage = rura.createHook(
|
|
30
39
|
"findMessage",
|
|
31
40
|
(ctx) => {
|
|
32
|
-
ctx.
|
|
33
|
-
ctx.rawString = void 0;
|
|
34
|
-
const message = findMessageInLocales({
|
|
41
|
+
ctx.rawMessage = findMessageInLocales({
|
|
35
42
|
messages: ctx.messages,
|
|
36
43
|
candidateLocales: ctx.candidateLocales,
|
|
37
44
|
key: ctx.key
|
|
38
45
|
});
|
|
39
|
-
ctx.rawValue = message;
|
|
40
|
-
if (typeof message === "string") ctx.rawString = message;
|
|
41
46
|
},
|
|
42
47
|
200
|
|
43
48
|
);
|
|
@@ -52,8 +57,7 @@ function makeHandlerContext(ctx) {
|
|
|
52
57
|
key: ctx.key,
|
|
53
58
|
replacements: ctx.replacements,
|
|
54
59
|
candidateLocales: ctx.candidateLocales,
|
|
55
|
-
|
|
56
|
-
rawString: ctx.rawString,
|
|
60
|
+
rawMessage: ctx.rawMessage,
|
|
57
61
|
formattedMessage: ctx.formattedMessage,
|
|
58
62
|
meta: ctx.meta
|
|
59
63
|
});
|
|
@@ -63,9 +67,9 @@ function makeHandlerContext(ctx) {
|
|
|
63
67
|
var format = rura.createHook(
|
|
64
68
|
"format",
|
|
65
69
|
(ctx) => {
|
|
66
|
-
const { config,
|
|
70
|
+
const { config, rawMessage } = ctx;
|
|
67
71
|
const { formatHandler } = config.handlers || {};
|
|
68
|
-
if (!formatHandler ||
|
|
72
|
+
if (!formatHandler || rawMessage === void 0) return;
|
|
69
73
|
ctx.formattedMessage = formatHandler(
|
|
70
74
|
makeHandlerContext(ctx)
|
|
71
75
|
);
|
|
@@ -96,8 +100,8 @@ var replaceValues = (message, params) => {
|
|
|
96
100
|
var interpolate = rura.createHook(
|
|
97
101
|
"interpolate",
|
|
98
102
|
(ctx) => {
|
|
99
|
-
const {
|
|
100
|
-
const message = formattedMessage ??
|
|
103
|
+
const { rawMessage, formattedMessage, replacements } = ctx;
|
|
104
|
+
const message = formattedMessage ?? rawMessage;
|
|
101
105
|
if (typeof message !== "string" || !replacements) {
|
|
102
106
|
ctx.finalMessage = message;
|
|
103
107
|
return;
|
|
@@ -128,8 +132,8 @@ var loading = rura.createHook(
|
|
|
128
132
|
var missing = rura.createHook(
|
|
129
133
|
"missing",
|
|
130
134
|
(ctx) => {
|
|
131
|
-
const { config, key,
|
|
132
|
-
if (
|
|
135
|
+
const { config, key, rawMessage } = ctx;
|
|
136
|
+
if (rawMessage !== void 0) return;
|
|
133
137
|
const { missingHandler } = config.handlers || {};
|
|
134
138
|
if (missingHandler) {
|
|
135
139
|
return {
|
|
@@ -234,15 +238,6 @@ var hasKey = ({
|
|
|
234
238
|
const message = findMessageInLocales({ messages, candidateLocales, key });
|
|
235
239
|
return message !== void 0;
|
|
236
240
|
};
|
|
237
|
-
function runTranslate(options) {
|
|
238
|
-
const context = {
|
|
239
|
-
...options,
|
|
240
|
-
config: options.translateConfig,
|
|
241
|
-
candidateLocales: [],
|
|
242
|
-
meta: {}
|
|
243
|
-
};
|
|
244
|
-
return rura.run(context, options.hooks);
|
|
245
|
-
}
|
|
246
241
|
|
|
247
242
|
// src/translators/methods/translate.ts
|
|
248
243
|
function translate(options) {
|
|
@@ -254,15 +249,6 @@ function translate(options) {
|
|
|
254
249
|
return ctx.finalMessage;
|
|
255
250
|
}
|
|
256
251
|
|
|
257
|
-
// src/translators/methods/translate-raw.ts
|
|
258
|
-
function translateRaw(options) {
|
|
259
|
-
const { ctx } = runTranslate(options);
|
|
260
|
-
if (ctx.rawValue === void 0) {
|
|
261
|
-
throw new Error("Invariant violated: missing hook did not produce output");
|
|
262
|
-
}
|
|
263
|
-
return ctx.rawValue;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
252
|
// src/translators/core-translator/core-translator.ts
|
|
267
253
|
var CoreTranslator = class extends BaseTranslator {
|
|
268
254
|
/** User-provided options including messages, locale, and config. */
|
|
@@ -307,7 +293,7 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
307
293
|
});
|
|
308
294
|
};
|
|
309
295
|
/** Get the translated message for a key, with optional replacements. */
|
|
310
|
-
t = (key,
|
|
296
|
+
t = (key, ...replacementArgs) => {
|
|
311
297
|
return translate({
|
|
312
298
|
hooks: this.hooks,
|
|
313
299
|
messages: this._messages,
|
|
@@ -315,19 +301,7 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
315
301
|
isLoading: this._isLoading,
|
|
316
302
|
translateConfig: this.translateConfig,
|
|
317
303
|
key,
|
|
318
|
-
replacements
|
|
319
|
-
});
|
|
320
|
-
};
|
|
321
|
-
/** Get the raw message value for a key without formatting or interpolation. */
|
|
322
|
-
tRaw = (key, replacements) => {
|
|
323
|
-
return translateRaw({
|
|
324
|
-
hooks: this.hooks,
|
|
325
|
-
messages: this._messages,
|
|
326
|
-
locale: this._locale,
|
|
327
|
-
isLoading: this._isLoading,
|
|
328
|
-
translateConfig: this.translateConfig,
|
|
329
|
-
key,
|
|
330
|
-
replacements
|
|
304
|
+
replacements: replacementArgs[0]
|
|
331
305
|
});
|
|
332
306
|
};
|
|
333
307
|
};
|
|
@@ -356,7 +330,7 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
356
330
|
targetLocale
|
|
357
331
|
});
|
|
358
332
|
},
|
|
359
|
-
t: (key,
|
|
333
|
+
t: (key, ...args) => {
|
|
360
334
|
const fullKey = getFullKey(preKey, key);
|
|
361
335
|
return translate({
|
|
362
336
|
hooks: this.hooks,
|
|
@@ -365,19 +339,7 @@ var ScopeTranslator = class extends CoreTranslator {
|
|
|
365
339
|
isLoading: this._isLoading,
|
|
366
340
|
translateConfig: this.translateConfig,
|
|
367
341
|
key: fullKey,
|
|
368
|
-
replacements
|
|
369
|
-
});
|
|
370
|
-
},
|
|
371
|
-
tRaw: (key, replacements) => {
|
|
372
|
-
const fullKey = getFullKey(preKey, key);
|
|
373
|
-
return translateRaw({
|
|
374
|
-
hooks: this.hooks,
|
|
375
|
-
messages: this._messages,
|
|
376
|
-
locale: this._locale,
|
|
377
|
-
isLoading: this._isLoading,
|
|
378
|
-
translateConfig: this.translateConfig,
|
|
379
|
-
key: fullKey,
|
|
380
|
-
replacements
|
|
342
|
+
replacements: args[0]
|
|
381
343
|
});
|
|
382
344
|
}
|
|
383
345
|
};
|