@@ -14,47 +14,58 @@ const updater = mitt()
14
14
15
15
export type Language = ( typeof languages ) [ number ]
16
16
17
- export type I18NTranslations = ParseObject <
17
+ export type I18NTranslations = MakeTranslations <
18
18
| typeof import ( './generated/cn' ) . default
19
19
| typeof import ( './generated/en' ) . default
20
20
> & { essentials : I18NEssentials }
21
21
22
- type I18NEssentials = ParseObject < ( typeof ESSENTIALS ) [ Language ] >
22
+ type I18NEssentials = MakeTranslations < ( typeof ESSENTIALS ) [ Language ] >
23
23
24
- type ParseObject < T > = T extends string
24
+ type MakeTranslations < T > = MakeEndpoints < ParseValue < T > >
25
+
26
+ type ParseValue < T > = T extends string
25
27
? ParseMessage < T , [ ] >
26
28
: T extends PluralObject
27
29
? ParseMessage < T [ 'other' ] , [ 'count' ] >
28
- : { [ K in keyof T ] : ParseObject < T [ K ] > }
29
-
30
- type PluralObject = Record < `${number } ` | 'other' , string >
30
+ : { [ P in keyof T ] : ParseValue < T [ P ] > }
31
31
32
- type ParseMessage < T extends string , InitialKeys extends unknown [ ] > =
33
- InterpolationKeys < T , InitialKeys > extends infer Keys
34
- ? Keys extends [ ]
35
- ? string
36
- : Keys extends unknown [ ]
37
- ? Endpoint < Keys >
38
- : never
39
- : never
40
-
41
- type Endpoint < Keys extends unknown [ ] > = Keys extends IndexKey [ ]
42
- ? < T extends { [ K in keyof Keys ] ?: ReactNode } > (
43
- ...args : T
44
- ) => T [ number ] extends string | number ? string : ReactElement
45
- : < T extends { [ K in Extract < Keys [ number ] , string > ] ?: ReactNode } > (
46
- ...args : [ T ]
47
- ) => ValueOf < T > extends string | number ? string : ReactElement
32
+ type ParseMessage <
33
+ T extends string ,
34
+ InitialKeys extends unknown [ ] ,
35
+ Keys = InterpolationKeys < T , InitialKeys > ,
36
+ > = Keys extends [ ] ? string : Keys
48
37
49
38
type InterpolationKeys <
50
39
Str ,
51
40
Keys extends unknown [ ] ,
52
41
> = Str extends `${string } {{${infer Key } }}${infer End } `
53
- ? InterpolationKeys < End , [ ...Keys , Key extends '' ? IndexKey : Key ] >
42
+ ? InterpolationKeys < End , [ ...Keys , Key extends '' ? UnnamedKey : Key ] >
54
43
: Keys
55
44
56
- declare const indexKey : unique symbol
57
- type IndexKey = typeof indexKey
45
+ type PluralObject = Record < `${number } ` | 'other' , string >
46
+
47
+ type MakeEndpoints < T , K extends keyof T = keyof T > = string extends T
48
+ ? T
49
+ : [ T ] extends [ unknown [ ] ]
50
+ ? Endpoint < T >
51
+ : { [ P in K ] : MakeEndpoints < T [ P ] > }
52
+
53
+ type Endpoint < Keys extends unknown [ ] > = Keys [ number ] extends UnnamedKey
54
+ ? UnnamedInterpolation < { [ K in keyof Keys ] : ReactNode } >
55
+ : Interpolation < { [ K in Extract < Keys [ number ] , string > ] : ReactNode } >
56
+
57
+ type Interpolation < Arg > = < T extends Arg > (
58
+ ...args : [ T ]
59
+ ) => InterpolationResult < ValueOf < T > >
60
+
61
+ type UnnamedInterpolation < Arg extends unknown [ ] > = < T extends Arg > (
62
+ ...args : T
63
+ ) => InterpolationResult < T [ number ] >
64
+
65
+ type InterpolationResult < T > = T extends string | number ? string : ReactElement
66
+
67
+ declare const unnamedKey : unique symbol
68
+ type UnnamedKey = typeof unnamedKey
58
69
59
70
export const allEssentials = Object . fromEntries (
60
71
Object . entries ( ESSENTIALS ) . map ( ( [ language , data ] ) => [
@@ -81,7 +92,7 @@ export const i18n = new Proxy({} as I18NTranslations, {
81
92
// before the translations are loaded, in which case you should change it to i18nDefer.*
82
93
throw new Error ( allEssentials [ currentLanguage ] . translations_not_loaded )
83
94
}
84
- return currentTranslations [ prop as keyof I18NTranslations ] || prop
95
+ return currentTranslations [ prop ] || prop
85
96
} ,
86
97
} )
87
98
0 commit comments