UNPKG

17.1 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 fallbackLng?: InitOptions['fallbackLng'];
331 /**
332 * if `undefined` is returned default checks are performed.
333 */
334 precheck?: (
335 i18n: i18n,
336 /**
337 * Check if the language namespace provided are not in loading status:
338 * returns `true` if load is completed successfully or with an error.
339 */
340 loadNotPending: (
341 lng: string | readonly string[],
342 ns: string | readonly string[],
343 ) => boolean,
344 ) => boolean | undefined;
345 },
346 ): boolean;
347
348 /**
349 * Loads additional namespaces not defined in init options.
350 */
351 loadNamespaces(ns: string | readonly string[], callback?: Callback): Promise<void>;
352
353 /**
354 * Loads additional languages not defined in init options (preload).
355 */
356 loadLanguages(lngs: string | readonly string[], callback?: Callback): Promise<void>;
357
358 /**
359 * 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.
360 */
361 reloadResources(
362 lngs?: string | readonly string[],
363 ns?: string | readonly string[],
364 callback?: () => void,
365 ): Promise<void>;
366 reloadResources(lngs: null, ns: string | readonly string[], callback?: () => void): Promise<void>;
367
368 /**
369 * Changes the default namespace.
370 */
371 setDefaultNamespace(ns: string): void;
372
373 /**
374 * Returns rtl or ltr depending on languages read direction.
375 */
376 dir(lng?: string): 'ltr' | 'rtl';
377
378 /**
379 * Exposes interpolation.format function added on init.
380 */
381 format: FormatFunction;
382
383 /**
384 * Will return a new i18next instance.
385 * Please read the options page for details on configuration options.
386 * Providing a callback will automatically call init.
387 * The callback will be called after all translations were loaded or with an error when failed (in case of using a backend).
388 */
389 createInstance(options?: InitOptions, callback?: Callback): i18n;
390
391 /**
392 * Creates a clone of the current instance. Shares store, plugins and initial configuration.
393 * Can be used to create an instance sharing storage but being independent on set language or namespaces.
394 */
395 cloneInstance(options?: CloneOptions, callback?: Callback): i18n;
396
397 /**
398 * Gets fired after initialization.
399 */
400 on(event: 'initialized', callback: (options: InitOptions) => void): void;
401
402 /**
403 * Gets fired on loaded resources.
404 */
405 on(
406 event: 'loaded',
407 callback: (loaded: { [language: string]: { [namespace: string]: boolean } }) => void,
408 ): void;
409
410 /**
411 * Gets fired if loading resources failed.
412 */
413 on(event: 'failedLoading', callback: (lng: string, ns: string, msg: string) => void): void;
414
415 /**
416 * Gets fired on accessing a key not existing.
417 */
418 on(
419 event: 'missingKey',
420 callback: (lngs: readonly string[], namespace: string, key: string, res: string) => void,
421 ): void;
422
423 /**
424 * Gets fired when resources got added or removed.
425 */
426 on(event: 'added' | 'removed', callback: (lng: string, ns: string) => void): void;
427
428 /**
429 * Gets fired when changeLanguage got called.
430 */
431 on(event: 'languageChanged', callback: (lng: string) => void): void;
432
433 /**
434 * Event listener
435 */
436 on(event: string, listener: (...args: any[]) => void): void;
437
438 /**
439 * Remove event listener
440 * removes all callback when callback not specified
441 */
442 off(event: string, listener?: (...args: any[]) => void): void;
443
444 /**
445 * Gets one value by given key.
446 */
447 getResource(
448 lng: string,
449 ns: string,
450 key: string,
451 options?: Pick<InitOptions, 'keySeparator' | 'ignoreJSONStructure'>,
452 ): any;
453
454 /**
455 * Adds one key/value.
456 */
457 addResource(
458 lng: string,
459 ns: string,
460 key: string,
461 value: string,
462 options?: { keySeparator?: string; silent?: boolean },
463 ): i18n;
464
465 /**
466 * Adds multiple key/values.
467 */
468 addResources(lng: string, ns: string, resources: any): i18n;
469
470 /**
471 * Adds a complete bundle.
472 * Setting deep param to true will extend existing translations in that file.
473 * Setting overwrite to true it will overwrite existing translations in that file.
474 */
475 addResourceBundle(
476 lng: string,
477 ns: string,
478 resources: any,
479 deep?: boolean,
480 overwrite?: boolean,
481 ): i18n;
482
483 /**
484 * Checks if a resource bundle exists.
485 */
486 hasResourceBundle(lng: string, ns: string): boolean;
487
488 /**
489 * Returns a resource bundle.
490 */
491 getResourceBundle(lng: string, ns: string): any;
492
493 /**
494 * Removes an existing bundle.
495 */
496 removeResourceBundle(lng: string, ns: string): i18n;
497
498 /**
499 * Current options
500 */
501 options: InitOptions;
502
503 /**
504 * Is initialized
505 */
506 isInitialized: boolean;
507
508 /**
509 * Is initializing
510 */
511 isInitializing: boolean;
512
513 /**
514 * Store was initialized
515 */
516 initializedStoreOnce: boolean;
517
518 /**
519 * Language was initialized
520 */
521 initializedLanguageOnce: boolean;
522
523 /**
524 * Emit event
525 */
526 emit(eventName: string, ...args: any[]): void;
527}
528
529export type * from './typescript/options.js';
530export type {
531 // we need to explicitely export some types, to prevent some issues with next-i18next and interpolation variable validation, etc...
532 FallbackLngObjList,
533 FallbackLng,
534 InitOptions,
535 TypeOptions,
536 CustomTypeOptions,
537 CustomPluginOptions,
538 PluginOptions,
539 FormatFunction,
540 InterpolationOptions,
541 ReactOptions,
542 ResourceKey,
543 ResourceLanguage,
544 Resource,
545 TOptions,
546 Namespace,
547 DefaultNamespace,
548 FlatNamespace,
549} from './typescript/options.js';
550export type * from './typescript/t.js';
551export type {
552 TFunction,
553 ParseKeys,
554 TFunctionReturn,
555 TFunctionDetailedResult,
556 KeyPrefix,
557} from './typescript/t.js';
558
559declare const i18next: i18n;
560export default i18next;
561
562export const createInstance: i18n['createInstance'];
563
564export const dir: i18n['dir'];
565export const init: i18n['init'];
566export const loadResources: i18n['loadResources'];
567export const reloadResources: i18n['reloadResources'];
568export const use: i18n['use'];
569export const changeLanguage: i18n['changeLanguage'];
570export const getFixedT: i18n['getFixedT'];
571export const t: i18n['t'];
572export const exists: i18n['exists'];
573export const setDefaultNamespace: i18n['setDefaultNamespace'];
574export const hasLoadedNamespace: i18n['hasLoadedNamespace'];
575export const loadNamespaces: i18n['loadNamespaces'];
576export const loadLanguages: i18n['loadLanguages'];