intor-translator 1.0.1 → 1.0.3
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 +119 -81
- package/dist/index.cjs +205 -155
- package/dist/index.d.cts +339 -221
- package/dist/index.d.ts +339 -221
- package/dist/index.js +204 -154
- package/package.json +19 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,265 +1,383 @@
|
|
|
1
|
-
import { LocaleNamespaceMessages, Locale, RichReplacement, FallbackLocalesMap, Replacement } from 'intor-types';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Represents
|
|
2
|
+
* Represents a locale identifier, such as 'en', 'zh-TW', or 'fr-FR'.
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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'.
|
|
8
11
|
*
|
|
9
|
-
* @
|
|
12
|
+
* @example
|
|
13
|
+
* const namespace: Namespace = "dashboard";
|
|
10
14
|
*/
|
|
11
|
-
type
|
|
15
|
+
type Namespace = string;
|
|
12
16
|
/**
|
|
13
|
-
*
|
|
17
|
+
* Represents a single translatable message string.
|
|
14
18
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
21
|
-
* };
|
|
22
|
-
* };
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
* Will generate: `"a" | "a.b" | "a.b.c"`
|
|
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.
|
|
26
25
|
*
|
|
27
|
-
*
|
|
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
28
|
*
|
|
29
|
-
* @
|
|
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
|
+
* };
|
|
30
39
|
*/
|
|
31
|
-
type
|
|
32
|
-
[
|
|
33
|
-
}
|
|
40
|
+
type Replacement = {
|
|
41
|
+
[key: string]: string | number | Replacement;
|
|
42
|
+
};
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
messageFormatter?: MessageFormatter;
|
|
41
|
-
/**
|
|
42
|
-
* Handler for loading state of the translation message.
|
|
43
|
-
* Useful when translations are loaded asynchronously.
|
|
44
|
-
*/
|
|
45
|
-
loadingMessageHandler?: LoadingMessageHandler;
|
|
46
|
-
/**
|
|
47
|
-
* Handler for placeholders in translation messages.
|
|
48
|
-
* Useful for handling missing or fallback placeholders.
|
|
49
|
-
*/
|
|
50
|
-
placeholderHandler?: PlaceholderHandler;
|
|
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;
|
|
51
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;
|
|
52
57
|
/**
|
|
53
|
-
*
|
|
58
|
+
* A recursive replacement object that supports rich replacement values,
|
|
59
|
+
* allowing complex nested interpolation structures.
|
|
54
60
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
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
|
+
/**
|
|
79
|
+
* A nested message structure or a simple string message.
|
|
80
|
+
* Used to represent either a plain message or an object containing more nested messages.
|
|
57
81
|
*
|
|
58
|
-
* @
|
|
82
|
+
* @example
|
|
83
|
+
* const greeting: NestedMessage = "Hello";
|
|
59
84
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
85
|
+
* const userMessages: NestedMessage = {
|
|
86
|
+
* profile: {
|
|
87
|
+
* greeting: "Hello, user!",
|
|
88
|
+
* farewell: "Goodbye!"
|
|
89
|
+
* }
|
|
90
|
+
* };
|
|
91
|
+
*/
|
|
92
|
+
type NestedMessage = Message | {
|
|
93
|
+
[key: string]: NestedMessage;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
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`.
|
|
65
98
|
*
|
|
66
|
-
* @
|
|
99
|
+
* @example
|
|
100
|
+
* const messages: MessageRecord = {
|
|
101
|
+
* greeting: "Hello",
|
|
102
|
+
* user: {
|
|
103
|
+
* profile: {
|
|
104
|
+
* name: "Your Name"
|
|
105
|
+
* }
|
|
106
|
+
* }
|
|
107
|
+
* };
|
|
67
108
|
*/
|
|
68
|
-
type
|
|
69
|
-
message: string;
|
|
70
|
-
}) => Result;
|
|
109
|
+
type MessageRecord = Record<string, NestedMessage>;
|
|
71
110
|
/**
|
|
72
|
-
*
|
|
111
|
+
* A record of messages grouped by namespace.
|
|
112
|
+
* Each namespace contains its own `MessageRecord` structure.
|
|
73
113
|
*
|
|
74
|
-
* @
|
|
114
|
+
* @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.
|
|
75
131
|
*
|
|
76
|
-
* @
|
|
77
|
-
*
|
|
132
|
+
* @example
|
|
133
|
+
* const messages: LocaleNamespaceMessages = {
|
|
134
|
+
* en: {
|
|
135
|
+
* common: {
|
|
136
|
+
* welcome: "Welcome"
|
|
137
|
+
* },
|
|
138
|
+
* auth: {
|
|
139
|
+
* login: {
|
|
140
|
+
* success: "Login successful"
|
|
141
|
+
* }
|
|
142
|
+
* }
|
|
143
|
+
* },
|
|
144
|
+
* "zh-TW": {
|
|
145
|
+
* common: {
|
|
146
|
+
* welcome: "歡迎"
|
|
147
|
+
* }
|
|
148
|
+
* }
|
|
149
|
+
* };
|
|
78
150
|
*/
|
|
79
|
-
type
|
|
151
|
+
type LocaleNamespaceMessages = Record<Locale, NamespaceMessages>;
|
|
80
152
|
/**
|
|
81
|
-
*
|
|
153
|
+
* Merges messages from all locales into a single unified structure.
|
|
82
154
|
*
|
|
83
|
-
* @
|
|
155
|
+
* @example
|
|
156
|
+
* const messages = {
|
|
157
|
+
* en: { auth: { login: "Login" } },
|
|
158
|
+
* zh: { auth: { logout: "登出" } },
|
|
159
|
+
* };
|
|
84
160
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
161
|
+
* type Result = UnionLocaleMessages<typeof messages>;
|
|
162
|
+
* // Result: { auth: { login: "Login" } } | { auth: { logout: "登出" } }
|
|
87
163
|
*/
|
|
88
|
-
type
|
|
164
|
+
type UnionLocaleMessages<M extends LocaleNamespaceMessages> = M[LocaleKey<M>];
|
|
165
|
+
|
|
89
166
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
167
|
+
* Extracts the locale keys from the messages object as string literals.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* type Locales = LocaleKey<{
|
|
171
|
+
* en: {};
|
|
172
|
+
* "zh-TW": {};
|
|
173
|
+
* }>;
|
|
174
|
+
* // Locales is "en" | "zh-TW"
|
|
92
175
|
*/
|
|
93
|
-
type
|
|
94
|
-
locale: Locale;
|
|
95
|
-
key: string;
|
|
96
|
-
replacements?: RichReplacement;
|
|
97
|
-
};
|
|
98
|
-
|
|
176
|
+
type LocaleKey<M extends LocaleNamespaceMessages> = keyof M & string;
|
|
99
177
|
/**
|
|
100
|
-
*
|
|
178
|
+
* A map that defines fallback locales for each base locale.
|
|
179
|
+
*
|
|
180
|
+
* When a message is missing for a given locale, the system will attempt to find the message
|
|
181
|
+
* by falling back to the locales listed here, in the specified order.
|
|
101
182
|
*
|
|
102
183
|
* @example
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* messages: {
|
|
107
|
-
* en: { common: { hello: "Hello" } },
|
|
108
|
-
* zh: { common: { hello: "你好" } },
|
|
109
|
-
* },
|
|
110
|
-
* fallbackLocales: { zh: ['en'] },
|
|
111
|
-
* handlers: {
|
|
112
|
-
* messageFormatter: ({ message }) => message.toUpperCase(),
|
|
113
|
-
* },
|
|
184
|
+
* const fallbacks: FallbackLocalesMap = {
|
|
185
|
+
* "en-AU": ["en-GB", "en"],
|
|
186
|
+
* "zh-TW": ["zh-HK", "zh"]
|
|
114
187
|
* };
|
|
115
|
-
* ```
|
|
116
188
|
*/
|
|
117
|
-
type
|
|
118
|
-
/**
|
|
119
|
-
* - The message definitions to be used by the translator.
|
|
120
|
-
* - These should be pre-loaded and structured by locale and namespace.
|
|
121
|
-
*/
|
|
122
|
-
messages: Readonly<Messages>;
|
|
123
|
-
/**
|
|
124
|
-
* - The current active locale, e.g., "en" or "zh-TW".
|
|
125
|
-
*/
|
|
126
|
-
locale: RawLocale<Messages>;
|
|
127
|
-
/**
|
|
128
|
-
* - Optional fallback locale(s) to use when a message is missing in the primary locale.
|
|
129
|
-
*/
|
|
130
|
-
fallbackLocales?: FallbackLocalesMap;
|
|
131
|
-
/**
|
|
132
|
-
* - Whether the translator is currently in a loading state.
|
|
133
|
-
* - Useful for SSR or async loading scenarios.
|
|
134
|
-
*/
|
|
135
|
-
isLoading?: boolean;
|
|
136
|
-
/**
|
|
137
|
-
* - The message string to return while in loading state.
|
|
138
|
-
* - Will be overridden if you provide a `loadingMessageHandler` in handlers.
|
|
139
|
-
*/
|
|
140
|
-
loadingMessage?: string;
|
|
141
|
-
/**
|
|
142
|
-
* - A fallback string to show when the message key is missing.
|
|
143
|
-
* - Will be overridden if you provide a `placeholderHandler` in handlers.
|
|
144
|
-
*/
|
|
145
|
-
placeholder?: string;
|
|
146
|
-
/**
|
|
147
|
-
* - Optional handlers to customize translation behavior (formatting, placeholders, etc).
|
|
148
|
-
*/
|
|
149
|
-
handlers?: TranslatorHandlers;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
type GetLocale<Messages extends LocaleNamespaceMessages> = () => RawLocale<Messages>;
|
|
153
|
-
|
|
154
|
-
type GetMessages<Messages extends LocaleNamespaceMessages> = () => Readonly<Messages>;
|
|
155
|
-
|
|
156
|
-
type HasKey<Messages extends LocaleNamespaceMessages> = {
|
|
157
|
-
<Locale extends RawLocale<Messages>>(key: NestedKeyPaths<Messages[Locale]>, locale?: Locale): boolean;
|
|
158
|
-
(key: string, locale?: Locale): boolean;
|
|
159
|
-
};
|
|
160
|
-
type LooseHasKey = (key?: string, locale?: Locale) => boolean;
|
|
161
|
-
|
|
162
|
-
type Translate<Messages extends LocaleNamespaceMessages> = {
|
|
163
|
-
<Locale extends RawLocale<Messages>>(key: NestedKeyPaths<Messages[Locale]>, replacements?: Replacement | RichReplacement): string;
|
|
164
|
-
(key: string, replacements?: Replacement | RichReplacement): string;
|
|
165
|
-
};
|
|
166
|
-
type LooseTranslate = (key?: string, replacements?: Replacement | RichReplacement) => string;
|
|
167
|
-
|
|
168
|
-
type Scoped<Messages extends LocaleNamespaceMessages> = <Locale extends RawLocale<Messages>>(preKey?: NestedKeyPaths<Messages[Locale]>) => {
|
|
169
|
-
t: LooseTranslate;
|
|
170
|
-
hasKey: LooseHasKey;
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
type SetLocale<Messages extends LocaleNamespaceMessages> = (newLocale: RawLocale<Messages>) => void;
|
|
189
|
+
type FallbackLocalesMap<L extends string = string> = Partial<Record<L, L[]>>;
|
|
174
190
|
|
|
175
191
|
/**
|
|
176
|
-
*
|
|
192
|
+
* Gets all dot-separated keys (including non-leaf nodes) from a nested object.
|
|
177
193
|
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
194
|
+
* @example
|
|
195
|
+
* NodeKeys<{ a: { b: { c: string }, d: string } }> → "a" | "a.b" | "a.b.c" | "a.d"
|
|
196
|
+
*/
|
|
197
|
+
type NodeKeys<M> = M extends object ? {
|
|
198
|
+
[K in keyof M]: K extends string ? `${K}` | `${K}.${NodeKeys<M[K]>}` : never;
|
|
199
|
+
}[keyof M] : never;
|
|
200
|
+
/**
|
|
201
|
+
* Default maximum recursive depth for nested key type computations,
|
|
202
|
+
* balancing type safety and compiler performance.
|
|
203
|
+
*/
|
|
204
|
+
type DefaultDepth = 15;
|
|
205
|
+
/** Countdown tuple for limiting recursive depth (up to 10 levels). */
|
|
206
|
+
type Prev = [
|
|
207
|
+
never,
|
|
208
|
+
0,
|
|
209
|
+
1,
|
|
210
|
+
2,
|
|
211
|
+
3,
|
|
212
|
+
4,
|
|
213
|
+
5,
|
|
214
|
+
6,
|
|
215
|
+
7,
|
|
216
|
+
8,
|
|
217
|
+
9,
|
|
218
|
+
10,
|
|
219
|
+
11,
|
|
220
|
+
12,
|
|
221
|
+
13,
|
|
222
|
+
14,
|
|
223
|
+
15,
|
|
224
|
+
16,
|
|
225
|
+
17,
|
|
226
|
+
18,
|
|
227
|
+
19,
|
|
228
|
+
20
|
|
229
|
+
];
|
|
230
|
+
/**
|
|
231
|
+
* Gets dot-separated keys to string leaf nodes in a nested object.
|
|
180
232
|
*
|
|
181
|
-
* @
|
|
182
|
-
*
|
|
233
|
+
* @example
|
|
234
|
+
* LeafKeys<{ a: { b: "x", c: { d: "y" } } }> → "a.b" | "a.c.d"
|
|
183
235
|
*/
|
|
184
|
-
type
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
* ```ts
|
|
214
|
-
* t("home.welcome.title"); // Fully typed with key autocompletion
|
|
215
|
-
* t("dashboard.stats.count", { count: 5 });
|
|
216
|
-
* ```
|
|
217
|
-
*
|
|
218
|
-
* @param key - A dot-separated translation key (e.g., `"common.hello"`).
|
|
219
|
-
* @param replacements - Optional values to replace placeholders in the message.
|
|
220
|
-
* @returns The translated message string.
|
|
221
|
-
*/
|
|
222
|
-
t: Translate<Messages>;
|
|
223
|
-
/**
|
|
224
|
-
* Check whether a strongly-typed translation key exists in the loaded messages.
|
|
225
|
-
*
|
|
226
|
-
* This method ensures the key path is valid according to the message schema
|
|
227
|
-
* for a given locale.
|
|
228
|
-
*
|
|
229
|
-
* @example
|
|
230
|
-
* ```ts
|
|
231
|
-
* hasKey("home.welcome.title"); // true or false
|
|
232
|
-
* hasKey("dashboard.stats.count", "zh");
|
|
233
|
-
* ```
|
|
234
|
-
*
|
|
235
|
-
* @param key - A dot-separated message key defined in the locale messages.
|
|
236
|
-
* @param locale - Optional locale to check against. If omitted, defaults to current locale.
|
|
237
|
-
* @returns A boolean indicating whether the key exists.
|
|
238
|
-
*/
|
|
239
|
-
hasKey: HasKey<Messages>;
|
|
240
|
-
/**
|
|
241
|
-
* Create a scoped translator bound to a specific namespace.
|
|
242
|
-
*
|
|
243
|
-
* Useful for modular translation logic (e.g., per-page or per-component).
|
|
244
|
-
*
|
|
245
|
-
* @param namespace - The namespace to scope to (e.g., "auth").
|
|
246
|
-
* @returns A new translator with scoped `t()` and helpers.
|
|
247
|
-
*/
|
|
248
|
-
scoped: Scoped<Messages>;
|
|
249
|
-
};
|
|
236
|
+
type LeafKeys<M, D extends number = DefaultDepth> = [D] extends [never] ? never : M extends object ? {
|
|
237
|
+
[K in keyof M]: M[K] extends string ? `${K & string}` : M[K] extends object ? `${K & string}.${LeafKeys<M[K], Prev[D]>}` : never;
|
|
238
|
+
}[keyof M] : never;
|
|
239
|
+
/**
|
|
240
|
+
* Gets string leaf keys from all locale messages combined.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* UnionLocaleLeafKeys<{ en: { a: { b: "x" } }, zh: { a: { c: "y" } } }> → "a.b" | "a.c"
|
|
244
|
+
*/
|
|
245
|
+
type UnionLocaleLeafKeys<M extends LocaleNamespaceMessages, D extends number = DefaultDepth> = UnionLocaleMessages<M> extends NamespaceMessages ? LeafKeys<UnionLocaleMessages<M>, D> : never;
|
|
246
|
+
/**
|
|
247
|
+
* Resolves the type at a dot-separated key in a nested object.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ResolvePathType<{ a: { b: { c: string } } }, "a.b.c"> → string
|
|
251
|
+
* ResolvePathType<{ a: { b: { c: "hello" } } }, "a.b.c"> → "hello"
|
|
252
|
+
*/
|
|
253
|
+
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;
|
|
254
|
+
/**
|
|
255
|
+
* Extracts leaf keys under a scoped path (K) from all locales combined.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* type Messages = {
|
|
259
|
+
* en: { auth: { login: { success: string } } },
|
|
260
|
+
* zh: { auth: { login: { success: string; failed: string } } }
|
|
261
|
+
* };
|
|
262
|
+
* ScopedLeafKeys<Messages, "auth.login"> → "success" | "failed"
|
|
263
|
+
*/
|
|
264
|
+
type ScopedLeafKeys<M extends LocaleNamespaceMessages, K extends string, D extends number = DefaultDepth> = UnionLocaleMessages<M> extends infer ResolvedLocaleMessages ? ResolvedLocaleMessages extends object ? LeafKeys<ResolvePathType<ResolvedLocaleMessages, K>, D> : never : never;
|
|
250
265
|
|
|
251
266
|
/**
|
|
252
|
-
*
|
|
267
|
+
* A ref object holding all localized messages by locale.
|
|
253
268
|
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
269
|
+
* @example
|
|
270
|
+
* const messagesRef: MessagesRef<AllMessages> = {
|
|
271
|
+
* current: {
|
|
272
|
+
* en: { home: { title: "Welcome" } },
|
|
273
|
+
* zh: { home: { title: "歡迎" } }
|
|
274
|
+
* }
|
|
275
|
+
* };
|
|
276
|
+
*/
|
|
277
|
+
type MessagesRef<M extends LocaleNamespaceMessages> = {
|
|
278
|
+
current: Readonly<M>;
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* A ref object holding the currently selected locale.
|
|
257
282
|
*
|
|
258
|
-
* @
|
|
283
|
+
* @example
|
|
284
|
+
* const localeRef: LocaleRef<AllMessages> = {
|
|
285
|
+
* current: "en"
|
|
286
|
+
* };
|
|
287
|
+
*/
|
|
288
|
+
type LocaleRef<M extends LocaleNamespaceMessages> = {
|
|
289
|
+
current: LocaleKey<M>;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* A ref object indicating whether translation is loading.
|
|
259
293
|
*
|
|
260
|
-
* @
|
|
261
|
-
*
|
|
294
|
+
* @example
|
|
295
|
+
* const isLoadingRef: IsLoadingRef = {
|
|
296
|
+
* current: true
|
|
297
|
+
* };
|
|
262
298
|
*/
|
|
263
|
-
|
|
299
|
+
type IsLoadingRef = {
|
|
300
|
+
current: boolean;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/** Config options for translation behavior. */
|
|
304
|
+
type TranslateConfig = {
|
|
305
|
+
fallbackLocales?: FallbackLocalesMap;
|
|
306
|
+
loadingMessage?: string;
|
|
307
|
+
placeholder?: string;
|
|
308
|
+
handlers?: TranslateHandlers;
|
|
309
|
+
};
|
|
310
|
+
/** Optional handler functions for customizing translation behavior. */
|
|
311
|
+
type TranslateHandlers = {
|
|
312
|
+
formatMessage?: FormatMessage;
|
|
313
|
+
onLoading?: OnLoading;
|
|
314
|
+
onMissing?: OnMissing;
|
|
315
|
+
};
|
|
316
|
+
/** Format a resolved message before returning it. */
|
|
317
|
+
type FormatMessage<Result = unknown> = (ctx: TranslateContext & {
|
|
318
|
+
message: string;
|
|
319
|
+
}) => Result;
|
|
320
|
+
/** Called when translation is still loading. */
|
|
321
|
+
type OnLoading<Result = unknown> = (ctx: TranslateContext) => Result;
|
|
322
|
+
/** Called when no message is found for the given key. */
|
|
323
|
+
type OnMissing<Result = unknown> = (ctx: TranslateContext) => Result;
|
|
324
|
+
/**
|
|
325
|
+
* Context passed to translation-related functions.
|
|
326
|
+
* @example
|
|
327
|
+
* {
|
|
328
|
+
* locale: "en",
|
|
329
|
+
* key: "home.title",
|
|
330
|
+
* replacements: { name: "Yiming" }
|
|
331
|
+
* }
|
|
332
|
+
*/
|
|
333
|
+
type TranslateContext = {
|
|
334
|
+
locale: Locale;
|
|
335
|
+
key: string;
|
|
336
|
+
replacements?: Replacement | RichReplacement;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
interface BaseTranslatorOptions<M extends LocaleNamespaceMessages> {
|
|
340
|
+
messages: Readonly<M>;
|
|
341
|
+
locale: LocaleKey<M>;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
declare class BaseTranslator<M extends LocaleNamespaceMessages> {
|
|
345
|
+
protected options: BaseTranslatorOptions<M>;
|
|
346
|
+
protected messagesRef: MessagesRef<M>;
|
|
347
|
+
protected localeRef: LocaleRef<M>;
|
|
348
|
+
constructor(options: BaseTranslatorOptions<M>);
|
|
349
|
+
/** Get all message data. */
|
|
350
|
+
get messages(): M;
|
|
351
|
+
/** Replace messages with new ones. */
|
|
352
|
+
setMessages(messages: M): void;
|
|
353
|
+
/** Get the current active locale. */
|
|
354
|
+
get locale(): LocaleKey<M>;
|
|
355
|
+
/** Change the active locale if available. */
|
|
356
|
+
setLocale(newLocale: LocaleKey<M>): boolean;
|
|
357
|
+
/** Check if a key exists in the specified locale or current locale. */
|
|
358
|
+
hasKey: (key: UnionLocaleLeafKeys<M>, targetLocale?: LocaleKey<M>) => boolean;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
interface CoreTranslatorOptions<M extends LocaleNamespaceMessages> extends BaseTranslatorOptions<M>, TranslateConfig {
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
declare class CoreTranslator<M extends LocaleNamespaceMessages> extends BaseTranslator<M> {
|
|
365
|
+
protected options: CoreTranslatorOptions<M>;
|
|
366
|
+
protected isLoadingRef: IsLoadingRef;
|
|
367
|
+
constructor(options: CoreTranslatorOptions<M>);
|
|
368
|
+
/** Get the current loading state. */
|
|
369
|
+
get isLoading(): boolean;
|
|
370
|
+
/** Set the loading state. */
|
|
371
|
+
setLoading(state: boolean): void;
|
|
372
|
+
t: <Result = string>(key: UnionLocaleLeafKeys<M>, replacements?: Replacement | RichReplacement) => Result;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
declare class ScopeTranslator<M extends LocaleNamespaceMessages> extends CoreTranslator<M> {
|
|
376
|
+
constructor(options: CoreTranslatorOptions<M>);
|
|
377
|
+
scoped: <K extends NodeKeys<UnionLocaleMessages<M>> & string, ScopedKeys extends ScopedLeafKeys<M, K> & string>(preKey: K) => {
|
|
378
|
+
hasKey: (key?: ScopedKeys | undefined, targetLocale?: string) => boolean;
|
|
379
|
+
t: (key?: ScopedKeys | undefined, replacements?: Replacement | RichReplacement) => string;
|
|
380
|
+
};
|
|
381
|
+
}
|
|
264
382
|
|
|
265
|
-
export { type
|
|
383
|
+
export { type FallbackLocalesMap, type FormatMessage, 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 TranslateConfig, type TranslateContext, type TranslateHandlers, ScopeTranslator as Translator, type UnionLocaleLeafKeys, type UnionLocaleMessages };
|