1 | import type {
|
2 | $OmitArrayKeys,
|
3 | $PreservedValue,
|
4 | $Dictionary,
|
5 | $SpecialObject,
|
6 | $StringKeyPathToRecord,
|
7 | } from './helpers.js';
|
8 | import type {
|
9 | TypeOptions,
|
10 | Namespace,
|
11 | FlatNamespace,
|
12 | DefaultNamespace,
|
13 | TOptions,
|
14 | } from './options.js';
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | type _ReturnObjects = TypeOptions['returnObjects'];
|
21 | type _ReturnEmptyString = TypeOptions['returnEmptyString'];
|
22 | type _ReturnNull = TypeOptions['returnNull'];
|
23 | type _KeySeparator = TypeOptions['keySeparator'];
|
24 | type _NsSeparator = TypeOptions['nsSeparator'];
|
25 | type _PluralSeparator = TypeOptions['pluralSeparator'];
|
26 | type _ContextSeparator = TypeOptions['contextSeparator'];
|
27 | type _FallbackNamespace = TypeOptions['fallbackNS'];
|
28 | type _Resources = TypeOptions['resources'];
|
29 | type _JSONFormat = TypeOptions['jsonFormat'];
|
30 | type _InterpolationPrefix = TypeOptions['interpolationPrefix'];
|
31 | type _InterpolationSuffix = TypeOptions['interpolationSuffix'];
|
32 |
|
33 | type $IsResourcesDefined = [keyof _Resources] extends [never] ? false : true;
|
34 | type $ValueIfResourcesDefined<Value, Fallback> = $IsResourcesDefined extends true
|
35 | ? Value
|
36 | : Fallback;
|
37 | type $FirstNamespace<Ns extends Namespace> = Ns extends readonly any[] ? Ns[0] : Ns;
|
38 |
|
39 | type Resources = $ValueIfResourcesDefined<_Resources, $Dictionary<string>>;
|
40 |
|
41 | type PluralSuffix = _JSONFormat extends 'v4'
|
42 | ? 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'
|
43 | : number | 'plural';
|
44 |
|
45 | type WithOrWithoutPlural<Key> = _JSONFormat extends 'v4' | 'v3'
|
46 | ? Key extends `${infer KeyWithoutOrdinalPlural}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`
|
47 | ? KeyWithoutOrdinalPlural | Key
|
48 | : Key extends `${infer KeyWithoutPlural}${_PluralSeparator}${PluralSuffix}`
|
49 | ? KeyWithoutPlural | Key
|
50 | : Key
|
51 | : Key;
|
52 |
|
53 | type JoinKeys<K1, K2> = `${K1 & string}${_KeySeparator}${K2 & string}`;
|
54 | type AppendNamespace<Ns, Keys> = `${Ns & string}${_NsSeparator}${Keys & string}`;
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | type KeysBuilderWithReturnObjects<Res, Key = keyof Res> = Key extends keyof Res
|
60 | ? Res[Key] extends $Dictionary | readonly unknown[]
|
61 | ?
|
62 | | JoinKeys<Key, WithOrWithoutPlural<keyof $OmitArrayKeys<Res[Key]>>>
|
63 | | JoinKeys<Key, KeysBuilderWithReturnObjects<Res[Key]>>
|
64 | : never
|
65 | : never;
|
66 |
|
67 | type KeysBuilderWithoutReturnObjects<Res, Key = keyof $OmitArrayKeys<Res>> = Key extends keyof Res
|
68 | ? Res[Key] extends $Dictionary | readonly unknown[]
|
69 | ? JoinKeys<Key, KeysBuilderWithoutReturnObjects<Res[Key]>>
|
70 | : Key
|
71 | : never;
|
72 |
|
73 | type KeysBuilder<Res, WithReturnObjects> = $IsResourcesDefined extends true
|
74 | ? WithReturnObjects extends true
|
75 | ? keyof Res | KeysBuilderWithReturnObjects<Res>
|
76 | : KeysBuilderWithoutReturnObjects<Res>
|
77 | : string;
|
78 |
|
79 | type KeysWithReturnObjects = {
|
80 | [Ns in FlatNamespace]: WithOrWithoutPlural<KeysBuilder<Resources[Ns], true>>;
|
81 | };
|
82 | type KeysWithoutReturnObjects = {
|
83 | [Ns in FlatNamespace]: WithOrWithoutPlural<KeysBuilder<Resources[Ns], false>>;
|
84 | };
|
85 |
|
86 | type ResourceKeys<WithReturnObjects = _ReturnObjects> = WithReturnObjects extends true
|
87 | ? KeysWithReturnObjects
|
88 | : KeysWithoutReturnObjects;
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | export type KeysByTOptions<TOpt extends TOptions> = TOpt['returnObjects'] extends true
|
94 | ? ResourceKeys<true>
|
95 | : ResourceKeys;
|
96 |
|
97 | export type NsByTOptions<Ns extends Namespace, TOpt extends TOptions> = TOpt['ns'] extends Namespace
|
98 | ? TOpt['ns']
|
99 | : Ns;
|
100 |
|
101 | type ParseKeysByKeyPrefix<Keys, KPrefix> = KPrefix extends string
|
102 | ? Keys extends `${KPrefix}${_KeySeparator}${infer Key}`
|
103 | ? Key
|
104 | : never
|
105 | : Keys;
|
106 |
|
107 | type ParseKeysByNamespaces<Ns extends Namespace, Keys> = Ns extends readonly (infer UnionNsps)[]
|
108 | ? UnionNsps extends keyof Keys
|
109 | ? AppendNamespace<UnionNsps, Keys[UnionNsps]>
|
110 | : never
|
111 | : never;
|
112 |
|
113 | type ParseKeysByFallbackNs<Keys extends $Dictionary> = _FallbackNamespace extends false
|
114 | ? never
|
115 | : _FallbackNamespace extends (infer UnionFallbackNs extends string)[]
|
116 | ? Keys[UnionFallbackNs]
|
117 | : Keys[_FallbackNamespace & string];
|
118 |
|
119 | type FilterKeysByContext<Keys, TOpt extends TOptions> = TOpt['context'] extends string
|
120 | ? Keys extends `${infer Prefix}${_ContextSeparator}${TOpt['context']}${infer Suffix}`
|
121 | ? `${Prefix}${Suffix}`
|
122 | : never
|
123 | : Keys;
|
124 |
|
125 | export type ParseKeys<
|
126 | Ns extends Namespace = DefaultNamespace,
|
127 | TOpt extends TOptions = {},
|
128 | KPrefix = undefined,
|
129 | Keys extends $Dictionary = KeysByTOptions<TOpt>,
|
130 | ActualNS extends Namespace = NsByTOptions<Ns, TOpt>,
|
131 | > = $IsResourcesDefined extends true
|
132 | ? FilterKeysByContext<
|
133 | | ParseKeysByKeyPrefix<Keys[$FirstNamespace<ActualNS>], KPrefix>
|
134 | | ParseKeysByNamespaces<ActualNS, Keys>
|
135 | | ParseKeysByFallbackNs<Keys>,
|
136 | TOpt
|
137 | >
|
138 | : string;
|
139 |
|
140 |
|
141 |
|
142 |
|
143 | type ParseInterpolationValues<Ret> =
|
144 | Ret extends `${string}${_InterpolationPrefix}${infer Value}${_InterpolationSuffix}${infer Rest}`
|
145 | ?
|
146 | | (Value extends `${infer ActualValue},${string}` ? ActualValue : Value)
|
147 | | ParseInterpolationValues<Rest>
|
148 | : never;
|
149 |
|
150 | type InterpolationMap<Ret> = $PreservedValue<
|
151 | $StringKeyPathToRecord<ParseInterpolationValues<Ret>, unknown>,
|
152 | Record<string, unknown>
|
153 | >;
|
154 |
|
155 | type ParseTReturnPlural<
|
156 | Res,
|
157 | Key,
|
158 | KeyWithPlural = `${Key & string}${_PluralSeparator}${PluralSuffix}`,
|
159 | > = Res[(KeyWithPlural | Key) & keyof Res];
|
160 |
|
161 | type ParseTReturnPluralOrdinal<
|
162 | Res,
|
163 | Key,
|
164 | KeyWithOrdinalPlural = `${Key &
|
165 | string}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`,
|
166 | > = Res[(KeyWithOrdinalPlural | Key) & keyof Res];
|
167 |
|
168 | type ParseTReturnWithFallback<Key, Val> = Val extends ''
|
169 | ? _ReturnEmptyString extends true
|
170 | ? ''
|
171 | : Key
|
172 | : Val extends null
|
173 | ? _ReturnNull extends true
|
174 | ? null
|
175 | : Key
|
176 | : Val;
|
177 |
|
178 | type ParseTReturn<Key, Res, TOpt extends TOptions = {}> = ParseTReturnWithFallback<
|
179 | Key,
|
180 | Key extends `${infer K1}${_KeySeparator}${infer RestKey}`
|
181 | ? ParseTReturn<RestKey, Res[K1 & keyof Res], TOpt>
|
182 | :
|
183 | TOpt['count'] extends number
|
184 | ? TOpt['ordinal'] extends boolean
|
185 | ? ParseTReturnPluralOrdinal<Res, Key>
|
186 | : ParseTReturnPlural<Res, Key>
|
187 | :
|
188 | Res extends readonly unknown[]
|
189 | ? Key extends `${infer NKey extends number}`
|
190 | ? Res[NKey]
|
191 | : never
|
192 | : Res[Key & keyof Res]
|
193 | >;
|
194 |
|
195 | type TReturnOptionalNull = _ReturnNull extends true ? null : never;
|
196 | type TReturnOptionalObjects<TOpt extends TOptions> = _ReturnObjects extends true
|
197 | ? $SpecialObject | string
|
198 | : TOpt['returnObjects'] extends true
|
199 | ? $SpecialObject
|
200 | : string;
|
201 | type DefaultTReturn<TOpt extends TOptions> = TReturnOptionalObjects<TOpt> | TReturnOptionalNull;
|
202 |
|
203 | export type KeyWithContext<Key, TOpt extends TOptions> = TOpt['context'] extends string
|
204 | ? `${Key & string}${_ContextSeparator}${TOpt['context']}`
|
205 | : Key;
|
206 |
|
207 | export type TFunctionReturn<
|
208 | Ns extends Namespace,
|
209 | Key,
|
210 | TOpt extends TOptions,
|
211 | ActualNS extends Namespace = NsByTOptions<Ns, TOpt>,
|
212 | ActualKey = KeyWithContext<Key, TOpt>,
|
213 | > = $IsResourcesDefined extends true
|
214 | ? ActualKey extends `${infer Nsp}${_NsSeparator}${infer RestKey}`
|
215 | ? ParseTReturn<RestKey, Resources[Nsp & keyof Resources], TOpt>
|
216 | : ParseTReturn<ActualKey, Resources[$FirstNamespace<ActualNS>], TOpt>
|
217 | : DefaultTReturn<TOpt>;
|
218 |
|
219 | export type TFunctionDetailedResult<T = string, TOpt extends TOptions = {}> = {
|
220 | |
221 |
|
222 |
|
223 | usedKey: string;
|
224 | |
225 |
|
226 |
|
227 | res: T;
|
228 | |
229 |
|
230 |
|
231 | exactUsedKey: string;
|
232 | |
233 |
|
234 |
|
235 | usedLng: string;
|
236 | |
237 |
|
238 |
|
239 | usedNS: string;
|
240 | |
241 |
|
242 |
|
243 | usedParams: InterpolationMap<T> & { count?: TOpt['count'] };
|
244 | };
|
245 |
|
246 | type TFunctionReturnOptionalDetails<Ret, TOpt extends TOptions> = TOpt['returnDetails'] extends true
|
247 | ? TFunctionDetailedResult<Ret, TOpt>
|
248 | : Ret;
|
249 |
|
250 | type AppendKeyPrefix<Key, KPrefix> = KPrefix extends string
|
251 | ? `${KPrefix}${_KeySeparator}${Key & string}`
|
252 | : Key;
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | export interface TFunction<Ns extends Namespace = DefaultNamespace, KPrefix = undefined> {
|
258 | $TFunctionBrand: $IsResourcesDefined extends true ? `${$FirstNamespace<Ns>}` : never;
|
259 | <
|
260 | const Key extends ParseKeys<Ns, TOpt, KPrefix> | TemplateStringsArray,
|
261 | const TOpt extends TOptions,
|
262 | Ret extends TFunctionReturn<Ns, AppendKeyPrefix<Key, KPrefix>, TOpt>,
|
263 | const ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,
|
264 | >(
|
265 | ...args:
|
266 | | [key: Key | Key[], options?: ActualOptions]
|
267 | | [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]
|
268 | | [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]
|
269 | ): TFunctionReturnOptionalDetails<Ret, TOpt>;
|
270 | }
|
271 |
|
272 | export type KeyPrefix<Ns extends Namespace> = ResourceKeys<true>[$FirstNamespace<Ns>] | undefined;
|