intor-translator 1.0.14 → 1.1.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/README.md +15 -13
- package/dist/index.cjs +68 -180
- package/dist/index.d.cts +238 -246
- package/dist/index.d.ts +238 -246
- package/dist/index.js +68 -181
- package/package.json +26 -21
package/dist/index.d.cts
CHANGED
|
@@ -1,421 +1,413 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Represents a locale identifier, such as 'en', 'zh-TW', or 'fr-FR'.
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* const locale: Locale = "en";
|
|
6
|
-
*/
|
|
7
|
-
type Locale = string;
|
|
8
|
-
/**
|
|
9
|
-
* Represents a message namespace.
|
|
10
|
-
* Typically used to group related messages, such as 'common', 'auth', or 'dashboard'.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* const namespace: Namespace = "dashboard";
|
|
14
|
-
*/
|
|
15
|
-
type Namespace = string;
|
|
16
|
-
/**
|
|
17
|
-
* Represents a single translatable message string.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* const message: Message = "Hello World";
|
|
21
|
-
*/
|
|
22
|
-
type Message = string;
|
|
23
|
-
/**
|
|
24
|
-
* A recursive replacement object used for interpolating values in message templates.
|
|
25
|
-
*
|
|
26
|
-
* Each key maps to a value that can be a string, number, or another nested `Replacement`.
|
|
27
|
-
* This structure supports deep replacements such as `user.profile.link`.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* const replacements: Replacement = {
|
|
31
|
-
* name: "intor",
|
|
32
|
-
* count: 5,
|
|
33
|
-
* user: {
|
|
34
|
-
* profile: {
|
|
35
|
-
* link: "https://example.com/avatar.png"
|
|
36
|
-
* }
|
|
37
|
-
* }
|
|
38
|
-
* };
|
|
39
|
-
*/
|
|
40
|
-
type Replacement = {
|
|
41
|
-
[key: string]: string | number | Replacement;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/** Represents primitive types supported in rich replacements. */
|
|
45
|
-
type RichPrimitive = string | number | boolean | Date;
|
|
46
|
-
/** Represents serializable objects that provide a custom string representation. */
|
|
47
|
-
type RichSerializable = {
|
|
48
|
-
toString(): string;
|
|
49
|
-
};
|
|
50
|
-
/** A formatter function that takes a string chunk and returns any formatted output. */
|
|
51
|
-
type RichFormatterFunction = (value: unknown, ...args: unknown[]) => unknown;
|
|
52
|
-
/**
|
|
53
|
-
* Possible value types for rich replacements.
|
|
54
|
-
* Can be a primitive, serializable object, formatter function, or null/undefined.
|
|
55
|
-
*/
|
|
56
|
-
type ReplacementValue = RichPrimitive | RichSerializable | RichFormatterFunction | null | undefined;
|
|
57
|
-
/**
|
|
58
|
-
* A recursive replacement object that supports rich replacement values,
|
|
59
|
-
* allowing complex nested interpolation structures.
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* const replacements: RichReplacement = {
|
|
63
|
-
* name: "Alice",
|
|
64
|
-
* age: 30,
|
|
65
|
-
* isActive: true,
|
|
66
|
-
* birthday: new Date("1993-04-25"),
|
|
67
|
-
* formatter: (value, ...args) => `<b>${value}</b>`,
|
|
68
|
-
* nested: {
|
|
69
|
-
* score: 100,
|
|
70
|
-
* note: null,
|
|
71
|
-
* },
|
|
72
|
-
* };
|
|
73
|
-
*/
|
|
74
|
-
type RichReplacement = {
|
|
75
|
-
[key: string]: ReplacementValue;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
1
|
/**
|
|
79
2
|
* A nested message structure or a simple string message.
|
|
80
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* - Used to represent either a plain message or an object containing more nested messages.
|
|
81
5
|
*
|
|
82
6
|
* @example
|
|
7
|
+
* ```ts
|
|
83
8
|
* const greeting: NestedMessage = "Hello";
|
|
84
|
-
*
|
|
85
9
|
* const userMessages: NestedMessage = {
|
|
86
10
|
* profile: {
|
|
87
11
|
* greeting: "Hello, user!",
|
|
88
12
|
* farewell: "Goodbye!"
|
|
89
13
|
* }
|
|
90
14
|
* };
|
|
15
|
+
* ```
|
|
91
16
|
*/
|
|
92
|
-
type NestedMessage =
|
|
17
|
+
type NestedMessage = string | {
|
|
93
18
|
[key: string]: NestedMessage;
|
|
94
19
|
};
|
|
95
20
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
21
|
+
* Messages grouped by locale.
|
|
22
|
+
* Used to structure all available messages for multiple locales.
|
|
98
23
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* greeting: "Hello",
|
|
102
|
-
* user: {
|
|
103
|
-
* profile: {
|
|
104
|
-
* name: "Your Name"
|
|
105
|
-
* }
|
|
106
|
-
* }
|
|
107
|
-
* };
|
|
108
|
-
*/
|
|
109
|
-
type MessageRecord = Record<string, NestedMessage>;
|
|
110
|
-
/**
|
|
111
|
-
* A record of messages grouped by namespace.
|
|
112
|
-
* Each namespace contains its own `MessageRecord` structure.
|
|
24
|
+
* - Each key is a locale string, e.g., "en" or "zh-TW".
|
|
25
|
+
* - Each value is a `NestedMessage`, allowing for deeply nested message objects.
|
|
113
26
|
*
|
|
114
27
|
* @example
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* hello: "Hello",
|
|
118
|
-
* goodbye: "Goodbye"
|
|
119
|
-
* },
|
|
120
|
-
* auth: {
|
|
121
|
-
* login: {
|
|
122
|
-
* success: "Login successful"
|
|
123
|
-
* }
|
|
124
|
-
* }
|
|
125
|
-
* };
|
|
126
|
-
*/
|
|
127
|
-
type NamespaceMessages = Record<Namespace, NestedMessage>;
|
|
128
|
-
/**
|
|
129
|
-
* Messages grouped by locale and then by namespace.
|
|
130
|
-
* Used to structure all available messages for multiple locales and namespaces.
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* const messages: LocaleNamespaceMessages = {
|
|
28
|
+
* ```ts
|
|
29
|
+
* const messages: LocaleMessages = {
|
|
134
30
|
* en: {
|
|
135
|
-
*
|
|
136
|
-
* welcome: "Welcome"
|
|
137
|
-
* },
|
|
31
|
+
* welcome: "Welcome",
|
|
138
32
|
* auth: {
|
|
139
33
|
* login: {
|
|
140
|
-
* success: "Login successful"
|
|
34
|
+
* success: "Login successful",
|
|
35
|
+
* failure: "Login failed"
|
|
141
36
|
* }
|
|
142
37
|
* }
|
|
143
38
|
* },
|
|
144
39
|
* "zh-TW": {
|
|
145
|
-
*
|
|
146
|
-
*
|
|
40
|
+
* welcome: "歡迎",
|
|
41
|
+
* auth: {
|
|
42
|
+
* login: {
|
|
43
|
+
* success: "登入成功",
|
|
44
|
+
* failure: "登入失敗"
|
|
45
|
+
* }
|
|
147
46
|
* }
|
|
148
47
|
* }
|
|
149
48
|
* };
|
|
49
|
+
* ```
|
|
150
50
|
*/
|
|
151
|
-
type
|
|
51
|
+
type LocaleMessages = Record<string, {
|
|
52
|
+
[x: string]: NestedMessage;
|
|
53
|
+
}>;
|
|
152
54
|
/**
|
|
153
|
-
* Merges messages from all locales into a single unified structure
|
|
55
|
+
* Merges messages from all locales into a single unified structure,
|
|
56
|
+
* or extracts messages for a specific locale if `L` is provided.
|
|
154
57
|
*
|
|
155
58
|
* @example
|
|
59
|
+
* ```ts
|
|
156
60
|
* const messages = {
|
|
157
|
-
* en: {
|
|
158
|
-
* zh: {
|
|
61
|
+
* en: { greeting: { morning: "morning" } },
|
|
62
|
+
* zh: { greeting: { evening: "晚上好" } },
|
|
159
63
|
* };
|
|
160
64
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
|
|
164
|
-
type UnionLocaleMessages<M> = M[StrictLocaleKey<M>];
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Extracts the locale keys from the messages object as string literals.
|
|
65
|
+
* // 1. Union of all locales
|
|
66
|
+
* UnionLocaleMessages<typeof messages>;
|
|
67
|
+
* // → { greeting: { morning: string; }; } | { greeting: { evening: string; }; }
|
|
168
68
|
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
* //
|
|
69
|
+
* // 2. Messages for a specified locale
|
|
70
|
+
* UnionLocaleMessages<typeof messages, "en">; // → { greeting: { morning: string; }; }
|
|
71
|
+
* UnionLocaleMessages<typeof messages, "zh">; // → { greeting: { evening: string; }; }
|
|
72
|
+
*
|
|
73
|
+
* // 3. Fallback if M is not LocaleMessages
|
|
74
|
+
* UnionLocaleMessages // → unknown
|
|
75
|
+
* ```
|
|
175
76
|
*/
|
|
176
|
-
type
|
|
77
|
+
type LocalizedMessagesUnion<M = unknown, L extends keyof M | "union" = "union"> = M extends LocaleMessages ? L extends "union" ? M[Locale<M>] : M[L & keyof M] : unknown;
|
|
78
|
+
|
|
177
79
|
/**
|
|
178
80
|
* Extracts locale keys only when M is a valid messages object.
|
|
179
81
|
*
|
|
180
|
-
* When M is a concrete `
|
|
181
|
-
* will be inferred as a union of its top-level keys like `"en" | "zh-TW"`.
|
|
82
|
+
* - When M is a concrete `LocaleMessages`,
|
|
83
|
+
* the locale key will be inferred as a union of its top-level keys like `"en" | "zh-TW"`.
|
|
182
84
|
* Otherwise, falls back to a generic `string`.
|
|
183
85
|
*
|
|
184
|
-
* This helps retain intellisense when `messages` is provided,
|
|
86
|
+
* - This helps retain intellisense when `messages` is provided,
|
|
185
87
|
* but avoids TypeScript errors when M is left as `unknown`.
|
|
186
88
|
*
|
|
187
89
|
* @example
|
|
188
|
-
*
|
|
90
|
+
* ```ts
|
|
91
|
+
* type Locales = Locale<{
|
|
189
92
|
* en: {};
|
|
190
93
|
* fr: {};
|
|
191
94
|
* }>;
|
|
192
|
-
* //
|
|
95
|
+
* // → "en" | "fr"
|
|
193
96
|
*
|
|
194
|
-
* type
|
|
195
|
-
* //
|
|
97
|
+
* type Locales = Locale<unknown>;
|
|
98
|
+
* // → string
|
|
99
|
+
* ```
|
|
196
100
|
*/
|
|
197
|
-
type
|
|
101
|
+
type Locale<M = unknown> = M extends LocaleMessages ? keyof M & string : string;
|
|
198
102
|
/**
|
|
199
103
|
* A map that defines fallback locales for each base locale.
|
|
200
104
|
*
|
|
201
|
-
* When a message is missing for a given locale, the system will attempt to find the message
|
|
105
|
+
* - When a message is missing for a given locale, the system will attempt to find the message
|
|
202
106
|
* by falling back to the locales listed here, in the specified order.
|
|
203
107
|
*
|
|
204
108
|
* @example
|
|
109
|
+
* ```ts
|
|
205
110
|
* const fallbacks: FallbackLocalesMap = {
|
|
206
111
|
* "en-AU": ["en-GB", "en"],
|
|
207
112
|
* "zh-TW": ["zh-HK", "zh"]
|
|
208
113
|
* };
|
|
114
|
+
* ```
|
|
209
115
|
*/
|
|
210
116
|
type FallbackLocalesMap<L extends string = string> = Partial<Record<L, L[]>>;
|
|
211
117
|
|
|
212
118
|
/**
|
|
213
|
-
*
|
|
119
|
+
* Represents a recursive replacement object used for interpolating values in message templates.
|
|
120
|
+
*
|
|
121
|
+
* - Each key can be any value (`string`, `number`, `boolean`, `Date`, `function`, nested object, etc.).
|
|
122
|
+
* - Supports nested structures for complex interpolation.
|
|
123
|
+
* - Can be used directly with `intl-messageformat` or custom format handlers.
|
|
214
124
|
*
|
|
215
125
|
* @example
|
|
216
|
-
*
|
|
126
|
+
* const replacements: Replacement = {
|
|
127
|
+
* name: "Alice",
|
|
128
|
+
* count: 5,
|
|
129
|
+
* nested: {
|
|
130
|
+
* score: 100
|
|
131
|
+
* },
|
|
132
|
+
* formatter: (value: unknown) => `<b>${value}</b>`
|
|
133
|
+
* };
|
|
217
134
|
*/
|
|
218
|
-
type
|
|
219
|
-
|
|
220
|
-
}[keyof M] : never;
|
|
135
|
+
type Replacement = Record<string, unknown>;
|
|
136
|
+
|
|
221
137
|
/**
|
|
222
138
|
* Default maximum recursive depth for nested key type computations,
|
|
223
139
|
* balancing type safety and compiler performance.
|
|
224
140
|
*/
|
|
225
141
|
type DefaultDepth = 15;
|
|
226
|
-
/** Countdown tuple for limiting recursive depth (up to
|
|
227
|
-
type Prev = [
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
10,
|
|
240
|
-
11,
|
|
241
|
-
12,
|
|
242
|
-
13,
|
|
243
|
-
14,
|
|
244
|
-
15,
|
|
245
|
-
16,
|
|
246
|
-
17,
|
|
247
|
-
18,
|
|
248
|
-
19,
|
|
249
|
-
20
|
|
250
|
-
];
|
|
142
|
+
/** Countdown tuple for limiting recursive depth (up to 15 levels). */
|
|
143
|
+
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
144
|
+
/**
|
|
145
|
+
* Gets all dot-separated keys (including non-leaf nodes) from a nested object.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* NodeKeys<{ a: { b: { c: string }, d: string } }> // → "a" | "a.b" | "a.b.c" | "a.d"
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
type NodeKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
153
|
+
[K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K], Prev[D]>}` : never;
|
|
154
|
+
}[keyof M] : never;
|
|
251
155
|
/**
|
|
252
156
|
* Gets dot-separated keys to string leaf nodes in a nested object.
|
|
253
157
|
*
|
|
254
158
|
* @example
|
|
255
|
-
*
|
|
159
|
+
* ```ts
|
|
160
|
+
* LeafKeys<{ a: { b: { c: string }, d: string } }> // → "a.d" | "a.b.c"
|
|
161
|
+
* ```
|
|
256
162
|
*/
|
|
257
163
|
type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
258
164
|
[K in keyof M]: M[K] extends string ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
|
|
259
165
|
}[keyof M] : never;
|
|
166
|
+
|
|
260
167
|
/**
|
|
261
|
-
*
|
|
168
|
+
* Extracts all **node keys** from the messages
|
|
169
|
+
* of a specified locale (or union of locales).
|
|
262
170
|
*
|
|
263
171
|
* @example
|
|
264
|
-
*
|
|
172
|
+
* ```ts
|
|
173
|
+
* const messages = {
|
|
174
|
+
* en: { greeting: { morning: "morning" } },
|
|
175
|
+
* zh: { greeting: { evening: "晚上好" } },
|
|
176
|
+
* };
|
|
177
|
+
*
|
|
178
|
+
* // 1. Union of all locales
|
|
179
|
+
* LocalizedNodeKeys<typeof messages> // → "greeting" | "greeting.morning" | "greeting.evening"
|
|
180
|
+
*
|
|
181
|
+
* // 2. For a specified locale
|
|
182
|
+
* LocalizedNodeKeys<typeof messages, "en"> // → "greeting" | "greeting.morning"
|
|
183
|
+
* LocalizedNodeKeys<typeof messages, "zh"> // → "greeting" | "greeting.evening"
|
|
184
|
+
*
|
|
185
|
+
* // 3. Fallback when M is not LocaleMessages
|
|
186
|
+
* LocalizedNodeKeys // → string
|
|
187
|
+
* ```
|
|
265
188
|
*/
|
|
266
|
-
type
|
|
189
|
+
type LocalizedNodeKeys<M = unknown, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends NestedMessage ? NodeKeys<LocalizedMessagesUnion<M, L>, D> : never : string;
|
|
267
190
|
/**
|
|
268
|
-
*
|
|
191
|
+
* Extracts all **leaf keys** from the messages
|
|
192
|
+
* of a specified locale (or union of locales).
|
|
269
193
|
*
|
|
270
194
|
* @example
|
|
271
|
-
*
|
|
272
|
-
*
|
|
195
|
+
* ```ts
|
|
196
|
+
* const messages = {
|
|
197
|
+
* en: { greeting: { morning: "morning" } },
|
|
198
|
+
* zh: { greeting: { evening: "晚上好" } },
|
|
199
|
+
* };
|
|
200
|
+
*
|
|
201
|
+
* // 1. Union of all locales
|
|
202
|
+
* LocalizedLeafKeys<typeof messages> // → "greeting.morning" | "greeting.evening"
|
|
203
|
+
*
|
|
204
|
+
* // 2. For a specified locale
|
|
205
|
+
* LocalizedLeafKeys<typeof messages, "en"> // → "greeting.morning"
|
|
206
|
+
* LocalizedLeafKeys<typeof messages, "zh"> // → "greeting.evening"
|
|
207
|
+
*
|
|
208
|
+
* // 3. Fallback if M is not LocaleMessages
|
|
209
|
+
* LocalizedLeafKeys // → string
|
|
210
|
+
* ```
|
|
273
211
|
*/
|
|
274
|
-
type
|
|
212
|
+
type LocalizedLeafKeys<M = unknown, L extends keyof M | "union" = "union", D extends number = DefaultDepth> = M extends LocaleMessages ? LocalizedMessagesUnion<M, L> extends NestedMessage ? LeafKeys<LocalizedMessagesUnion<M, L>, D> : never : string;
|
|
213
|
+
|
|
275
214
|
/**
|
|
276
|
-
*
|
|
215
|
+
* Resolves the type at a dot-separated key in a nested object.
|
|
277
216
|
*
|
|
278
217
|
* @example
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
218
|
+
* ```ts
|
|
219
|
+
* const structure = {
|
|
220
|
+
* a: {
|
|
221
|
+
* b: { c: "hello" },
|
|
222
|
+
* z: "world",
|
|
223
|
+
* },
|
|
282
224
|
* };
|
|
283
|
-
*
|
|
225
|
+
*
|
|
226
|
+
* MessagesAtPreKey<typeof structure, "a"> // → { b: { c: string; }; z: string;}
|
|
227
|
+
* MessagesAtPreKey<typeof structure, "a.b"> // → { c: string; };
|
|
228
|
+
* ```
|
|
284
229
|
*/
|
|
285
|
-
type
|
|
230
|
+
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;
|
|
286
231
|
/**
|
|
287
|
-
*
|
|
232
|
+
* Extracts all **leaf keys** under a scoped path (`PK`) from the messages
|
|
233
|
+
* of a specified locale (`L`) (or union of locales).
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* const messages = {
|
|
238
|
+
* en: { a: { b: { c: "hello" }, z: "world" } },
|
|
239
|
+
* zh: { a: { b: "hello" },
|
|
240
|
+
* };
|
|
288
241
|
*
|
|
289
|
-
*
|
|
242
|
+
* ScopedLeafKeys<typeof messages, "a">; // → "b.c" | "z"
|
|
243
|
+
* ScopedLeafKeys<typeof messages, "a.b">; // → "c"
|
|
244
|
+
* ScopedLeafKeys<typeof messages, "a", "zh">; // → "b"
|
|
245
|
+
* ```
|
|
290
246
|
*/
|
|
291
|
-
type
|
|
247
|
+
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 NestedMessage ? LeafKeys<MessagesAtPreKey<messages, PK>, D> : never : never : string;
|
|
292
248
|
|
|
293
249
|
/**
|
|
294
250
|
* A ref object holding all localized messages by locale.
|
|
295
251
|
*
|
|
296
252
|
* @example
|
|
297
|
-
*
|
|
253
|
+
* ```ts
|
|
254
|
+
* const messagesRef: MessagesRef<Messages> = {
|
|
298
255
|
* current: {
|
|
299
256
|
* en: { home: { title: "Welcome" } },
|
|
300
257
|
* zh: { home: { title: "歡迎" } }
|
|
301
258
|
* }
|
|
302
259
|
* };
|
|
260
|
+
* ```
|
|
303
261
|
*/
|
|
304
|
-
type MessagesRef<M> = {
|
|
262
|
+
type MessagesRef<M = unknown> = {
|
|
305
263
|
current?: Readonly<M>;
|
|
306
264
|
};
|
|
307
265
|
/**
|
|
308
266
|
* A ref object holding the currently selected locale.
|
|
309
267
|
*
|
|
310
268
|
* @example
|
|
311
|
-
*
|
|
269
|
+
* ```ts
|
|
270
|
+
* const localeRef: LocaleRef<Messages> = {
|
|
312
271
|
* current: "en"
|
|
313
272
|
* };
|
|
273
|
+
* ```
|
|
314
274
|
*/
|
|
315
|
-
type LocaleRef<M> = {
|
|
316
|
-
current
|
|
275
|
+
type LocaleRef<M = unknown> = {
|
|
276
|
+
current: Locale<M>;
|
|
317
277
|
};
|
|
318
278
|
/**
|
|
319
279
|
* A ref object indicating whether translation is loading.
|
|
320
280
|
*
|
|
321
281
|
* @example
|
|
282
|
+
* ```ts
|
|
322
283
|
* const isLoadingRef: IsLoadingRef = {
|
|
323
284
|
* current: true
|
|
324
285
|
* };
|
|
286
|
+
* ```
|
|
325
287
|
*/
|
|
326
288
|
type IsLoadingRef = {
|
|
327
289
|
current: boolean;
|
|
328
290
|
};
|
|
329
291
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
/** Config options for translation behavior. */
|
|
340
|
-
type TranslateConfig<M> = {
|
|
341
|
-
fallbackLocales?: FallbackLocalesMap<LocaleKey<M>>;
|
|
292
|
+
/**
|
|
293
|
+
* Configuration options for translation behavior.
|
|
294
|
+
*/
|
|
295
|
+
type TranslateConfig<M = unknown> = {
|
|
296
|
+
/** Optional mapping of fallback locales to use when a message is missing in the current locale. */
|
|
297
|
+
fallbackLocales?: FallbackLocalesMap<Locale<M>>;
|
|
298
|
+
/** Optional message to display while translations are still loading. */
|
|
342
299
|
loadingMessage?: string;
|
|
300
|
+
/** Optional placeholder to use when a message cannot be found. */
|
|
343
301
|
placeholder?: string;
|
|
302
|
+
/** Optional set of handler functions for customizing translation behavior. */
|
|
344
303
|
handlers?: TranslateHandlers;
|
|
345
304
|
};
|
|
346
|
-
/**
|
|
305
|
+
/**
|
|
306
|
+
* Optional handler functions for customizing translation behavior.
|
|
307
|
+
*/
|
|
347
308
|
type TranslateHandlers = {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
309
|
+
/** Function to format a resolved message before returning it. */
|
|
310
|
+
formatHandler?: FormatHandler;
|
|
311
|
+
/** Function called when a translation is still loading. */
|
|
312
|
+
loadingHandler?: LoadingHandler;
|
|
313
|
+
/** Function called when no message is found for a given key. */
|
|
314
|
+
missingHandler?: MissingHandler;
|
|
351
315
|
};
|
|
352
|
-
/**
|
|
353
|
-
type
|
|
316
|
+
/** Function to format a resolved message. */
|
|
317
|
+
type FormatHandler<Result = unknown> = (ctx: TranslateHandlerContext & {
|
|
354
318
|
message: string;
|
|
355
319
|
}) => Result;
|
|
356
|
-
/**
|
|
357
|
-
type
|
|
358
|
-
/**
|
|
359
|
-
type
|
|
320
|
+
/** Function called when translation is still loading. */
|
|
321
|
+
type LoadingHandler<Result = unknown> = (ctx: TranslateHandlerContext) => Result;
|
|
322
|
+
/** Function called when no message is found for the given key. */
|
|
323
|
+
type MissingHandler<Result = unknown> = (ctx: TranslateHandlerContext) => Result;
|
|
360
324
|
/**
|
|
361
|
-
* Context passed to translation-related functions.
|
|
325
|
+
* Context object passed to translation-related functions.
|
|
326
|
+
*
|
|
362
327
|
* @example
|
|
363
328
|
* {
|
|
364
329
|
* locale: "en",
|
|
365
330
|
* key: "home.title",
|
|
366
|
-
* replacements: { name: "
|
|
331
|
+
* replacements: { name: "John" }
|
|
367
332
|
* }
|
|
368
333
|
*/
|
|
369
|
-
type
|
|
334
|
+
type TranslateHandlerContext = {
|
|
335
|
+
/** The current locale being translated. */
|
|
370
336
|
locale: Locale;
|
|
337
|
+
/** The translation key for the message. */
|
|
371
338
|
key: string;
|
|
372
|
-
replacements
|
|
339
|
+
/** Optional replacements for dynamic interpolation in the message. */
|
|
340
|
+
replacements?: Replacement;
|
|
373
341
|
};
|
|
374
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Options for initializing a translator
|
|
345
|
+
*
|
|
346
|
+
* @template M - type of messages object
|
|
347
|
+
*/
|
|
375
348
|
interface BaseTranslatorOptions<M = unknown> {
|
|
349
|
+
/**
|
|
350
|
+
* Messages object for translations.
|
|
351
|
+
* - Use `LocaleMessages` type to enable key inference for `hasKey` and `t`.
|
|
352
|
+
*/
|
|
376
353
|
messages?: Readonly<M>;
|
|
377
|
-
|
|
354
|
+
/**
|
|
355
|
+
* Current locale key.
|
|
356
|
+
* - If `messages` is typed as `LocaleMessages`, this can be inferred automatically.
|
|
357
|
+
*/
|
|
358
|
+
locale: Locale<M>;
|
|
378
359
|
}
|
|
379
360
|
|
|
380
361
|
declare class BaseTranslator<M = unknown> {
|
|
362
|
+
/** Current messages for translation, updatable at runtime */
|
|
381
363
|
protected messagesRef: MessagesRef<M>;
|
|
364
|
+
/** Current active locale, can be changed dynamically */
|
|
382
365
|
protected localeRef: LocaleRef<M>;
|
|
383
|
-
constructor(options
|
|
384
|
-
/** Get
|
|
366
|
+
constructor(options: BaseTranslatorOptions<M>);
|
|
367
|
+
/** Get messages. */
|
|
385
368
|
get messages(): M | undefined;
|
|
369
|
+
/** Get the current active locale. */
|
|
370
|
+
get locale(): Locale<M>;
|
|
386
371
|
/**
|
|
387
372
|
* Replace messages with new ones.
|
|
388
373
|
*
|
|
389
|
-
* Note: This allows runtime setting of messages even if M is inferred as `never
|
|
390
|
-
*
|
|
374
|
+
* - Note: This allows runtime setting of messages even if `M` is inferred as `never`.
|
|
375
|
+
* The type cast bypasses TypeScript restrictions on dynamic messages.
|
|
391
376
|
*/
|
|
392
|
-
setMessages<N extends
|
|
393
|
-
/**
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
377
|
+
setMessages<N extends LocaleMessages>(messages: N): void;
|
|
378
|
+
/**
|
|
379
|
+
* Set the active locale.
|
|
380
|
+
*
|
|
381
|
+
* - Note: Unlike `setMessages`, the locale structure cannot be changed at runtime.
|
|
382
|
+
*/
|
|
383
|
+
setLocale(newLocale: Locale<M>): void;
|
|
399
384
|
}
|
|
400
385
|
|
|
401
386
|
interface CoreTranslatorOptions<M> extends BaseTranslatorOptions<M>, TranslateConfig<M> {
|
|
402
387
|
}
|
|
403
388
|
|
|
404
|
-
declare class CoreTranslator<M = unknown> extends BaseTranslator<M> {
|
|
389
|
+
declare class CoreTranslator<M = unknown, L extends keyof M | "union" = "union"> extends BaseTranslator<M> {
|
|
405
390
|
protected options: CoreTranslatorOptions<M>;
|
|
406
391
|
protected isLoadingRef: IsLoadingRef;
|
|
407
|
-
constructor(options
|
|
392
|
+
constructor(options: CoreTranslatorOptions<M>);
|
|
408
393
|
/** Get the current loading state. */
|
|
409
394
|
get isLoading(): boolean;
|
|
410
395
|
/** Set the loading state. */
|
|
411
396
|
setLoading(state: boolean): void;
|
|
412
|
-
|
|
397
|
+
/** Check if a key exists in the specified locale or current locale. */
|
|
398
|
+
hasKey: <K = LocalizedLeafKeys<M, L>>(key: K, targetLocale?: Locale<M>) => boolean;
|
|
399
|
+
t: <Result = string, L_1 extends keyof M | "union" = "union", K = LocalizedLeafKeys<M, L_1>>(key: K, replacements?: Replacement) => Result;
|
|
413
400
|
}
|
|
414
401
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
402
|
+
type ScopeTranslatorOptions<M> = CoreTranslatorOptions<M>;
|
|
403
|
+
type ScopeTranslatorMethods<M, L extends keyof M | "union" = "union", K = LocalizedLeafKeys<M, L>> = {
|
|
404
|
+
hasKey: (key?: K, targetLocale?: Locale<M>) => boolean;
|
|
405
|
+
t: <Result = string>(key?: K, replacements?: Replacement) => Result;
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
declare class ScopeTranslator<M = unknown, L extends keyof M | "union" = "union"> extends CoreTranslator<M> {
|
|
409
|
+
constructor(options: ScopeTranslatorOptions<M>);
|
|
410
|
+
scoped<PK extends LocalizedNodeKeys<M, L> | undefined = undefined>(preKey?: PK): PK extends string ? ScopeTranslatorMethods<M, L, ScopedLeafKeys<M, PK, L>> : ScopeTranslatorMethods<M, L>;
|
|
419
411
|
}
|
|
420
412
|
|
|
421
|
-
export { type FallbackLocalesMap, type
|
|
413
|
+
export { type FallbackLocalesMap, type FormatHandler, type IsLoadingRef, type LeafKeys, type LoadingHandler, type Locale, type LocaleMessages, type LocaleRef, type LocalizedLeafKeys, type LocalizedMessagesUnion, type MessagesRef, type MissingHandler, type NestedMessage, type NodeKeys, type Replacement, ScopeTranslator, type ScopeTranslatorMethods, type ScopeTranslatorOptions, type ScopedLeafKeys, type TranslateHandlerContext, type TranslateHandlers, ScopeTranslator as Translator };
|