i18next 26.5.0 → 26.5.1

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.
@@ -1 +1 @@
1
- {"type":"module","version":"26.5.0"}
1
+ {"type":"module","version":"26.5.1"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next",
3
- "version": "26.5.0",
3
+ "version": "26.5.1",
4
4
  "description": "i18next internationalization framework",
5
5
  "main": "./dist/cjs/i18next.js",
6
6
  "module": "./dist/esm/i18next.js",
package/typescript/t.d.ts CHANGED
@@ -74,6 +74,26 @@ interface Branded<Ns extends Namespace> {
74
74
  : never;
75
75
  }
76
76
 
77
+ /**
78
+ * `keyof Res`, built once per resource object. TypeScript does not cache
79
+ * `keyof` of an object type, so `keyof Res` inside a conditional that runs per
80
+ * key (or per `t()` call) rebuilt the union of all keys every time: quadratic
81
+ * in the namespace size. Conditional type instantiations are cached.
82
+ */
83
+ type _KeysOf<Res> = [Res] extends [unknown] ? keyof Res : never;
84
+
85
+ /**
86
+ * `Res[Key & keyof Res]`: a literal key is looked up directly instead of being
87
+ * intersected with every key; a wide key (`string`, `${string}_suffix` from a
88
+ * string context) still matches all keys it covers.
89
+ */
90
+ type _ValueOf<Res, Key> =
91
+ Key extends _KeysOf<Res>
92
+ ? Res[Key]
93
+ : _IsLiteral<Key & PropertyKey> extends true
94
+ ? never
95
+ : Res[Key & _KeysOf<Res>];
96
+
77
97
  /** ****************************************************
78
98
  * Build all keys and key prefixes based on Resources *
79
99
  ***************************************************** */
@@ -81,18 +101,20 @@ interface Branded<Ns extends Namespace> {
81
101
  // conditional types, so `KeyPrefix<Ns>` no longer resolves to a literal union
82
102
  // and `keyPrefix` inference widens to the whole namespace, polluting `t()`
83
103
  // return types with sibling keys (#2434 regression). Guard `never` in the merge.
84
- type KeysBuilderWithReturnObjects<Res, Key = keyof Res> = Key extends keyof Res
85
- ? Res[Key] extends $Dictionary | readonly unknown[]
86
- ? | JoinKeys<Key, WithOrWithoutPlural<keyof $OmitArrayKeys<Res[Key]>>>
87
- | JoinKeys<Key, KeysBuilderWithReturnObjects<Res[Key]>>
88
- : never
89
- : never;
104
+ type KeysBuilderWithReturnObjects<Res, Key = keyof Res> =
105
+ Key extends _KeysOf<Res>
106
+ ? Res[Key] extends $Dictionary | readonly unknown[]
107
+ ? | JoinKeys<Key, WithOrWithoutPlural<keyof $OmitArrayKeys<Res[Key]>>>
108
+ | JoinKeys<Key, KeysBuilderWithReturnObjects<Res[Key]>>
109
+ : never
110
+ : never;
90
111
 
91
- type KeysBuilderWithoutReturnObjects<Res, Key = keyof $OmitArrayKeys<Res>> = Key extends keyof Res
92
- ? Res[Key] extends $Dictionary | readonly unknown[]
93
- ? JoinKeys<Key, KeysBuilderWithoutReturnObjects<Res[Key]>>
94
- : Key
95
- : never;
112
+ type KeysBuilderWithoutReturnObjects<Res, Key = keyof $OmitArrayKeys<Res>> =
113
+ Key extends _KeysOf<Res>
114
+ ? Res[Key] extends $Dictionary | readonly unknown[]
115
+ ? JoinKeys<Key, KeysBuilderWithoutReturnObjects<Res[Key]>>
116
+ : Key
117
+ : never;
96
118
 
97
119
  type KeysBuilder<Res, WithReturnObjects> = $IsResourcesDefined extends true
98
120
  ? WithReturnObjects extends true
@@ -424,14 +446,14 @@ type ParseTReturnPlural<
424
446
  Res,
425
447
  Key,
426
448
  KeyWithPlural = `${Key & string}${_PluralSeparator}${PluralSuffix}`,
427
- > = Res[(KeyWithPlural | Key) & keyof Res];
449
+ > = _ValueOf<Res, KeyWithPlural | Key>;
428
450
 
429
451
  type ParseTReturnPluralOrdinal<
430
452
  Res,
431
453
  Key,
432
454
  KeyWithOrdinalPlural = `${Key &
433
455
  string}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`,
434
- > = Res[(KeyWithOrdinalPlural | Key) & keyof Res];
456
+ > = _ValueOf<Res, KeyWithOrdinalPlural | Key>;
435
457
 
436
458
  type ParseTReturnWithFallback<Key, Val> = Val extends ''
437
459
  ? _ReturnEmptyString extends true
@@ -446,7 +468,7 @@ type ParseTReturnWithFallback<Key, Val> = Val extends ''
446
468
  type ParseTReturn<Key, Res, TOpt extends TOptions = {}> = ParseTReturnWithFallback<
447
469
  Key,
448
470
  Key extends `${infer K1}${_KeySeparator}${infer RestKey}`
449
- ? ParseTReturn<RestKey, Res[K1 & keyof Res], TOpt>
471
+ ? ParseTReturn<RestKey, _ValueOf<Res, K1>, TOpt>
450
472
  : // Process plurals only if count is provided inside options
451
473
  TOpt['count'] extends number
452
474
  ? TOpt['ordinal'] extends boolean
@@ -457,7 +479,7 @@ type ParseTReturn<Key, Res, TOpt extends TOptions = {}> = ParseTReturnWithFallba
457
479
  ? Key extends `${infer NKey extends number}`
458
480
  ? Res[NKey]
459
481
  : never
460
- : Res[Key & keyof Res]
482
+ : _ValueOf<Res, Key>
461
483
  >;
462
484
 
463
485
  type TReturnOptionalNull = _ReturnNull extends true ? null : never;
@@ -973,26 +995,97 @@ type _DefinedContextKeys<T, Pattern extends string> = {
973
995
  [P in keyof T as P extends Pattern ? ([T[P]] extends [undefined] ? never : P) : never]: true;
974
996
  };
975
997
 
976
- type _HasContextVariant<T, K extends string, Context> = [
977
- keyof _DefinedContextKeys<
978
- T,
979
- | `${K}${_ContextSeparator}${Context & string}`
980
- | `${K}${_ContextSeparator}${Context & string}${_PluralSeparator}${PluralSuffix}`
981
- >,
998
+ /**
999
+ * Keys of T whose value is not `undefined` (JSON-union phantoms are typed as
1000
+ * optional `undefined`), built once per object.
1001
+ */
1002
+ type _DefinedKeys<T> = [T] extends [unknown]
1003
+ ? keyof { [P in keyof T as [T[P]] extends [undefined] ? never : P]: true }
1004
+ : never;
1005
+
1006
+ /**
1007
+ * For every defined key, the prefixes K before each context separator, as
1008
+ * `[all, bases]`: `all` has every K with a defined key `${K}${_ContextSeparator}...`,
1009
+ * `bases` only those where the rest is not just a plural suffix. Jumps from one
1010
+ * separator occurrence to the next (so the recursion depth is the number of
1011
+ * separators, not the key length, which can be a whole sentence) and resumes one
1012
+ * character after the match, so overlapping occurrences (`a___b` with `__`) count.
1013
+ */
1014
+ type _ContextPrefixesOf<
1015
+ P,
1016
+ Head extends string = '',
1017
+ All = never,
1018
+ Bases = never,
1019
+ > = P extends `${infer B}${_ContextSeparator}${string}`
1020
+ ? P extends `${B}${infer FromSep}`
1021
+ ? FromSep extends `${infer C}${infer Rest}`
1022
+ ? _ContextPrefixesOf<
1023
+ Rest,
1024
+ `${Head}${B}${C}`,
1025
+ All | `${Head}${B}`,
1026
+ FromSep extends
1027
+ | `${_PluralSeparator}${PluralSuffix}`
1028
+ | `${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`
1029
+ ? Bases
1030
+ : Bases | `${Head}${B}`
1031
+ >
1032
+ : [All, Bases]
1033
+ : [All, Bases]
1034
+ : [All, Bases];
1035
+
1036
+ /**
1037
+ * The context prefixes of an object, built once per object (conditional type
1038
+ * instantiations are cached): scanning all keys for every key was quadratic
1039
+ * in the object size, TS2589 at about 1,000 keys with context variants.
1040
+ */
1041
+ type _ContextPrefixes<T> = [T] extends [unknown]
1042
+ ? _ContextPrefixesOf<_DefinedKeys<T> & string>
1043
+ : never;
1044
+ type _AllContextPrefixes<T> = [T] extends [unknown] ? _ContextPrefixes<T>[0] : never;
1045
+ type _ContextBases<T> = [T] extends [unknown] ? _ContextPrefixes<T>[1] : never;
1046
+
1047
+ /** Whether a string type is a single literal (not `string` or a `${string}` pattern). */
1048
+ type _IsLiteral<S extends PropertyKey> = {} extends Record<S, unknown> ? false : true;
1049
+
1050
+ /**
1051
+ * Whether T has a defined key matching Pattern: literal keys are looked up, a
1052
+ * pattern with a wide member scans the keys.
1053
+ */
1054
+ type _HasDefinedKey<T, Pattern extends string> = [
1055
+ false extends (Pattern extends unknown ? _IsLiteral<Pattern> : never)
1056
+ ? keyof _DefinedContextKeys<T, Pattern>
1057
+ : Extract<Pattern, _DefinedKeys<T>>,
982
1058
  ] extends [never]
983
1059
  ? false
984
1060
  : true;
985
1061
 
1062
+ type _HasContextVariant<T, K extends string, Context> = string extends Context
1063
+ ? _IsLiteral<K> extends true
1064
+ ? K extends _AllContextPrefixes<T>
1065
+ ? true
1066
+ : false
1067
+ : _HasDefinedKey<T, `${K}${_ContextSeparator}${string}`>
1068
+ : _HasDefinedKey<
1069
+ T,
1070
+ | `${K}${_ContextSeparator}${Context & string}`
1071
+ | `${K}${_ContextSeparator}${Context & string}${_PluralSeparator}${PluralSuffix}`
1072
+ >;
1073
+
986
1074
  /** Checks whether key K has **any** context variant in T (excluding pure plural suffixes). */
987
- type _IsContextualKey<T, K extends string> = [
988
- Exclude<
989
- keyof _DefinedContextKeys<T, `${K}${_ContextSeparator}${string}`>,
990
- | `${K}${_PluralSeparator}${PluralSuffix}`
991
- | `${K}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`
992
- >,
993
- ] extends [never]
994
- ? false
995
- : true;
1075
+ type _IsContextualKey<T, K extends string> =
1076
+ _IsLiteral<K> extends true
1077
+ ? K extends _ContextBases<T>
1078
+ ? true
1079
+ : false
1080
+ : [
1081
+ Exclude<
1082
+ keyof _DefinedContextKeys<T, `${K}${_ContextSeparator}${string}`>,
1083
+ | `${K}${_PluralSeparator}${PluralSuffix}`
1084
+ | `${K}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`
1085
+ >,
1086
+ ] extends [never]
1087
+ ? false
1088
+ : true;
996
1089
 
997
1090
  /**
998
1091
  * Distributes {@link FilterKeysObject} over unions so heterogeneous JSON array