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/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
- * Used to represent either a plain message or an object containing more nested messages.
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 = Message | {
17
+ type NestedMessage = string | {
93
18
  [key: string]: NestedMessage;
94
19
  };
95
20
  /**
96
- * A record of messages where keys are strings, and values can be strings or nested message objects.
97
- * Supports deep message trees like `errors.form.required`.
21
+ * Messages grouped by locale.
22
+ * Used to structure all available messages for multiple locales.
98
23
  *
99
- * @example
100
- * const messages: MessageRecord = {
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
- * const namespaceMessages: NamespaceMessages = {
116
- * common: {
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
- * common: {
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
- * common: {
146
- * welcome: "歡迎"
40
+ * welcome: "歡迎",
41
+ * auth: {
42
+ * login: {
43
+ * success: "登入成功",
44
+ * failure: "登入失敗"
45
+ * }
147
46
  * }
148
47
  * }
149
48
  * };
49
+ * ```
150
50
  */
151
- type LocaleNamespaceMessages = Record<Locale, NamespaceMessages>;
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: { auth: { login: "Login" } },
158
- * zh: { auth: { logout: "登出" } },
61
+ * en: { greeting: { morning: "morning" } },
62
+ * zh: { greeting: { evening: "晚上好" } },
159
63
  * };
160
64
  *
161
- * type Result = UnionLocaleMessages<typeof messages>;
162
- * // Result: { auth: { login: "Login" } } | { auth: { logout: "登出" } }
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
- * @example
170
- * type Locales = LocaleKey<{
171
- * en: {};
172
- * "zh-TW": {};
173
- * }>;
174
- * // Locales is "en" | "zh-TW"
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 StrictLocaleKey<M> = keyof M & string;
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 `LocaleNamespaceMessages`, the locale key
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
- * type Locales = LocaleKey<{
90
+ * ```ts
91
+ * type Locales = Locale<{
189
92
  * en: {};
190
93
  * fr: {};
191
94
  * }>;
192
- * // → "en" | "fr"
95
+ * // → "en" | "fr"
193
96
  *
194
- * type Fallback = LocaleKey<unknown>;
195
- * // → string
97
+ * type Locales = Locale<unknown>;
98
+ * // → string
99
+ * ```
196
100
  */
197
- type LocaleKey<M = unknown> = M extends LocaleNamespaceMessages ? StrictLocaleKey<M> : string;
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
- * Gets all dot-separated keys (including non-leaf nodes) from a nested object.
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
- * NodeKeys<{ a: { b: { c: string }, d: string } }> → "a" | "a.b" | "a.b.c" | "a.d"
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 NodeKeys<M> = M extends object ? {
219
- [K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K]>}` : never;
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 10 levels). */
227
- type Prev = [
228
- never,
229
- 0,
230
- 1,
231
- 2,
232
- 3,
233
- 4,
234
- 5,
235
- 6,
236
- 7,
237
- 8,
238
- 9,
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
- * LeafKeys<{ a: { b: "x", c: { d: "y" } } }> → "a.b" | "a.c.d"
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
- * Gets string leaf keys from all locale messages combined.
168
+ * Extracts all **node keys** from the messages
169
+ * of a specified locale (or union of locales).
262
170
  *
263
171
  * @example
264
- * UnionLocaleLeafKeys<{ en: { a: { b: "x" } }, zh: { a: { c: "y" } } }> → "a.b" | "a.c"
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 UnionLocaleLeafKeys<M, D extends number = DefaultDepth> = UnionLocaleMessages<M> extends NamespaceMessages ? LeafKeys<UnionLocaleMessages<M>, D> : never;
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
- * Resolves the type at a dot-separated key in a nested object.
191
+ * Extracts all **leaf keys** from the messages
192
+ * of a specified locale (or union of locales).
269
193
  *
270
194
  * @example
271
- * ResolvePathType<{ a: { b: { c: string } } }, "a.b.c"> → string
272
- * ResolvePathType<{ a: { b: { c: "hello" } } }, "a.b.c"> → "hello"
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 ResolvePathType<T, P extends string> = P extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? ResolvePathType<T[Head], Tail> : never : P extends keyof T ? T[P] : never;
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
- * Extracts leaf keys under a scoped path (K) from all locales combined.
215
+ * Resolves the type at a dot-separated key in a nested object.
277
216
  *
278
217
  * @example
279
- * type Messages = {
280
- * en: { auth: { login: { success: string } } },
281
- * zh: { auth: { login: { success: string; failed: string } } }
218
+ * ```ts
219
+ * const structure = {
220
+ * a: {
221
+ * b: { c: "hello" },
222
+ * z: "world",
223
+ * },
282
224
  * };
283
- * ScopedLeafKeys<Messages, "auth.login"> → "success" | "failed"
225
+ *
226
+ * MessagesAtPreKey<typeof structure, "a"> // → { b: { c: string; }; z: string;}
227
+ * MessagesAtPreKey<typeof structure, "a.b"> // → { c: string; };
228
+ * ```
284
229
  */
285
- type ScopedLeafKeys<M, K extends string, D extends number = DefaultDepth> = UnionLocaleMessages<M> extends infer ResolvedLocaleMessages ? ResolvedLocaleMessages extends object ? LeafKeys<ResolvePathType<ResolvedLocaleMessages, K>, D> : never : never;
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
- * Infer valid key type from locale messages.
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
- * If `M` is not passed or empty, fallback to `string`.
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 InferTranslatorKey<M> = M extends LocaleNamespaceMessages ? UnionLocaleLeafKeys<M> : string;
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
- * const messagesRef: MessagesRef<AllMessages> = {
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
- * const localeRef: LocaleRef<AllMessages> = {
269
+ * ```ts
270
+ * const localeRef: LocaleRef<Messages> = {
312
271
  * current: "en"
313
272
  * };
273
+ * ```
314
274
  */
315
- type LocaleRef<M> = {
316
- current?: LocaleKey<M>;
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
- type ScopedTranslatorMethods<M, K extends string> = {
331
- hasKey: (key?: ScopedLeafKeys<M, K> & string, targetLocale?: LocaleKey<M>) => boolean;
332
- t: (key?: ScopedLeafKeys<M, K> & string, replacements?: Replacement | RichReplacement) => string;
333
- };
334
- type TranslatorMethods<M> = {
335
- hasKey: (key?: InferTranslatorKey<M> & string, targetLocale?: LocaleKey<M>) => boolean;
336
- t: (key?: InferTranslatorKey<M> & string, replacements?: Replacement | RichReplacement) => string;
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
- /** Optional handler functions for customizing translation behavior. */
305
+ /**
306
+ * Optional handler functions for customizing translation behavior.
307
+ */
347
308
  type TranslateHandlers = {
348
- formatMessage?: FormatMessage;
349
- onLoading?: OnLoading;
350
- onMissing?: OnMissing;
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
- /** Format a resolved message before returning it. */
353
- type FormatMessage<Result = unknown> = (ctx: TranslateContext & {
316
+ /** Function to format a resolved message. */
317
+ type FormatHandler<Result = unknown> = (ctx: TranslateHandlerContext & {
354
318
  message: string;
355
319
  }) => Result;
356
- /** Called when translation is still loading. */
357
- type OnLoading<Result = unknown> = (ctx: TranslateContext) => Result;
358
- /** Called when no message is found for the given key. */
359
- type OnMissing<Result = unknown> = (ctx: TranslateContext) => Result;
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: "Yiming" }
331
+ * replacements: { name: "John" }
367
332
  * }
368
333
  */
369
- type TranslateContext = {
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?: Replacement | RichReplacement;
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
- locale?: LocaleKey<M>;
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?: BaseTranslatorOptions<M>);
384
- /** Get all message data. */
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` (uninitialized).
390
- * Type cast is used to bypass TypeScript restrictions on dynamic messages.
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 LocaleNamespaceMessages>(messages: N): void;
393
- /** Get the current active locale. */
394
- get locale(): LocaleKey<M> | undefined;
395
- /** Change the active locale. */
396
- setLocale(newLocale: LocaleKey<M>): void;
397
- /** Check if a key exists in the specified locale or current locale. */
398
- hasKey: (key: InferTranslatorKey<M>, targetLocale?: LocaleKey<M>) => boolean;
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?: CoreTranslatorOptions<M>);
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
- t: <Result = string>(key: InferTranslatorKey<M>, replacements?: Replacement | RichReplacement) => Result;
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
- declare class ScopeTranslator<M = unknown> extends CoreTranslator<M> {
416
- constructor(options?: CoreTranslatorOptions<M>);
417
- scoped<K extends NodeKeys<UnionLocaleMessages<M>> & string>(preKey: K): ScopedTranslatorMethods<M, K>;
418
- scoped(): TranslatorMethods<M>;
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 FormatMessage, type InferTranslatorKey, type IsLoadingRef, type LeafKeys, type Locale, type LocaleKey, type LocaleNamespaceMessages, type LocaleRef, type Message, type MessageRecord, type MessagesRef, type Namespace, type NamespaceMessages, type NestedMessage, type NodeKeys, type OnLoading, type OnMissing, type Replacement, type RichReplacement, type ScopedLeafKeys, type StrictLocaleKey, type TranslateConfig, type TranslateContext, type TranslateHandlers, ScopeTranslator as Translator, type UnionLocaleLeafKeys, type UnionLocaleMessages };
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 };