i18next 21.9.2 → 22.0.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/index.d.ts CHANGED
@@ -1,21 +1,126 @@
1
- type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
1
+ // Helpers
2
2
  type MergeBy<T, K> = Omit<T, keyof K> & K;
3
+ type StringMap = { [key: string]: any };
4
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
5
+ ? I
6
+ : never;
7
+ type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R
8
+ ? R
9
+ : never;
3
10
 
4
- export interface FallbackLngObjList {
5
- [language: string]: readonly string[];
6
- }
11
+ /**
12
+ * This interface can be augmented by users to add types to `i18next` default TypeOptions.
13
+ */
14
+ export interface CustomTypeOptions {}
7
15
 
8
- export type FallbackLng =
9
- | string
10
- | readonly string[]
11
- | FallbackLngObjList
12
- | ((code: string) => string | readonly string[] | FallbackLngObjList);
16
+ /**
17
+ * This interface can be augmented by users to add types to `i18next` default PluginOptions.
18
+ *
19
+ * Usage:
20
+ * ```ts
21
+ * // react-i18next.d.ts
22
+ * import 'react-i18next';
23
+ * declare module 'react-i18next' {
24
+ * interface CustomTypeOptions {
25
+ * defaultNS: 'custom';
26
+ * returnNull: false;
27
+ * returnEmptyString: false;
28
+ * nsSeparator: ':';
29
+ * keySeparator: '.';
30
+ * jsonFormat: 'v4';
31
+ * allowObjectInHTMLChildren: false;
32
+ * resources: {
33
+ * custom: {
34
+ * foo: 'foo';
35
+ * };
36
+ * };
37
+ * }
38
+ * }
39
+ * ```
40
+ */
41
+ export interface CustomPluginOptions {}
42
+
43
+ export type TypeOptions = MergeBy<
44
+ {
45
+ /**
46
+ * Allows null values as valid translation
47
+ */
48
+ returnNull: true;
49
+
50
+ /**
51
+ * Allows empty string as valid translation
52
+ */
53
+ returnEmptyString: true;
54
+
55
+ /**
56
+ * Char to separate keys
57
+ */
58
+ keySeparator: '.';
59
+
60
+ /**
61
+ * Char to split namespace from key
62
+ */
63
+ nsSeparator: ':';
64
+
65
+ /**
66
+ * Default namespace used if not passed to translation function
67
+ */
68
+ defaultNS: 'translation';
69
+
70
+ /**
71
+ * Json Format Version - V4 allows plural suffixes
72
+ */
73
+ jsonFormat: 'v4';
13
74
 
14
- export type FormatFunction = (
75
+ /**
76
+ * Resources to initialize with
77
+ */
78
+ resources: object;
79
+
80
+ /**
81
+ * Flag that allows HTML elements to receive objects. This is only useful for React applications
82
+ * where you pass objects to HTML elements so they can be replaced to their respective interpolation
83
+ * values (mostly with Trans component)
84
+ */
85
+ allowObjectInHTMLChildren: false;
86
+ },
87
+ CustomTypeOptions
88
+ >;
89
+
90
+ export type PluginOptions = MergeBy<
91
+ {
92
+ /**
93
+ * Options for language detection - check documentation of plugin
94
+ * @default undefined
95
+ */
96
+ detection?: object;
97
+
98
+ /**
99
+ * Options for backend - check documentation of plugin
100
+ * @default undefined
101
+ */
102
+ backend?: object;
103
+
104
+ /**
105
+ * Options for cache layer - check documentation of plugin
106
+ * @default undefined
107
+ */
108
+ cache?: object;
109
+
110
+ /**
111
+ * Options for i18n message format - check documentation of plugin
112
+ * @default undefined
113
+ */
114
+ i18nFormat?: object;
115
+ },
116
+ CustomPluginOptions
117
+ >;
118
+
119
+ type FormatFunction = (
15
120
  value: any,
16
121
  format?: string,
17
122
  lng?: string,
18
- options?: InterpolationOptions & { [key: string]: any },
123
+ options?: InterpolationOptions & StringMap,
19
124
  ) => string;
20
125
 
21
126
  export interface InterpolationOptions {
@@ -124,6 +229,16 @@ export interface InterpolationOptions {
124
229
  skipOnVariables?: boolean;
125
230
  }
126
231
 
232
+ export interface FallbackLngObjList {
233
+ [language: string]: readonly string[];
234
+ }
235
+
236
+ export type FallbackLng =
237
+ | string
238
+ | readonly string[]
239
+ | FallbackLngObjList
240
+ | ((code: string) => string | readonly string[] | FallbackLngObjList);
241
+
127
242
  export interface ReactOptions {
128
243
  /**
129
244
  * Set it to fallback to let passed namespaces to translated hoc act as fallbacks
@@ -191,38 +306,7 @@ export interface ReactOptions {
191
306
  unescape?(str: string): string;
192
307
  }
193
308
 
194
- /**
195
- * This interface can be augmented by users to add types to `i18next` default PluginOptions.
196
- */
197
- export interface PluginOptions {}
198
-
199
- interface DefaultPluginOptions {
200
- /**
201
- * Options for language detection - check documentation of plugin
202
- * @default undefined
203
- */
204
- detection?: object;
205
-
206
- /**
207
- * Options for backend - check documentation of plugin
208
- * @default undefined
209
- */
210
- backend?: object;
211
-
212
- /**
213
- * Options for cache layer - check documentation of plugin
214
- * @default undefined
215
- */
216
- cache?: object;
217
-
218
- /**
219
- * Options for i18n message format - check documentation of plugin
220
- * @default undefined
221
- */
222
- i18nFormat?: object;
223
- }
224
-
225
- export interface InitOptions extends MergeBy<DefaultPluginOptions, PluginOptions> {
309
+ export interface InitOptions extends PluginOptions {
226
310
  /**
227
311
  * Logs info level to console output. Helps finding issues with loading not working.
228
312
  * @default false
@@ -627,37 +711,87 @@ export interface TOptionsBase {
627
711
  interpolation?: InterpolationOptions;
628
712
  }
629
713
 
630
- /**
631
- * indexer that is open to any value
632
- */
633
- export type StringMap = { [key: string]: any };
634
-
635
714
  /**
636
715
  * Options that allow open ended values for interpolation unless type is provided.
637
716
  */
638
717
  export type TOptions<TInterpolationMap extends object = StringMap> = TOptionsBase &
639
718
  TInterpolationMap;
640
719
 
641
- export type Callback = (error: any, t: TFunction) => void;
642
-
643
- /**
644
- * Uses similar args as the t function and returns true if a key exists.
645
- */
646
- export interface ExistsFunction<
647
- TKeys extends string = string,
648
- TInterpolationMap extends object = StringMap,
649
- > {
650
- (key: TKeys | TKeys[], options?: TOptions<TInterpolationMap>): boolean;
651
- }
652
-
653
- export interface WithT {
720
+ type FallbackOrNS<F, T = keyof Resources> = [T] extends [never] ? F : T;
721
+
722
+ type Resources = TypeOptions['resources'];
723
+ type DefaultNamespace = TypeOptions['defaultNS'];
724
+
725
+ export type Namespace<T = FallbackOrNS<string>> = T | T[];
726
+
727
+ type PluralSuffix = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
728
+
729
+ type WithOrWithoutPlural<K> = TypeOptions['jsonFormat'] extends 'v4'
730
+ ? K extends `${infer B}_${PluralSuffix}`
731
+ ? B | K
732
+ : K
733
+ : K;
734
+
735
+ // Normalize single namespace
736
+ export type KeysWithSeparator<K1, K2, S extends string = TypeOptions['keySeparator']> = `${K1 &
737
+ string}${S}${K2 & string}`;
738
+ type KeysWithSeparator2<K1, K2> = KeysWithSeparator<K1, Exclude<K2, keyof any[]>>;
739
+ type Normalize2<T, K = keyof T> = K extends keyof T
740
+ ? T[K] extends StringMap
741
+ ? T[K] extends readonly any[]
742
+ ?
743
+ | KeysWithSeparator2<K, WithOrWithoutPlural<keyof T[K]>>
744
+ | KeysWithSeparator2<K, Normalize2<T[K]>>
745
+ :
746
+ | KeysWithSeparator<K, WithOrWithoutPlural<keyof T[K]>>
747
+ | KeysWithSeparator<K, Normalize2<T[K]>>
748
+ : never
749
+ : never;
750
+ type Normalize<T> = WithOrWithoutPlural<keyof T> | Normalize2<T>;
751
+
752
+ // Normalize multiple namespaces
753
+ type KeyWithNSSeparator<N, K, S extends string = TypeOptions['nsSeparator']> = `${N &
754
+ string}${S}${K & string}`;
755
+ type NormalizeMulti<T, U extends keyof T, L = LastOf<U>> = L extends U
756
+ ? KeyWithNSSeparator<L, Normalize<T[L]>> | NormalizeMulti<T, Exclude<U, L>>
757
+ : never;
758
+
759
+ // Normalize single namespace with key prefix
760
+ type NormalizeWithKeyPrefix<
761
+ T,
762
+ K,
763
+ S extends string = TypeOptions['keySeparator'],
764
+ > = K extends `${infer K1}${S}${infer K2}`
765
+ ? K1 extends keyof T
766
+ ? NormalizeWithKeyPrefix<T[K1], K2>
767
+ : never
768
+ : K extends keyof T
769
+ ? T[K] extends string
770
+ ? never
771
+ : Normalize<T[K]>
772
+ : never;
773
+
774
+ export type KeyPrefix<N extends Namespace> =
775
+ | (N extends keyof Resources ? Normalize<Resources[N]> : string)
776
+ | undefined;
777
+
778
+ export type TFuncKey<
779
+ N extends Namespace = DefaultNamespace,
780
+ TKPrefix = undefined,
781
+ T = Resources,
782
+ > = N extends (keyof T)[] | Readonly<(keyof T)[]>
783
+ ? NormalizeMulti<T, N[number]>
784
+ : N extends keyof T
785
+ ? TKPrefix extends undefined
786
+ ? Normalize<T[N]>
787
+ : NormalizeWithKeyPrefix<T[N], TKPrefix>
788
+ : string;
789
+
790
+ export interface WithT<N extends Namespace = DefaultNamespace> {
654
791
  // Expose parameterized t in the i18next interface hierarchy
655
- t: TFunction;
792
+ t: TFunction<N>;
656
793
  }
657
794
 
658
- /**
659
- * Object returned from t() function when passed returnDetails: true option.
660
- */
661
795
  export type TFunctionDetailedResult<T = string> = {
662
796
  /**
663
797
  * The plain used key
@@ -680,65 +814,102 @@ export type TFunctionDetailedResult<T = string> = {
680
814
  */
681
815
  usedNS: string;
682
816
  };
683
- export type TFunctionResult =
817
+
818
+ type TypeOptionsFallback<TranslationValue, Option, MatchingValue> = Option extends false
819
+ ? TranslationValue extends MatchingValue
820
+ ? string
821
+ : TranslationValue
822
+ : TranslationValue;
823
+
824
+ /**
825
+ * Checks if user has enabled `returnEmptyString` and `returnNull` options to retrieve correct values.
826
+ */
827
+ export type NormalizeByTypeOptions<
828
+ TranslationValue,
829
+ R = TypeOptionsFallback<TranslationValue, TypeOptions['returnEmptyString'], ''>,
830
+ > = TypeOptionsFallback<R, TypeOptions['returnNull'], null>;
831
+
832
+ type StringIfPlural<T> = TypeOptions['jsonFormat'] extends 'v4'
833
+ ? T extends `${string}_${PluralSuffix}`
834
+ ? string
835
+ : never
836
+ : never;
837
+
838
+ type NormalizeReturn<
839
+ T,
840
+ V,
841
+ S extends string | false = TypeOptions['keySeparator'],
842
+ > = V extends keyof T
843
+ ? NormalizeByTypeOptions<T[V]>
844
+ : S extends false
845
+ ? V
846
+ : V extends `${infer K}${S}${infer R}`
847
+ ? K extends keyof T
848
+ ? NormalizeReturn<T[K], R>
849
+ : never
850
+ : StringIfPlural<keyof T>;
851
+
852
+ type NormalizeMultiReturn<T, V> = V extends `${infer N}:${infer R}`
853
+ ? N extends keyof T
854
+ ? NormalizeReturn<T[N], R>
855
+ : never
856
+ : never;
857
+
858
+ export type DefaultTFuncReturn =
684
859
  | string
685
860
  | object
686
861
  | TFunctionDetailedResult
687
862
  | Array<string | object>
688
863
  | undefined
689
864
  | null;
690
- export type TFunctionKeys = string | TemplateStringsArray;
691
- export interface TFunction {
692
- // basic usage
693
- <
694
- TResult extends TFunctionResult = string,
695
- TKeys extends TFunctionKeys = string,
696
- TInterpolationMap extends object = StringMap,
697
- >(
698
- key: TKeys | TKeys[],
699
- ): TResult;
865
+
866
+ export type TFuncReturn<
867
+ N,
868
+ TKeys,
869
+ TDefaultResult,
870
+ TKPrefix = undefined,
871
+ T = Resources,
872
+ > = N extends (keyof T)[]
873
+ ? NormalizeMultiReturn<T, TKeys>
874
+ : N extends keyof T
875
+ ? TKPrefix extends undefined
876
+ ? NormalizeReturn<T[N], TKeys>
877
+ : NormalizeReturn<T[N], KeysWithSeparator<TKPrefix, TKeys>>
878
+ : TDefaultResult;
879
+
880
+ export interface TFunction<N extends Namespace = DefaultNamespace, TKPrefix = undefined> {
700
881
  <
701
- TResult extends TFunctionResult = TFunctionDetailedResult<object>,
702
- TKeys extends TFunctionKeys = string,
882
+ TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
883
+ TDefaultResult extends DefaultTFuncReturn,
703
884
  TInterpolationMap extends object = StringMap,
704
885
  >(
705
886
  key: TKeys | TKeys[],
706
- options?: TOptions<TInterpolationMap> & { returnDetails: true; returnObjects: true },
707
- ): TResult;
887
+ ): TFuncReturn<N, TKeys, TDefaultResult, TKPrefix>;
708
888
  <
709
- TResult extends TFunctionResult = TFunctionDetailedResult,
710
- TKeys extends TFunctionKeys = string,
889
+ TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
890
+ TDefaultResult extends DefaultTFuncReturn,
711
891
  TInterpolationMap extends object = StringMap,
712
892
  >(
713
893
  key: TKeys | TKeys[],
714
894
  options?: TOptions<TInterpolationMap> & { returnDetails: true },
715
- ): TResult;
716
- <
717
- TResult extends TFunctionResult = object,
718
- TKeys extends TFunctionKeys = string,
719
- TInterpolationMap extends object = StringMap,
720
- >(
721
- key: TKeys | TKeys[],
722
- options?: TOptions<TInterpolationMap> & { returnObjects: true },
723
- ): TResult;
895
+ ): TFunctionDetailedResult<TFuncReturn<N, TKeys, TDefaultResult, TKPrefix>>;
724
896
  <
725
- TResult extends TFunctionResult = string,
726
- TKeys extends TFunctionKeys = string,
897
+ TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
898
+ TDefaultResult extends DefaultTFuncReturn,
727
899
  TInterpolationMap extends object = StringMap,
728
900
  >(
729
901
  key: TKeys | TKeys[],
730
- options?: TOptions<TInterpolationMap> | string,
731
- ): TResult;
732
- // overloaded usage
902
+ options?: TOptions<TInterpolationMap>,
903
+ ): TFuncReturn<N, TKeys, TDefaultResult, TKPrefix>;
733
904
  <
734
- TResult extends TFunctionResult = string,
735
- TKeys extends TFunctionKeys = string,
905
+ TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
906
+ TDefaultResult extends DefaultTFuncReturn,
736
907
  TInterpolationMap extends object = StringMap,
737
908
  >(
738
909
  key: TKeys | TKeys[],
739
910
  defaultValue?: string,
740
911
  options?: TOptions<TInterpolationMap> | string,
741
- ): TResult;
912
+ ): TFuncReturn<N, TKeys, TDefaultResult, TKPrefix>;
742
913
  }
743
914
 
744
915
  export interface Resource {
@@ -920,14 +1091,25 @@ export interface Modules {
920
1091
  export interface Newable<T> {
921
1092
  new (...args: any[]): T;
922
1093
  }
923
-
924
1094
  export interface NewableModule<T extends Module> extends Newable<T> {
925
1095
  type: T['type'];
926
1096
  }
927
1097
 
1098
+ type Callback = (error: any, t: TFunction) => void;
1099
+
1100
+ /**
1101
+ * Uses similar args as the t function and returns true if a key exists.
1102
+ */
1103
+ export interface ExistsFunction<
1104
+ TKeys extends string = string,
1105
+ TInterpolationMap extends object = StringMap,
1106
+ > {
1107
+ (key: TKeys | TKeys[], options?: TOptions<TInterpolationMap>): boolean;
1108
+ }
1109
+
928
1110
  export interface i18n {
929
1111
  // Expose parameterized t in the i18next interface hierarchy
930
- t: TFunction;
1112
+ t: TFunction<FallbackOrNS<string>[]>;
931
1113
 
932
1114
  /**
933
1115
  * The default of the i18next module is an i18next instance ready to be initialized by calling init.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next",
3
- "version": "21.9.2",
3
+ "version": "22.0.0",
4
4
  "description": "i18next internationalization framework",
5
5
  "main": "./dist/cjs/i18next.js",
6
6
  "module": "./dist/esm/i18next.js",
@@ -98,15 +98,16 @@
98
98
  "rollup-plugin-terser": "^4.0.4",
99
99
  "sinon": "11.1.2",
100
100
  "tslint": "^5.12.1",
101
- "typescript": "^3.6.4",
101
+ "typescript": "^4.7.4",
102
102
  "watchify": "3.9.0"
103
103
  },
104
104
  "scripts": {
105
- "pretest": "npm run test:typescript && npm run test:typescript:noninterop",
105
+ "pretest": "npm run test:typescript && npm run test:custom-typescript && npm run test:typescript:noninterop",
106
106
  "test": "npm run test:new && npm run test:compat",
107
107
  "test:new": "karma start karma.conf.js --singleRun",
108
108
  "test:compat": "karma start karma.backward.conf.js --singleRun",
109
109
  "test:typescript": "tslint --project tsconfig.json",
110
+ "test:custom-typescript": "tslint --project test/typescript/custom-types/tsconfig.json",
110
111
  "test:typescript:noninterop": "tslint --project tsconfig.nonEsModuleInterop.json",
111
112
  "tdd": "karma start karma.conf.js",
112
113
  "tdd:compat": "karma start karma.backward.conf.js",