From 5bdb771c877c0455839c34e4190656764915e3a1 Mon Sep 17 00:00:00 2001 From: Michal Ledin Date: Wed, 16 Mar 2016 00:48:26 +0300 Subject: [PATCH] Updated i18next definitions to 2.3.4. --- .../i18next-browser-languagedetector-tests.ts | 2 +- .../i18next-browser-languagedetector.d.ts | 2 +- .../i18next-express-middleware-tests.ts | 2 +- .../i18next-express-middleware.d.ts | 2 +- .../i18next-node-fs-backend.d.ts | 2 +- .../i18next-sprintf-postprocessor.d.ts | 2 +- i18next/i18next-2.0.17.d.ts | 160 ++ i18next/i18next-tests-2.0.17.ts | 1379 ++++++++++++++++ i18next/i18next-tests.ts | 1427 +---------------- i18next/i18next.d.ts | 261 ++- ng-i18next/ng-i18next.d.ts | 2 +- 11 files changed, 1715 insertions(+), 1526 deletions(-) create mode 100644 i18next/i18next-2.0.17.d.ts create mode 100644 i18next/i18next-tests-2.0.17.ts diff --git a/i18next-browser-languagedetector/i18next-browser-languagedetector-tests.ts b/i18next-browser-languagedetector/i18next-browser-languagedetector-tests.ts index a2d3cc925..fb346894e 100644 --- a/i18next-browser-languagedetector/i18next-browser-languagedetector-tests.ts +++ b/i18next-browser-languagedetector/i18next-browser-languagedetector-tests.ts @@ -1,4 +1,4 @@ -/// +/// /// import * as i18next from 'i18next'; diff --git a/i18next-browser-languagedetector/i18next-browser-languagedetector.d.ts b/i18next-browser-languagedetector/i18next-browser-languagedetector.d.ts index 68b0231c7..cef510304 100644 --- a/i18next-browser-languagedetector/i18next-browser-languagedetector.d.ts +++ b/i18next-browser-languagedetector/i18next-browser-languagedetector.d.ts @@ -4,7 +4,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /// -/// +/// declare namespace I18next { interface I18nextStatic extends i18nextBrowserLanguageDetector.I18nextStatic { } diff --git a/i18next-express-middleware/i18next-express-middleware-tests.ts b/i18next-express-middleware/i18next-express-middleware-tests.ts index a696f4f8a..6fd69a348 100644 --- a/i18next-express-middleware/i18next-express-middleware-tests.ts +++ b/i18next-express-middleware/i18next-express-middleware-tests.ts @@ -1,4 +1,4 @@ -/// +/// /// import * as express from "express"; diff --git a/i18next-express-middleware/i18next-express-middleware.d.ts b/i18next-express-middleware/i18next-express-middleware.d.ts index 0014c4e57..960b39612 100644 --- a/i18next-express-middleware/i18next-express-middleware.d.ts +++ b/i18next-express-middleware/i18next-express-middleware.d.ts @@ -4,7 +4,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /// -/// +/// declare namespace I18next { interface I18nextOptions extends i18nextExpressMiddleware.I18nextOptions { } diff --git a/i18next-node-fs-backend/i18next-node-fs-backend.d.ts b/i18next-node-fs-backend/i18next-node-fs-backend.d.ts index 637dea352..dd2ec3b79 100644 --- a/i18next-node-fs-backend/i18next-node-fs-backend.d.ts +++ b/i18next-node-fs-backend/i18next-node-fs-backend.d.ts @@ -3,7 +3,7 @@ // Definitions by: Cyril Schumacher // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -/// +/// declare namespace I18next { interface I18nextOptions extends i18nextNodeFsBackEnd.I18nextOptions { } diff --git a/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts b/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts index 19f786e59..a069e45ff 100644 --- a/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts +++ b/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts @@ -4,7 +4,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /// -/// +/// declare namespace I18next { interface I18nextOptions extends i18nextSprintfPostProcessor.I18nextOptions {} diff --git a/i18next/i18next-2.0.17.d.ts b/i18next/i18next-2.0.17.d.ts new file mode 100644 index 000000000..c8f803f05 --- /dev/null +++ b/i18next/i18next-2.0.17.d.ts @@ -0,0 +1,160 @@ +// Type definitions for i18next v2.0.17 +// Project: http://i18next.com +// Definitions by: Maarten Docter +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +// Sources: https://github.com/jamuhl/i18next/ + +/// +/// +/// +/// + +declare namespace I18next { + export interface I18nextStatic {} + export interface I18nextOptions {} +} + +interface IResourceStore { + [language: string]: IResourceStoreLanguage; +} +interface IResourceStoreLanguage { + [namespace: string]: IResourceStoreKey; +} +interface IResourceStoreKey { + [key: string]: any; +} + +interface I18nTranslateOptions extends I18nextOptions { + defaultValue?: any; // normally a string + // NOTE https://github.com/DefinitelyTyped/DefinitelyTyped/pull/5590 + toAdd?: any; + child?: any; + sprintf?: any; + count?: any; + context?: any; +} + +interface I18nextOptions extends I18next.I18nextOptions { + lng?: string; // Default value: undefined + load?: string; // Default value: 'all' + preload?: string[]; // Default value: [] + lowerCaseLng?: boolean; // Default value: false + returnObjectTrees?: boolean; // Default value: false + fallbackLng?: string|boolean; // Default value: 'dev' + detectLngQS?: string; // Default value: 'setLng' + ns?: any; // Default value: 'translation' (string), can also be an object + nsseparator?: string; // Default value: '::' + keyseparator?: string; // Default value: '.' + selectorAttr?: string; // Default value: 'data-i18n' + debug?: boolean; // Default value: false + + resGetPath?: string; // Default value: 'locales/__lng__/__ns__.json' + resPostPath?: string; // Default value: 'locales/add/__lng__/__ns__' + + getAsync?: boolean; // Default value: true + postAsync?: boolean; // Default value: true + + resStore?: IResourceStore; // Default value: undefined + useLocalStorage?: boolean; // Default value: false + localStorageExpirationTime?: number; // Default value: 7 * 24 * 60 * 60 * 1000 (in ms default one week) + + dynamicLoad?: boolean; // Default value: false + sendMissing?: boolean; // Default value: false + sendMissingTo?: string; // Default value: 'fallback'. Other options are: current | all + sendType?: string; // Default value: 'POST' + + interpolationPrefix?: string; // Default value: '__' + interpolationSuffix?: string; // Default value: '__' + reusePrefix?: string; // Default value: '$t(' + reuseSuffix?: string; // Default value: ')' + pluralSuffix?: string; // Default value: '_plural' + pluralNotFound?: string; // Default value: ['plural_not_found' Math.random()].join( '' ) + contextNotFound?: string; // Default value: ['context_not_found' Math.random()].join( '' ) + + setJqueryExt?: boolean; // Default value: true + defaultValueFromContent?: boolean; // Default value: true + useDataAttrOptions?: boolean; // Default value: false + cookieExpirationTime?: number; // Default value: undefined + useCookie?: boolean; // Default value: true + cookieName?: string; // Default value: 'i18next' + + postProcess?: string; // Default value: undefined + + // NOTE https://github.com/DefinitelyTyped/DefinitelyTyped/pull/5590 + replace?: any; +} + +interface I18nextStatic extends I18next.I18nextStatic { + + addPostProcessor(name: string, fn: (value: any, key: string, options: any) => string): void; + addResources(language: string, namespace: string, resources: IResourceStoreKey): void; + detectLanguage(): string; + functions: { + extend(target: any, ...objs: any[]): Object; + extend(deep: boolean, target: any, ...objs: any[]): Object; + each(collection: any, callback: (indexInArray: any, valueOfElement: any) => any): any; + ajax(settings: JQueryAjaxSettings): JQueryXHR; + ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR; + cookie: { + create: (name: string, value: string, minutes: number) => void; + read: (name: string) => string; + remove: (name: string) => void; + }; + detectLanguage(): string; + log(message: string): void; + toLanguages(language: string): string[]; + regexEscape(str: string): string; + }; + init(callback?: (err: any, t: (key: string, options?: any) => string) => void ): JQueryDeferred; + init(options?: I18nextOptions, callback?: (err: any, t: (key: string, options?: any) => string) => void ): JQueryDeferred; + lng(): string; + loadNamespace(namespace: string, callback?: () => void ): void; + loadNamespaces(namespaces: string[], callback?: () => void ): void; + pluralExtensions: { + addRule(language: string, obj: { + name: string; + numbers: number[]; + plurals: (n: number) => number; + }): void; + get (language: string, count: number): number; + rules: any; + setCurrentLng: (language: string) => void; + }; + preload(language: string, callback?: (err: any, t: (key: string, options?: any) => string) => void ): void; + preload(languages: string[], callback?: (err: any, t: (key: string, options?: any) => string) => void ): void; + setDefaultNamespace(namespace: string): void; + setLng(language: string, callback?: (err: any, t: (key: string, options?: any) => string) => void ): void; + sync: { + load: (languages: string[], options: I18nextOptions, callback: (err: Error, store: IResourceStore) => void ) => void; + postMissing: (language: string, namespace: string, key: string, defaultValue: any, languages: string[]) => void; + }; + t(key: string, options?: I18nTranslateOptions): string; + translate(key: string, options?: I18nTranslateOptions): string; + exists(key: string, options?: any): boolean; + use(module: any): I18nextStatic; +} + +// jQuery extensions +interface JQueryStatic { + i18n: I18nextStatic; + t: (key: string, options?: any) => string; +} + +interface JQuery { + /* Note: options are same options as used by the translate function. Alternatively by + setting init option or translation option 'useDataAttrOptions = true' the Options + for translation will be read and cached in the elements data-i18n-options attribute. + */ + i18n: (options?: I18nextOptions) => void; +} + +declare var i18n: I18nextStatic; + +declare module 'i18next' { + export = i18n; +} + +declare module 'i18next-client' { + export = i18n; +} diff --git a/i18next/i18next-tests-2.0.17.ts b/i18next/i18next-tests-2.0.17.ts new file mode 100644 index 000000000..464811bb7 --- /dev/null +++ b/i18next/i18next-tests-2.0.17.ts @@ -0,0 +1,1379 @@ +/// +/// +/// +/// +/// +/// + +declare function done(): void; + +describe('i18next', function () { + + var i18n = $.i18n + , opts: I18nextOptions; + + beforeEach(function () { + opts = { + lng: 'en-US', + load: 'all', + fallbackLng: 'dev', + preload: [], + lowerCaseLng: false, + ns: 'translation', + resGetPath: 'locales/__lng__/__ns__.json', + dynamicLoad: false, + useLocalStorage: false, + sendMissing: false, + getAsync: true, + returnObjectTrees: false, + debug: true, + selectorAttr: 'data-i18n', + postProcess: '', + interpolationPrefix: '__', + interpolationSuffix: '__' + }; + }); + + + describe('Initialisation', function () { + + describe('with passed in resource set', function () { + + var resStore = { + dev: { translation: { 'simple_dev': 'ok_from_dev' } }, + en: { translation: { 'simple_en': 'ok_from_en' } }, + 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should provide passed in resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('loading from server', function () { + + describe('with static route', function () { + + beforeEach(function (done) { + i18n.init(opts, function (t) { done(); }); + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('with dynamic route', function () { + + beforeEach(function (done) { + + var res = { + dev: { translation: { 'simple_dev': 'ok_from_dev' } }, + en: { translation: { 'simple_en': 'ok_from_en' } }, + 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } + }; + + var server = sinon.fakeServer.create(); + server.autoRespond = true; + + server.respondWith([200, { "Content-Type": "application/json" }, JSON.stringify(res)]); + + i18n.init($.extend(opts, { + resGetPath: 'locales/resources.json?lng=__lng__&ns=__ns__', + dynamicLoad: true + }), + function (t) { server.restore(); done(); }); + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + }); + + describe('advanced initialisation options', function () { + + describe('setting load', function () { + + describe('to current', function () { + + var spy: any; + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init($.extend(opts, { + load: 'current' + }), + function (t) { done(); }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should load only current and fallback language', function () { + expect(spy.callCount).to.be(2); // en-US, en + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).not.to.be('ok_from_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('to unspecific', function () { + + var spy: any; + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init($.extend(opts, { + load: 'unspecific' + }), + function (t) { done(); }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should load only unspecific and fallback language', function () { + expect(spy.callCount).to.be(2); // en-US, en + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).not.to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_dev'); + }); + + it('it should return unspecific language', function () { + expect(i18n.lng()).to.be('en'); + }); + + }); + + }); + + describe('with fallback language set to false', function () { + + var spy: any; + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init($.extend(opts, { + fallbackLng: false + }), + function (t) { done(); }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should load only specific and unspecific languages', function () { + expect(spy.callCount).to.be(2); // en-US, en + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_en'); + expect(i18n.t('simple_dev')).not.to.be('ok_from_dev'); + }); + + }); + + describe('preloading multiple languages', function () { + + var spy: any; + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init($.extend(opts, { + preload: ['fr', 'de-DE'] + }), + function (t) { done(); }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should load additional languages', function () { + expect(spy.callCount).to.be(6); // en-US, en, de-DE, de, fr, dev + }); + + describe('changing the language', function () { + + beforeEach(function (done) { + spy.reset(); + i18n.setLng('de-DE', + function (t) { done(); }); + }); + + it('it should reload the preloaded languages', function () { + expect(spy.callCount).to.be(4); // de-DE, de, fr, dev + }); + + }); + + }); + + describe('with synchronous flag', function () { + + beforeEach(function () { + i18n.init($.extend(opts, { getAsync: false })); + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('with namespace', function () { + + describe('with one namespace set', function () { + + beforeEach(function (done) { + i18n.init($.extend(opts, { ns: 'ns.special' }), + function (t) { done(); }); + }); + + it('it should provide loaded resources for translation', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_special_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_special_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_special_dev'); + }); + + }); + + describe('with more than one namespace set', function () { + + beforeEach(function (done) { + i18n.init($.extend(opts, { ns: { namespaces: ['ns.common', 'ns.special'], defaultNs: 'ns.special' } }), + function (t) { done(); }); + }); + + it('it should provide loaded resources for translation', function () { + // default ns + expect(i18n.t('simple_en-US')).to.be('ok_from_special_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_special_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_special_dev'); + + // ns prefix + expect(i18n.t('ns.common:simple_en-US')).to.be('ok_from_common_en-US'); + expect(i18n.t('ns.common:simple_en')).to.be('ok_from_common_en'); + expect(i18n.t('ns.common:simple_dev')).to.be('ok_from_common_dev'); + + // ns in options + expect(i18n.t('simple_en-US', { ns: 'ns.common' })).to.be('ok_from_common_en-US'); + expect(i18n.t('simple_en', { ns: 'ns.common' })).to.be('ok_from_common_en'); + expect(i18n.t('simple_dev', { ns: 'ns.common' })).to.be('ok_from_common_dev'); + }); + + }); + + describe('with reloading additional namespace', function () { + + describe('without using localStorage', function () { + beforeEach(function (done) { + i18n.init(opts, + function (t) { + i18n.setDefaultNamespace('ns.special'); + i18n.loadNamespaces(['ns.common', 'ns.special'], done); + }); + }); + + it('it should provide loaded resources for translation', function () { + // default ns + expect(i18n.t('simple_en-US')).to.be('ok_from_special_en-US'); + expect(i18n.t('simple_en')).to.be('ok_from_special_en'); + expect(i18n.t('simple_dev')).to.be('ok_from_special_dev'); + + // ns prefix + expect(i18n.t('ns.common:simple_en-US')).to.be('ok_from_common_en-US'); + expect(i18n.t('ns.common:simple_en')).to.be('ok_from_common_en'); + expect(i18n.t('ns.common:simple_dev')).to.be('ok_from_common_dev'); + + // ns in options + expect(i18n.t('simple_en-US', { ns: 'ns.common' })).to.be('ok_from_common_en-US'); + expect(i18n.t('simple_en', { ns: 'ns.common' })).to.be('ok_from_common_en'); + expect(i18n.t('simple_dev', { ns: 'ns.common' })).to.be('ok_from_common_dev'); + }); + + }); + + describe('with using localStorage', function () { + + var spy: any; + + before(function () { + window.localStorage.removeItem('res_en-US'); + window.localStorage.removeItem('res_en'); + window.localStorage.removeItem('res_dev'); + }); + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init($.extend(opts, { + useLocalStorage: true + }), function (t) { + i18n.setDefaultNamespace('ns.special'); + i18n.loadNamespaces(['ns.common', 'ns.special'], done); + }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should load language', function () { + expect(spy.callCount).to.be(9); // en-US, en, de-DE, de, fr, dev * 3 namespaces (translate, common, special) + }); + + describe('on later reload of namespaces', function () { + + beforeEach(function (done) { + spy.reset(); + i18n.init($.extend(opts, { + useLocalStorage: true, + ns: 'translation' + }), function (t) { + i18n.setDefaultNamespace('ns.special'); + i18n.loadNamespaces(['ns.common', 'ns.special'], done); + }); + }); + + it('it should not reload language', function () { + expect(spy.callCount).to.be(0); + }); + + }); + + }); + + }); + + }); + + describe('using function provided in callback\'s argument', function () { + + var cbT: any; + + beforeEach(function (done) { + i18n.init(opts, function (t) { cbT = t; done(); }); + }); + + it('it should provide loaded resources for translation', function () { + expect(cbT('simple_en-US')).to.be('ok_from_en-US'); + expect(cbT('simple_en')).to.be('ok_from_en'); + expect(cbT('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('using localStorage', function () { + + var spy: any; + + before(function () { + window.localStorage.removeItem('res_en-US'); + window.localStorage.removeItem('res_en'); + window.localStorage.removeItem('res_dev'); + }); + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init($.extend(opts, { + useLocalStorage: true + }), function (t) { done(); }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should load language', function () { + expect(spy.callCount).to.be(3); // en-US, en, de-DE, de, fr, dev + }); + + describe('on later init', function () { + + beforeEach(function (done) { + spy.reset(); + i18n.init(function (t) { done(); }); + }); + + it('it should not reload language', function () { + expect(spy.callCount).to.be(0); // de-DE, de, fr, dev + }); + + describe('on later init - after caching duration', function () { + + beforeEach(function (done) { + spy.reset(); + + // exipred + var local = window.localStorage.getItem('res_en-US'); + local = JSON.parse(local); + local.i18nStamp = 0; + window.localStorage.setItem('res_en-US', JSON.stringify(local)); + + i18n.init(function (t) { done(); }); + }); + + it('it should reload language', function () { + expect(spy.callCount).to.be(1); // de-DE, de, fr, dev + }); + + }); + + }); + + }); + + describe('with lowercase flag', function () { + + describe('default behaviour will uppercase specifc country part.', function () { + + beforeEach(function () { + i18n.init($.extend(opts, { + lng: 'en-us', + resStore: { + 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } + } + }, function (t: any) { done(); })); + }); + + it('it should translate the uppercased lng value', function () { + expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); + }); + + it('it should get uppercased set language', function () { + expect(i18n.lng()).to.be('en-US'); + }); + + }); + + describe('overridden behaviour will accept lowercased country part.', function () { + + beforeEach(function () { + i18n.init($.extend(opts, { + lng: 'en-us', + lowerCaseLng: true, + resStore: { + 'en-us': { translation: { 'simple_en-us': 'ok_from_en-us' } } + } + }, function (t: any) { done(); })); + }); + + it('it should translate the lowercase lng value', function () { + expect(i18n.t('simple_en-us')).to.be('ok_from_en-us'); + }); + + it('it should get lowercased set language', function () { + expect(i18n.lng()).to.be('en-us'); + }); + + }); + + }); + + }); + + }); + describe('basic functionality', function () { + + describe('setting language', function () { + + beforeEach(function (done) { + i18n.init($.extend(opts, { + resStore: { + 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } }, + 'de-DE': { translation: { 'simpleTest': 'ok_from_de-DE' } } + } + }), function (t) { done(); }); + }); + + it('it should provide resources for set language', function (done) { + expect(i18n.t('simpleTest')).to.be('ok_from_en-US'); + + i18n.setLng('de-DE', function (t) { + expect(t('simpleTest')).to.be('ok_from_de-DE'); + done(); + }); + + }); + + }); + + describe('preloading multiple languages', function () { + + var spy: any; + + beforeEach(function (done) { + spy = sinon.spy(i18n.sync, '_fetchOne'); + i18n.init(opts, function (t) { done(); }); + }); + + afterEach(function () { + spy.restore(); + }); + + it('it should preload resources for languages', function (done) { + spy.reset(); + i18n.preload('de-DE', function (t) { + expect(spy.callCount).to.be(5); // en-US, en, de-DE, de, dev + done(); + }); + + }); + + }); + + describe('postprocessing tranlation', function () { + + describe('having a postprocessor', function () { + + before(function () { + i18n.addPostProcessor('myProcessor', function (val, key, opts) { + return 'ok_from_postprocessor'; + }); + }); + + beforeEach(function (done) { + i18n.init($.extend(opts, { + resStore: { + 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } }, + 'de-DE': { translation: { 'simpleTest': 'ok_from_de-DE' } } + } + }), function (t) { done(); }); + }); + + it('it should postprocess the translation by passing in postProcess name to t function', function () { + expect(i18n.t('simpleTest', { postProcess: 'myProcessor' })).to.be('ok_from_postprocessor'); + }); + + describe('or setting it as default on init', function () { + + beforeEach(function (done) { + i18n.init($.extend(opts, { + resStore: { + 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } }, + 'de-DE': { translation: { 'simpleTest': 'ok_from_de-DE' } } + }, + postProcess: 'myProcessor' + }), function (t) { done(); }); + }); + + it('it should postprocess the translation by default', function () { + expect(i18n.t('simpleTest')).to.be('ok_from_postprocessor'); + }); + + }); + + }); + + }); + + describe('post missing resources', function () { + + describe('to fallback', function () { + var server: any, stub: any; + + beforeEach(function (done) { + server = sinon.fakeServer.create(); + stub = sinon.stub(i18n.functions, "ajax"); + + server.respondWith([200, { "Content-Type": "text/html", "Content-Length": 2 }, "OK"]); + + i18n.init($.extend(opts, { + sendMissing: true, + resStore: { + 'en-US': { translation: {} }, + 'en': { translation: {} }, + 'dev': { translation: {} } + } + }), function (t) { done(); }); + }); + + afterEach(function () { + server.restore(); + stub.restore(); + }); + + it('it should post missing resource to server', function () { + i18n.t('missing'); + server.respond(); + expect(stub.calledOnce).to.be(true); + }); + + }); + + describe('to all', function () { + var server: any, stub: any; + + beforeEach(function (done) { + server = sinon.fakeServer.create(); + stub = sinon.stub(i18n.functions, "ajax"); + + server.respondWith([200, { "Content-Type": "text/html", "Content-Length": 2 }, "OK"]); + + i18n.init($.extend(opts, { + sendMissing: true, + sendMissingTo: 'all', + resStore: { + 'en-US': { translation: {} }, + 'en': { translation: {} }, + 'dev': { translation: {} } + } + }), function (t) { done(); }); + }); + + afterEach(function () { + server.restore(); + stub.restore(); + }); + + it('it should post missing resource for all lng to server', function () { + i18n.t('missing'); + server.respond(); + expect(stub.calledThrice).to.be(true); + }); + + }); + + }); + + describe('adding resources after initialisation', function () { + + var frResource = { 'simple_fr': 'ok_from_fr' }; + var enResource = { 'simple_en': 'ok_from_en' }; + + beforeEach(function (done) { + i18n.init({ resStore: {} }, + function (t) { done(); }); + }); + + it('it should use resources for translation added after initialisation', function () { + i18n.addResources('fr', 'translation', frResource); + i18n.addResources('en', 'translation', enResource); + expect(i18n.t('simple_fr', { lng: 'fr' })).to.be('ok_from_fr'); + expect(i18n.t('simple_en', { lng: 'en' })).to.be('ok_from_en'); + }); + + }); + }); + describe('translation functionality', function () { + + describe('key with empty string value as valid option', function () { + var resStore = { + dev: { translation: { empty: '' } }, + en: { translation: {} }, + 'en-US': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should translate correctly', function () { + expect(i18n.t('empty')).to.be(''); + }); + }); + + describe('exists functionality', function () { + var resStore = { + dev: { translation: { empty: '' } }, + en: { translation: {} }, + 'en-US': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should be able to test if a key exists', function () { + expect(i18n.exists('empty')).to.be(false); + }); + }); + + describe('resource string as array', function () { + var resStore = { + dev: { translation: { testarray: ["title", "text"] } }, + en: { translation: {} }, + 'en-US': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should translate nested value', function () { + expect(i18n.t('testarray')).to.be('title\ntext'); + }); + }); + + describe('accessing nested values', function () { + + beforeEach(function (done) { + i18n.init(opts, function (t) { done(); }); + }); + + it('it should return nested string', function () { + expect(i18n.t('test.simple_en-US')).to.be('ok_from_en-US'); + }); + + it('it should not fail silently on accessing a objectTree', function () { + expect(i18n.t('test')).to.be('key \'translation:test (en-US)\' returned a object instead of string.'); + }); + + describe('optional return an objectTree for UI components,...', function () { + + describe('with init flag', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { + translation: { + test: { res: 'added __replace__' } + } + } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { + returnObjectTrees: true, + resStore: resStore + } + ), function (t) { done(); }); + }); + + it('it should return objectTree applying options', function () { + expect(i18n.t('test', { replace: 'two' })).to.eql({ 'res': 'added two' }); + }); + + }); + + describe('with flag in options', function () { + + beforeEach(function (done) { + i18n.init($.extend(opts, { returnObjectTrees: false }), + function (t) { done(); }); + }); + + it('it should return objectTree', function () { + expect(i18n.t('test', { returnObjectTrees: true })).to.eql({ 'simple_en-US': 'ok_from_en-US' }); + }); + + }); + + }); + + }); + + describe('resource nesting', function () { + var resStore = { + dev: { translation: { nesting1: '1 $t(nesting2)' } }, + en: { translation: { nesting2: '2 $t(nesting3)' } }, + 'en-US': { translation: { nesting3: '3' } } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should translate nested value', function () { + expect(i18n.t('nesting1')).to.be('1 2 3'); + }); + + it('it should apply nested value on defaultValue', function () { + expect(i18n.t('nesting_default', { defaultValue: '0 $t(nesting1)' })).to.be('0 1 2 3'); + }); + }); + + describe('interpolation - replacing values inside a string', function () { + + describe('default i18next way', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { + translation: { + interpolationTest1: 'added __toAdd__', + interpolationTest2: 'added __toAdd__ __toAdd__ twice', + interpolationTest3: 'added __child.one__ __child.two__', + interpolationTest4: 'added __child.grandChild.three__' + } + } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should replace passed in key/values', function () { + expect(i18n.t('interpolationTest1', { toAdd: 'something' })).to.be('added something'); + expect(i18n.t('interpolationTest2', { toAdd: 'something' })).to.be('added something something twice'); + expect(i18n.t('interpolationTest3', { child: { one: '1', two: '2' } })).to.be('added 1 2'); + expect(i18n.t('interpolationTest4', { child: { grandChild: { three: '3' } } })).to.be('added 3'); + }); + + it('it should replace passed in key/values on defaultValue', function () { + expect(i18n.t('interpolationTest5', { defaultValue: 'added __toAdd__', toAdd: 'something' })).to.be('added something'); + }); + + }); + + describe('default i18next way - different prefix/suffix', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { + translation: { + interpolationTest1: 'added *toAdd*', + interpolationTest2: 'added *toAdd* *toAdd* twice', + interpolationTest3: 'added *child.one* *child.two*', + interpolationTest4: 'added *child.grandChild.three*' + } + } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { + resStore: resStore, + interpolationPrefix: '*', + interpolationSuffix: '*' + }), function (t) { done(); }); + }); + + it('it should replace passed in key/values', function () { + expect(i18n.t('interpolationTest1', { toAdd: 'something' })).to.be('added something'); + expect(i18n.t('interpolationTest2', { toAdd: 'something' })).to.be('added something something twice'); + expect(i18n.t('interpolationTest3', { child: { one: '1', two: '2' } })).to.be('added 1 2'); + expect(i18n.t('interpolationTest4', { child: { grandChild: { three: '3' } } })).to.be('added 3'); + }); + + it('it should replace passed in key/values on defaultValue', function () { + expect(i18n.t('interpolationTest5', { defaultValue: 'added *toAdd*', toAdd: 'something' })).to.be('added something'); + }); + + }); + + describe('using sprintf', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { + translation: { + interpolationTest1: 'The first 4 letters of the english alphabet are: %s, %s, %s and %s', + interpolationTest2: 'Hello %(users[0].name)s, %(users[1].name)s and %(users[2].name)s' + } + } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should replace passed in key/values', function () { + expect(i18n.t('interpolationTest1', { postProcess: 'sprintf', sprintf: ['a', 'b', 'c', 'd'] })).to.be('The first 4 letters of the english alphabet are: a, b, c and d'); + expect(i18n.t('interpolationTest2', { postProcess: 'sprintf', sprintf: { users: [{ name: 'Dolly' }, { name: 'Molly' }, { name: 'Polly' }] } })).to.be('Hello Dolly, Molly and Polly'); + }); + + }); + + }); + + describe('plural usage', function () { + + describe('basic usage - singular and plural form', function () { + var resStore = { + dev: { + 'ns.2': { + pluralTest: 'singular from ns.2', + pluralTest_plural: 'plural from ns.2', + pluralTestWithCount: '__count__ item from ns.2', + pluralTestWithCount_plural: '__count__ items from ns.2' + } + }, + en: {}, + 'en-US': { + 'ns.1': { + pluralTest: 'singular', + pluralTest_plural: 'plural', + pluralTestWithCount: '__count__ item', + pluralTestWithCount_plural: '__count__ items' + } + } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { + resStore: resStore, + ns: { namespaces: ['ns.1', 'ns.2'], defaultNs: 'ns.1' } + }), + function (t) { done(); }); + }); + + it('it should provide correct plural or singular form', function () { + expect(i18n.t('pluralTest', { count: 0 })).to.be('plural'); + expect(i18n.t('pluralTest', { count: 1 })).to.be('singular'); + expect(i18n.t('pluralTest', { count: 2 })).to.be('plural'); + expect(i18n.t('pluralTest', { count: 7 })).to.be('plural'); + + expect(i18n.t('pluralTestWithCount', { count: 0 })).to.be('0 items'); + expect(i18n.t('pluralTestWithCount', { count: 1 })).to.be('1 item'); + expect(i18n.t('pluralTestWithCount', { count: 7 })).to.be('7 items'); + }); + + it('it should provide correct plural or singular form for second namespace', function () { + expect(i18n.t('ns.2:pluralTest', { count: 0 })).to.be('plural from ns.2'); + expect(i18n.t('ns.2:pluralTest', { count: 1 })).to.be('singular from ns.2'); + expect(i18n.t('ns.2:pluralTest', { count: 2 })).to.be('plural from ns.2'); + expect(i18n.t('ns.2:pluralTest', { count: 7 })).to.be('plural from ns.2'); + + expect(i18n.t('ns.2:pluralTestWithCount', { count: 1 })).to.be('1 item from ns.2'); + expect(i18n.t('ns.2:pluralTestWithCount', { count: 7 })).to.be('7 items from ns.2'); + }); + }); + + describe('basic usage 2 - singular and plural form in french', function () { + var resStore = { + dev: { + 'ns.2': { + pluralTest: 'singular from ns.2', + pluralTest_plural: 'plural from ns.2', + pluralTestWithCount: '__count__ item from ns.2', + pluralTestWithCount_plural: '__count__ items from ns.2' + } + }, + en: {}, + 'fr': { + 'ns.1': { + pluralTest: 'singular', + pluralTest_plural: 'plural', + pluralTestWithCount: '__count__ item', + pluralTestWithCount_plural: '__count__ items' + } + } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { + lng: 'fr', + resStore: resStore, + ns: { namespaces: ['ns.1', 'ns.2'], defaultNs: 'ns.1' } + }), + function (t) { done(); }); + }); + + it('it should provide correct plural or singular form', function () { + expect(i18n.t('pluralTest', { count: 0 })).to.be('singular'); + expect(i18n.t('pluralTest', { count: 1 })).to.be('singular'); + expect(i18n.t('pluralTest', { count: 2 })).to.be('plural'); + expect(i18n.t('pluralTest', { count: 7 })).to.be('plural'); + + expect(i18n.t('pluralTestWithCount', { count: 0 })).to.be('0 item'); + expect(i18n.t('pluralTestWithCount', { count: 1 })).to.be('1 item'); + expect(i18n.t('pluralTestWithCount', { count: 7 })).to.be('7 items'); + }); + }); + + describe('extended usage - multiple plural forms - ar', function () { + var resStore = { + dev: { translation: {} }, + ar: { + translation: { + key: 'singular', + key_plural_0: 'zero', + key_plural_2: 'two', + key_plural_3: 'few', + key_plural_11: 'many', + key_plural_100: 'plural' + } + }, + 'ar-??': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { lng: 'ar', resStore: resStore }), + function (t) { done(); }); + }); + + it('it should provide correct plural forms', function () { + expect(i18n.t('key', { count: 0 })).to.be('zero'); + expect(i18n.t('key', { count: 1 })).to.be('singular'); + expect(i18n.t('key', { count: 2 })).to.be('two'); + expect(i18n.t('key', { count: 3 })).to.be('few'); + expect(i18n.t('key', { count: 4 })).to.be('few'); + expect(i18n.t('key', { count: 104 })).to.be('few'); + expect(i18n.t('key', { count: 11 })).to.be('many'); + expect(i18n.t('key', { count: 99 })).to.be('many'); + expect(i18n.t('key', { count: 199 })).to.be('many'); + expect(i18n.t('key', { count: 100 })).to.be('plural'); + }); + }); + + describe('extended usage - multiple plural forms - ru', function () { + var resStore = { + dev: { translation: {} }, + ru: { + translation: { + key: '1,21,31', + key_plural_2: '2,3,4', + key_plural_5: '0,5,6' + } + }, + 'ru-??': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { lng: 'ru', resStore: resStore }), + function (t) { done(); }); + }); + + it('it should provide correct plural forms', function () { + expect(i18n.t('key', { count: 0 })).to.be('0,5,6'); + expect(i18n.t('key', { count: 1 })).to.be('1,21,31'); + expect(i18n.t('key', { count: 2 })).to.be('2,3,4'); + expect(i18n.t('key', { count: 3 })).to.be('2,3,4'); + expect(i18n.t('key', { count: 4 })).to.be('2,3,4'); + expect(i18n.t('key', { count: 104 })).to.be('2,3,4'); + expect(i18n.t('key', { count: 11 })).to.be('0,5,6'); + expect(i18n.t('key', { count: 24 })).to.be('2,3,4'); + expect(i18n.t('key', { count: 25 })).to.be('0,5,6'); + expect(i18n.t('key', { count: 99 })).to.be('0,5,6'); + expect(i18n.t('key', { count: 199 })).to.be('0,5,6'); + expect(i18n.t('key', { count: 100 })).to.be('0,5,6'); + }); + }); + + }); + + describe('context usage', function () { + + describe('basic usage', function () { + var resStore = { + dev: { + 'ns.2': { + friend_context: 'A friend from ns2', + friend_context_male: 'A boyfriend from ns2', + friend_context_female: 'A girlfriend from ns2' + } + }, + en: { + 'ns.1': { + friend_context: 'A friend', + friend_context_male: 'A boyfriend', + friend_context_female: 'A girlfriend' + } + }, + 'en-US': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { + resStore: resStore, + ns: { namespaces: ['ns.1', 'ns.2'], defaultNs: 'ns.1' } + }), + function (t) { done(); }); + }); + + it('it should provide correct context form', function () { + expect(i18n.t('friend_context')).to.be('A friend'); + expect(i18n.t('friend_context', { context: '' })).to.be('A friend'); + expect(i18n.t('friend_context', { context: 'male' })).to.be('A boyfriend'); + expect(i18n.t('friend_context', { context: 'female' })).to.be('A girlfriend'); + }); + + it('it should provide correct context form for second namespace', function () { + expect(i18n.t('ns.2:friend_context')).to.be('A friend from ns2'); + expect(i18n.t('ns.2:friend_context', { context: '' })).to.be('A friend from ns2'); + expect(i18n.t('ns.2:friend_context', { context: 'male' })).to.be('A boyfriend from ns2'); + expect(i18n.t('ns.2:friend_context', { context: 'female' })).to.be('A girlfriend from ns2'); + }); + }); + + describe('extended usage - in combination with plurals', function () { + var resStore = { + dev: { translation: {} }, + en: { + translation: { + friend_context: '__count__ friend', + friend_context_male: '__count__ boyfriend', + friend_context_female: '__count__ girlfriend', + friend_context_plural: '__count__ friends', + friend_context_male_plural: '__count__ boyfriends', + friend_context_female_plural: '__count__ girlfriends' + } + }, + 'en-US': { translation: {} } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should provide correct context with plural forms', function () { + expect(i18n.t('friend_context', { count: 1 })).to.be('1 friend'); + expect(i18n.t('friend_context', { context: '', count: 1 })).to.be('1 friend'); + expect(i18n.t('friend_context', { context: 'male', count: 1 })).to.be('1 boyfriend'); + expect(i18n.t('friend_context', { context: 'female', count: 1 })).to.be('1 girlfriend'); + + expect(i18n.t('friend_context', { count: 10 })).to.be('10 friends'); + expect(i18n.t('friend_context', { context: '', count: 10 })).to.be('10 friends'); + expect(i18n.t('friend_context', { context: 'male', count: 10 })).to.be('10 boyfriends'); + expect(i18n.t('friend_context', { context: 'female', count: 10 })).to.be('10 girlfriends'); + }); + + }); + + }); + + describe('with passed in languages different from set one', function () { + + beforeEach(function (done) { + i18n.init($.extend(opts, { + preload: ['de-DE'] + }), + function (t) { done(); }); + }); + + it('it should provide translation for passed in language', function () { + expect(i18n.t('simple_de', { lng: 'de-DE' })).to.be('ok_from_de'); + }); + + describe('with language not preloaded', function () { + + it('it should provide translation for passed in language after loading file sync', function () { + expect(i18n.t('simple_fr', { lng: 'fr' })).to.be('ok_from_fr'); + }); + + }); + + }); + + }); + + describe('jQuery integration / specials', function () { + + describe('initialise - use deferrer instead of callback', function () { + + describe('with passed in resource set', function () { + + var resStore = { + dev: { translation: { 'simple_dev': 'ok_from_dev' } }, + en: { translation: { 'simple_en': 'ok_from_en' } }, + 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } + }; + + beforeEach(function (done) { + i18n.init($.extend(opts, { resStore: resStore })).done(function (t: any) { done(); }); + }); + + it('it should provide passed in resources for translation', function () { + expect($.t('simple_en-US')).to.be('ok_from_en-US'); + expect($.t('simple_en')).to.be('ok_from_en'); + expect($.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('loading from server', function () { + + beforeEach(function (done) { + i18n.init(opts).done(function () { done(); }); + }); + + it('it should provide loaded resources for translation', function () { + expect($.t('simple_en-US')).to.be('ok_from_en-US'); + expect($.t('simple_en')).to.be('ok_from_en'); + expect($.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + }); + + describe('use translation function shortcut $.t', function () { + + beforeEach(function (done) { + i18n.init(opts, function (t) { done(); }); + }); + + it('it should provide translation via $.t', function () { + expect($.t('simple_en-US')).to.be('ok_from_en-US'); + expect($.t('simple_en')).to.be('ok_from_en'); + expect($.t('simple_dev')).to.be('ok_from_dev'); + }); + + }); + + describe('using bindings $([selector].i18n())', function () { + + describe('basic - setting text', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } } + }; + + beforeEach(function (done) { + fixtures.set(''); + + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should set text of elements inside selector having data-i18n attribute', function () { + $('#container').i18n(); + expect($('#testBtn').text()).to.be('ok_from_en-US'); + }); + + it('it should set text of element itself if having data-i18n attribute', function () { + $('#testBtn').i18n(); + expect($('#testBtn').text()).to.be('ok_from_en-US'); + }); + + }); + + describe('extended - setting other attributes', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } } + }; + + beforeEach(function (done) { + fixtures.set(''); + + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should set text of elements inside selector having data-i18n attribute', function () { + $('#container').i18n(); + expect($('#testBtn').text()).to.be('ok_from_en-US'); + }); + + it('it should set attributes of elements inside selector having data-i18n attribute', function () { + $('#container').i18n(); + expect($('#testBtn').attr('title')).to.be('ok_from_en-US'); + }); + + }); + + describe('extended - pass in options', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { translation: { 'simpleTest': '__replace__ ok_from_en-US' } } + }; + + beforeEach(function (done) { + fixtures.set(''); + + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should set text with passed in options', function () { + $('#container').i18n({ replace: 'replaced' }); + expect($('#testBtn').text()).to.be('replaced ok_from_en-US'); + }); + + }); + + describe('extended - render inner html', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { translation: { 'simpleTest': 'test' } } + }; + + beforeEach(function (done) { + fixtures.set(''); + + i18n.init($.extend(opts, { resStore: resStore }), + function (t) { done(); }); + }); + + it('it should set inner html', function () { + $('#container').i18n(); + expect($('#inner').html()).to.be('test'); + }); + + }); + + + describe('extended - read options from data attribute', function () { + + var resStore = { + dev: { translation: {} }, + en: { translation: {} }, + 'en-US': { translation: { 'simpleTest': '__replace__ ok_from_en-US' } } + }; + + beforeEach(function (done) { + fixtures.set(''); + + i18n.init($.extend(opts, { + resStore: resStore, + useDataAttrOptions: true + }), + function (t) { + $('#container').i18n({ replace: 'replaced' }); + $('#testBtn').text(''); + done(); + }); + }); + + it('it should set text with attributes options', function () { + $('#container').i18n(); // without option + expect($('#testBtn').text()).to.be('replaced ok_from_en-US'); + }); + + }); + + }); + + }); + + +}); diff --git a/i18next/i18next-tests.ts b/i18next/i18next-tests.ts index c1d1d147c..e46a9ed5b 100644 --- a/i18next/i18next-tests.ts +++ b/i18next/i18next-tests.ts @@ -5,1375 +5,60 @@ /// /// -declare function done(): void; - -describe('i18next', function () { - - var i18n = $.i18n - , opts: I18nextOptions; - - beforeEach(function () { - opts = { - lng: 'en-US', - load: 'all', - fallbackLng: 'dev', - preload: [], - lowerCaseLng: false, - ns: 'translation', - resGetPath: 'locales/__lng__/__ns__.json', - dynamicLoad: false, - useLocalStorage: false, - sendMissing: false, - getAsync: true, - returnObjectTrees: false, - debug: true, - selectorAttr: 'data-i18n', - postProcess: '', - interpolationPrefix: '__', - interpolationSuffix: '__' - }; - }); - - - describe('Initialisation', function () { - - describe('with passed in resource set', function () { - - var resStore = { - dev: { translation: { 'simple_dev': 'ok_from_dev' } }, - en: { translation: { 'simple_en': 'ok_from_en' } }, - 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should provide passed in resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('loading from server', function () { - - describe('with static route', function () { - - beforeEach(function (done) { - i18n.init(opts, function (t) { done(); }); - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('with dynamic route', function () { - - beforeEach(function (done) { - - var res = { - dev: { translation: { 'simple_dev': 'ok_from_dev' } }, - en: { translation: { 'simple_en': 'ok_from_en' } }, - 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } - }; - - var server = sinon.fakeServer.create(); - server.autoRespond = true; - - server.respondWith([200, { "Content-Type": "application/json" }, JSON.stringify(res)]); - - i18n.init($.extend(opts, { - resGetPath: 'locales/resources.json?lng=__lng__&ns=__ns__', - dynamicLoad: true - }), - function (t) { server.restore(); done(); }); - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - }); - - describe('advanced initialisation options', function () { - - describe('setting load', function () { - - describe('to current', function () { - - var spy: any; - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init($.extend(opts, { - load: 'current' - }), - function (t) { done(); }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should load only current and fallback language', function () { - expect(spy.callCount).to.be(2); // en-US, en - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).not.to.be('ok_from_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('to unspecific', function () { - - var spy: any; - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init($.extend(opts, { - load: 'unspecific' - }), - function (t) { done(); }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should load only unspecific and fallback language', function () { - expect(spy.callCount).to.be(2); // en-US, en - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).not.to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_dev'); - }); - - it('it should return unspecific language', function () { - expect(i18n.lng()).to.be('en'); - }); - - }); - - }); - - describe('with fallback language set to false', function () { - - var spy: any; - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init($.extend(opts, { - fallbackLng: false - }), - function (t) { done(); }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should load only specific and unspecific languages', function () { - expect(spy.callCount).to.be(2); // en-US, en - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_en'); - expect(i18n.t('simple_dev')).not.to.be('ok_from_dev'); - }); - - }); - - describe('preloading multiple languages', function () { - - var spy: any; - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init($.extend(opts, { - preload: ['fr', 'de-DE'] - }), - function (t) { done(); }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should load additional languages', function () { - expect(spy.callCount).to.be(6); // en-US, en, de-DE, de, fr, dev - }); - - describe('changing the language', function () { - - beforeEach(function (done) { - spy.reset(); - i18n.setLng('de-DE', - function (t) { done(); }); - }); - - it('it should reload the preloaded languages', function () { - expect(spy.callCount).to.be(4); // de-DE, de, fr, dev - }); - - }); - - }); - - describe('with synchronous flag', function () { - - beforeEach(function () { - i18n.init($.extend(opts, { getAsync: false })); - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('with namespace', function () { - - describe('with one namespace set', function () { - - beforeEach(function (done) { - i18n.init($.extend(opts, { ns: 'ns.special' }), - function (t) { done(); }); - }); - - it('it should provide loaded resources for translation', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_special_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_special_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_special_dev'); - }); - - }); - - describe('with more than one namespace set', function () { - - beforeEach(function (done) { - i18n.init($.extend(opts, { ns: { namespaces: ['ns.common', 'ns.special'], defaultNs: 'ns.special' } }), - function (t) { done(); }); - }); - - it('it should provide loaded resources for translation', function () { - // default ns - expect(i18n.t('simple_en-US')).to.be('ok_from_special_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_special_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_special_dev'); - - // ns prefix - expect(i18n.t('ns.common:simple_en-US')).to.be('ok_from_common_en-US'); - expect(i18n.t('ns.common:simple_en')).to.be('ok_from_common_en'); - expect(i18n.t('ns.common:simple_dev')).to.be('ok_from_common_dev'); - - // ns in options - expect(i18n.t('simple_en-US', { ns: 'ns.common' })).to.be('ok_from_common_en-US'); - expect(i18n.t('simple_en', { ns: 'ns.common' })).to.be('ok_from_common_en'); - expect(i18n.t('simple_dev', { ns: 'ns.common' })).to.be('ok_from_common_dev'); - }); - - }); - - describe('with reloading additional namespace', function () { - - describe('without using localStorage', function () { - beforeEach(function (done) { - i18n.init(opts, - function (t) { - i18n.setDefaultNamespace('ns.special'); - i18n.loadNamespaces(['ns.common', 'ns.special'], done); - }); - }); - - it('it should provide loaded resources for translation', function () { - // default ns - expect(i18n.t('simple_en-US')).to.be('ok_from_special_en-US'); - expect(i18n.t('simple_en')).to.be('ok_from_special_en'); - expect(i18n.t('simple_dev')).to.be('ok_from_special_dev'); - - // ns prefix - expect(i18n.t('ns.common:simple_en-US')).to.be('ok_from_common_en-US'); - expect(i18n.t('ns.common:simple_en')).to.be('ok_from_common_en'); - expect(i18n.t('ns.common:simple_dev')).to.be('ok_from_common_dev'); - - // ns in options - expect(i18n.t('simple_en-US', { ns: 'ns.common' })).to.be('ok_from_common_en-US'); - expect(i18n.t('simple_en', { ns: 'ns.common' })).to.be('ok_from_common_en'); - expect(i18n.t('simple_dev', { ns: 'ns.common' })).to.be('ok_from_common_dev'); - }); - - }); - - describe('with using localStorage', function () { - - var spy: any; - - before(function () { - window.localStorage.removeItem('res_en-US'); - window.localStorage.removeItem('res_en'); - window.localStorage.removeItem('res_dev'); - }); - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init($.extend(opts, { - useLocalStorage: true - }), function (t) { - i18n.setDefaultNamespace('ns.special'); - i18n.loadNamespaces(['ns.common', 'ns.special'], done); - }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should load language', function () { - expect(spy.callCount).to.be(9); // en-US, en, de-DE, de, fr, dev * 3 namespaces (translate, common, special) - }); - - describe('on later reload of namespaces', function () { - - beforeEach(function (done) { - spy.reset(); - i18n.init($.extend(opts, { - useLocalStorage: true, - ns: 'translation' - }), function (t) { - i18n.setDefaultNamespace('ns.special'); - i18n.loadNamespaces(['ns.common', 'ns.special'], done); - }); - }); - - it('it should not reload language', function () { - expect(spy.callCount).to.be(0); - }); - - }); - - }); - - }); - - }); - - describe('using function provided in callback\'s argument', function () { - - var cbT: any; - - beforeEach(function (done) { - i18n.init(opts, function (t) { cbT = t; done(); }); - }); - - it('it should provide loaded resources for translation', function () { - expect(cbT('simple_en-US')).to.be('ok_from_en-US'); - expect(cbT('simple_en')).to.be('ok_from_en'); - expect(cbT('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('using localStorage', function () { - - var spy: any; - - before(function () { - window.localStorage.removeItem('res_en-US'); - window.localStorage.removeItem('res_en'); - window.localStorage.removeItem('res_dev'); - }); - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init($.extend(opts, { - useLocalStorage: true - }), function (t) { done(); }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should load language', function () { - expect(spy.callCount).to.be(3); // en-US, en, de-DE, de, fr, dev - }); - - describe('on later init', function () { - - beforeEach(function (done) { - spy.reset(); - i18n.init(function (t) { done(); }); - }); - - it('it should not reload language', function () { - expect(spy.callCount).to.be(0); // de-DE, de, fr, dev - }); - - describe('on later init - after caching duration', function () { - - beforeEach(function (done) { - spy.reset(); - - // exipred - var local = window.localStorage.getItem('res_en-US'); - local = JSON.parse(local); - local.i18nStamp = 0; - window.localStorage.setItem('res_en-US', JSON.stringify(local)); - - i18n.init(function (t) { done(); }); - }); - - it('it should reload language', function () { - expect(spy.callCount).to.be(1); // de-DE, de, fr, dev - }); - - }); - - }); - - }); - - describe('with lowercase flag', function () { - - describe('default behaviour will uppercase specifc country part.', function () { - - beforeEach(function () { - i18n.init($.extend(opts, { - lng: 'en-us', - resStore: { - 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } - } - }, function (t: any) { done(); })); - }); - - it('it should translate the uppercased lng value', function () { - expect(i18n.t('simple_en-US')).to.be('ok_from_en-US'); - }); - - it('it should get uppercased set language', function () { - expect(i18n.lng()).to.be('en-US'); - }); - - }); - - describe('overridden behaviour will accept lowercased country part.', function () { - - beforeEach(function () { - i18n.init($.extend(opts, { - lng: 'en-us', - lowerCaseLng: true, - resStore: { - 'en-us': { translation: { 'simple_en-us': 'ok_from_en-us' } } - } - }, function (t: any) { done(); })); - }); - - it('it should translate the lowercase lng value', function () { - expect(i18n.t('simple_en-us')).to.be('ok_from_en-us'); - }); - - it('it should get lowercased set language', function () { - expect(i18n.lng()).to.be('en-us'); - }); - - }); - - }); - - }); - - }); - describe('basic functionality', function () { - - describe('setting language', function () { - - beforeEach(function (done) { - i18n.init($.extend(opts, { - resStore: { - 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } }, - 'de-DE': { translation: { 'simpleTest': 'ok_from_de-DE' } } - } - }), function (t) { done(); }); - }); - - it('it should provide resources for set language', function (done) { - expect(i18n.t('simpleTest')).to.be('ok_from_en-US'); - - i18n.setLng('de-DE', function (t) { - expect(t('simpleTest')).to.be('ok_from_de-DE'); - done(); - }); - - }); - - }); - - describe('preloading multiple languages', function () { - - var spy: any; - - beforeEach(function (done) { - spy = sinon.spy(i18n.sync, '_fetchOne'); - i18n.init(opts, function (t) { done(); }); - }); - - afterEach(function () { - spy.restore(); - }); - - it('it should preload resources for languages', function (done) { - spy.reset(); - i18n.preload('de-DE', function (t) { - expect(spy.callCount).to.be(5); // en-US, en, de-DE, de, dev - done(); - }); - - }); - - }); - - describe('postprocessing tranlation', function () { - - describe('having a postprocessor', function () { - - before(function () { - i18n.addPostProcessor('myProcessor', function (val, key, opts) { - return 'ok_from_postprocessor'; - }); - }); - - beforeEach(function (done) { - i18n.init($.extend(opts, { - resStore: { - 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } }, - 'de-DE': { translation: { 'simpleTest': 'ok_from_de-DE' } } - } - }), function (t) { done(); }); - }); - - it('it should postprocess the translation by passing in postProcess name to t function', function () { - expect(i18n.t('simpleTest', { postProcess: 'myProcessor' })).to.be('ok_from_postprocessor'); - }); - - describe('or setting it as default on init', function () { - - beforeEach(function (done) { - i18n.init($.extend(opts, { - resStore: { - 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } }, - 'de-DE': { translation: { 'simpleTest': 'ok_from_de-DE' } } - }, - postProcess: 'myProcessor' - }), function (t) { done(); }); - }); - - it('it should postprocess the translation by default', function () { - expect(i18n.t('simpleTest')).to.be('ok_from_postprocessor'); - }); - - }); - - }); - - }); - - describe('post missing resources', function () { - - describe('to fallback', function () { - var server: any, stub: any; - - beforeEach(function (done) { - server = sinon.fakeServer.create(); - stub = sinon.stub(i18n.functions, "ajax"); - - server.respondWith([200, { "Content-Type": "text/html", "Content-Length": 2 }, "OK"]); - - i18n.init($.extend(opts, { - sendMissing: true, - resStore: { - 'en-US': { translation: {} }, - 'en': { translation: {} }, - 'dev': { translation: {} } - } - }), function (t) { done(); }); - }); - - afterEach(function () { - server.restore(); - stub.restore(); - }); - - it('it should post missing resource to server', function () { - i18n.t('missing'); - server.respond(); - expect(stub.calledOnce).to.be(true); - }); - - }); - - describe('to all', function () { - var server: any, stub: any; - - beforeEach(function (done) { - server = sinon.fakeServer.create(); - stub = sinon.stub(i18n.functions, "ajax"); - - server.respondWith([200, { "Content-Type": "text/html", "Content-Length": 2 }, "OK"]); - - i18n.init($.extend(opts, { - sendMissing: true, - sendMissingTo: 'all', - resStore: { - 'en-US': { translation: {} }, - 'en': { translation: {} }, - 'dev': { translation: {} } - } - }), function (t) { done(); }); - }); - - afterEach(function () { - server.restore(); - stub.restore(); - }); - - it('it should post missing resource for all lng to server', function () { - i18n.t('missing'); - server.respond(); - expect(stub.calledThrice).to.be(true); - }); - - }); - - }); - - describe('adding resources after initialisation', function () { - - var frResource = { 'simple_fr': 'ok_from_fr' }; - var enResource = { 'simple_en': 'ok_from_en' }; - - beforeEach(function (done) { - i18n.init({ resStore: {} }, - function (t) { done(); }); - }); - - it('it should use resources for translation added after initialisation', function () { - i18n.addResources('fr', 'translation', frResource); - i18n.addResources('en', 'translation', enResource); - expect(i18n.t('simple_fr', { lng: 'fr' })).to.be('ok_from_fr'); - expect(i18n.t('simple_en', { lng: 'en' })).to.be('ok_from_en'); - }); - - }); - }); - describe('translation functionality', function () { - - describe('key with empty string value as valid option', function () { - var resStore = { - dev: { translation: { empty: '' } }, - en: { translation: {} }, - 'en-US': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should translate correctly', function () { - expect(i18n.t('empty')).to.be(''); - }); - }); - - describe('exists functionality', function () { - var resStore = { - dev: { translation: { empty: '' } }, - en: { translation: {} }, - 'en-US': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should be able to test if a key exists', function () { - expect(i18n.exists('empty')).to.be(false); - }); - }); - - describe('resource string as array', function () { - var resStore = { - dev: { translation: { testarray: ["title", "text"] } }, - en: { translation: {} }, - 'en-US': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should translate nested value', function () { - expect(i18n.t('testarray')).to.be('title\ntext'); - }); - }); - - describe('accessing nested values', function () { - - beforeEach(function (done) { - i18n.init(opts, function (t) { done(); }); - }); - - it('it should return nested string', function () { - expect(i18n.t('test.simple_en-US')).to.be('ok_from_en-US'); - }); - - it('it should not fail silently on accessing a objectTree', function () { - expect(i18n.t('test')).to.be('key \'translation:test (en-US)\' returned a object instead of string.'); - }); - - describe('optional return an objectTree for UI components,...', function () { - - describe('with init flag', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { - translation: { - test: { res: 'added __replace__' } - } - } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { - returnObjectTrees: true, - resStore: resStore - } - ), function (t) { done(); }); - }); - - it('it should return objectTree applying options', function () { - expect(i18n.t('test', { replace: 'two' })).to.eql({ 'res': 'added two' }); - }); - - }); - - describe('with flag in options', function () { - - beforeEach(function (done) { - i18n.init($.extend(opts, { returnObjectTrees: false }), - function (t) { done(); }); - }); - - it('it should return objectTree', function () { - expect(i18n.t('test', { returnObjectTrees: true })).to.eql({ 'simple_en-US': 'ok_from_en-US' }); - }); - - }); - - }); - - }); - - describe('resource nesting', function () { - var resStore = { - dev: { translation: { nesting1: '1 $t(nesting2)' } }, - en: { translation: { nesting2: '2 $t(nesting3)' } }, - 'en-US': { translation: { nesting3: '3' } } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should translate nested value', function () { - expect(i18n.t('nesting1')).to.be('1 2 3'); - }); - - it('it should apply nested value on defaultValue', function () { - expect(i18n.t('nesting_default', { defaultValue: '0 $t(nesting1)' })).to.be('0 1 2 3'); - }); - }); - - describe('interpolation - replacing values inside a string', function () { - - describe('default i18next way', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { - translation: { - interpolationTest1: 'added __toAdd__', - interpolationTest2: 'added __toAdd__ __toAdd__ twice', - interpolationTest3: 'added __child.one__ __child.two__', - interpolationTest4: 'added __child.grandChild.three__' - } - } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should replace passed in key/values', function () { - expect(i18n.t('interpolationTest1', { toAdd: 'something' })).to.be('added something'); - expect(i18n.t('interpolationTest2', { toAdd: 'something' })).to.be('added something something twice'); - expect(i18n.t('interpolationTest3', { child: { one: '1', two: '2' } })).to.be('added 1 2'); - expect(i18n.t('interpolationTest4', { child: { grandChild: { three: '3' } } })).to.be('added 3'); - }); - - it('it should replace passed in key/values on defaultValue', function () { - expect(i18n.t('interpolationTest5', { defaultValue: 'added __toAdd__', toAdd: 'something' })).to.be('added something'); - }); - - }); - - describe('default i18next way - different prefix/suffix', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { - translation: { - interpolationTest1: 'added *toAdd*', - interpolationTest2: 'added *toAdd* *toAdd* twice', - interpolationTest3: 'added *child.one* *child.two*', - interpolationTest4: 'added *child.grandChild.three*' - } - } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { - resStore: resStore, - interpolationPrefix: '*', - interpolationSuffix: '*' - }), function (t) { done(); }); - }); - - it('it should replace passed in key/values', function () { - expect(i18n.t('interpolationTest1', { toAdd: 'something' })).to.be('added something'); - expect(i18n.t('interpolationTest2', { toAdd: 'something' })).to.be('added something something twice'); - expect(i18n.t('interpolationTest3', { child: { one: '1', two: '2' } })).to.be('added 1 2'); - expect(i18n.t('interpolationTest4', { child: { grandChild: { three: '3' } } })).to.be('added 3'); - }); - - it('it should replace passed in key/values on defaultValue', function () { - expect(i18n.t('interpolationTest5', { defaultValue: 'added *toAdd*', toAdd: 'something' })).to.be('added something'); - }); - - }); - - describe('using sprintf', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { - translation: { - interpolationTest1: 'The first 4 letters of the english alphabet are: %s, %s, %s and %s', - interpolationTest2: 'Hello %(users[0].name)s, %(users[1].name)s and %(users[2].name)s' - } - } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should replace passed in key/values', function () { - expect(i18n.t('interpolationTest1', { postProcess: 'sprintf', sprintf: ['a', 'b', 'c', 'd'] })).to.be('The first 4 letters of the english alphabet are: a, b, c and d'); - expect(i18n.t('interpolationTest2', { postProcess: 'sprintf', sprintf: { users: [{ name: 'Dolly' }, { name: 'Molly' }, { name: 'Polly' }] } })).to.be('Hello Dolly, Molly and Polly'); - }); - - }); - - }); - - describe('plural usage', function () { - - describe('basic usage - singular and plural form', function () { - var resStore = { - dev: { - 'ns.2': { - pluralTest: 'singular from ns.2', - pluralTest_plural: 'plural from ns.2', - pluralTestWithCount: '__count__ item from ns.2', - pluralTestWithCount_plural: '__count__ items from ns.2' - } - }, - en: {}, - 'en-US': { - 'ns.1': { - pluralTest: 'singular', - pluralTest_plural: 'plural', - pluralTestWithCount: '__count__ item', - pluralTestWithCount_plural: '__count__ items' - } - } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { - resStore: resStore, - ns: { namespaces: ['ns.1', 'ns.2'], defaultNs: 'ns.1' } - }), - function (t) { done(); }); - }); - - it('it should provide correct plural or singular form', function () { - expect(i18n.t('pluralTest', { count: 0 })).to.be('plural'); - expect(i18n.t('pluralTest', { count: 1 })).to.be('singular'); - expect(i18n.t('pluralTest', { count: 2 })).to.be('plural'); - expect(i18n.t('pluralTest', { count: 7 })).to.be('plural'); - - expect(i18n.t('pluralTestWithCount', { count: 0 })).to.be('0 items'); - expect(i18n.t('pluralTestWithCount', { count: 1 })).to.be('1 item'); - expect(i18n.t('pluralTestWithCount', { count: 7 })).to.be('7 items'); - }); - - it('it should provide correct plural or singular form for second namespace', function () { - expect(i18n.t('ns.2:pluralTest', { count: 0 })).to.be('plural from ns.2'); - expect(i18n.t('ns.2:pluralTest', { count: 1 })).to.be('singular from ns.2'); - expect(i18n.t('ns.2:pluralTest', { count: 2 })).to.be('plural from ns.2'); - expect(i18n.t('ns.2:pluralTest', { count: 7 })).to.be('plural from ns.2'); - - expect(i18n.t('ns.2:pluralTestWithCount', { count: 1 })).to.be('1 item from ns.2'); - expect(i18n.t('ns.2:pluralTestWithCount', { count: 7 })).to.be('7 items from ns.2'); - }); - }); - - describe('basic usage 2 - singular and plural form in french', function () { - var resStore = { - dev: { - 'ns.2': { - pluralTest: 'singular from ns.2', - pluralTest_plural: 'plural from ns.2', - pluralTestWithCount: '__count__ item from ns.2', - pluralTestWithCount_plural: '__count__ items from ns.2' - } - }, - en: {}, - 'fr': { - 'ns.1': { - pluralTest: 'singular', - pluralTest_plural: 'plural', - pluralTestWithCount: '__count__ item', - pluralTestWithCount_plural: '__count__ items' - } - } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { - lng: 'fr', - resStore: resStore, - ns: { namespaces: ['ns.1', 'ns.2'], defaultNs: 'ns.1' } - }), - function (t) { done(); }); - }); - - it('it should provide correct plural or singular form', function () { - expect(i18n.t('pluralTest', { count: 0 })).to.be('singular'); - expect(i18n.t('pluralTest', { count: 1 })).to.be('singular'); - expect(i18n.t('pluralTest', { count: 2 })).to.be('plural'); - expect(i18n.t('pluralTest', { count: 7 })).to.be('plural'); - - expect(i18n.t('pluralTestWithCount', { count: 0 })).to.be('0 item'); - expect(i18n.t('pluralTestWithCount', { count: 1 })).to.be('1 item'); - expect(i18n.t('pluralTestWithCount', { count: 7 })).to.be('7 items'); - }); - }); - - describe('extended usage - multiple plural forms - ar', function () { - var resStore = { - dev: { translation: {} }, - ar: { - translation: { - key: 'singular', - key_plural_0: 'zero', - key_plural_2: 'two', - key_plural_3: 'few', - key_plural_11: 'many', - key_plural_100: 'plural' - } - }, - 'ar-??': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { lng: 'ar', resStore: resStore }), - function (t) { done(); }); - }); - - it('it should provide correct plural forms', function () { - expect(i18n.t('key', { count: 0 })).to.be('zero'); - expect(i18n.t('key', { count: 1 })).to.be('singular'); - expect(i18n.t('key', { count: 2 })).to.be('two'); - expect(i18n.t('key', { count: 3 })).to.be('few'); - expect(i18n.t('key', { count: 4 })).to.be('few'); - expect(i18n.t('key', { count: 104 })).to.be('few'); - expect(i18n.t('key', { count: 11 })).to.be('many'); - expect(i18n.t('key', { count: 99 })).to.be('many'); - expect(i18n.t('key', { count: 199 })).to.be('many'); - expect(i18n.t('key', { count: 100 })).to.be('plural'); - }); - }); - - describe('extended usage - multiple plural forms - ru', function () { - var resStore = { - dev: { translation: {} }, - ru: { - translation: { - key: '1,21,31', - key_plural_2: '2,3,4', - key_plural_5: '0,5,6' - } - }, - 'ru-??': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { lng: 'ru', resStore: resStore }), - function (t) { done(); }); - }); - - it('it should provide correct plural forms', function () { - expect(i18n.t('key', { count: 0 })).to.be('0,5,6'); - expect(i18n.t('key', { count: 1 })).to.be('1,21,31'); - expect(i18n.t('key', { count: 2 })).to.be('2,3,4'); - expect(i18n.t('key', { count: 3 })).to.be('2,3,4'); - expect(i18n.t('key', { count: 4 })).to.be('2,3,4'); - expect(i18n.t('key', { count: 104 })).to.be('2,3,4'); - expect(i18n.t('key', { count: 11 })).to.be('0,5,6'); - expect(i18n.t('key', { count: 24 })).to.be('2,3,4'); - expect(i18n.t('key', { count: 25 })).to.be('0,5,6'); - expect(i18n.t('key', { count: 99 })).to.be('0,5,6'); - expect(i18n.t('key', { count: 199 })).to.be('0,5,6'); - expect(i18n.t('key', { count: 100 })).to.be('0,5,6'); - }); - }); - - }); - - describe('context usage', function () { - - describe('basic usage', function () { - var resStore = { - dev: { - 'ns.2': { - friend_context: 'A friend from ns2', - friend_context_male: 'A boyfriend from ns2', - friend_context_female: 'A girlfriend from ns2' - } - }, - en: { - 'ns.1': { - friend_context: 'A friend', - friend_context_male: 'A boyfriend', - friend_context_female: 'A girlfriend' - } - }, - 'en-US': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { - resStore: resStore, - ns: { namespaces: ['ns.1', 'ns.2'], defaultNs: 'ns.1' } - }), - function (t) { done(); }); - }); - - it('it should provide correct context form', function () { - expect(i18n.t('friend_context')).to.be('A friend'); - expect(i18n.t('friend_context', { context: '' })).to.be('A friend'); - expect(i18n.t('friend_context', { context: 'male' })).to.be('A boyfriend'); - expect(i18n.t('friend_context', { context: 'female' })).to.be('A girlfriend'); - }); - - it('it should provide correct context form for second namespace', function () { - expect(i18n.t('ns.2:friend_context')).to.be('A friend from ns2'); - expect(i18n.t('ns.2:friend_context', { context: '' })).to.be('A friend from ns2'); - expect(i18n.t('ns.2:friend_context', { context: 'male' })).to.be('A boyfriend from ns2'); - expect(i18n.t('ns.2:friend_context', { context: 'female' })).to.be('A girlfriend from ns2'); - }); - }); - - describe('extended usage - in combination with plurals', function () { - var resStore = { - dev: { translation: {} }, - en: { - translation: { - friend_context: '__count__ friend', - friend_context_male: '__count__ boyfriend', - friend_context_female: '__count__ girlfriend', - friend_context_plural: '__count__ friends', - friend_context_male_plural: '__count__ boyfriends', - friend_context_female_plural: '__count__ girlfriends' - } - }, - 'en-US': { translation: {} } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should provide correct context with plural forms', function () { - expect(i18n.t('friend_context', { count: 1 })).to.be('1 friend'); - expect(i18n.t('friend_context', { context: '', count: 1 })).to.be('1 friend'); - expect(i18n.t('friend_context', { context: 'male', count: 1 })).to.be('1 boyfriend'); - expect(i18n.t('friend_context', { context: 'female', count: 1 })).to.be('1 girlfriend'); - - expect(i18n.t('friend_context', { count: 10 })).to.be('10 friends'); - expect(i18n.t('friend_context', { context: '', count: 10 })).to.be('10 friends'); - expect(i18n.t('friend_context', { context: 'male', count: 10 })).to.be('10 boyfriends'); - expect(i18n.t('friend_context', { context: 'female', count: 10 })).to.be('10 girlfriends'); - }); - - }); - - }); - - describe('with passed in languages different from set one', function () { - - beforeEach(function (done) { - i18n.init($.extend(opts, { - preload: ['de-DE'] - }), - function (t) { done(); }); - }); - - it('it should provide translation for passed in language', function () { - expect(i18n.t('simple_de', { lng: 'de-DE' })).to.be('ok_from_de'); - }); - - describe('with language not preloaded', function () { - - it('it should provide translation for passed in language after loading file sync', function () { - expect(i18n.t('simple_fr', { lng: 'fr' })).to.be('ok_from_fr'); - }); - - }); - - }); - - }); - - describe('jQuery integration / specials', function () { - - describe('initialise - use deferrer instead of callback', function () { - - describe('with passed in resource set', function () { - - var resStore = { - dev: { translation: { 'simple_dev': 'ok_from_dev' } }, - en: { translation: { 'simple_en': 'ok_from_en' } }, - 'en-US': { translation: { 'simple_en-US': 'ok_from_en-US' } } - }; - - beforeEach(function (done) { - i18n.init($.extend(opts, { resStore: resStore })).done(function (t: any) { done(); }); - }); - - it('it should provide passed in resources for translation', function () { - expect($.t('simple_en-US')).to.be('ok_from_en-US'); - expect($.t('simple_en')).to.be('ok_from_en'); - expect($.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('loading from server', function () { - - beforeEach(function (done) { - i18n.init(opts).done(function () { done(); }); - }); - - it('it should provide loaded resources for translation', function () { - expect($.t('simple_en-US')).to.be('ok_from_en-US'); - expect($.t('simple_en')).to.be('ok_from_en'); - expect($.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - }); - - describe('use translation function shortcut $.t', function () { - - beforeEach(function (done) { - i18n.init(opts, function (t) { done(); }); - }); - - it('it should provide translation via $.t', function () { - expect($.t('simple_en-US')).to.be('ok_from_en-US'); - expect($.t('simple_en')).to.be('ok_from_en'); - expect($.t('simple_dev')).to.be('ok_from_dev'); - }); - - }); - - describe('using bindings $([selector].i18n())', function () { - - describe('basic - setting text', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } } - }; - - beforeEach(function (done) { - fixtures.set(''); - - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should set text of elements inside selector having data-i18n attribute', function () { - $('#container').i18n(); - expect($('#testBtn').text()).to.be('ok_from_en-US'); - }); - - it('it should set text of element itself if having data-i18n attribute', function () { - $('#testBtn').i18n(); - expect($('#testBtn').text()).to.be('ok_from_en-US'); - }); - - }); - - describe('extended - setting other attributes', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { translation: { 'simpleTest': 'ok_from_en-US' } } - }; - - beforeEach(function (done) { - fixtures.set(''); - - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should set text of elements inside selector having data-i18n attribute', function () { - $('#container').i18n(); - expect($('#testBtn').text()).to.be('ok_from_en-US'); - }); - - it('it should set attributes of elements inside selector having data-i18n attribute', function () { - $('#container').i18n(); - expect($('#testBtn').attr('title')).to.be('ok_from_en-US'); - }); - - }); - - describe('extended - pass in options', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { translation: { 'simpleTest': '__replace__ ok_from_en-US' } } - }; - - beforeEach(function (done) { - fixtures.set(''); - - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should set text with passed in options', function () { - $('#container').i18n({ replace: 'replaced' }); - expect($('#testBtn').text()).to.be('replaced ok_from_en-US'); - }); - - }); - - describe('extended - render inner html', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { translation: { 'simpleTest': 'test' } } - }; - - beforeEach(function (done) { - fixtures.set(''); - - i18n.init($.extend(opts, { resStore: resStore }), - function (t) { done(); }); - }); - - it('it should set inner html', function () { - $('#container').i18n(); - expect($('#inner').html()).to.be('test'); - }); - - }); - - - describe('extended - read options from data attribute', function () { - - var resStore = { - dev: { translation: {} }, - en: { translation: {} }, - 'en-US': { translation: { 'simpleTest': '__replace__ ok_from_en-US' } } - }; - - beforeEach(function (done) { - fixtures.set(''); - - i18n.init($.extend(opts, { - resStore: resStore, - useDataAttrOptions: true - }), - function (t) { - $('#container').i18n({ replace: 'replaced' }); - $('#testBtn').text(''); - done(); - }); - }); - - it('it should set text with attributes options', function () { - $('#container').i18n(); // without option - expect($('#testBtn').text()).to.be('replaced ok_from_en-US'); - }); - - }); - - }); - - }); - - +import * as i18n from 'i18next'; + +i18n.init({ + debug: true, + resources: { + en: { + translation: { + helloWorld: 'Hello, world!' + } + }, + ru: { + translation: { + helloWorld: 'Привет, мир!' + } + } + }, + lng: 'en', + fallbackLng: 'ru', + ns: 'translation', + defaultNS: 'translation', + fallbackNS: 'translation', + whitelist: ['en'], + lowerCaseLng: false, + load: 'languageOnly', + preload: ['ru', 'en'], + keySeparator: '.', + nsSeparator: ':', + pluralSeparator: '_', + contextSeparator: '_', + saveMissing: true, + saveMissingTo: 'all', + missingKeyHandler: (lng:string, ns:string, key:string, fallbackValue:string) => { + console.log('Lng: ' + lng + ', ns: ' + ns + ', key' + key + ', fallbackValue: ' + fallbackValue); + }, + parseMissingKeyHandler: (key:string) => { + console.log(key); + }, + appendNamespaceToMissingKey: true, + returnNull: false, + returnEmptyString: false, + returnObjects: false, + returnedObjectHandler: (key:string, value:string, options:any) => { + }, + joinArrays: '\n', + overloadTranslationOptionHandler: (args:any[]) => { + return {} + }, + interpolation: {}, + detection: null, + backend: null, + cache: null +}); + +i18n.t('helloWorld', { + defaultValue: 'default', + count: 10 }); diff --git a/i18next/i18next.d.ts b/i18next/i18next.d.ts index c8f803f05..d8627c446 100644 --- a/i18next/i18next.d.ts +++ b/i18next/i18next.d.ts @@ -1,160 +1,125 @@ -// Type definitions for i18next v2.0.17 +// Type definitions for i18next v2.3.4 // Project: http://i18next.com -// Definitions by: Maarten Docter +// Definitions by: Michael Ledin // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// Sources: https://github.com/jamuhl/i18next/ +// Sources: https://github.com/i18next/i18next/ -/// -/// -/// -/// declare namespace I18next { - export interface I18nextStatic {} - export interface I18nextOptions {} + interface ResourceStore { + [language: string]: ResourceStoreLanguage; + } + + interface ResourceStoreLanguage { + [namespace: string]: ResourceStoreKey; + } + + interface ResourceStoreKey { + [key: string]: any; + } + + interface InterpolationOptions { + escapeValue?: boolean; + prefix?: string; + suffix?: string; + prefixEscaped?: string; + suffixEscaped?: string; + unescapeSuffix?: string; + unescapePrefix?: string; + nestingPrefix?: string; + nestingSuffix?: string; + nestingPrefixEscaped?: string; + nestedSuffixEscaped?: string; + defaultVariables?: any; + } + + interface TranslationOptions { + defaultValue?: string; + count?: number; + context?: any; + replace?: any; + lng?:string; + lngs?:string[]; + fallbackLng?:string; + ns?:string|string[]; + keySeparator?:string; + nsSeparator?:string; + returnObjects?:boolean; + joinArrays?:string; + postProcess?:string|any[]; + interpolation?: InterpolationOptions; + } + + interface Options { + debug?: boolean; + resources?: ResourceStore; + lng?: string; + fallbackLng?: string; + ns?: string|string[]; + defaultNS?: string; + fallbackNS?: string|string[]; + whitelist?:string[]; + lowerCaseLng?: boolean; + load?: string + preload?: string[]; + keySeparator?: string; + nsSeparator?: string; + pluralSeparator?: string; + contextSeparator?: string; + saveMissing?: boolean; + saveMissingTo?: string; + missingKeyHandler?: (lng:string, ns:string, key:string, fallbackValue:string) => void; + parseMissingKeyHandler?: (key:string) => void; + appendNamespaceToMissingKey?: boolean; + postProcess?: string|any[]; + returnNull?: boolean; + returnEmptyString?: boolean; + returnObjects?: boolean; + returnedObjectHandler?: (key:string, value:string, options:any) => void; + joinArrays?: string; + overloadTranslationOptionHandler?: (args:any[]) => TranslationOptions; + interpolation?: InterpolationOptions; + detection?: any; + backend?: any; + cache?: any; + } + + type TranslationFunction = (key:string, options?:TranslationOptions) => string; + + class I18n { + constructor(options?:Options, callback?:(err:any, t:TranslationFunction) => void); + + init(options?:Options, callback?:(err:any, t:TranslationFunction) => void):I18n; + + loadResources(callback?:(err:any) => void):void; + + use(module:any):I18n; + + changeLanguage(lng:string, callback?:(err:any, t:TranslationFunction) => void):void; + + getFixedT(lng?:string, ns?:string|string[]):TranslationFunction; + + t(key:string, options?:TranslationOptions):string; + + exists():boolean; + + setDefaultNamespace(ns:string):void; + + loadNamespaces(ns:string[], callback?:() => void):void; + + loadLanguages(lngs:string[], callback?:()=>void):void; + + dir(lng?:string):string; + + createInstance(options?:Options, callback?:(err:any, t:TranslationFunction) => void):I18n; + + cloneInstance(options?:Options, callback?:(err:any, t:TranslationFunction) => void):I18n; + } } -interface IResourceStore { - [language: string]: IResourceStoreLanguage; -} -interface IResourceStoreLanguage { - [namespace: string]: IResourceStoreKey; -} -interface IResourceStoreKey { - [key: string]: any; -} - -interface I18nTranslateOptions extends I18nextOptions { - defaultValue?: any; // normally a string - // NOTE https://github.com/DefinitelyTyped/DefinitelyTyped/pull/5590 - toAdd?: any; - child?: any; - sprintf?: any; - count?: any; - context?: any; -} - -interface I18nextOptions extends I18next.I18nextOptions { - lng?: string; // Default value: undefined - load?: string; // Default value: 'all' - preload?: string[]; // Default value: [] - lowerCaseLng?: boolean; // Default value: false - returnObjectTrees?: boolean; // Default value: false - fallbackLng?: string|boolean; // Default value: 'dev' - detectLngQS?: string; // Default value: 'setLng' - ns?: any; // Default value: 'translation' (string), can also be an object - nsseparator?: string; // Default value: '::' - keyseparator?: string; // Default value: '.' - selectorAttr?: string; // Default value: 'data-i18n' - debug?: boolean; // Default value: false - - resGetPath?: string; // Default value: 'locales/__lng__/__ns__.json' - resPostPath?: string; // Default value: 'locales/add/__lng__/__ns__' - - getAsync?: boolean; // Default value: true - postAsync?: boolean; // Default value: true - - resStore?: IResourceStore; // Default value: undefined - useLocalStorage?: boolean; // Default value: false - localStorageExpirationTime?: number; // Default value: 7 * 24 * 60 * 60 * 1000 (in ms default one week) - - dynamicLoad?: boolean; // Default value: false - sendMissing?: boolean; // Default value: false - sendMissingTo?: string; // Default value: 'fallback'. Other options are: current | all - sendType?: string; // Default value: 'POST' - - interpolationPrefix?: string; // Default value: '__' - interpolationSuffix?: string; // Default value: '__' - reusePrefix?: string; // Default value: '$t(' - reuseSuffix?: string; // Default value: ')' - pluralSuffix?: string; // Default value: '_plural' - pluralNotFound?: string; // Default value: ['plural_not_found' Math.random()].join( '' ) - contextNotFound?: string; // Default value: ['context_not_found' Math.random()].join( '' ) - - setJqueryExt?: boolean; // Default value: true - defaultValueFromContent?: boolean; // Default value: true - useDataAttrOptions?: boolean; // Default value: false - cookieExpirationTime?: number; // Default value: undefined - useCookie?: boolean; // Default value: true - cookieName?: string; // Default value: 'i18next' - - postProcess?: string; // Default value: undefined - - // NOTE https://github.com/DefinitelyTyped/DefinitelyTyped/pull/5590 - replace?: any; -} - -interface I18nextStatic extends I18next.I18nextStatic { - - addPostProcessor(name: string, fn: (value: any, key: string, options: any) => string): void; - addResources(language: string, namespace: string, resources: IResourceStoreKey): void; - detectLanguage(): string; - functions: { - extend(target: any, ...objs: any[]): Object; - extend(deep: boolean, target: any, ...objs: any[]): Object; - each(collection: any, callback: (indexInArray: any, valueOfElement: any) => any): any; - ajax(settings: JQueryAjaxSettings): JQueryXHR; - ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR; - cookie: { - create: (name: string, value: string, minutes: number) => void; - read: (name: string) => string; - remove: (name: string) => void; - }; - detectLanguage(): string; - log(message: string): void; - toLanguages(language: string): string[]; - regexEscape(str: string): string; - }; - init(callback?: (err: any, t: (key: string, options?: any) => string) => void ): JQueryDeferred; - init(options?: I18nextOptions, callback?: (err: any, t: (key: string, options?: any) => string) => void ): JQueryDeferred; - lng(): string; - loadNamespace(namespace: string, callback?: () => void ): void; - loadNamespaces(namespaces: string[], callback?: () => void ): void; - pluralExtensions: { - addRule(language: string, obj: { - name: string; - numbers: number[]; - plurals: (n: number) => number; - }): void; - get (language: string, count: number): number; - rules: any; - setCurrentLng: (language: string) => void; - }; - preload(language: string, callback?: (err: any, t: (key: string, options?: any) => string) => void ): void; - preload(languages: string[], callback?: (err: any, t: (key: string, options?: any) => string) => void ): void; - setDefaultNamespace(namespace: string): void; - setLng(language: string, callback?: (err: any, t: (key: string, options?: any) => string) => void ): void; - sync: { - load: (languages: string[], options: I18nextOptions, callback: (err: Error, store: IResourceStore) => void ) => void; - postMissing: (language: string, namespace: string, key: string, defaultValue: any, languages: string[]) => void; - }; - t(key: string, options?: I18nTranslateOptions): string; - translate(key: string, options?: I18nTranslateOptions): string; - exists(key: string, options?: any): boolean; - use(module: any): I18nextStatic; -} - -// jQuery extensions -interface JQueryStatic { - i18n: I18nextStatic; - t: (key: string, options?: any) => string; -} - -interface JQuery { - /* Note: options are same options as used by the translate function. Alternatively by - setting init option or translation option 'useDataAttrOptions = true' the Options - for translation will be read and cached in the elements data-i18n-options attribute. - */ - i18n: (options?: I18nextOptions) => void; -} - -declare var i18n: I18nextStatic; - declare module 'i18next' { - export = i18n; -} + var i18n:I18next.I18n; -declare module 'i18next-client' { export = i18n; } diff --git a/ng-i18next/ng-i18next.d.ts b/ng-i18next/ng-i18next.d.ts index fb12019aa..650952c2e 100644 --- a/ng-i18next/ng-i18next.d.ts +++ b/ng-i18next/ng-i18next.d.ts @@ -3,7 +3,7 @@ // Definitions by: Cyril Schumacher // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -/// +/// declare namespace angular.i18next { interface I18nextProvider {