From 138afa6e2c2e3c4f77a13073bdeb8e8ea4f62af8 Mon Sep 17 00:00:00 2001 From: Silas Rech Date: Thu, 20 Sep 2018 15:03:20 +0200 Subject: [PATCH] Fixes + update to 11.9 --- types/i18next/index.d.ts | 50 ++- types/i18next/v8/i18next-tests.ts | 455 ++++++++++++++++++++++ types/i18next/v8/index.d.ts | 619 ++++++++++++++++++++++++++++++ types/i18next/v8/tsconfig.json | 29 ++ types/i18next/v8/tslint.json | 1 + 5 files changed, 1148 insertions(+), 6 deletions(-) create mode 100644 types/i18next/v8/i18next-tests.ts create mode 100644 types/i18next/v8/index.d.ts create mode 100644 types/i18next/v8/tsconfig.json create mode 100644 types/i18next/v8/tslint.json diff --git a/types/i18next/index.d.ts b/types/i18next/index.d.ts index 484745bcad..9c310a4770 100644 --- a/types/i18next/index.d.ts +++ b/types/i18next/index.d.ts @@ -1,8 +1,9 @@ -// Type definitions for i18next 8.4 +// Type definitions for i18next 11.9 // Project: http://i18next.com // Definitions by: Michael Ledin // Budi Irawan // Giedrius Grabauskas +// Silas Rech // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.3 @@ -15,6 +16,18 @@ declare namespace i18next { type FormatFunction = (value: string, format?: string, lng?: string) => string; + /* tslint:disable-next-line:no-empty-interface */ + interface DetectionPluginOptions { + } + + /* tslint:disable-next-line:no-empty-interface */ + interface BackendPluginOptions { + } + + /* tslint:disable-next-line:no-empty-interface */ + interface CachePluginOptions { + } + interface InterpolationOptions { /** * format function see formatting for details @@ -37,6 +50,11 @@ declare namespace i18next { * @default true */ escapeValue?: boolean; + /** + * If true, then value passed into escape function is not casted to string, use with custom escape function that does its own type check + * @default false + */ + useRawValueToEscape?: boolean; /** * prefix for interpolation * @default '{{' @@ -91,7 +109,12 @@ declare namespace i18next { * global variables to use in interpolation replacements * @default undefined */ - defaultVariables?: any; + defaultVariables?: { [index: string]: any }; + /** + * after how many interpolation runs to break out before throwing a stack overflow + * @default 1000 + */ + maxReplaces?: number; } interface ReactOptions { @@ -204,6 +227,15 @@ declare namespace i18next { */ saveMissing?: boolean; + /** + * experimental: enable to update default values using the saveMissing + * (Works only if defaultValue different from translated value. + * Only useful on initial development or when keeping code as source of truth not changing values outside of code. + * Only supported if backend supports it already) + * @default false + */ + updateMissing?: boolean; + /** * @default 'fallback' */ @@ -213,7 +245,7 @@ declare namespace i18next { * Used for custom missing key handling (needs saveMissing set to true!) * @default false */ - missingKeyHandler?: false | ((lng: string, ns: string, key: string, fallbackValue: string) => void); + missingKeyHandler?: false | ((lngs: string[], ns: string, key: string, fallbackValue: string) => void); /** * receives a key that was not found in `t()` and returns a value, that will be returned by `t()` @@ -227,6 +259,12 @@ declare namespace i18next { */ appendNamespaceToMissingKey?: boolean; + /** + * gets called in case a interpolation value is undefined. This method will not be called if the value is empty string or null + * @default noop + */ + missingInterpolationHandler?: (text: string, value: any) => any; + /** * will use 'plural' as suffix for languages only having 1 plural form, setting it to false will suffix all with numbers * @default true @@ -284,19 +322,19 @@ declare namespace i18next { * options for language detection - check documentation of plugin * @default undefined */ - detection?: object; + detection?: DetectionPluginOptions; /** * options for backend - check documentation of plugin * @default undefined */ - backend?: object; + backend?: BackendPluginOptions; /** * options for cache layer - check documentation of plugin * @default undefined */ - cache?: object; + cache?: CachePluginOptions; /** * options for react - check documentation of plugin diff --git a/types/i18next/v8/i18next-tests.ts b/types/i18next/v8/i18next-tests.ts new file mode 100644 index 0000000000..1a425084e8 --- /dev/null +++ b/types/i18next/v8/i18next-tests.ts @@ -0,0 +1,455 @@ +import * as i18next from 'i18next'; + +i18next.init({ + lng: "en", + debug: true, + resources: { + en: { + translation: { + key: "hello world" + } + } + } +}, (err: any, t: i18next.TranslationFunction) => { + // initialized and ready to go! + const value: string = i18next.t('key'); +}); + +i18next.init({ initImmediate: false }); + +i18next.init({ + lng: 'en', + debug: true, + resources: { + en: { + translation: { + key: "hello world" + } + }, + de: { + translation: { + key: "hello welt" + } + } + } +}, (err: any, t: i18next.TranslationFunction) => { + // init set content + updateContent(); +}); + +i18next.init({ + ns: ['common', 'moduleA', 'moduleB'], + defaultNS: 'moduleA' +}, (err: any, t: i18next.TranslationFunction) => { + i18next.t('myKey'); // key in moduleA namespace (defined default) + i18next.t('common:myKey'); // key in common namespace +}); + +i18next.loadNamespaces('anotherNamespace', (err: any, t: i18next.TranslationFunction) => { /* ... */ }); + +// fallback to one language +i18next.init({ + lng: 'en-GB' +}, () => { + i18next.t('i18n'); // -> "Internationalisation" + i18next.t('i18n_short'); // -> "i18n" (from en.json) + + // force loading en + i18next.t('i18n', { lng: 'en' }); // -> "Internationalization" +}); + +// fallback to one language +i18next.init({ + fallbackLng: 'en' +}); + +// fallback ordered +i18next.init({ + fallbackLng: ['fr', 'en'] +}); + +// fallback depending on user language +i18next.init({ + fallbackLng: { + 'de-CH': ['fr', 'it'], + 'zh-HANT': ['zh-HANS', 'en'], + es: ['fr'], + default: ['en'] + } +}); + +const updateContent = () => { + const value: string = i18next.t('key'); +}; + +const changeLng = (lng: string) => { + i18next.changeLanguage(lng); +}; + +i18next.init({ + // files to load + ns: ['app', 'common'], + + // default namespace (needs no prefix on calling t) + defaultNS: 'app', + + // fallback, can be a string or an array of namespaces + fallbackNS: 'common' +}, () => { + i18next.t('title'); // -> "i18next" + + i18next.t('button.save'); // -> "save" (fallback from common) + + // without fallbackNS you would have to prefix namespace + // to access keys in that namespace + i18next.t('common:button.save'); // -> "save" +}); + +i18next.init({ + lng: 'de', + + // allow keys to be phrases having `:`, `.` + nsSeparator: false, + keySeparator: false, + + // do not load a fallback + fallbackLng: false +}); + +const error404 = '404'; +i18next.t([`error.${error404}`, 'error.unspecific']); // -> "The page was not found" + +const error502 = '502'; +i18next.t([`error.${error502}`, 'error.unspecific']); // -> "Something went wrong" + +i18next.t('No one says a key can not be the fallback.'); +// -> "Niemand sagt ein key kann nicht als Ersatz dienen." + +i18next.t('This will be shown if the current loaded translations to not have this.'); +// -> "This will be shown if the current loaded translations to not have this." + +const languageChangedCallback = () => { + updateContent(); +}; + +i18next.on('languageChanged', languageChangedCallback); +i18next.off('languageChanged', languageChangedCallback); + +i18next + .init({ + fallbackLng: 'en', + debug: true, + ns: ['special', 'common'], + defaultNS: 'special', + backend: { + // load from i18next-gitbook repo + loadPath: 'https://raw.githubusercontent.com/i18next/i18next-gitbook/master/locales/{{lng}}/{{ns}}.json', + crossDomain: true + } + }, (err: any, t: i18next.TranslationFunction) => { + // init set content + updateContent2(); + }); + +// just set some content and react to language changes +// could be optimized using vue-i18next, jquery-i18next, react-i18next, ... +const updateContent2 = () => { + const value: string = i18next.t('title', { what: 'i18next' }); + const value2: string = i18next.t('common:button.save', { count: Math.floor(Math.random() * 2 + 1) }); + const value3 = `detected user language: "${i18next.language}" --> loaded languages: "${i18next.languages.join(', ')}"`; +}; + +i18next.init({ + fallbackLng: 'en', + ns: ['file1', 'file2'], + defaultNS: 'file1', + debug: true +}, (err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +// with only callback +i18next.init((err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +const v: string = i18next.t('my.key'); +const a: boolean = i18next.exists('my.key'); + +// fix language to german +const de = i18next.getFixedT('de'); +const z: string = de('myKey'); + +// or fix the namespace to anotherNamespace +const anotherNamespace = i18next.getFixedT(null, 'anotherNamespace'); +const x: string = anotherNamespace('anotherNamespaceKey'); // no need to prefix ns i18n.t('anotherNamespace:anotherNamespaceKey'); + +i18next.changeLanguage('en', (err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +i18next.loadNamespaces('myNamespace', (err: any, t: i18next.TranslationFunction) => { /* resources have been loaded */ }); +i18next.loadNamespaces(['myNamespace1', 'myNamespace2'], (err: any, t: i18next.TranslationFunction) => { /* resources have been loaded */ }); + +i18next.loadLanguages('de', (err: any, t: i18next.TranslationFunction) => { /* resources have been loaded */ }); +i18next.loadLanguages(['de', 'fr'], (err: any, t: i18next.TranslationFunction) => { /* resources have been loaded */ }); + +// reload all +i18next.reloadResources(); + +// reload languages +i18next.reloadResources(['de', 'fr']); + +// reload namespaces for all languages +i18next.reloadResources(null, ['ns1', 'ns2']); + +// reload namespaces in languages +i18next.reloadResources(['de', 'fr'], ['ns1', 'ns2']); + +// for current language +i18next.dir(); + +// for another language +i18next.dir('en-US'); // -> "ltr"; +i18next.dir('ar'); // -> "rtl"; + +// key = 'hello {{what}}' +i18next.t('key', { what: i18next.format('world', 'uppercase') }); // -> hello WORLD + +const newInstance = i18next.createInstance({ + fallbackLng: 'en', + ns: ['file1', 'file2'], + defaultNS: 'file1', + debug: true +}, (err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +// is the same as +newInstance.init({ + fallbackLng: 'en', + ns: ['file1', 'file2'], + defaultNS: 'file1', + debug: true +}, (err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +const newInstance2 = i18next.cloneInstance({ + fallbackLng: 'en', + ns: ['file1', 'file2'], + defaultNS: 'file1', + debug: true +}, (err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +// is the same as +const newInstance3 = i18next.cloneInstance(); +newInstance.init({ + fallbackLng: 'en', + ns: ['file1', 'file2'], + defaultNS: 'file1', + debug: true +}, (err: any, t: i18next.TranslationFunction) => { + if (err) { + console.log('something went wrong loading', err); + return; + } + t('key'); // -> same as i18next.t +}); + +i18next.on('initialized', options => { }); +i18next.on('loaded', loaded => { }); +i18next.on('failedLoading', (lng: string, ns: string, msg: string) => { }); +i18next.on('missingKey', (lngs: string[], namespace: string, key: string, res: string) => { }); +i18next.on('added', (lng: string, ns: string) => { }); +i18next.on('removed', (lng: string, ns: string) => { }); +i18next.on('languageChanged', (lng: string) => { }); +i18next.on("customEvent", () => { }); + +i18next.getResource("en", "test", "key"); +i18next.getResource("en", "test", "key", { keySeparator: "-" }); + +i18next.addResource("en", "test", "key", "value"); +i18next.addResource("en", "test", "key", "value", { keySeparator: "-", silent: false }); + +i18next.addResources("en", "test", { key: "value" }); + +i18next.addResourceBundle('en', 'translations', { + key: 'value', +}, true, true); + +const has: boolean = i18next.hasResourceBundle("en", "test"); + +i18next.getResourceBundle("en", "test"); + +i18next.removeResourceBundle("en", "test"); + +i18next + .init({ + resources: { + en: { + namespace1: { + key: 'hello from namespace 1' + }, + namespace2: { + key: 'hello from namespace 2' + } + }, + de: { + namespace1: { + key: 'hallo von namespace 1' + }, + namespace2: { + key: 'hallo von namespace 2' + } + } + } + }); + +i18next.init(); + +i18next.addResourceBundle("en", 'namespace1', { + key: 'hello from namespace 1' +}); + +i18next + .init({ + backend: { + // for all available options read the backend's repository readme file + loadPath: '/locales/{{lng}}/{{ns}}.json' + } + }); + +i18next.init({ + ns: ['common', 'moduleA'], + defaultNS: 'moduleA' +}); + +i18next.t('key', { what: 'i18next', how: 'great' }); + +const author = { + name: 'Jan', + github: 'jamuhl' +}; +i18next.t('key', { author }); + +i18next.t('keyEscaped', { myVar: '' }); +// -> "no danger <img />" + +i18next.t('keyUnescaped', { myVar: '' }); +// -> "dangerous " + +i18next.t('keyEscaped', { myVar: '', interpolation: { escapeValue: false } }); +// -> "no danger " (obviously could be dangerous) + +i18next + .init({ + lng: 'en', + fallbackLng: 'en', + + resources: { + en: { + translation: { + key1: 'test', + interpolateKey: 'add {{insert}} {{up, uppercase}}', + interpolateKey2: 'add {{insert}} {{up, uppercase}}' + } + } + }, + + interpolation: { + escapeValue: false, // not needed for react!! + formatSeparator: ',', + format: (value: string, format: string, lng: string) => { + if (format === 'uppercase') return value.toUpperCase(); + return value; + } + } + }); + +i18next.t('key', { count: 0 }); // -> "items" +i18next.t('key', { count: 1 }); // -> "item" +i18next.t('key', { count: 5 }); // -> "items" +i18next.t('key', { count: 100 }); // -> "items" +i18next.t('keyWithCount', { count: 0 }); // -> "0 items" +i18next.t('keyWithCount', { count: 1 }); // -> "1 item" +i18next.t('keyWithCount', { count: 5 }); // -> "5 items" +i18next.t('keyWithCount', { count: 100 }); // -> "100 items" + +i18next.t('key1_interval', { postProcess: 'interval', count: 1 }); // -> "one item" +i18next.t('key1_interval', { postProcess: 'interval', count: 4 }); // -> "a few items" +i18next.t('key1_interval', { postProcess: 'interval', count: 100 }); // -> "a lot of items" + +// not matching into a range it will fallback to +// the regular plural form +i18next.t('key2_interval', { postProcess: 'interval', count: 1 }); // -> "one item" +i18next.t('key2_interval', { postProcess: 'interval', count: 4 }); // -> "a few items" +i18next.t('key2_interval', { postProcess: 'interval', count: 100 }); // -> "100 items" +i18next.t('friend', { context: 'male', count: 1 }); // -> "A boyfriend" +i18next.t('friend', { context: 'male', count: 1 }); // -> "A boyfriend" +i18next.t('friend', { context: 'female', count: 100 }); // -> "100 girlfriends" +i18next.t('friend', { context: 'female', count: 100 }); // -> "100 girlfriends" +i18next.t('tree', { returnObjects: true, something: 'gold' }); +// -> { res: 'added gold' } + +i18next.t('array', { returnObjects: true }); +// -> ['a', 'b', 'c'] +i18next.t('arrayJoin', { joinArrays: '+' }); +// -> "line1+line2+line3" + +i18next.t('arrayJoinWithInterpolation', { myVar: 'interpolate', joinArrays: ' ' }); +// -> "you can interpolate" + +i18next.t('arrayOfObjects.0.name'); +// -> "tom" + +type KeyList = "friend" | "tree"; + +interface CustomOptions { + myVar: string; +} + +i18next.t("friend"); +i18next.t(["friend", "tree"]); +i18next.t("friend", { myVar: "someValue" }); +i18next.t(["friend", "tree"], { myVar: "someValue" }); +i18next.t("friend", { myVar: "someValue" }); +i18next.t(["friend", "tree"], { myVar: "someValue" }); + +const t1: i18next.TranslationFunction = (key: string, options: i18next.TranslationOptions) => ""; +const t2: i18next.TranslationFunction<{ value: string }> = (key: string, options: i18next.TranslationOptions) => ({ value: "asd" }); +const t3: i18next.TranslationFunction = (key: string | string[], options: i18next.TranslationOptions) => ""; +const t4: i18next.TranslationFunction = (key: KeyList | KeyList[], options: i18next.TranslationOptions) => ""; + +i18next.exists("friend"); +i18next.exists(["friend", "tree"]); +i18next.exists("friend", { myVar: "someValue" }); +i18next.exists(["friend", "tree"], { myVar: "someValue" }); +i18next.exists("friend", { myVar: "someValue" }); +i18next.exists(["friend", "tree"], { myVar: "someValue" }); diff --git a/types/i18next/v8/index.d.ts b/types/i18next/v8/index.d.ts new file mode 100644 index 0000000000..484745bcad --- /dev/null +++ b/types/i18next/v8/index.d.ts @@ -0,0 +1,619 @@ +// Type definitions for i18next 8.4 +// Project: http://i18next.com +// Definitions by: Michael Ledin +// Budi Irawan +// Giedrius Grabauskas +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.3 + +declare namespace i18next { + interface FallbackLngObjList { + [language: string]: string[]; + } + + type FallbackLng = string | string[] | FallbackLngObjList; + + type FormatFunction = (value: string, format?: string, lng?: string) => string; + + interface InterpolationOptions { + /** + * format function see formatting for details + * @default noop + */ + format?: FormatFunction; + /** + * used to separate format from interpolation value + * @default ',' + */ + formatSeparator?: string; + /** + * escape function + * @default str => str + */ + escape?(str: string): string; + + /** + * escape passed in values to avoid xss injection + * @default true + */ + escapeValue?: boolean; + /** + * prefix for interpolation + * @default '{{' + */ + prefix?: string; + /** + * suffix for interpolation + * @default '}}' + */ + suffix?: string; + /** + * escaped prefix for interpolation (regexSafe) + * @default undefined + */ + prefixEscaped?: string; + /** + * escaped suffix for interpolation (regexSafe) + * @default undefined + */ + suffixEscaped?: string; + /** + * suffix to unescaped mode + * @default undefined + */ + unescapeSuffix?: string; + /** + * prefix to unescaped mode + * @default '-' + */ + unescapePrefix?: string; + /** + * prefix for nesting + * @default '$t(' + */ + nestingPrefix?: string; + /** + * suffix for nesting + * @default ')' + */ + nestingSuffix?: string; + /** + * escaped prefix for nesting (regexSafe) + * @default undefined + */ + nestingPrefixEscaped?: string; + /** + * escaped suffix for nesting (regexSafe) + * @default undefined + */ + nestingSuffixEscaped?: string; + /** + * global variables to use in interpolation replacements + * @default undefined + */ + defaultVariables?: any; + } + + interface ReactOptions { + /** + * set to true if you like to wait for loaded in every translated hoc + * @default false + */ + wait?: boolean; + /** + * set it to fallback to let passed namespaces to translated hoc act as fallbacks + * @default 'default' + */ + nsMode?: 'default' | 'fallback'; + /** + * set it to the default parent element created by the Trans component. + * @default 'div' + */ + defaultTransParent?: string; + /** + * set which events trigger a rerender, can be set to false or string of events + * @default 'languageChanged loaded' + */ + bindI18n?: string | false; + /** + * set which events on store trigger a rerender, can be set to false or string of events + * @default 'added removed' + */ + bindStore?: string | false; + } + + interface InitOptions { + /** + * logs info level to console output. Helps finding issues with loading not working. + * @default false + */ + debug?: boolean; + + /** + * resources to initialize with (if not using loading or not appending using addResourceBundle) + * @default undefined + */ + resources?: Resource; + + /** + * language to use (overrides language detection) + * @default undefined + */ + lng?: string; + + /** + * language to use if translations in user language are not available. + * @default 'dev' + */ + fallbackLng?: false | FallbackLng; + + /** + * array of allowed languages + * @default false + */ + whitelist?: false | string[]; + + /** + * if true will pass eg. en-US if finding en in whitelist + * @default false + */ + nonExplicitWhitelist?: boolean; + + /** + * language codes to lookup, given set language is + * 'en-US': 'all' --> ['en-US', 'en', 'dev'], + * 'currentOnly' --> 'en-US', + * 'languageOnly' --> 'en' + * @default 'all' + */ + load?: "all" | "currentOnly" | "languageOnly"; + + /** + * array of languages to preload. Important on serverside to assert translations are loaded before rendering views. + * @default false + */ + preload?: false | string[]; + + /** + * language will be lowercased eg. en-US --> en-us + * @default false + */ + lowerCaseLng?: boolean; + + /** + * string or array of namespaces to load + * @default 'translation' + */ + ns?: string | string[]; + + /** + * default namespace used if not passed to translation function + * @default 'translation' + */ + defaultNS?: string; + + /** + * string or array of namespaces to lookup key if not found in given namespace. + * @default false + */ + fallbackNS?: false | string | string[]; + + /** + * calls save missing key function on backend if key not found + * @default false + */ + saveMissing?: boolean; + + /** + * @default 'fallback' + */ + saveMissingTo?: "current" | "all" | "fallback"; + + /** + * Used for custom missing key handling (needs saveMissing set to true!) + * @default false + */ + missingKeyHandler?: false | ((lng: string, ns: string, key: string, fallbackValue: string) => void); + + /** + * receives a key that was not found in `t()` and returns a value, that will be returned by `t()` + * @default noop + */ + parseMissingKeyHandler?(key: string): any; + + /** + * appends namespace to missing key + * @default false + */ + appendNamespaceToMissingKey?: boolean; + + /** + * will use 'plural' as suffix for languages only having 1 plural form, setting it to false will suffix all with numbers + * @default true + */ + simplifyPluralSuffix?: boolean; + + /** + * string or array of postProcessors to apply per default + * @default false + */ + postProcess?: false | string | string[]; + + /** + * allows null values as valid translation + * @default true + */ + returnNull?: boolean; + + /** + * allows empty string as valid translation + * @default true + */ + returnEmptyString?: boolean; + + /** + * allows objects as valid translation result + * @default false + */ + returnObjects?: boolean; + + /** + * Gets called if object was passed in as key but returnObjects was set to false + * @default noop + */ + returnedObjectHandler?(key: string, value: string, options: any): void; + + /** + * char, eg. '\n' that arrays will be joined by + * @default false + */ + joinArrays?: false | string; + + /** + * default: sets defaultValue + * @default args => ({ defaultValue: args[1] }) + */ + overloadTranslationOptionHandler?(args: string[]): TranslationOptions; + + /** + * @see https://www.i18next.com/interpolation.html + */ + interpolation?: InterpolationOptions; + + /** + * options for language detection - check documentation of plugin + * @default undefined + */ + detection?: object; + + /** + * options for backend - check documentation of plugin + * @default undefined + */ + backend?: object; + + /** + * options for cache layer - check documentation of plugin + * @default undefined + */ + cache?: object; + + /** + * options for react - check documentation of plugin + * @default undefined + */ + react?: ReactOptions; + + /** + * triggers resource loading in init function inside a setTimeout (default async behaviour). + * Set it to false if your backend loads resources sync - that way calling i18next.t after + * init is possible without relaying on the init callback. + * @default true + */ + initImmediate?: boolean; + + /** + * char to separate keys + * @default '.' + */ + keySeparator?: false | string; + + /** + * char to split namespace from key + * @default ':' + */ + nsSeparator?: false | string; + + /** + * char to split plural from key + * @default '_' + */ + pluralSeparator?: string; + + /** + * char to split context from key + * @default '_' + */ + contextSeparator?: string; + + /** + * prefixes the namespace to the returned key when using cimode + * @default false + */ + appendNamespaceToCIMode?: boolean; + + /** + * Compatibility JSON version + */ + compatibilityJSON?: string; + } + + // Add an indexer to assure that interpolation arguments can be passed + type TranslationOptions = TranslationOptionsBase & TCustomOptions & { [key: string]: any }; + + interface TranslationOptionsBase { + /** + * defaultValue to return if a translation was not found + */ + defaultValue?: any; + /** + * count value used for plurals + */ + count?: number; + /** + * used for contexts (eg. male\female) + */ + context?: any; + /** + * object with vars for interpolation - or put them directly in options + */ + replace?: any; + /** + * override language to use + */ + lng?: string; + /** + * override languages to use + */ + lngs?: string[]; + /** + * override language to lookup key if not found see fallbacks for details + */ + fallbackLng?: FallbackLng; + /** + * override namespaces (string or array) + */ + ns?: string | string[]; + /** + * override char to separate keys + */ + keySeparator?: string; + /** + * override char to split namespace from key + */ + nsSeparator?: string; + /** + * accessing an object not a translation string (can be set globally too) + */ + returnObjects?: boolean; + /** + * char, eg. '\n' that arrays will be joined by (can be set globally too) + */ + joinArrays?: string; + /** + * string or array of postProcessors to apply see interval plurals as a sample + */ + postProcess?: string | string[]; + /** + * override interpolation options + */ + interpolation?: InterpolationOptions; + } + + type Callback = (error: any, t: TranslationFunction) => void; + + type TranslationFunction = + (key: TKeys | TKeys[], options?: TranslationOptions) => TResult; + + interface Resource { + [language: string]: ResourceLanguage; + } + + interface ResourceLanguage { + [namespace: string]: ResourceKey; + } + + interface ResourceKey { + [key: string]: any; + } + + interface i18n { + /** + * The default export of the i18next module is an i18next instance ready to be initialized by calling init. + * You can create additional instances using the createInstance function. + * + * @param options - Initial options. + * @param callback - will be called after all translations were loaded or with an error when failed (in case of using a backend). + */ + init(options: InitOptions, callback?: Callback): i18n; + init(callback?: Callback): i18n; + + loadResources(callback?: (err: any) => void): void; + + /** + * The use function is there to load additional plugins to i18next. + * For available module see the plugins page and don't forget to read the documentation of the plugin. + */ + use(module: any): i18n; + + /** + * Please have a look at the translation functions like interpolation, formatting and plurals for more details on using it. + */ + t: TranslationFunction; + + /** + * Uses the same resolve functionality as the t function and returns true if a key exists. + */ + exists: TranslationFunction; + + /** + * Returns a t function that defaults to given language or namespace. + * Both params could be arrays of languages or namespaces and will be treated as fallbacks in that case. + * 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. + */ + getFixedT(lng: string | string[], ns?: string | string[]): TranslationFunction; + getFixedT(lng: null, ns: string | string[]): TranslationFunction; + + /** + * Changes the language. The callback will be called as soon translations were loaded or an error occurs while loading. + * HINT: For easy testing - setting lng to 'cimode' will set t function to always return the key. + */ + changeLanguage(lng: string, callback?: Callback): void; + + /** + * Is set to the current detected or set language. + * If you need the primary used language depending on your configuration (whilelist, load) you will prefer using i18next.languages[0]. + */ + language: string; + + /** + * Is set to an array of language-codes that will be used it order to lookup the translation value. + */ + languages: string[]; + + /** + * Loads additional namespaces not defined in init options. + */ + loadNamespaces(ns: string | string[], callback: Callback): void; + + /** + * Loads additional languages not defined in init options (preload). + */ + loadLanguages(lngs: string | string[], callback: Callback): void; + + /** + * 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. + */ + reloadResources(lngs?: string[], ns?: string[]): void; + reloadResources(lngs: null, ns: string[]): void; + + /** + * Changes the default namespace. + */ + setDefaultNamespace(ns: string): void; + + /** + * Returns rtl or ltr depending on languages read direction. + */ + dir(lng?: string): "ltr" | "rtl"; + + /** + * Exposes interpolation.format function added on init. + */ + format: FormatFunction; + + /** + * Will return a new i18next instance. + * Please read the options page for details on configuration options. + * Providing a callback will automatically call init. + * The callback will be called after all translations were loaded or with an error when failed (in case of using a backend). + */ + createInstance(options?: InitOptions, callback?: Callback): i18n; + + /** + * Creates a clone of the current instance. Shares store, plugins and initial configuration. + * Can be used to create an instance sharing storage but being independent on set language or namespaces. + */ + cloneInstance(options?: InitOptions, callback?: Callback): i18n; + + /** + * Gets fired after initialization. + */ + on(event: "initialized", callback: (options: InitOptions) => void): void; + + /** + * Gets fired on loaded resources. + */ + on(event: "loaded", callback: (loaded: boolean) => void): void; + + /** + * Gets fired if loading resources failed. + */ + on(event: "failedLoading", callback: (lng: string, ns: string, msg: string) => void): void; + + /** + * Gets fired on accessing a key not existing. + */ + on(event: "missingKey", callback: (lngs: string[], namespace: string, key: string, res: string) => void): void; + + /** + * Gets fired when resources got added or removed. + */ + on(event: "added" | "removed", callback: (lng: string, ns: string) => void): void; + + /** + * Gets fired when changeLanguage got called. + */ + on(event: "languageChanged", callback: (lng: string) => void): void; + + /** + * Event listener + */ + on(event: string, listener: (...args: any[]) => void): void; + + /** + * Remove event listener + */ + off(event: string, listener: (...args: any[]) => void): void; + + /** + * Gets one value by given key. + */ + getResource(lng: string, ns: string, key: string, options?: { keySeparator?: string }): any; + + /** + * Adds one key/value. + */ + addResource(lng: string, ns: string, key: string, value: string, options?: { keySeparator?: string, silent?: boolean }): void; + + /** + * Adds multiple key/values. + */ + addResources(lng: string, ns: string, resources: any): void; + + /** + * Adds a complete bundle. + * Setting deep param to true will extend existing translations in that file. + * Setting overwrite to true it will overwrite existing translations in that file. + */ + addResourceBundle(lng: string, ns: string, resources: any, deep?: boolean, overwrite?: boolean): void; + + /** + * Checks if a resource bundle exists. + */ + hasResourceBundle(lng: string, ns: string): boolean; + + /** + * Returns a resource bundle. + */ + getResourceBundle(lng: string, ns: string): any; + + /** + * Removes an existing bundle. + */ + removeResourceBundle(lng: string, ns: string): void; + + /** + * Current options + */ + options: InitOptions; + + /** + * Is initialized + */ + isInitialized: boolean; + } +} + +declare const i18next: i18next.i18n; +export = i18next; diff --git a/types/i18next/v8/tsconfig.json b/types/i18next/v8/tsconfig.json new file mode 100644 index 0000000000..cb9f9ab724 --- /dev/null +++ b/types/i18next/v8/tsconfig.json @@ -0,0 +1,29 @@ +{ + "files": [ + "index.d.ts", + "i18next-tests.ts" + ], + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": false, + "baseUrl": "../../", + "typeRoots": [ + "../../" + ], + "paths": { + "i18next": [ + "i18next/v8" + ] + }, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + } +} diff --git a/types/i18next/v8/tslint.json b/types/i18next/v8/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/i18next/v8/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }