intor-translator 1.3.1 → 1.4.0
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 +50 -22
- package/dist/index.d.cts +27 -40
- package/dist/index.d.ts +27 -40
- package/dist/index.js +50 -22
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -11,19 +11,19 @@ var findMessageInLocales = ({
|
|
|
11
11
|
key
|
|
12
12
|
}) => {
|
|
13
13
|
for (const locale of candidateLocales) {
|
|
14
|
-
const
|
|
15
|
-
if (!
|
|
16
|
-
let candidate =
|
|
14
|
+
const messagesForLocale = messages[locale];
|
|
15
|
+
if (!messagesForLocale) continue;
|
|
16
|
+
let candidate = messagesForLocale;
|
|
17
17
|
const keys = key.split(".");
|
|
18
|
-
for (const
|
|
19
|
-
if (candidate && typeof candidate === "object" &&
|
|
20
|
-
candidate = candidate[
|
|
18
|
+
for (const key2 of keys) {
|
|
19
|
+
if (candidate !== null && typeof candidate === "object" && key2 in candidate) {
|
|
20
|
+
candidate = candidate[key2];
|
|
21
21
|
} else {
|
|
22
22
|
candidate = void 0;
|
|
23
23
|
break;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
if (
|
|
26
|
+
if (candidate !== void 0) return candidate;
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
|
|
@@ -31,11 +31,15 @@ var findMessageInLocales = ({
|
|
|
31
31
|
var findMessage = rura.rura.createHook(
|
|
32
32
|
"findMessage",
|
|
33
33
|
(ctx) => {
|
|
34
|
-
ctx.
|
|
34
|
+
ctx.rawValue = void 0;
|
|
35
|
+
ctx.rawString = void 0;
|
|
36
|
+
const message = findMessageInLocales({
|
|
35
37
|
messages: ctx.messages,
|
|
36
38
|
candidateLocales: ctx.candidateLocales,
|
|
37
39
|
key: ctx.key
|
|
38
40
|
});
|
|
41
|
+
ctx.rawValue = message;
|
|
42
|
+
if (typeof message === "string") ctx.rawString = message;
|
|
39
43
|
},
|
|
40
44
|
200
|
|
41
45
|
);
|
|
@@ -50,7 +54,8 @@ function makeHandlerContext(ctx) {
|
|
|
50
54
|
key: ctx.key,
|
|
51
55
|
replacements: ctx.replacements,
|
|
52
56
|
candidateLocales: ctx.candidateLocales,
|
|
53
|
-
|
|
57
|
+
rawValue: ctx.rawValue,
|
|
58
|
+
rawString: ctx.rawString,
|
|
54
59
|
formattedMessage: ctx.formattedMessage,
|
|
55
60
|
meta: ctx.meta
|
|
56
61
|
});
|
|
@@ -60,9 +65,9 @@ function makeHandlerContext(ctx) {
|
|
|
60
65
|
var format = rura.rura.createHook(
|
|
61
66
|
"format",
|
|
62
67
|
(ctx) => {
|
|
63
|
-
const { config,
|
|
68
|
+
const { config, rawString } = ctx;
|
|
64
69
|
const { formatHandler } = config.handlers || {};
|
|
65
|
-
if (!formatHandler ||
|
|
70
|
+
if (!formatHandler || rawString === void 0) return;
|
|
66
71
|
ctx.formattedMessage = formatHandler(
|
|
67
72
|
makeHandlerContext(ctx)
|
|
68
73
|
);
|
|
@@ -93,8 +98,8 @@ var replaceValues = (message, params) => {
|
|
|
93
98
|
var interpolate = rura.rura.createHook(
|
|
94
99
|
"interpolate",
|
|
95
100
|
(ctx) => {
|
|
96
|
-
const {
|
|
97
|
-
const message = formattedMessage ??
|
|
101
|
+
const { rawString, formattedMessage, replacements } = ctx;
|
|
102
|
+
const message = formattedMessage ?? rawString;
|
|
98
103
|
if (typeof message !== "string" || !replacements) {
|
|
99
104
|
ctx.finalMessage = message;
|
|
100
105
|
return;
|
|
@@ -116,7 +121,7 @@ var loading = rura.rura.createHook(
|
|
|
116
121
|
};
|
|
117
122
|
}
|
|
118
123
|
const { loadingMessage } = config;
|
|
119
|
-
if (loadingMessage) {
|
|
124
|
+
if ("loadingMessage" in config) {
|
|
120
125
|
return { early: true, output: loadingMessage };
|
|
121
126
|
}
|
|
122
127
|
},
|
|
@@ -125,8 +130,8 @@ var loading = rura.rura.createHook(
|
|
|
125
130
|
var missing = rura.rura.createHook(
|
|
126
131
|
"missing",
|
|
127
132
|
(ctx) => {
|
|
128
|
-
const { config, key,
|
|
129
|
-
if (
|
|
133
|
+
const { config, key, rawString } = ctx;
|
|
134
|
+
if (rawString !== void 0) return;
|
|
130
135
|
const { missingHandler } = config.handlers || {};
|
|
131
136
|
if (missingHandler) {
|
|
132
137
|
return {
|
|
@@ -134,9 +139,9 @@ var missing = rura.rura.createHook(
|
|
|
134
139
|
output: missingHandler(makeHandlerContext(ctx))
|
|
135
140
|
};
|
|
136
141
|
}
|
|
137
|
-
const {
|
|
138
|
-
if (
|
|
139
|
-
return { early: true, output:
|
|
142
|
+
const { missingMessage } = config;
|
|
143
|
+
if ("missingMessage" in config) {
|
|
144
|
+
return { early: true, output: missingMessage };
|
|
140
145
|
}
|
|
141
146
|
return { early: true, output: key };
|
|
142
147
|
},
|
|
@@ -229,20 +234,31 @@ var hasKey = ({
|
|
|
229
234
|
}) => {
|
|
230
235
|
const candidateLocales = resolveCandidateLocales(targetLocale || locale);
|
|
231
236
|
const message = findMessageInLocales({ messages, candidateLocales, key });
|
|
232
|
-
return
|
|
237
|
+
return message !== void 0;
|
|
233
238
|
};
|
|
234
|
-
function
|
|
239
|
+
function runTranslate(options) {
|
|
235
240
|
const context = {
|
|
236
241
|
...options,
|
|
237
242
|
config: options.translateConfig,
|
|
238
243
|
candidateLocales: [],
|
|
239
244
|
meta: {}
|
|
240
245
|
};
|
|
241
|
-
|
|
246
|
+
return rura.rura.run(context, options.hooks);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/translators/methods/translate.ts
|
|
250
|
+
function translate(options) {
|
|
251
|
+
const { early, ctx, output } = runTranslate(options);
|
|
242
252
|
if (early === true) return output;
|
|
243
253
|
return ctx.finalMessage;
|
|
244
254
|
}
|
|
245
255
|
|
|
256
|
+
// src/translators/methods/translate-raw.ts
|
|
257
|
+
function translateRaw(options) {
|
|
258
|
+
const { ctx } = runTranslate(options);
|
|
259
|
+
return ctx.rawValue;
|
|
260
|
+
}
|
|
261
|
+
|
|
246
262
|
// src/translators/core-translator/core-translator.ts
|
|
247
263
|
var CoreTranslator = class extends BaseTranslator {
|
|
248
264
|
/** User-provided options including messages, locale, and config. */
|
|
@@ -298,6 +314,18 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
298
314
|
replacements
|
|
299
315
|
});
|
|
300
316
|
};
|
|
317
|
+
/** Get the raw message value for a key without formatting or interpolation. */
|
|
318
|
+
tRaw = (key, replacements) => {
|
|
319
|
+
return translateRaw({
|
|
320
|
+
hooks: this.hooks,
|
|
321
|
+
messages: this._messages,
|
|
322
|
+
locale: this._locale,
|
|
323
|
+
isLoading: this._isLoading,
|
|
324
|
+
translateConfig: this.translateConfig,
|
|
325
|
+
key,
|
|
326
|
+
replacements
|
|
327
|
+
});
|
|
328
|
+
};
|
|
301
329
|
};
|
|
302
330
|
|
|
303
331
|
// src/translators/scope-translator/utils/get-full-key.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
import { RuraHook } from 'rura';
|
|
2
2
|
|
|
3
|
+
type MessagePrimitive = string | number | boolean | null;
|
|
4
|
+
type MessageArray = readonly MessageValue[];
|
|
5
|
+
interface MessageObject {
|
|
6
|
+
[key: string]: MessageValue;
|
|
7
|
+
}
|
|
8
|
+
/** A message value in the locale message tree. */
|
|
9
|
+
type MessageValue = MessagePrimitive | MessageObject | MessageArray;
|
|
3
10
|
/**
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
* - Used to represent either a plain message or an object containing more nested messages.
|
|
11
|
+
* A non-traversable message value.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* const greeting: NestedMessage = "Hello";
|
|
11
|
-
* const userMessages: NestedMessage = {
|
|
12
|
-
* profile: {
|
|
13
|
-
* greeting: "Hello, user!",
|
|
14
|
-
* farewell: "Goodbye!"
|
|
15
|
-
* }
|
|
16
|
-
* };
|
|
17
|
-
* ```
|
|
13
|
+
* Leaf values represent the end of a message path.
|
|
18
14
|
*/
|
|
19
|
-
type
|
|
20
|
-
[key: string]: NestedMessage;
|
|
21
|
-
};
|
|
15
|
+
type MessageLeaf = MessagePrimitive | MessageArray;
|
|
22
16
|
/**
|
|
23
17
|
* Messages grouped by locale.
|
|
24
18
|
* Used to structure all available messages for multiple locales.
|
|
25
19
|
*
|
|
26
20
|
* - The root-level keys are locale identifiers, e.g., "en" or "zh-TW".
|
|
27
|
-
* - Each value is a `
|
|
21
|
+
* - Each value is a `MessageObject`, allowing for deeply nested message objects.
|
|
28
22
|
*
|
|
29
23
|
* @example
|
|
30
24
|
* ```ts
|
|
@@ -37,22 +31,11 @@ type NestedMessage = string | {
|
|
|
37
31
|
* failure: "Login failed"
|
|
38
32
|
* }
|
|
39
33
|
* }
|
|
40
|
-
* },
|
|
41
|
-
* "zh-TW": {
|
|
42
|
-
* welcome: "歡迎",
|
|
43
|
-
* auth: {
|
|
44
|
-
* login: {
|
|
45
|
-
* success: "登入成功",
|
|
46
|
-
* failure: "登入失敗"
|
|
47
|
-
* }
|
|
48
|
-
* }
|
|
49
34
|
* }
|
|
50
35
|
* };
|
|
51
36
|
* ```
|
|
52
37
|
*/
|
|
53
|
-
type LocaleMessages = Record<string,
|
|
54
|
-
[x: string]: NestedMessage;
|
|
55
|
-
}>;
|
|
38
|
+
type LocaleMessages = Record<string, MessageObject>;
|
|
56
39
|
/**
|
|
57
40
|
* Merges messages from all locales into a single unified structure,
|
|
58
41
|
* or extracts messages for a specific locale if `L` is provided.
|
|
@@ -144,7 +127,7 @@ type DefaultDepth = 15;
|
|
|
144
127
|
/** Countdown tuple for limiting recursive depth (up to 15 levels). */
|
|
145
128
|
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
146
129
|
/**
|
|
147
|
-
* Gets all dot-separated keys
|
|
130
|
+
* Gets all dot-separated keys of a nested object, stopping at message leaf values.
|
|
148
131
|
*
|
|
149
132
|
* @example
|
|
150
133
|
* ```ts
|
|
@@ -152,10 +135,10 @@ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
|
152
135
|
* ```
|
|
153
136
|
*/
|
|
154
137
|
type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
155
|
-
[K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K], Prev[D]>}` : never;
|
|
138
|
+
[K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}` | `${K & string}.${NodeKeys<M[K], Prev[D]>}` : never;
|
|
156
139
|
}[keyof M] : never;
|
|
157
140
|
/**
|
|
158
|
-
* Gets dot-separated keys to
|
|
141
|
+
* Gets dot-separated keys that resolve to message leaf values in a nested object.
|
|
159
142
|
*
|
|
160
143
|
* @example
|
|
161
144
|
* ```ts
|
|
@@ -163,7 +146,7 @@ type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never
|
|
|
163
146
|
* ```
|
|
164
147
|
*/
|
|
165
148
|
type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
166
|
-
[K in keyof M]: M[K] extends
|
|
149
|
+
[K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
|
|
167
150
|
}[keyof M] : never;
|
|
168
151
|
|
|
169
152
|
/**
|
|
@@ -246,7 +229,7 @@ type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer
|
|
|
246
229
|
* ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
|
|
247
230
|
* ```
|
|
248
231
|
*/
|
|
249
|
-
type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer
|
|
232
|
+
type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer Messages ? Messages extends MessageValue ? MessagesAtPreKey<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafKeys<Scoped, D> : never : never : never : never : string;
|
|
250
233
|
|
|
251
234
|
/**
|
|
252
235
|
* Configuration options for translation behavior.
|
|
@@ -258,8 +241,8 @@ type TranslateConfig<M = unknown> = {
|
|
|
258
241
|
fallbackLocales?: FallbackLocalesMap<Locale<M>>;
|
|
259
242
|
/** Optional message to display while translations are still loading. */
|
|
260
243
|
loadingMessage?: string;
|
|
261
|
-
/** Optional
|
|
262
|
-
|
|
244
|
+
/** Optional message used when a translation is missing. */
|
|
245
|
+
missingMessage?: string;
|
|
263
246
|
/** Optional set of handler functions for customizing translation behavior. */
|
|
264
247
|
handlers?: TranslateHandlers;
|
|
265
248
|
};
|
|
@@ -278,7 +261,7 @@ type LoadingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
|
|
|
278
261
|
type MissingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
|
|
279
262
|
/** Function to format a resolved message. */
|
|
280
263
|
type FormatHandler<Result = unknown> = (ctx: HandlerContext & {
|
|
281
|
-
|
|
264
|
+
rawString: string;
|
|
282
265
|
}) => Result;
|
|
283
266
|
/**
|
|
284
267
|
* Snapshot of the translate pipeline context exposed to handlers.
|
|
@@ -310,8 +293,10 @@ interface TranslateContext<Result = unknown> {
|
|
|
310
293
|
replacements?: Replacement;
|
|
311
294
|
/** Ordered list of locales to try, including fallbacks */
|
|
312
295
|
candidateLocales: string[];
|
|
313
|
-
/** Raw message
|
|
314
|
-
|
|
296
|
+
/** Raw message value resolved from the message tree. */
|
|
297
|
+
rawValue?: MessageValue;
|
|
298
|
+
/** Raw string message before formatting. */
|
|
299
|
+
rawString?: string;
|
|
315
300
|
/** Message after formatting (e.g. ICU, custom formatters) */
|
|
316
301
|
formattedMessage?: unknown;
|
|
317
302
|
/** Final value produced by the pipeline */
|
|
@@ -416,6 +401,8 @@ declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, L ext
|
|
|
416
401
|
hasKey: <K extends LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
|
|
417
402
|
/** Get the translated message for a key, with optional replacements. */
|
|
418
403
|
t: <Result = string, K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => Result;
|
|
404
|
+
/** Get the raw message value for a key without formatting or interpolation. */
|
|
405
|
+
tRaw: <K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => MessageValue | undefined;
|
|
419
406
|
}
|
|
420
407
|
|
|
421
408
|
type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
|
|
@@ -496,4 +483,4 @@ interface Renderer<Output> {
|
|
|
496
483
|
*/
|
|
497
484
|
declare function renderRichMessage<Output>(message: string, renderer: Renderer<Output>): Output[];
|
|
498
485
|
|
|
499
|
-
export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type
|
|
486
|
+
export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MessageObject, type MessageValue, type MissingHandler, type NodeKeys, type Renderer, type Replacement, type ScopedLeafKeys, 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
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
import { RuraHook } from 'rura';
|
|
2
2
|
|
|
3
|
+
type MessagePrimitive = string | number | boolean | null;
|
|
4
|
+
type MessageArray = readonly MessageValue[];
|
|
5
|
+
interface MessageObject {
|
|
6
|
+
[key: string]: MessageValue;
|
|
7
|
+
}
|
|
8
|
+
/** A message value in the locale message tree. */
|
|
9
|
+
type MessageValue = MessagePrimitive | MessageObject | MessageArray;
|
|
3
10
|
/**
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
* - Used to represent either a plain message or an object containing more nested messages.
|
|
11
|
+
* A non-traversable message value.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* const greeting: NestedMessage = "Hello";
|
|
11
|
-
* const userMessages: NestedMessage = {
|
|
12
|
-
* profile: {
|
|
13
|
-
* greeting: "Hello, user!",
|
|
14
|
-
* farewell: "Goodbye!"
|
|
15
|
-
* }
|
|
16
|
-
* };
|
|
17
|
-
* ```
|
|
13
|
+
* Leaf values represent the end of a message path.
|
|
18
14
|
*/
|
|
19
|
-
type
|
|
20
|
-
[key: string]: NestedMessage;
|
|
21
|
-
};
|
|
15
|
+
type MessageLeaf = MessagePrimitive | MessageArray;
|
|
22
16
|
/**
|
|
23
17
|
* Messages grouped by locale.
|
|
24
18
|
* Used to structure all available messages for multiple locales.
|
|
25
19
|
*
|
|
26
20
|
* - The root-level keys are locale identifiers, e.g., "en" or "zh-TW".
|
|
27
|
-
* - Each value is a `
|
|
21
|
+
* - Each value is a `MessageObject`, allowing for deeply nested message objects.
|
|
28
22
|
*
|
|
29
23
|
* @example
|
|
30
24
|
* ```ts
|
|
@@ -37,22 +31,11 @@ type NestedMessage = string | {
|
|
|
37
31
|
* failure: "Login failed"
|
|
38
32
|
* }
|
|
39
33
|
* }
|
|
40
|
-
* },
|
|
41
|
-
* "zh-TW": {
|
|
42
|
-
* welcome: "歡迎",
|
|
43
|
-
* auth: {
|
|
44
|
-
* login: {
|
|
45
|
-
* success: "登入成功",
|
|
46
|
-
* failure: "登入失敗"
|
|
47
|
-
* }
|
|
48
|
-
* }
|
|
49
34
|
* }
|
|
50
35
|
* };
|
|
51
36
|
* ```
|
|
52
37
|
*/
|
|
53
|
-
type LocaleMessages = Record<string,
|
|
54
|
-
[x: string]: NestedMessage;
|
|
55
|
-
}>;
|
|
38
|
+
type LocaleMessages = Record<string, MessageObject>;
|
|
56
39
|
/**
|
|
57
40
|
* Merges messages from all locales into a single unified structure,
|
|
58
41
|
* or extracts messages for a specific locale if `L` is provided.
|
|
@@ -144,7 +127,7 @@ type DefaultDepth = 15;
|
|
|
144
127
|
/** Countdown tuple for limiting recursive depth (up to 15 levels). */
|
|
145
128
|
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
146
129
|
/**
|
|
147
|
-
* Gets all dot-separated keys
|
|
130
|
+
* Gets all dot-separated keys of a nested object, stopping at message leaf values.
|
|
148
131
|
*
|
|
149
132
|
* @example
|
|
150
133
|
* ```ts
|
|
@@ -152,10 +135,10 @@ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
|
152
135
|
* ```
|
|
153
136
|
*/
|
|
154
137
|
type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
155
|
-
[K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K], Prev[D]>}` : never;
|
|
138
|
+
[K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}` | `${K & string}.${NodeKeys<M[K], Prev[D]>}` : never;
|
|
156
139
|
}[keyof M] : never;
|
|
157
140
|
/**
|
|
158
|
-
* Gets dot-separated keys to
|
|
141
|
+
* Gets dot-separated keys that resolve to message leaf values in a nested object.
|
|
159
142
|
*
|
|
160
143
|
* @example
|
|
161
144
|
* ```ts
|
|
@@ -163,7 +146,7 @@ type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never
|
|
|
163
146
|
* ```
|
|
164
147
|
*/
|
|
165
148
|
type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
166
|
-
[K in keyof M]: M[K] extends
|
|
149
|
+
[K in keyof M]: M[K] extends MessageLeaf ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
|
|
167
150
|
}[keyof M] : never;
|
|
168
151
|
|
|
169
152
|
/**
|
|
@@ -246,7 +229,7 @@ type MessagesAtPreKey<T, PK extends string> = PK extends `${infer Head}.${infer
|
|
|
246
229
|
* ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
|
|
247
230
|
* ```
|
|
248
231
|
*/
|
|
249
|
-
type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer
|
|
232
|
+
type ScopedLeafKeys<M, PK extends string, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends infer Messages ? Messages extends MessageValue ? MessagesAtPreKey<Messages, PK> extends infer Scoped ? Scoped extends MessageObject ? LeafKeys<Scoped, D> : never : never : never : never : string;
|
|
250
233
|
|
|
251
234
|
/**
|
|
252
235
|
* Configuration options for translation behavior.
|
|
@@ -258,8 +241,8 @@ type TranslateConfig<M = unknown> = {
|
|
|
258
241
|
fallbackLocales?: FallbackLocalesMap<Locale<M>>;
|
|
259
242
|
/** Optional message to display while translations are still loading. */
|
|
260
243
|
loadingMessage?: string;
|
|
261
|
-
/** Optional
|
|
262
|
-
|
|
244
|
+
/** Optional message used when a translation is missing. */
|
|
245
|
+
missingMessage?: string;
|
|
263
246
|
/** Optional set of handler functions for customizing translation behavior. */
|
|
264
247
|
handlers?: TranslateHandlers;
|
|
265
248
|
};
|
|
@@ -278,7 +261,7 @@ type LoadingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
|
|
|
278
261
|
type MissingHandler<Result = unknown> = (ctx: HandlerContext) => Result;
|
|
279
262
|
/** Function to format a resolved message. */
|
|
280
263
|
type FormatHandler<Result = unknown> = (ctx: HandlerContext & {
|
|
281
|
-
|
|
264
|
+
rawString: string;
|
|
282
265
|
}) => Result;
|
|
283
266
|
/**
|
|
284
267
|
* Snapshot of the translate pipeline context exposed to handlers.
|
|
@@ -310,8 +293,10 @@ interface TranslateContext<Result = unknown> {
|
|
|
310
293
|
replacements?: Replacement;
|
|
311
294
|
/** Ordered list of locales to try, including fallbacks */
|
|
312
295
|
candidateLocales: string[];
|
|
313
|
-
/** Raw message
|
|
314
|
-
|
|
296
|
+
/** Raw message value resolved from the message tree. */
|
|
297
|
+
rawValue?: MessageValue;
|
|
298
|
+
/** Raw string message before formatting. */
|
|
299
|
+
rawString?: string;
|
|
315
300
|
/** Message after formatting (e.g. ICU, custom formatters) */
|
|
316
301
|
formattedMessage?: unknown;
|
|
317
302
|
/** Final value produced by the pipeline */
|
|
@@ -416,6 +401,8 @@ declare class CoreTranslator<M extends LocaleMessages | unknown = unknown, L ext
|
|
|
416
401
|
hasKey: <K extends LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
|
|
417
402
|
/** Get the translated message for a key, with optional replacements. */
|
|
418
403
|
t: <Result = string, K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => Result;
|
|
404
|
+
/** Get the raw message value for a key without formatting or interpolation. */
|
|
405
|
+
tRaw: <K extends LocalizedLeafKeys<M, L> = LocalizedLeafKeys<M, L>>(key: K, replacements?: Replacement) => MessageValue | undefined;
|
|
419
406
|
}
|
|
420
407
|
|
|
421
408
|
type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
|
|
@@ -496,4 +483,4 @@ interface Renderer<Output> {
|
|
|
496
483
|
*/
|
|
497
484
|
declare function renderRichMessage<Output>(message: string, renderer: Renderer<Output>): Output[];
|
|
498
485
|
|
|
499
|
-
export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type
|
|
486
|
+
export { type ASTNode, type Attributes, type DefaultDepth, type FallbackLocalesMap, type FormatHandler, type HandlerContext, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocalizedLeafKeys, type LocalizedMessagesUnion, type LocalizedNodeKeys, type MessageObject, type MessageValue, type MissingHandler, type NodeKeys, type Renderer, type Replacement, type ScopedLeafKeys, 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
|
@@ -9,19 +9,19 @@ var findMessageInLocales = ({
|
|
|
9
9
|
key
|
|
10
10
|
}) => {
|
|
11
11
|
for (const locale of candidateLocales) {
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
14
|
-
let candidate =
|
|
12
|
+
const messagesForLocale = messages[locale];
|
|
13
|
+
if (!messagesForLocale) continue;
|
|
14
|
+
let candidate = messagesForLocale;
|
|
15
15
|
const keys = key.split(".");
|
|
16
|
-
for (const
|
|
17
|
-
if (candidate && typeof candidate === "object" &&
|
|
18
|
-
candidate = candidate[
|
|
16
|
+
for (const key2 of keys) {
|
|
17
|
+
if (candidate !== null && typeof candidate === "object" && key2 in candidate) {
|
|
18
|
+
candidate = candidate[key2];
|
|
19
19
|
} else {
|
|
20
20
|
candidate = void 0;
|
|
21
21
|
break;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
if (
|
|
24
|
+
if (candidate !== void 0) return candidate;
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -29,11 +29,15 @@ var findMessageInLocales = ({
|
|
|
29
29
|
var findMessage = rura.createHook(
|
|
30
30
|
"findMessage",
|
|
31
31
|
(ctx) => {
|
|
32
|
-
ctx.
|
|
32
|
+
ctx.rawValue = void 0;
|
|
33
|
+
ctx.rawString = void 0;
|
|
34
|
+
const message = findMessageInLocales({
|
|
33
35
|
messages: ctx.messages,
|
|
34
36
|
candidateLocales: ctx.candidateLocales,
|
|
35
37
|
key: ctx.key
|
|
36
38
|
});
|
|
39
|
+
ctx.rawValue = message;
|
|
40
|
+
if (typeof message === "string") ctx.rawString = message;
|
|
37
41
|
},
|
|
38
42
|
200
|
|
39
43
|
);
|
|
@@ -48,7 +52,8 @@ function makeHandlerContext(ctx) {
|
|
|
48
52
|
key: ctx.key,
|
|
49
53
|
replacements: ctx.replacements,
|
|
50
54
|
candidateLocales: ctx.candidateLocales,
|
|
51
|
-
|
|
55
|
+
rawValue: ctx.rawValue,
|
|
56
|
+
rawString: ctx.rawString,
|
|
52
57
|
formattedMessage: ctx.formattedMessage,
|
|
53
58
|
meta: ctx.meta
|
|
54
59
|
});
|
|
@@ -58,9 +63,9 @@ function makeHandlerContext(ctx) {
|
|
|
58
63
|
var format = rura.createHook(
|
|
59
64
|
"format",
|
|
60
65
|
(ctx) => {
|
|
61
|
-
const { config,
|
|
66
|
+
const { config, rawString } = ctx;
|
|
62
67
|
const { formatHandler } = config.handlers || {};
|
|
63
|
-
if (!formatHandler ||
|
|
68
|
+
if (!formatHandler || rawString === void 0) return;
|
|
64
69
|
ctx.formattedMessage = formatHandler(
|
|
65
70
|
makeHandlerContext(ctx)
|
|
66
71
|
);
|
|
@@ -91,8 +96,8 @@ var replaceValues = (message, params) => {
|
|
|
91
96
|
var interpolate = rura.createHook(
|
|
92
97
|
"interpolate",
|
|
93
98
|
(ctx) => {
|
|
94
|
-
const {
|
|
95
|
-
const message = formattedMessage ??
|
|
99
|
+
const { rawString, formattedMessage, replacements } = ctx;
|
|
100
|
+
const message = formattedMessage ?? rawString;
|
|
96
101
|
if (typeof message !== "string" || !replacements) {
|
|
97
102
|
ctx.finalMessage = message;
|
|
98
103
|
return;
|
|
@@ -114,7 +119,7 @@ var loading = rura.createHook(
|
|
|
114
119
|
};
|
|
115
120
|
}
|
|
116
121
|
const { loadingMessage } = config;
|
|
117
|
-
if (loadingMessage) {
|
|
122
|
+
if ("loadingMessage" in config) {
|
|
118
123
|
return { early: true, output: loadingMessage };
|
|
119
124
|
}
|
|
120
125
|
},
|
|
@@ -123,8 +128,8 @@ var loading = rura.createHook(
|
|
|
123
128
|
var missing = rura.createHook(
|
|
124
129
|
"missing",
|
|
125
130
|
(ctx) => {
|
|
126
|
-
const { config, key,
|
|
127
|
-
if (
|
|
131
|
+
const { config, key, rawString } = ctx;
|
|
132
|
+
if (rawString !== void 0) return;
|
|
128
133
|
const { missingHandler } = config.handlers || {};
|
|
129
134
|
if (missingHandler) {
|
|
130
135
|
return {
|
|
@@ -132,9 +137,9 @@ var missing = rura.createHook(
|
|
|
132
137
|
output: missingHandler(makeHandlerContext(ctx))
|
|
133
138
|
};
|
|
134
139
|
}
|
|
135
|
-
const {
|
|
136
|
-
if (
|
|
137
|
-
return { early: true, output:
|
|
140
|
+
const { missingMessage } = config;
|
|
141
|
+
if ("missingMessage" in config) {
|
|
142
|
+
return { early: true, output: missingMessage };
|
|
138
143
|
}
|
|
139
144
|
return { early: true, output: key };
|
|
140
145
|
},
|
|
@@ -227,20 +232,31 @@ var hasKey = ({
|
|
|
227
232
|
}) => {
|
|
228
233
|
const candidateLocales = resolveCandidateLocales(targetLocale || locale);
|
|
229
234
|
const message = findMessageInLocales({ messages, candidateLocales, key });
|
|
230
|
-
return
|
|
235
|
+
return message !== void 0;
|
|
231
236
|
};
|
|
232
|
-
function
|
|
237
|
+
function runTranslate(options) {
|
|
233
238
|
const context = {
|
|
234
239
|
...options,
|
|
235
240
|
config: options.translateConfig,
|
|
236
241
|
candidateLocales: [],
|
|
237
242
|
meta: {}
|
|
238
243
|
};
|
|
239
|
-
|
|
244
|
+
return rura.run(context, options.hooks);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/translators/methods/translate.ts
|
|
248
|
+
function translate(options) {
|
|
249
|
+
const { early, ctx, output } = runTranslate(options);
|
|
240
250
|
if (early === true) return output;
|
|
241
251
|
return ctx.finalMessage;
|
|
242
252
|
}
|
|
243
253
|
|
|
254
|
+
// src/translators/methods/translate-raw.ts
|
|
255
|
+
function translateRaw(options) {
|
|
256
|
+
const { ctx } = runTranslate(options);
|
|
257
|
+
return ctx.rawValue;
|
|
258
|
+
}
|
|
259
|
+
|
|
244
260
|
// src/translators/core-translator/core-translator.ts
|
|
245
261
|
var CoreTranslator = class extends BaseTranslator {
|
|
246
262
|
/** User-provided options including messages, locale, and config. */
|
|
@@ -296,6 +312,18 @@ var CoreTranslator = class extends BaseTranslator {
|
|
|
296
312
|
replacements
|
|
297
313
|
});
|
|
298
314
|
};
|
|
315
|
+
/** Get the raw message value for a key without formatting or interpolation. */
|
|
316
|
+
tRaw = (key, replacements) => {
|
|
317
|
+
return translateRaw({
|
|
318
|
+
hooks: this.hooks,
|
|
319
|
+
messages: this._messages,
|
|
320
|
+
locale: this._locale,
|
|
321
|
+
isLoading: this._isLoading,
|
|
322
|
+
translateConfig: this.translateConfig,
|
|
323
|
+
key,
|
|
324
|
+
replacements
|
|
325
|
+
});
|
|
326
|
+
};
|
|
299
327
|
};
|
|
300
328
|
|
|
301
329
|
// src/translators/scope-translator/utils/get-full-key.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intor-translator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "🤖 A modern, type-safe i18n engine.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Yiming Liao",
|
|
@@ -50,13 +50,14 @@
|
|
|
50
50
|
"node": ">=16.0.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
|
-
"build": "tsup",
|
|
54
|
-
"prepublishOnly": "yarn build",
|
|
55
|
-
"test": "vitest",
|
|
56
53
|
"type": "tsc --noEmit",
|
|
57
54
|
"lint": "eslint",
|
|
58
55
|
"lint:debug": "eslint --debug",
|
|
56
|
+
"test": "vitest",
|
|
57
|
+
"test:types": "tsx scripts/test-types.ts",
|
|
59
58
|
"knip": "knip --config .config/knip.config.ts",
|
|
59
|
+
"build": "tsup",
|
|
60
|
+
"prepublishOnly": "yarn build",
|
|
60
61
|
"examples:html": "vite --config examples/html/basic/vite.config.ts",
|
|
61
62
|
"examples:html:rich-message": "vite --config examples/html/rich-message/vite.config.ts"
|
|
62
63
|
},
|