UNPKG

16.9 kBTypeScriptView Raw
1// Internal Helpers
2import type { $Dictionary, $NormalizeIntoArray } from './typescript/helpers.js';
3import type {
4 DefaultNamespace,
5 FlatNamespace,
6 FormatFunction,
7 InitOptions,
8 InterpolationOptions,
9 Namespace,
10 Resource,
11 ResourceKey,
12 ResourceLanguage,
13 TOptions,
14} from './typescript/options.js';
15import type { KeyPrefix, TFunction } from './typescript/t.js';
16
17export interface WithT<Ns extends Namespace = DefaultNamespace> {
18 // Expose parameterized t in the i18next interface hierarchy
19 t: TFunction<Ns>;
20}
21
22export interface Interpolator {
23 init(options: InterpolationOptions, reset: boolean): undefined;
24 reset(): undefined;
25 resetRegExp(): undefined;
26 interpolate(str: string, data: object, lng: string, options: InterpolationOptions): string;
27 nest(str: string, fc: (...args: any[]) => any, options: InterpolationOptions): string;
28}
29
30export class ResourceStore {
31 constructor(data: Resource, options: InitOptions);
32
33 public data: Resource;
34
35 public options: InitOptions;
36
37 /**
38 * Gets fired when resources got added or removed
39 */
40 on(event: 'added' | 'removed', callback: (lng: string, ns: string) => void): void;
41
42 /**
43 * Remove event listener
44 * removes all callback when callback not specified
45 */
46 off(event: 'added' | 'removed', callback?: (lng: string, ns: string) => void): void;
47}
48
49export interface Formatter {
50 init(services: Services, i18nextOptions: InitOptions): void;
51 add(name: string, fc: (value: any, lng: string | undefined, options: any) => string): void;
52 addCached(
53 name: string,
54 fc: (lng: string | undefined, options: any) => (value: any) => string,
55 ): void;
56 format: FormatFunction;
57}
58
59export interface Services {
60 backendConnector: any;
61 i18nFormat: any;
62 interpolator: Interpolator;
63 languageDetector: any;
64 languageUtils: any;
65 logger: any;
66 pluralResolver: any;
67 resourceStore: ResourceStore;
68 formatter?: Formatter;
69}
70
71export type ModuleType =
72 | 'backend'
73 | 'logger'
74 | 'languageDetector'
75 | 'postProcessor'
76 | 'i18nFormat'
77 | 'formatter'
78 | '3rdParty';
79
80export interface Module {
81 type: ModuleType;
82}
83
84export type CallbackError = Error | string | null | undefined;
85export type ReadCallback = (
86 err: CallbackError,
87 data: ResourceKey | boolean | null | undefined,
88) => void;
89export type MultiReadCallback = (err: CallbackError, data: Resource | null | undefined) => void;
90
91/**
92 * Used to load data for i18next.
93 * Can be provided as a singleton or as a prototype constructor (preferred for supporting multiple instances of i18next).
94 * For singleton set property `type` to `'backend'` For a prototype constructor set static property.
95 */
96export interface BackendModule<Options = object> extends Module {
97 type: 'backend';
98 init(services: Services, backendOptions: Options, i18nextOptions: InitOptions): void;
99 read(language: string, namespace: string, callback: ReadCallback): void;
100 /** Save the missing translation */
101 create?(
102 languages: readonly string[],
103 namespace: string,
104 key: string,
105 fallbackValue: string,
106 ): void;
107 /** Load multiple languages and namespaces. For backends supporting multiple resources loading */
108 readMulti?(
109 languages: readonly string[],
110 namespaces: readonly string[],
111 callback: MultiReadCallback,
112 ): void;
113 /** Store the translation. For backends acting as cache layer */
114 save?(language: string, namespace: string, data: ResourceLanguage): void;
115}
116
117/**
118 * Used to detect language in user land.
119 * Can be provided as a singleton or as a prototype constructor (preferred for supporting multiple instances of i18next).
120 * For singleton set property `type` to `'languageDetector'` For a prototype constructor set static property.
121 */
122export interface LanguageDetectorModule extends Module {
123 type: 'languageDetector';
124 init?(services: Services, detectorOptions: object, i18nextOptions: InitOptions): void;
125 /** Must return detected language */
126 detect(): string | readonly string[] | undefined;
127 cacheUserLanguage?(lng: string): void;
128}
129
130/**
131 * Used to detect language in user land.
132 * Can be provided as a singleton or as a prototype constructor (preferred for supporting multiple instances of i18next).
133 * For singleton set property `type` to `'languageDetector'` For a prototype constructor set static property.
134 */
135export interface LanguageDetectorAsyncModule extends Module {
136 type: 'languageDetector';
137 /** Set to true to enable async detection */
138 async: true;
139 init?(services: Services, detectorOptions: object, i18nextOptions: InitOptions): void;
140 /** Must call callback passing detected language or return a Promise */
141 detect(
142 callback: (lng: string | readonly string[] | undefined) => void | undefined,
143 ): void | Promise<string | readonly string[] | undefined>;
144 cacheUserLanguage?(lng: string): void | Promise<void>;
145}
146
147/**
148 * Used to extend or manipulate the translated values before returning them in `t` function.
149 * Need to be a singleton object.
150 */
151export interface PostProcessorModule extends Module {
152 /** Unique name */
153 name: string;
154 type: 'postProcessor';
155 process(value: string, key: string | string[], options: TOptions, translator: any): string;
156}
157
158/**
159 * Override the built-in console logger.
160 * Do not need to be a prototype function.
161 */
162export interface LoggerModule extends Module {
163 type: 'logger';
164 log(...args: any[]): void;
165 warn(...args: any[]): void;
166 error(...args: any[]): void;
167}
168
169export interface I18nFormatModule extends Module {
170 type: 'i18nFormat';
171}
172
173export interface FormatterModule extends Module, Formatter {
174 type: 'formatter';
175}
176
177export interface ThirdPartyModule extends Module {
178 type: '3rdParty';
179 init(i18next: i18n): void;
180}
181
182export interface Modules {
183 backend?: BackendModule;
184 logger?: LoggerModule;
185 languageDetector?: LanguageDetectorModule | LanguageDetectorAsyncModule;
186 i18nFormat?: I18nFormatModule;
187 formatter?: FormatterModule;
188 external: ThirdPartyModule[];
189}
190
191// helper to identify class https://stackoverflow.com/a/45983481/2363935
192export interface Newable<T> {
193 new (...args: any[]): T;
194}
195export interface NewableModule<T extends Module> extends Newable<T> {
196 type: T['type'];
197}
198
199export type Callback = (error: any, t: TFunction) => void;
200
201/**
202 * Uses similar args as the t function and returns true if a key exists.
203 */
204export interface ExistsFunction<
205 TKeys extends string = string,
206 TInterpolationMap extends object = $Dictionary,
207> {
208 (key: TKeys | TKeys[], options?: TOptions<TInterpolationMap>): boolean;
209}
210
211export interface CloneOptions extends InitOptions {
212 /**
213 * Will create a new instance of the resource store and import the existing translation resources.
214 * This way it will not shared the resource store instance.
215 * @default false
216 */
217 forkResourceStore?: boolean;
218}
219
220export interface CustomInstanceExtensions {}
221
222// Used just here to exclude `DefaultNamespace` which can be both string or array from `FlatNamespace`
223// in TFunction declaration below.
224// Due to this only very special usage I'm not moving this inside helpers.
225type InferArrayValuesElseReturnType<T> = T extends (infer A)[] ? A : T;
226
227// eslint-disable-next-line @typescript-eslint/naming-convention
228export interface i18n extends CustomInstanceExtensions {
229 // Expose parameterized t in the i18next interface hierarchy
230 t: TFunction<
231 [
232 ...$NormalizeIntoArray<DefaultNamespace>,
233 ...Exclude<FlatNamespace, InferArrayValuesElseReturnType<DefaultNamespace>>[],
234 ]
235 >;
236
237 /**
238 * The default of the i18next module is an i18next instance ready to be initialized by calling init.
239 * You can create additional instances using the createInstance function.
240 *
241 * @param options - Initial options.
242 * @param callback - will be called after all translations were loaded or with an error when failed (in case of using a backend).
243 */
244 init(callback?: Callback): Promise<TFunction>;
245 init<T>(options: InitOptions<T>, callback?: Callback): Promise<TFunction>;
246
247 loadResources(callback?: (err: any) => void): void;
248
249 /**
250 * The use function is there to load additional plugins to i18next.
251 * For available module see the plugins page and don't forget to read the documentation of the plugin.
252 *
253 * @param module Accepts a class or object
254 */
255 use<T extends Module>(module: T | NewableModule<T> | Newable<T>): this;
256
257 /**
258 * List of modules used
259 */
260 modules: Modules;
261
262 /**
263 * Internal container for all used plugins and implementation details like languageUtils, pluralResolvers, etc.
264 */
265 services: Services;
266
267 /**
268 * Internal container for translation resources
269 */
270 store: ResourceStore;
271
272 /**
273 * Uses similar args as the t function and returns true if a key exists.
274 */
275 exists: ExistsFunction;
276
277 /**
278 * Returns a resource data by language.
279 */
280 getDataByLanguage(lng: string): { [key: string]: { [key: string]: string } } | undefined;
281
282 /**
283 * Returns a t function that defaults to given language or namespace.
284 * Both params could be arrays of languages or namespaces and will be treated as fallbacks in that case.
285 * On the returned function you can like in the t function override the languages or namespaces by passing them in options or by prepending namespace.
286 *
287 * Accepts optional keyPrefix that will be automatically applied to returned t function.
288 */
289 getFixedT<
290 Ns extends Namespace | null = DefaultNamespace,
291 TKPrefix extends KeyPrefix<ActualNs> = undefined,
292 ActualNs extends Namespace = Ns extends null ? DefaultNamespace : Ns,
293 >(
294 ...args:
295 | [lng: string | readonly string[], ns?: Ns, keyPrefix?: TKPrefix]
296 | [lng: null, ns: Ns, keyPrefix?: TKPrefix]
297 ): TFunction<ActualNs, TKPrefix>;
298
299 /**
300 * Changes the language. The callback will be called as soon translations were loaded or an error occurs while loading.
301 * HINT: For easy testing - setting lng to 'cimode' will set t function to always return the key.
302 */
303 changeLanguage(lng?: string, callback?: Callback): Promise<TFunction>;
304
305 /**
306 * Is set to the current detected or set language.
307 * If you need the primary used language depending on your configuration (supportedLngs, load) you will prefer using i18next.languages[0].
308 */
309 language: string;
310
311 /**
312 * Is set to an array of language-codes that will be used it order to lookup the translation value.
313 */
314 languages: readonly string[];
315
316 /**
317 * Is set to the current resolved language.
318 * It can be used as primary used language, for example in a language switcher.
319 */
320 resolvedLanguage?: string;
321
322 /**
323 * Checks if namespace has loaded yet.
324 * i.e. used by react-i18next
325 */
326 hasLoadedNamespace(
327 ns: string | readonly string[],
328 options?: {
329 lng?: string | readonly string[];
330 precheck: (
331 i18n: i18n,
332 loadNotPending: (
333 lng: string | readonly string[],
334 ns: string | readonly string[],
335 ) => boolean,
336 ) => boolean;
337 },
338 ): boolean;
339
340 /**
341 * Loads additional namespaces not defined in init options.
342 */
343 loadNamespaces(ns: string | readonly string[], callback?: Callback): Promise<void>;
344
345 /**
346 * Loads additional languages not defined in init options (preload).
347 */
348 loadLanguages(lngs: string | readonly string[], callback?: Callback): Promise<void>;
349
350 /**
351 * Reloads resources on given state. Optionally you can pass an array of languages and namespaces as params if you don't want to reload all.
352 */
353 reloadResources(
354 lngs?: string | readonly string[],
355 ns?: string | readonly string[],
356 callback?: () => void,
357 ): Promise<void>;
358 reloadResources(lngs: null, ns: string | readonly string[], callback?: () => void): Promise<void>;
359
360 /**
361 * Changes the default namespace.
362 */
363 setDefaultNamespace(ns: string): void;
364
365 /**
366 * Checks if a namespace has been loaded.
367 */
368 hasLoadedNamespace(ns: string, options?: Pick<InitOptions, 'fallbackLng'>): boolean;
369
370 /**
371 * Returns rtl or ltr depending on languages read direction.
372 */
373 dir(lng?: string): 'ltr' | 'rtl';
374
375 /**
376 * Exposes interpolation.format function added on init.
377 */
378 format: FormatFunction;
379
380 /**
381 * Will return a new i18next instance.
382 * Please read the options page for details on configuration options.
383 * Providing a callback will automatically call init.
384 * The callback will be called after all translations were loaded or with an error when failed (in case of using a backend).
385 */
386 createInstance(options?: InitOptions, callback?: Callback): i18n;
387
388 /**
389 * Creates a clone of the current instance. Shares store, plugins and initial configuration.
390 * Can be used to create an instance sharing storage but being independent on set language or namespaces.
391 */
392 cloneInstance(options?: CloneOptions, callback?: Callback): i18n;
393
394 /**
395 * Gets fired after initialization.
396 */
397 on(event: 'initialized', callback: (options: InitOptions) => void): void;
398
399 /**
400 * Gets fired on loaded resources.
401 */
402 on(
403 event: 'loaded',
404 callback: (loaded: { [language: string]: { [namespace: string]: boolean } }) => void,
405 ): void;
406
407 /**
408 * Gets fired if loading resources failed.
409 */
410 on(event: 'failedLoading', callback: (lng: string, ns: string, msg: string) => void): void;
411
412 /**
413 * Gets fired on accessing a key not existing.
414 */
415 on(
416 event: 'missingKey',
417 callback: (lngs: readonly string[], namespace: string, key: string, res: string) => void,
418 ): void;
419
420 /**
421 * Gets fired when resources got added or removed.
422 */
423 on(event: 'added' | 'removed', callback: (lng: string, ns: string) => void): void;
424
425 /**
426 * Gets fired when changeLanguage got called.
427 */
428 on(event: 'languageChanged', callback: (lng: string) => void): void;
429
430 /**
431 * Event listener
432 */
433 on(event: string, listener: (...args: any[]) => void): void;
434
435 /**
436 * Remove event listener
437 * removes all callback when callback not specified
438 */
439 off(event: string, listener?: (...args: any[]) => void): void;
440
441 /**
442 * Gets one value by given key.
443 */
444 getResource(
445 lng: string,
446 ns: string,
447 key: string,
448 options?: Pick<InitOptions, 'keySeparator' | 'ignoreJSONStructure'>,
449 ): any;
450
451 /**
452 * Adds one key/value.
453 */
454 addResource(
455 lng: string,
456 ns: string,
457 key: string,
458 value: string,
459 options?: { keySeparator?: string; silent?: boolean },
460 ): i18n;
461
462 /**
463 * Adds multiple key/values.
464 */
465 addResources(lng: string, ns: string, resources: any): i18n;
466
467 /**
468 * Adds a complete bundle.
469 * Setting deep param to true will extend existing translations in that file.
470 * Setting overwrite to true it will overwrite existing translations in that file.
471 */
472 addResourceBundle(
473 lng: string,
474 ns: string,
475 resources: any,
476 deep?: boolean,
477 overwrite?: boolean,
478 ): i18n;
479
480 /**
481 * Checks if a resource bundle exists.
482 */
483 hasResourceBundle(lng: string, ns: string): boolean;
484
485 /**
486 * Returns a resource bundle.
487 */
488 getResourceBundle(lng: string, ns: string): any;
489
490 /**
491 * Removes an existing bundle.
492 */
493 removeResourceBundle(lng: string, ns: string): i18n;
494
495 /**
496 * Current options
497 */
498 options: InitOptions;
499
500 /**
501 * Is initialized
502 */
503 isInitialized: boolean;
504
505 /**
506 * Is initializing
507 */
508 isInitializing: boolean;
509
510 /**
511 * Store was initialized
512 */
513 initializedStoreOnce: boolean;
514
515 /**
516 * Language was initialized
517 */
518 initializedLanguageOnce: boolean;
519
520 /**
521 * Emit event
522 */
523 emit(eventName: string, ...args: any[]): void;
524}
525
526export type * from './typescript/options.js';
527export type {
528 // we need to explicitely export some types, to prevent some issues with next-i18next and interpolation variable validation, etc...
529 FallbackLngObjList,
530 FallbackLng,
531 InitOptions,
532 TypeOptions,
533 CustomTypeOptions,
534 CustomPluginOptions,
535 PluginOptions,
536 FormatFunction,
537 InterpolationOptions,
538 ReactOptions,
539 ResourceKey,
540 ResourceLanguage,
541 Resource,
542 TOptions,
543 Namespace,
544 DefaultNamespace,
545 FlatNamespace,
546} from './typescript/options.js';
547export type * from './typescript/t.js';
548export type {
549 TFunction,
550 ParseKeys,
551 TFunctionReturn,
552 TFunctionDetailedResult,
553 KeyPrefix,
554} from './typescript/t.js';
555
556declare const i18next: i18n;
557export default i18next;
558
559export const createInstance: i18n['createInstance'];
560
561export const dir: i18n['dir'];
562export const init: i18n['init'];
563export const loadResources: i18n['loadResources'];
564export const reloadResources: i18n['reloadResources'];
565export const use: i18n['use'];
566export const changeLanguage: i18n['changeLanguage'];
567export const getFixedT: i18n['getFixedT'];
568export const t: i18n['t'];
569export const exists: i18n['exists'];
570export const setDefaultNamespace: i18n['setDefaultNamespace'];
571export const hasLoadedNamespace: i18n['hasLoadedNamespace'];
572export const loadNamespaces: i18n['loadNamespaces'];
573export const loadLanguages: i18n['loadLanguages'];