i18next 26.4.7 → 26.5.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/esm/package.json +1 -1
- package/package.json +1 -1
- package/typescript/options.d.ts +18 -2
- package/typescript/t.d.ts +234 -12
package/dist/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"26.
|
|
1
|
+
{"type":"module","version":"26.5.0"}
|
package/package.json
CHANGED
package/typescript/options.d.ts
CHANGED
|
@@ -189,8 +189,24 @@ export type TypeOptions = $MergeBy<
|
|
|
189
189
|
* `}}`. This flag is type-only; runtime interpolation is governed by
|
|
190
190
|
* `InterpolationOptions` and is unaffected.
|
|
191
191
|
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
192
|
+
* Set to `'icu'` with `i18next-icu` to type `t()` options from the ICU
|
|
193
|
+
* MessageFormat arguments instead: `{name}` takes `string | number`,
|
|
194
|
+
* `{n, number}`, `plural` and `selectordinal` take `number`, `{d, date}`
|
|
195
|
+
* and `{t, time}` take `Date`, `select` takes its case keys or any string
|
|
196
|
+
* (for `other`), and arguments nested in cases are required too.
|
|
197
|
+
* `interpolationFormatTypeMap` overrides a type by its format name (e.g.
|
|
198
|
+
* `date: Date | number`). Options become required for a message with
|
|
199
|
+
* arguments.
|
|
200
|
+
*
|
|
201
|
+
* Set to `'mf2'` with `i18next-mf2` to type `t()` options from the
|
|
202
|
+
* MessageFormat 2 variables: `{$name}` takes `string | number`, a
|
|
203
|
+
* variable annotated with `:number`, `:integer`, `:currency`, `:percent`
|
|
204
|
+
* or `:unit` (directly or through `.input`/`.local`) takes `number`,
|
|
205
|
+
* `:datetime`, `:date` and `:time` take `Date`, `:string` takes `string`,
|
|
206
|
+
* option and markup variables (`minimumFractionDigits=$digits`,
|
|
207
|
+
* `{#link href=$url}`) take `string | number`, and `.local` variables are
|
|
208
|
+
* not arguments. `interpolationFormatTypeMap` overrides a type by its
|
|
209
|
+
* function name.
|
|
194
210
|
*
|
|
195
211
|
* @default true
|
|
196
212
|
*/
|
package/typescript/t.d.ts
CHANGED
|
@@ -172,7 +172,7 @@ type ParseActualValue<Ret> = Ret extends `${_UnescapePrefix}${infer ActualValue}
|
|
|
172
172
|
: Ret;
|
|
173
173
|
|
|
174
174
|
/** Parses interpolation entries as `[variableName, formatSpecifier | never]` tuples. */
|
|
175
|
-
type ParseInterpolationEntries<Ret> = [_ParseInterpolation] extends [false]
|
|
175
|
+
type ParseInterpolationEntries<Ret> = [_ParseInterpolation] extends [false | 'icu' | 'mf2']
|
|
176
176
|
? never
|
|
177
177
|
: Ret extends `${string}${_InterpolationPrefix}${infer Value}${_InterpolationSuffix}${infer Rest}`
|
|
178
178
|
? | (Value extends `${infer ActualValue},${infer Format}`
|
|
@@ -225,10 +225,200 @@ type _InterpolationMapFromEntries<E> = _UnionToIntersection<
|
|
|
225
225
|
: never
|
|
226
226
|
>;
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
/** *********************************************************************
|
|
229
|
+
* ICU MessageFormat arguments (`parseInterpolation: 'icu'`) *
|
|
230
|
+
*********************************************************************** */
|
|
231
|
+
type _IcuWhitespace = ' ' | '\n' | '\t' | '\r';
|
|
232
|
+
type _IcuTrim<S> = S extends `${_IcuWhitespace}${infer R}`
|
|
233
|
+
? _IcuTrim<R>
|
|
234
|
+
: S extends `${infer R}${_IcuWhitespace}`
|
|
235
|
+
? _IcuTrim<R>
|
|
236
|
+
: S;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Drops ICU apostrophe quoting as intl-messageformat (i18next-icu) reads it:
|
|
240
|
+
* `''` is a literal apostrophe, `'{...}'` (also `'}'`, `'<'`, `'>'`, `'#'`) is
|
|
241
|
+
* literal text up to the next single apostrophe.
|
|
242
|
+
* Simplification: `'#` quotes everywhere here, at runtime only inside plurals.
|
|
243
|
+
*/
|
|
244
|
+
type _IcuStripQuotes<S, Acc extends string = ''> = S extends `${infer L}'${infer R}`
|
|
245
|
+
? R extends `'${infer R2}`
|
|
246
|
+
? _IcuStripQuotes<R2, `${Acc}${L}`>
|
|
247
|
+
: R extends `${'{' | '}' | '<' | '>' | '#'}${string}`
|
|
248
|
+
? _IcuStripQuotes<_IcuSkipQuoted<R>, `${Acc}${L}`>
|
|
249
|
+
: _IcuStripQuotes<R, `${Acc}${L}'`>
|
|
250
|
+
: `${Acc}${S & string}`;
|
|
251
|
+
type _IcuSkipQuoted<S> = S extends `${string}'${infer R}`
|
|
252
|
+
? R extends `'${infer R2}`
|
|
253
|
+
? _IcuSkipQuoted<R2>
|
|
254
|
+
: R
|
|
255
|
+
: '';
|
|
256
|
+
|
|
257
|
+
/** Reads up to the `}` closing an already opened `{`; returns `[content, rest]`. */
|
|
258
|
+
type _IcuBlock<
|
|
259
|
+
S,
|
|
260
|
+
Acc extends string = '',
|
|
261
|
+
Depth extends 0[] = [],
|
|
262
|
+
> = S extends `${infer L}}${infer R}`
|
|
263
|
+
? L extends `${infer L2}{${infer R2}`
|
|
264
|
+
? _IcuBlock<`${R2}}${R}`, `${Acc}${L2}{`, [...Depth, 0]>
|
|
265
|
+
: Depth extends [0, ...infer D extends 0[]]
|
|
266
|
+
? _IcuBlock<R, `${Acc}${L}}`, D>
|
|
267
|
+
: [`${Acc}${L}`, R]
|
|
268
|
+
: never;
|
|
269
|
+
|
|
270
|
+
/** `[name, type]` entries of every argument in a message, nested cases included. */
|
|
271
|
+
type _IcuEntries<S, Acc = never> = S extends `${string}{${infer R}`
|
|
272
|
+
? _IcuBlock<R> extends [infer Arg, infer Rest]
|
|
273
|
+
? _IcuEntries<Rest, Acc | _IcuArg<Arg>>
|
|
274
|
+
: Acc
|
|
275
|
+
: Acc;
|
|
276
|
+
|
|
277
|
+
/** Walks plural/select cases: `[selector keys, entries of all case messages]`. */
|
|
278
|
+
type _IcuCases<S, Keys = never, Acc = never> = S extends `${infer L}{${infer R}`
|
|
279
|
+
? _IcuBlock<R> extends [infer Msg, infer Rest]
|
|
280
|
+
? _IcuCases<Rest, Keys | _IcuTrim<L>, Acc | _IcuEntries<Msg>>
|
|
281
|
+
: [Keys, Acc]
|
|
282
|
+
: [Keys, Acc];
|
|
283
|
+
|
|
284
|
+
type _IcuArg<A> = A extends `${infer Name},${infer Type},${infer Cases}`
|
|
285
|
+
? _IcuTrim<Type> extends 'plural' | 'selectordinal'
|
|
286
|
+
? [_IcuTrim<Name>, _IcuFormatType<_IcuTrim<Type>>] | _IcuCases<Cases>[1]
|
|
287
|
+
: _IcuTrim<Type> extends 'select'
|
|
288
|
+
? _IcuCases<Cases> extends [infer Keys, infer E]
|
|
289
|
+
? [_IcuTrim<Name>, 'other' extends Keys ? Exclude<Keys, 'other'> | (string & {}) : Keys] | E
|
|
290
|
+
: never
|
|
291
|
+
: [_IcuTrim<Name>, _IcuFormatType<_IcuTrim<Type>>] // `{n, number, ::currency/EUR}`
|
|
292
|
+
: A extends `${infer Name},${infer Type}`
|
|
293
|
+
? [_IcuTrim<Name>, _IcuFormatType<_IcuTrim<Type>>]
|
|
294
|
+
: [_IcuTrim<A>, _IcuFormatType<never>];
|
|
295
|
+
|
|
296
|
+
/** `interpolationFormatTypeMap` wins, then ICU's built-in argument types. */
|
|
297
|
+
type _IcuFormatType<F> = [F] extends [never]
|
|
298
|
+
? string | number
|
|
299
|
+
: F extends keyof _InterpolationFormatTypeMap
|
|
300
|
+
? _InterpolationFormatTypeMap[F]
|
|
301
|
+
: F extends 'number' | 'plural' | 'selectordinal'
|
|
302
|
+
? number
|
|
303
|
+
: F extends 'date' | 'time'
|
|
304
|
+
? Date
|
|
305
|
+
: string | number;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Merges `[name, type]` entries into one record: a name used twice gets both
|
|
309
|
+
* types, a dotted MF2 name (`$user.name`) becomes a nested object.
|
|
310
|
+
*/
|
|
311
|
+
type _ArgsFromEntries<E> =
|
|
312
|
+
_UnionToIntersection<
|
|
313
|
+
E extends [infer Name extends string, infer Type]
|
|
314
|
+
? Name extends `${string}.${string}`
|
|
315
|
+
? $StringKeyPathToRecord<Name, Type>
|
|
316
|
+
: { [K in Name]: Type }
|
|
317
|
+
: never
|
|
318
|
+
> extends infer M
|
|
319
|
+
? [E] extends [never]
|
|
320
|
+
? never
|
|
321
|
+
: { [K in keyof M]: M[K] }
|
|
322
|
+
: never;
|
|
323
|
+
|
|
324
|
+
type _IcuArgsMap<Ret> = Ret extends string
|
|
325
|
+
? string extends Ret
|
|
326
|
+
? never
|
|
327
|
+
: _ArgsFromEntries<_IcuEntries<_IcuStripQuotes<Ret>>>
|
|
328
|
+
: never;
|
|
329
|
+
|
|
330
|
+
/** *********************************************************************
|
|
331
|
+
* MessageFormat 2 variables (`parseInterpolation: 'mf2'`) *
|
|
332
|
+
*********************************************************************** */
|
|
333
|
+
/** Drops `\`-escapes (`\{`, `\}`, `\|`, `\\`), so they are neither braces nor quotes. */
|
|
334
|
+
type _Mf2StripEscapes<S, Acc extends string = ''> = S extends `${infer L}\\${string}${infer R}`
|
|
335
|
+
? _Mf2StripEscapes<R, `${Acc}${L}`>
|
|
336
|
+
: `${Acc}${S & string}`;
|
|
337
|
+
|
|
338
|
+
/** Reads an expression up to its `}`, skipping `|quoted literals|`; returns `[body, rest]`. */
|
|
339
|
+
type _Mf2Expression<S, Acc extends string = ''> = S extends `${infer B}}${infer Rest}`
|
|
340
|
+
? B extends `${infer Before}|${infer Lit}`
|
|
341
|
+
? `${Lit}}${Rest}` extends `${string}|${infer After}`
|
|
342
|
+
? _Mf2Expression<After, `${Acc}${Before} `>
|
|
343
|
+
: never
|
|
344
|
+
: [`${Acc}${B}`, Rest]
|
|
345
|
+
: never;
|
|
346
|
+
|
|
347
|
+
/** `[name, type]` entries of every variable in a message's expressions; `{{` opens a quoted pattern. */
|
|
348
|
+
type _Mf2Entries<S, Acc = never> = S extends `${string}{${infer R}`
|
|
349
|
+
? R extends `{${infer Pattern}`
|
|
350
|
+
? _Mf2Entries<Pattern, Acc>
|
|
351
|
+
: _Mf2Expression<R> extends [infer Body, infer Rest]
|
|
352
|
+
? _Mf2Entries<Rest, Acc | _Mf2ExprEntries<_Mf2Spaces<Body>>>
|
|
353
|
+
: Acc
|
|
354
|
+
: Acc;
|
|
355
|
+
|
|
356
|
+
type _Mf2Space<S, C extends string> = S extends `${infer L}${C}${infer R}`
|
|
357
|
+
? _Mf2Space<`${L} ${R}`, C>
|
|
358
|
+
: S;
|
|
359
|
+
type _Mf2Spaces<S> = _IcuTrim<_Mf2Space<_Mf2Space<_Mf2Space<S, '\n'>, '\t'>, '\r'>>;
|
|
360
|
+
type _Mf2Name<S> = S extends `${infer N} ${string}`
|
|
361
|
+
? _Mf2Name<N>
|
|
362
|
+
: S extends `${infer N}/${string}`
|
|
363
|
+
? N
|
|
364
|
+
: S;
|
|
365
|
+
|
|
366
|
+
/** `{$x :fn opt=$y}`: `$x` typed by its function, option and markup variables `string | number`. */
|
|
367
|
+
type _Mf2ExprEntries<Body> = Body extends `$${infer R}`
|
|
368
|
+
? R extends `${infer Name} ${infer Tail}`
|
|
369
|
+
? | [Name, _Mf2FunctionType<_IcuTrim<Tail> extends `:${infer F}` ? _Mf2Name<F> : never>]
|
|
370
|
+
| _Mf2Vars<Tail>
|
|
371
|
+
: [_Mf2Name<R>, _Mf2FunctionType<never>]
|
|
372
|
+
: _Mf2Vars<Body>;
|
|
373
|
+
|
|
374
|
+
/** Every `$name` in a string, typed `string | number`. */
|
|
375
|
+
type _Mf2Vars<S, Acc = never> = S extends `${string}$${infer R}`
|
|
376
|
+
? _Mf2Vars<R, Acc | [_Mf2Name<R>, string | number]>
|
|
377
|
+
: Acc;
|
|
378
|
+
|
|
379
|
+
/** `interpolationFormatTypeMap` wins, then messageformat's built-in functions. */
|
|
380
|
+
type _Mf2FunctionType<F> = [F] extends [never]
|
|
381
|
+
? string | number
|
|
382
|
+
: F extends keyof _InterpolationFormatTypeMap
|
|
383
|
+
? _InterpolationFormatTypeMap[F]
|
|
384
|
+
: F extends 'number' | 'integer' | 'currency' | 'percent' | 'offset' | 'unit' | 'math'
|
|
385
|
+
? number
|
|
386
|
+
: F extends 'datetime' | 'date' | 'time'
|
|
387
|
+
? Date
|
|
388
|
+
: F extends 'string'
|
|
389
|
+
? string
|
|
390
|
+
: string | number;
|
|
391
|
+
|
|
392
|
+
/** Names declared by `.local $name = ...` (local, not passed in). */
|
|
393
|
+
type _Mf2Locals<S, Acc = never> = S extends `${string}.local${infer R}`
|
|
394
|
+
? _Mf2Locals<R, Acc | (_IcuTrim<R> extends `$${infer N}=${string}` ? _IcuTrim<N> : never)>
|
|
395
|
+
: Acc;
|
|
396
|
+
/** `.match $a $b`: selectors, normally also declared by `.input` or `.local`. */
|
|
397
|
+
type _Mf2Selectors<S> = S extends `${string}.match${infer R}`
|
|
398
|
+
? _Mf2Vars<_Mf2Spaces<R extends `${infer Sel}{${string}` ? Sel : R>>
|
|
399
|
+
: never;
|
|
400
|
+
|
|
401
|
+
type _Mf2ArgsMap<Ret> = Ret extends string
|
|
402
|
+
? string extends Ret
|
|
403
|
+
? never
|
|
404
|
+
: _Mf2StripEscapes<Ret> extends infer S
|
|
405
|
+
? _ArgsFromEntries<
|
|
406
|
+
Exclude<
|
|
407
|
+
_Mf2Entries<S> | _Mf2Selectors<S>,
|
|
408
|
+
[_IcuTrim<S> extends `.${string}` ? _Mf2Locals<S> : never, unknown]
|
|
409
|
+
>
|
|
410
|
+
>
|
|
411
|
+
: never
|
|
412
|
+
: never;
|
|
413
|
+
|
|
414
|
+
export type InterpolationMap<Ret> = [_ParseInterpolation] extends ['icu']
|
|
415
|
+
? $PreservedValue<_IcuArgsMap<Ret>, Record<string, unknown>>
|
|
416
|
+
: [_ParseInterpolation] extends ['mf2']
|
|
417
|
+
? $PreservedValue<_Mf2ArgsMap<Ret>, Record<string, unknown>>
|
|
418
|
+
: $PreservedValue<
|
|
419
|
+
_InterpolationMapFromEntries<ParseInterpolationEntries<Ret>>,
|
|
420
|
+
Record<string, unknown>
|
|
421
|
+
>;
|
|
232
422
|
|
|
233
423
|
type ParseTReturnPlural<
|
|
234
424
|
Res,
|
|
@@ -393,6 +583,28 @@ type EffectiveKPrefix<KPrefix, TOpt> = TOpt extends { keyPrefix: infer OptKP ext
|
|
|
393
583
|
? OptKP
|
|
394
584
|
: KPrefix;
|
|
395
585
|
|
|
586
|
+
/** `parseInterpolation: 'icu'` or `'mf2'`: messages are typed by their arguments. */
|
|
587
|
+
type _ParsesMessageFormat = [_ParseInterpolation] extends ['icu'] | ['mf2'] ? true : false;
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* `t()` options are optional, except for a message with arguments under
|
|
591
|
+
* `parseInterpolation: 'icu'` or `'mf2'` (on a missing one, i18next-icu renders
|
|
592
|
+
* the raw message and i18next-mf2 a `{$name}` fallback). The conditional
|
|
593
|
+
* resolves eagerly; a generic one here would break inference.
|
|
594
|
+
*/
|
|
595
|
+
type _KeyAndOptions<Key, Ret, Opts> = _ParsesMessageFormat extends true
|
|
596
|
+
? [key: Key | Key[], options: Opts] | [key: (Key | Key[]) & _IfOptionalOptions<Ret>]
|
|
597
|
+
: [key: Key | Key[], options?: Opts];
|
|
598
|
+
/** `unknown` when options may be left out, else a type naming the missing arguments. */
|
|
599
|
+
type _IfOptionalOptions<Ret> = _ParsesMessageFormat extends true
|
|
600
|
+
? {} extends InterpolationMap<Ret>
|
|
601
|
+
? unknown
|
|
602
|
+
: { 'pass these arguments as t() options': InterpolationMap<Ret> }
|
|
603
|
+
: unknown;
|
|
604
|
+
/** Options parameter of a selector overload: required for a message with arguments. */
|
|
605
|
+
type _SelectorOptionsArg<Ret, Opts> =
|
|
606
|
+
unknown extends _IfOptionalOptions<Ret> ? [options?: Opts] : [options: Opts];
|
|
607
|
+
|
|
396
608
|
/** ************************
|
|
397
609
|
* T function declaration *
|
|
398
610
|
************************* */
|
|
@@ -407,7 +619,7 @@ interface TFunctionStrict<
|
|
|
407
619
|
Ret extends TFunctionReturn<Ns, AppendKeyPrefix<Key, EffectiveKPrefix<KPrefix, TOpt>>, TOpt>,
|
|
408
620
|
>(
|
|
409
621
|
key: Key | Key[],
|
|
410
|
-
options
|
|
622
|
+
options: TOpt &
|
|
411
623
|
InterpolationMap<Ret> & {
|
|
412
624
|
context?: Key extends string
|
|
413
625
|
? unknown extends TOpt['context']
|
|
@@ -416,6 +628,13 @@ interface TFunctionStrict<
|
|
|
416
628
|
: never;
|
|
417
629
|
},
|
|
418
630
|
): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, never>, TOpt>;
|
|
631
|
+
<
|
|
632
|
+
const Key extends ParseKeys<Ns, TOpt, EffectiveKPrefix<KPrefix, TOpt>> | TemplateStringsArray,
|
|
633
|
+
const TOpt extends TOptions,
|
|
634
|
+
Ret extends TFunctionReturn<Ns, AppendKeyPrefix<Key, EffectiveKPrefix<KPrefix, TOpt>>, TOpt>,
|
|
635
|
+
>(
|
|
636
|
+
key: (Key | Key[]) & _IfOptionalOptions<$NoInfer<Ret>>,
|
|
637
|
+
): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, never>, TOpt>;
|
|
419
638
|
<
|
|
420
639
|
const Key extends ParseKeys<Ns, TOpt, EffectiveKPrefix<KPrefix, TOpt>> | TemplateStringsArray,
|
|
421
640
|
const TOpt extends TOptions,
|
|
@@ -460,9 +679,9 @@ interface TFunctionNonStrict<
|
|
|
460
679
|
DefaultValue extends string = never,
|
|
461
680
|
>(
|
|
462
681
|
...args:
|
|
463
|
-
| [key: Key | Key[], options?: ActualOptions]
|
|
464
682
|
| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: DefaultValue }]
|
|
465
683
|
| [key: string | string[], defaultValue: DefaultValue, options?: TOpt & $Dictionary]
|
|
684
|
+
| _KeyAndOptions<Key, $NoInfer<Ret>, ActualOptions>
|
|
466
685
|
): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, DefaultValue>, TOpt>;
|
|
467
686
|
}
|
|
468
687
|
|
|
@@ -596,10 +815,13 @@ interface TFunctionSelector<Ns extends Namespace, KPrefix, Source> extends Brand
|
|
|
596
815
|
const Opts extends SelectorOptions<Ns[number]> = SelectorOptions<Ns[number]>,
|
|
597
816
|
>(
|
|
598
817
|
selectors: Fns,
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
818
|
+
...args: _SelectorOptionsArg<
|
|
819
|
+
DeepUnwrapPlural<Fns[number] extends (...args: any[]) => infer R ? R : never>,
|
|
820
|
+
Opts &
|
|
821
|
+
InterpolationMap<
|
|
822
|
+
DeepUnwrapPlural<Fns[number] extends (...args: any[]) => infer R ? R : never>
|
|
823
|
+
>
|
|
824
|
+
>
|
|
603
825
|
): SelectorReturn<Fns[number] extends (...args: any[]) => infer R ? R : never, Opts>;
|
|
604
826
|
|
|
605
827
|
// ── Single selector with context + returnObjects ────────────────────────────
|
|
@@ -667,7 +889,7 @@ interface TFunctionSelector<Ns extends Namespace, KPrefix, Source> extends Brand
|
|
|
667
889
|
selector: Fn,
|
|
668
890
|
...args: ReturnType<Fn> extends PluralValue<string>
|
|
669
891
|
? [options: Opts & { count: number } & InterpolationMap<DeepUnwrapPlural<ReturnType<Fn>>>]
|
|
670
|
-
:
|
|
892
|
+
: _SelectorOptionsArg<ReturnType<Fn>, Opts & InterpolationMap<ReturnType<Fn>>>
|
|
671
893
|
): SelectorReturn<ReturnType<Fn>, Opts>;
|
|
672
894
|
}
|
|
673
895
|
|