@coherent.js/i18n 1.0.0-beta.5 → 1.0.0-beta.6
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/package.json +2 -2
- package/types/index.d.ts +354 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coherent.js/i18n",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.6",
|
|
4
4
|
"description": "Internationalization support for Coherent.js applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"author": "Coherent.js Team",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@coherent.js/core": "1.0.0-beta.
|
|
23
|
+
"@coherent.js/core": "1.0.0-beta.6"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
package/types/index.d.ts
CHANGED
|
@@ -3,41 +3,283 @@
|
|
|
3
3
|
* @module @coherent.js/i18n
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import type { CoherentNode } from '@coherent.js/core';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Translation Key Types
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Translation key type (can be extended for type-safe translations)
|
|
14
|
+
*/
|
|
15
|
+
export type TranslationKey = string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Nested translation messages object
|
|
19
|
+
*/
|
|
20
|
+
export type TranslationMessages = {
|
|
9
21
|
[key: string]: string | TranslationMessages;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Helper type to flatten nested keys with dot notation
|
|
26
|
+
* @example FlattenKeys<{ home: { title: 'Title' } }> = 'home.title'
|
|
27
|
+
*/
|
|
28
|
+
export type FlattenKeys<T, Prefix extends string = ''> = T extends string
|
|
29
|
+
? Prefix
|
|
30
|
+
: {
|
|
31
|
+
[K in keyof T]: FlattenKeys<
|
|
32
|
+
T[K],
|
|
33
|
+
`${Prefix}${Prefix extends '' ? '' : '.'}${K & string}`
|
|
34
|
+
>;
|
|
35
|
+
}[keyof T];
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Translation Function Types
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Translation function with overloads for different use cases
|
|
43
|
+
*/
|
|
44
|
+
export interface TranslationFunction {
|
|
45
|
+
/**
|
|
46
|
+
* Translate a key
|
|
47
|
+
*/
|
|
48
|
+
(key: TranslationKey): string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Translate a key with interpolation parameters
|
|
52
|
+
*/
|
|
53
|
+
(key: TranslationKey, params: Record<string, string | number>): string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Translate a key with interpolation and pluralization
|
|
57
|
+
*/
|
|
58
|
+
(key: TranslationKey, params: Record<string, string | number>, count: number): string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a typed translator for a specific message shape
|
|
63
|
+
* @template T - The translation messages type
|
|
64
|
+
*/
|
|
65
|
+
export function createTypedTranslator<T extends TranslationMessages>(
|
|
66
|
+
messages: T
|
|
67
|
+
): (key: FlattenKeys<T>, params?: Record<string, string | number>) => string;
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// I18n Configuration
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* I18n configuration options
|
|
75
|
+
*/
|
|
76
|
+
export interface I18nConfig {
|
|
77
|
+
/** Default locale code (e.g., 'en', 'en-US') */
|
|
78
|
+
defaultLocale: string;
|
|
79
|
+
/** List of supported locale codes */
|
|
80
|
+
supportedLocales: string[];
|
|
81
|
+
/** Fallback locale when translation is missing */
|
|
82
|
+
fallbackLocale?: string;
|
|
83
|
+
/** Async function to load messages for a locale */
|
|
84
|
+
loadMessages?: (locale: string) => Promise<TranslationMessages>;
|
|
85
|
+
/** Pre-loaded messages by locale */
|
|
86
|
+
messages?: Record<string, TranslationMessages>;
|
|
87
|
+
/** Handler for missing translation keys */
|
|
88
|
+
missingKeyHandler?: (key: string, locale: string) => string;
|
|
89
|
+
/** Interpolation settings */
|
|
90
|
+
interpolation?: {
|
|
91
|
+
/** Interpolation prefix (default: '{{') */
|
|
92
|
+
prefix?: string;
|
|
93
|
+
/** Interpolation suffix (default: '}}') */
|
|
94
|
+
suffix?: string;
|
|
95
|
+
/** Escape HTML in interpolated values */
|
|
96
|
+
escapeHtml?: boolean;
|
|
97
|
+
};
|
|
98
|
+
/** Enable pluralization support */
|
|
99
|
+
pluralization?: boolean;
|
|
100
|
+
/** Context separator for contextual translations */
|
|
101
|
+
contextSeparator?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// I18n Instance
|
|
106
|
+
// ============================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* I18n instance interface
|
|
110
|
+
*/
|
|
111
|
+
export interface I18nInstance {
|
|
112
|
+
/** Current locale code */
|
|
113
|
+
readonly locale: string;
|
|
114
|
+
|
|
115
|
+
/** Translation function */
|
|
116
|
+
t: TranslationFunction;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Change the current locale
|
|
120
|
+
*/
|
|
121
|
+
setLocale(locale: string): Promise<void>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get the current locale code
|
|
125
|
+
*/
|
|
126
|
+
getLocale(): string;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get list of supported locales
|
|
130
|
+
*/
|
|
131
|
+
getSupportedLocales(): string[];
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if a translation key exists
|
|
135
|
+
*/
|
|
136
|
+
hasTranslation(key: TranslationKey): boolean;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Format a number according to locale
|
|
140
|
+
*/
|
|
141
|
+
formatNumber(value: number, options?: Intl.NumberFormatOptions): string;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Format a date according to locale
|
|
145
|
+
*/
|
|
146
|
+
formatDate(value: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Format a currency value
|
|
150
|
+
*/
|
|
151
|
+
formatCurrency(
|
|
152
|
+
value: number,
|
|
153
|
+
currency: string,
|
|
154
|
+
options?: Intl.NumberFormatOptions
|
|
155
|
+
): string;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Format a relative time (e.g., "3 days ago")
|
|
159
|
+
*/
|
|
160
|
+
formatRelativeTime(
|
|
161
|
+
value: number,
|
|
162
|
+
unit: Intl.RelativeTimeFormatUnit,
|
|
163
|
+
options?: Intl.RelativeTimeFormatOptions
|
|
164
|
+
): string;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Format a list (e.g., "A, B, and C")
|
|
168
|
+
*/
|
|
169
|
+
formatList(values: string[], options?: Intl.ListFormatOptions): string;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Add messages for a locale
|
|
173
|
+
*/
|
|
174
|
+
addMessages(messages: TranslationMessages, locale?: string): void;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get all messages for current locale
|
|
178
|
+
*/
|
|
179
|
+
getMessages(): TranslationMessages;
|
|
10
180
|
}
|
|
11
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Create an i18n instance
|
|
184
|
+
*/
|
|
185
|
+
export function createI18n(config: I18nConfig): I18nInstance;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Hook to get the translation function (for component usage)
|
|
189
|
+
*/
|
|
190
|
+
export function useTranslation(): TranslationFunction;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Hook to get and set the current locale
|
|
194
|
+
*/
|
|
195
|
+
export function useLocale(): [string, (locale: string) => Promise<void>];
|
|
196
|
+
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// Translator Class
|
|
199
|
+
// ============================================================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Translator options
|
|
203
|
+
*/
|
|
12
204
|
export interface TranslatorOptions {
|
|
205
|
+
/** Current locale code */
|
|
13
206
|
locale: string;
|
|
207
|
+
/** Translation messages for current locale */
|
|
14
208
|
messages: TranslationMessages;
|
|
209
|
+
/** Fallback locale code */
|
|
15
210
|
fallbackLocale?: string;
|
|
211
|
+
/** Fallback messages */
|
|
16
212
|
fallbackMessages?: TranslationMessages;
|
|
213
|
+
/** Interpolation settings */
|
|
17
214
|
interpolation?: {
|
|
18
215
|
prefix?: string;
|
|
19
216
|
suffix?: string;
|
|
20
217
|
};
|
|
218
|
+
/** Enable pluralization */
|
|
21
219
|
pluralization?: boolean;
|
|
220
|
+
/** Context separator */
|
|
22
221
|
contextSeparator?: string;
|
|
23
222
|
}
|
|
24
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Translator class
|
|
226
|
+
*/
|
|
25
227
|
export class Translator {
|
|
26
228
|
constructor(options: TranslatorOptions);
|
|
27
|
-
|
|
28
|
-
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Translate a key
|
|
232
|
+
*/
|
|
233
|
+
t(key: string, params?: Record<string, unknown>): string;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Alias for t()
|
|
237
|
+
*/
|
|
238
|
+
translate(key: string, params?: Record<string, unknown>): string;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Check if a translation exists
|
|
242
|
+
*/
|
|
29
243
|
has(key: string): boolean;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Set the current locale
|
|
247
|
+
*/
|
|
30
248
|
setLocale(locale: string): void;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get the current locale
|
|
252
|
+
*/
|
|
31
253
|
getLocale(): string;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Add translation messages
|
|
257
|
+
*/
|
|
32
258
|
addMessages(messages: TranslationMessages, locale?: string): void;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Remove translation messages
|
|
262
|
+
*/
|
|
33
263
|
removeMessages(keys: string[], locale?: string): void;
|
|
34
264
|
}
|
|
35
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Create a translator instance
|
|
268
|
+
*/
|
|
36
269
|
export function createTranslator(options: TranslatorOptions): Translator;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Create a scoped translator (prefixes all keys)
|
|
273
|
+
*/
|
|
37
274
|
export function createScopedTranslator(translator: Translator, scope: string): Translator;
|
|
38
275
|
|
|
39
|
-
//
|
|
276
|
+
// ============================================================================
|
|
277
|
+
// Formatters
|
|
278
|
+
// ============================================================================
|
|
40
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Date formatter options
|
|
282
|
+
*/
|
|
41
283
|
export interface DateFormatterOptions {
|
|
42
284
|
locale?: string;
|
|
43
285
|
timeZone?: string;
|
|
@@ -46,13 +288,25 @@ export interface DateFormatterOptions {
|
|
|
46
288
|
format?: string;
|
|
47
289
|
}
|
|
48
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Date formatter class
|
|
293
|
+
*/
|
|
49
294
|
export class DateFormatter {
|
|
50
295
|
constructor(locale?: string, options?: DateFormatterOptions);
|
|
296
|
+
|
|
297
|
+
/** Format a date */
|
|
51
298
|
format(date: Date | number | string): string;
|
|
299
|
+
|
|
300
|
+
/** Format as relative time (e.g., "2 hours ago") */
|
|
52
301
|
formatRelative(date: Date | number | string): string;
|
|
302
|
+
|
|
303
|
+
/** Format distance between dates */
|
|
53
304
|
formatDistance(date: Date | number | string, baseDate?: Date | number): string;
|
|
54
305
|
}
|
|
55
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Number formatter options
|
|
309
|
+
*/
|
|
56
310
|
export interface NumberFormatterOptions {
|
|
57
311
|
locale?: string;
|
|
58
312
|
style?: 'decimal' | 'currency' | 'percent' | 'unit';
|
|
@@ -62,35 +316,63 @@ export interface NumberFormatterOptions {
|
|
|
62
316
|
useGrouping?: boolean;
|
|
63
317
|
}
|
|
64
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Number formatter class
|
|
321
|
+
*/
|
|
65
322
|
export class NumberFormatter {
|
|
66
323
|
constructor(locale?: string, options?: NumberFormatterOptions);
|
|
324
|
+
|
|
325
|
+
/** Format a number */
|
|
67
326
|
format(value: number): string;
|
|
327
|
+
|
|
328
|
+
/** Format as compact notation */
|
|
68
329
|
formatCompact(value: number): string;
|
|
330
|
+
|
|
331
|
+
/** Format as percentage */
|
|
69
332
|
formatPercent(value: number): string;
|
|
70
333
|
}
|
|
71
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Currency formatter options
|
|
337
|
+
*/
|
|
72
338
|
export interface CurrencyFormatterOptions {
|
|
73
339
|
locale?: string;
|
|
74
340
|
currency: string;
|
|
75
341
|
display?: 'symbol' | 'code' | 'name';
|
|
76
342
|
}
|
|
77
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Currency formatter class
|
|
346
|
+
*/
|
|
78
347
|
export class CurrencyFormatter {
|
|
79
348
|
constructor(locale?: string, options?: CurrencyFormatterOptions);
|
|
349
|
+
|
|
350
|
+
/** Format a currency value */
|
|
80
351
|
format(value: number): string;
|
|
81
352
|
}
|
|
82
353
|
|
|
354
|
+
/**
|
|
355
|
+
* List formatter options
|
|
356
|
+
*/
|
|
83
357
|
export interface ListFormatterOptions {
|
|
84
358
|
locale?: string;
|
|
85
359
|
type?: 'conjunction' | 'disjunction' | 'unit';
|
|
86
360
|
style?: 'long' | 'short' | 'narrow';
|
|
87
361
|
}
|
|
88
362
|
|
|
363
|
+
/**
|
|
364
|
+
* List formatter class
|
|
365
|
+
*/
|
|
89
366
|
export class ListFormatter {
|
|
90
367
|
constructor(locale?: string, options?: ListFormatterOptions);
|
|
368
|
+
|
|
369
|
+
/** Format a list of items */
|
|
91
370
|
format(list: string[]): string;
|
|
92
371
|
}
|
|
93
372
|
|
|
373
|
+
/**
|
|
374
|
+
* All formatters for a locale
|
|
375
|
+
*/
|
|
94
376
|
export interface Formatters {
|
|
95
377
|
date: DateFormatter;
|
|
96
378
|
number: NumberFormatter;
|
|
@@ -98,31 +380,97 @@ export interface Formatters {
|
|
|
98
380
|
list: ListFormatter;
|
|
99
381
|
}
|
|
100
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Create all formatters for a locale
|
|
385
|
+
*/
|
|
101
386
|
export function createFormatters(locale: string): Formatters;
|
|
102
387
|
|
|
103
|
-
//
|
|
388
|
+
// ============================================================================
|
|
389
|
+
// Locale Management
|
|
390
|
+
// ============================================================================
|
|
104
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Locale configuration
|
|
394
|
+
*/
|
|
105
395
|
export interface LocaleConfig {
|
|
396
|
+
/** Locale code (e.g., 'en-US') */
|
|
106
397
|
code: string;
|
|
398
|
+
/** English name */
|
|
107
399
|
name: string;
|
|
400
|
+
/** Native name */
|
|
108
401
|
nativeName: string;
|
|
402
|
+
/** Text direction */
|
|
109
403
|
direction?: 'ltr' | 'rtl';
|
|
404
|
+
/** Date format pattern */
|
|
110
405
|
dateFormat?: string;
|
|
406
|
+
/** Time format pattern */
|
|
111
407
|
timeFormat?: string;
|
|
408
|
+
/** First day of week (0 = Sunday, 1 = Monday, etc.) */
|
|
112
409
|
firstDayOfWeek?: number;
|
|
113
410
|
}
|
|
114
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Locale manager class
|
|
414
|
+
*/
|
|
115
415
|
export class LocaleManager {
|
|
116
416
|
constructor(locales: LocaleConfig[]);
|
|
417
|
+
|
|
418
|
+
/** Add a locale configuration */
|
|
117
419
|
addLocale(locale: LocaleConfig): void;
|
|
420
|
+
|
|
421
|
+
/** Remove a locale */
|
|
118
422
|
removeLocale(code: string): void;
|
|
423
|
+
|
|
424
|
+
/** Get locale configuration */
|
|
119
425
|
getLocale(code: string): LocaleConfig | undefined;
|
|
426
|
+
|
|
427
|
+
/** Get all locale configurations */
|
|
120
428
|
getAllLocales(): LocaleConfig[];
|
|
429
|
+
|
|
430
|
+
/** Set current locale */
|
|
121
431
|
setCurrentLocale(code: string): void;
|
|
432
|
+
|
|
433
|
+
/** Get current locale configuration */
|
|
122
434
|
getCurrentLocale(): LocaleConfig;
|
|
123
435
|
}
|
|
124
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Create a locale manager
|
|
439
|
+
*/
|
|
125
440
|
export function createLocaleManager(locales: LocaleConfig[]): LocaleManager;
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Detect user's preferred locale
|
|
444
|
+
*/
|
|
126
445
|
export function detectLocale(): string;
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Normalize a locale code (e.g., 'en_US' -> 'en-US')
|
|
449
|
+
*/
|
|
127
450
|
export function normalizeLocale(locale: string): string;
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Check if a locale uses RTL text direction
|
|
454
|
+
*/
|
|
128
455
|
export function isRTL(locale: string): boolean;
|
|
456
|
+
|
|
457
|
+
// ============================================================================
|
|
458
|
+
// Component Helpers
|
|
459
|
+
// ============================================================================
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Create a translated component node
|
|
463
|
+
*/
|
|
464
|
+
export function translatedNode(
|
|
465
|
+
key: TranslationKey,
|
|
466
|
+
tagName?: string,
|
|
467
|
+
params?: Record<string, string | number>
|
|
468
|
+
): CoherentNode;
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Create an i18n context provider component
|
|
472
|
+
*/
|
|
473
|
+
export function createI18nProvider(
|
|
474
|
+
i18n: I18nInstance,
|
|
475
|
+
children: CoherentNode
|
|
476
|
+
): CoherentNode;
|