diff --git a/i18next/i18next.d.ts b/i18next/i18next.d.ts new file mode 100644 index 0000000000..572f74a775 --- /dev/null +++ b/i18next/i18next.d.ts @@ -0,0 +1,127 @@ +/// + +// Type definitions for i18next (v1.5.10 incl. jQuery) +// Project: http://i18next.com +// Sources: https://github.com/jamuhl/i18next/ +// Definitions by: Maarten Docter - Blog: http://www.maartendocter.nl +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +interface IResourceStore { + [language: string]: IResourceStoreLanguage; +} +interface IResourceStoreLanguage { + [namespace: string]: IResourceStoreKey; +} +interface IResourceStoreKey { + [key: string]; +} + +interface I18nextOptions { + lng?: string; // Default value: undefined + load?: string; // Default value: 'all' + preload?: string[]; // Default value: [] + lowerCaseLng?: bool; // Default value: false + returnObjectTrees?: bool; // Default value: false + fallbackLng?: string; // 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?: bool; // Default value: false + + resGetPath?: string; // Default value: 'locales/__lng__/__ns__.json' + resPostPath?: string; // Default value: 'locales/add/__lng__/__ns__' + + getAsync?: bool; // Default value: true + postAsync?: bool; // Default value: true + + resStore?: IResourceStore; // Default value: undefined + useLocalStorage?: bool; // Default value: false + localStorageExpirationTime?: number; // Default value: 7 * 24 * 60 * 60 * 1000 (in ms default one week) + + dynamicLoad?: bool; // Default value: false + sendMissing?: bool; // 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?: bool; // Default value: true + defaultValueFromContent?: bool; // Default value: true + useDataAttrOptions?: bool; // Default value: false + cookieExpirationTime?: number; // Default value: undefined + useCookie?: bool; // Default value: true + cookieName?: string; // Default value: 'i18next' + + postProcess?: string; // Default value: undefined +} + +interface I18nextStatic { + + addPostProcessor(name: string, fn: (value: any, key: string, options: any) => string): void; + detectLanguage(): string; + functions: { + extend(target: any, ...objs: any[]): Object; + extend(deep: bool, 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); + toLanguages(language: string): string[]; + regexEscape(str: string): string; + }; + init(callback?: (t: (key: string, options?: any) => string) => void ): JQueryDeferred; + init(options?: I18nextOptions, callback?: (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; + }); + get (language: string, count: number): number; + rules: any; + setCurrentLng: (language: string) => void; + }; + preload(language: string, callback?: (t: (key: string, options?: any) => string) => void ): void; + preload(languages: string[], callback?: (t: (key: string, options?: any) => string) => void ): void; + setDefaultNamespace(namespace: string): void; + setLng(language: string, callback?: (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?: any): string; + translate(key: string, options?: any): string; +} + +// 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 i18next: I18nextStatic; \ No newline at end of file diff --git a/i18next/lib/jquery.d.ts b/i18next/lib/jquery.d.ts new file mode 100644 index 0000000000..25e2aa6266 --- /dev/null +++ b/i18next/lib/jquery.d.ts @@ -0,0 +1,758 @@ +/* ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +// Typing for the jQuery library, version 1.7.x + +/* + Interface for the AJAX setting that will configure the AJAX request +*/ +interface JQueryAjaxSettings { + accepts?: any; + async?: bool; + beforeSend?(jqXHR: JQueryXHR, settings: JQueryAjaxSettings); + cache?: bool; + complete?(jqXHR: JQueryXHR, textStatus: string); + contents?: { [key: string]: any; }; + contentType?: string; + context?: any; + converters?: { [key: string]: any; }; + crossDomain?: bool; + data?: any; + dataFilter?(data: any, ty: any): any; + dataType?: string; + error?(jqXHR: JQueryXHR, textStatus: string, errorThrow: string): any; + global?: bool; + headers?: { [key: string]: any; }; + ifModified?: bool; + isLocal?: bool; + jsonp?: string; + jsonpCallback?: any; + mimeType?: string; + password?: string; + processData?: bool; + scriptCharset?: string; + statusCode?: { [key: string]: any; }; + success?(data: any, textStatus: string, jqXHR: JQueryXHR); + timeout?: number; + traditional?: bool; + type?: string; + url?: string; + username?: string; + xhr?: any; + xhrFields?: { [key: string]: any; }; +} + +/* + Interface for the jqXHR object +*/ +interface JQueryXHR extends XMLHttpRequest, JQueryPromise { + overrideMimeType(mimeType: string); +} + +/* + Interface for the JQuery callback +*/ +interface JQueryCallback { + add(...callbacks: any[]): any; + disable(): any; + empty(): any; + fire(...arguments: any[]): any; + fired(): bool; + fireWith(context: any, ...args: any[]): any; + has(callback: any): bool; + lock(): any; + locked(): bool; + remove(...callbacks: any[]): any; +} + +/* + Interface for the JQuery promise, part of callbacks +*/ +interface JQueryPromise { + always(...alwaysCallbacks: any[]): JQueryDeferred; + done(...doneCallbacks: any[]): JQueryDeferred; + fail(...failCallbacks: any[]): JQueryDeferred; + progress(...progressCallbacks: any[]): JQueryDeferred; + state(): string; + pipe(doneFilter?: (...args: any[]) => any, failFilter?: (...args: any[]) => any, progressFilter?: (...args: any[]) => any): JQueryPromise; + then(doneCallbacks: any, failCallbacks: any, progressCallbacks?: any): JQueryDeferred; +} + +/* + Interface for the JQuery deferred, part of callbacks +*/ +interface JQueryDeferred extends JQueryPromise { + notify(...args: any[]): JQueryDeferred; + notifyWith(context: any, ...args: any[]): JQueryDeferred; + + pipe(doneFilter?: any, failFilter?: any, progressFilter?: any): JQueryPromise; + progress(...progressCallbacks: any[]): JQueryDeferred; + promise(target? ): JQueryDeferred; + reject(...args: any[]): JQueryDeferred; + rejectWith(context:any, ...args: any[]): JQueryDeferred; + resolve(...args: any[]): JQueryDeferred; + resolveWith(context:any, ...args: any[]): JQueryDeferred; + state(): string; + then(doneCallbacks: any, failCallbacks: any, progressCallbacks?: any): JQueryDeferred; +} + +/* + Interface of the JQuery extension of the W3C event object +*/ +interface JQueryEventObject extends Event { + data: any; + delegateTarget: Element; + isDefaultPrevented(): bool; + isImmediatePropogationStopped(): bool; + isPropogationStopped(): bool; + namespace: string; + preventDefault(): any; + relatedTarget: Element; + result: any; + stopImmediatePropagation(); + stopPropagation(); + pageX: number; + pageY: number; + which: number; + metaKey: any; +} + +/* + Collection of properties of the current browser +*/ +interface JQueryBrowserInfo { + safari:bool; + opera:bool; + msie:bool; + mozilla:bool; + webkit:bool; + version:string; +} + +interface JQuerySupport { + ajax?: bool; + boxModel?: bool; + changeBubbles?: bool; + checkClone?: bool; + checkOn?: bool; + cors?: bool; + cssFloat?: bool; + hrefNormalized?: bool; + htmlSerialize?: bool; + leadingWhitespace?: bool; + noCloneChecked?: bool; + noCloneEvent?: bool; + opacity?: bool; + optDisabled?: bool; + optSelected?: bool; + scriptEval?(): bool; + style?: bool; + submitBubbles?: bool; + tbody?: bool; +} + +/* + Static members of jQuery (those on $ and jQuery themselves) +*/ +interface JQueryStatic { + + /**** + AJAX + *****/ + ajax(settings: JQueryAjaxSettings): JQueryXHR; + ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR; + + ajaxPrefilter(dataTypes: string, handler: (opts: any, originalOpts: any, jqXHR: JQueryXHR) => any): any; + ajaxPrefilter(handler: (opts: any, originalOpts: any, jqXHR: JQueryXHR) => any): any; + + ajaxSettings: JQueryAjaxSettings; + + ajaxSetup(options: any); + + get(url: string, data?: any, success?: any, dataType?: any): JQueryXHR; + getJSON(url: string, data?: any, success?: any): JQueryXHR; + getScript(url: string, success?: any): JQueryXHR; + + param(obj: any): string; + param(obj: any, traditional: bool): string; + + post(url: string, data?: any, success?: any, dataType?: any): JQueryXHR; + + /********* + CALLBACKS + **********/ + Callbacks(flags?: string): JQueryCallback; + + /**** + CORE + *****/ + holdReady(hold: bool): any; + + (selector: string, context?: any): JQuery; + (element: Element): JQuery; + (object: { }): JQuery; + (elementArray: Element[]): JQuery; + (object: JQuery): JQuery; + (func: Function): JQuery; + (array: any[]): JQuery; + (): JQuery; + + noConflict(removeAll?: bool): Object; + + when(...deferreds: any[]): JQueryPromise; + + /*** + CSS + ****/ + css(e: any, propertyName: string, value?: any); + css(e: any, propertyName: any, value?: any); + cssHooks: { [key: string]: any; }; + cssNumber: any; + + /**** + DATA + *****/ + data(element: Element, key: string, value: any): any; + data(element: Element, key: string): any; + data(element: Element): any; + + dequeue(element: Element, queueName?: string): any; + + hasData(element: Element): bool; + + queue(element: Element, queueName?: string): any[]; + queue(element: Element, queueName: string, newQueueOrCallback: any): JQuery; + + removeData(element: Element, name?: string): JQuery; + + /******* + EFFECTS + ********/ + fx: { tick: () => void; interval: number; stop: () => void; speeds: { slow: number; fast: number; }; off: bool; step: any; }; + + /****** + EVENTS + *******/ + proxy(fn: Function, context: any): any; + proxy(context: any, name: any): any; + Deferred(): JQueryDeferred; + + /********* + INTERNALS + **********/ + error(message: any); + + /************* + MISCELLANEOUS + **************/ + expr: any; + fn: any; //TODO: Decide how we want to type this + isReady: bool; + + /********** + PROPERTIES + ***********/ + browser: JQueryBrowserInfo; + support: JQuerySupport; + + /********* + UTILITIES + **********/ + contains(container: Element, contained: Element): bool; + + each(collection: any, callback: (indexInArray: any, valueOfElement: any) => any): any; + + extend(target: any, ...objs: any[]): Object; + extend(deep: bool, target: any, ...objs: any[]): Object; + + globalEval(code: string): any; + + grep(array: any[], func: any, invert?: bool): any[]; + + inArray(value: any, array: any[], fromIndex?: number): number; + + isArray(obj: any): bool; + isEmptyObject(obj: any): bool; + isFunction(obj: any): bool; + isNumeric(value: any): bool; + isPlainObject(obj: any): bool; + isWindow(obj: any): bool; + isXMLDoc(node: Node): bool; + + makeArray(obj: any): any[]; + + map(array: any[], callback: (elementOfArray: any, indexInArray: any) =>any): any[]; + + merge(first: any[], second: any[]): any[]; + + noop(): any; + + now(): number; + + parseJSON(json: string): Object; + + //FIXME: This should return an XMLDocument + parseXML(data: string): any; + + queue(element: Element, queueName: string, newQueue: any[]): JQuery; + + trim(str: string): string; + + type(obj: any): string; + + unique(arr: any[]): any[]; +} + +/* + The jQuery instance members +*/ +interface JQuery { + /**** + AJAX + *****/ + ajaxComplete(handler: any): JQuery; + ajaxError(handler: (event: any, jqXHR: any, settings: any, exception: any) => any): JQuery; + ajaxSend(handler: (event: any, jqXHR: any, settings: any, exception: any) => any): JQuery; + ajaxStart(handler: () => any): JQuery; + ajaxStop(handler: () => any): JQuery; + ajaxSuccess(handler: (event: any, jqXHR: any, settings: any, exception: any) => any): JQuery; + + load(url: string, data?: any, complete?: any): JQuery; + + serialize(): string; + serializeArray(): any[]; + + /********** + ATTRIBUTES + ***********/ + addClass(classNames: string): JQuery; + addClass(func: (index: any, currentClass: any) => string): JQuery; + + attr(attributeName: string): string; + attr(attributeName: string, value: any): JQuery; + attr(map: { [key: string]: any; }): JQuery; + attr(attributeName: string, func: (index: any, attr: any) => any): JQuery; + + hasClass(className: string): bool; + + html(): string; + html(htmlString: string): JQuery; + html(htmlContent: (index: number, oldhtml: string) => string): JQuery; + + prop(propertyName: string): any; + prop(propertyName: string, value: any): JQuery; + prop(map: any): JQuery; + prop(propertyName: string, func: (index: any, oldPropertyValue: any) => any): JQuery; + + removeAttr(attributeName: any): JQuery; + + removeClass(className?: any): JQuery; + removeClass(func: (index: any, cls: any) => any): JQuery; + + removeProp(propertyName: any): JQuery; + + toggleClass(className: any, swtch?: bool): JQuery; + toggleClass(swtch?: bool): JQuery; + toggleClass(func: (index: any, cls: any, swtch: any) => any): JQuery; + + val(): any; + val(value: string[]): JQuery; + val(value: string): JQuery; + val(value: number): JQuery; + val(func: (index: any, value: any) => any): JQuery; + + /*** + CSS + ****/ + css(propertyName: string, value?: any): any; + css(propertyName: any, value?: any): any; + + height(): number; + height(value: number): JQuery; + height(value: string): JQuery; + height(func: (index: any, height: any) => any): JQuery; + + innerHeight(): number; + innerWidth(): number; + + offset(): { left: number; top: number; }; + offset(coordinates: any): JQuery; + offset(func: (index: any, coords: any) => any): JQuery; + + outerHeight(includeMargin?: bool): number; + outerWidth(includeMargin?: bool): number; + + position(): { top: number; left: number; }; + + scrollLeft(): number; + scrollLeft(value: number): JQuery; + + scrollTop(): number; + scrollTop(value: number): JQuery; + + width(): number; + width(value: number): JQuery; + width(value: string): JQuery; + width(func: (index: any, height: any) => any): JQuery; + + /**** + DATA + *****/ + clearQueue(queueName?: string): JQuery; + + data(key: string, value: any): JQuery; + data(obj: { [key: string]: any; }): JQuery; + data(key?: string): any; + + dequeue(queueName?: string): JQuery; + + removeData(nameOrList?: any): JQuery; + + /******** + DEFERRED + *********/ + promise(type?: any, target?: any): JQueryPromise; + + /******* + EFFECTS + ********/ + animate(properties: any, duration?: any, complete?: Function): JQuery; + animate(properties: any, duration?: any, easing?: string, complete?: Function): JQuery; + animate(properties: any, options: { duration?: any; easing?: string; complete?: Function; step?: Function; queue?: bool; specialEasing?: any; }); + + delay(duration: number, queueName?: string): JQuery; + + fadeIn(duration?: any, callback?: any): JQuery; + fadeIn(duration?: any, easing?: string, callback?: any): JQuery; + + fadeOut(duration?: any, callback?: any): JQuery; + fadeOut(duration?: any, easing?: string, callback?: any): JQuery; + + fadeTo(duration: any, opacity: number, callback?: any): JQuery; + fadeTo(duration: any, opacity: number, easing?: string, callback?: any): JQuery; + + fadeToggle(duration?: any, callback?: any): JQuery; + fadeToggle(duration?: any, easing?: string, callback?: any): JQuery; + + hide(duration?: any, callback?: any): JQuery; + hide(duration?: any, easing?: string, callback?: any): JQuery; + + show(duration?: any, callback?: any): JQuery; + show(duration?: any, easing?: string, callback?: any): JQuery; + + slideDown(duration?: any, callback?: any): JQuery; + slideDown(duration?: any, easing?: string, callback?: any): JQuery; + + slideToggle(duration?: any, callback?: any): JQuery; + slideToggle(duration?: any, easing?: string, callback?: any): JQuery; + + slideUp(duration?: any, callback?: any): JQuery; + slideUp(duration?: any, easing?: string, callback?: any): JQuery; + + stop(clearQueue?: bool, jumpToEnd?: bool): JQuery; + stop(queue?:any, clearQueue?: bool, jumpToEnd?: bool): JQuery; + + toggle(duration?: any, callback?: any): JQuery; + toggle(duration?: any, easing?: string, callback?: any): JQuery; + toggle(showOrHide: bool): JQuery; + + /****** + EVENTS + *******/ + bind(eventType: string, eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + bind(eventType: string, eventData: any, preventBubble:bool): JQuery; + bind(eventType: string, preventBubble:bool): JQuery; + bind(...events: any[]); + + blur(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + blur(handler: (eventObject: JQueryEventObject) => any): JQuery; + + change(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + change(handler: (eventObject: JQueryEventObject) => any): JQuery; + + click(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + click(handler: (eventObject: JQueryEventObject) => any): JQuery; + + dblclick(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + dblclick(handler: (eventObject: JQueryEventObject) => any): JQuery; + + delegate(selector: any, eventType: string, handler: (eventObject: JQueryEventObject) => any): JQuery; + + focus(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + focus(handler: (eventObject: JQueryEventObject) => any): JQuery; + + focusin(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + focusin(handler: (eventObject: JQueryEventObject) => any): JQuery; + + focusout(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + focusout(handler: (eventObject: JQueryEventObject) => any): JQuery; + + hover(handlerIn: (eventObject: JQueryEventObject) => any, handlerOut: (eventObject: JQueryEventObject) => any): JQuery; + hover(handlerInOut: (eventObject: JQueryEventObject) => any): JQuery; + + keydown(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + keydown(handler: (eventObject: JQueryEventObject) => any): JQuery; + + keypress(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + keypress(handler: (eventObject: JQueryEventObject) => any): JQuery; + + keyup(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + keyup(handler: (eventObject: JQueryEventObject) => any): JQuery; + + load(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + load(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mousedown(): JQuery; + mousedown(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mousedown(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mouseevent(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mouseevent(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mouseenter(): JQuery; + mouseenter(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mouseenter(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mouseleave(): JQuery; + mouseleave(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mouseleave(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mousemove(): JQuery; + mousemove(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mousemove(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mouseout(): JQuery; + mouseout(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mouseout(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mouseover(): JQuery; + mouseover(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mouseover(handler: (eventObject: JQueryEventObject) => any): JQuery; + + mouseup(): JQuery; + mouseup(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + mouseup(handler: (eventObject: JQueryEventObject) => any): JQuery; + + off(events?: string, selector?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + off(eventsMap: { [key: string]: any; }, selector?: any): JQuery; + + on(events: string, selector?: any, data?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + on(eventsMap: { [key: string]: any; }, selector?: any, data?: any): JQuery; + + one(events: string, selector?: any, data?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + one(eventsMap: { [key: string]: any; }, selector?: any, data?: any): JQuery; + + ready(handler: any): JQuery; + + resize(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + resize(handler: (eventObject: JQueryEventObject) => any): JQuery; + + scroll(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + scroll(handler: (eventObject: JQueryEventObject) => any): JQuery; + + select(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + select(handler: (eventObject: JQueryEventObject) => any): JQuery; + + submit(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + submit(handler: (eventObject: JQueryEventObject) => any): JQuery; + + trigger(eventType: string, ...extraParameters: any[]): JQuery; + trigger(event: JQueryEventObject): JQuery; + + triggerHandler(eventType: string, ...extraParameters: any[]): Object; + + unbind(eventType?: string, handler?: (eventObject: JQueryEventObject) => any): JQuery; + unbind(eventType: string, fls: bool): JQuery; + unbind(evt: any): JQuery; + + undelegate(): JQuery; + undelegate(selector: any, eventType: string, handler?: (eventObject: JQueryEventObject) => any): JQuery; + undelegate(selector: any, events: any): JQuery; + undelegate(namespace: string): JQuery; + + unload(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + unload(handler: (eventObject: JQueryEventObject) => any): JQuery; + + /********* + INTERNALS + **********/ + + context: Element; + jquery: string; + + error(handler: (eventObject: JQueryEventObject) => any): JQuery; + error(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + + pushStack(elements: any[]): JQuery; + pushStack(elements: any[], name: any, arguments: any): JQuery; + + /************ + MANIPULATION + *************/ + after(...content: any[]): JQuery; + after(func: (index: any) => any); + + append(...content: any[]): JQuery; + append(func: (index: any, html: any) => any); + + appendTo(target: any): JQuery; + + before(...content: any[]): JQuery; + before(func: (index: any) => any); + + clone(withDataAndEvents?: bool, deepWithDataAndEvents?: bool): JQuery; + + detach(selector?: any): JQuery; + + empty(): JQuery; + + insertAfter(target: any): JQuery; + insertBefore(target: any): JQuery; + + prepend(...content: any[]): JQuery; + prepend(func: (index: any, html: any) =>any): JQuery; + + prependTo(target: any): JQuery; + + remove(selector?: any): JQuery; + + replaceAll(target: any): JQuery; + + replaceWith(func: any): JQuery; + + text(): string; + text(textString: any): JQuery; + text(textString: (index: number, text: string) => string): JQuery; + + toArray(): any[]; + + unwrap(): JQuery; + + wrap(wrappingElement: any): JQuery; + wrap(func: (index: any) =>any): JQuery; + + wrapAll(wrappingElement: any): JQuery; + + wrapInner(wrappingElement: any): JQuery; + wrapInner(func: (index: any) =>any): JQuery; + + /************* + MISCELLANEOUS + **************/ + each(func: (index: any, elem: Element) => any); + + get(index?: number): any; + + index(): number; + index(selector: string): number; + index(element: any): number; + + /********** + PROPERTIES + ***********/ + length: number; + [x: string]: HTMLElement; + [x: number]: HTMLElement; + + /********** + TRAVERSING + ***********/ + add(selector: string, context?: any): JQuery; + add(...elements: any[]): JQuery; + add(html: string): JQuery; + add(obj: JQuery): JQuery; + + andSelf(): JQuery; + + children(selector?: any): JQuery; + + closest(selector: string): JQuery; + closest(selector: string, context?: Element): JQuery; + closest(obj: JQuery): JQuery; + closest(element: any): JQuery; + closest(selectors: any, context?: Element): any[]; + + contents(): JQuery; + + end(): JQuery; + + eq(index: number): JQuery; + + filter(selector: string): JQuery; + filter(func: (index: any) =>any): JQuery; + filter(element: any): JQuery; + filter(obj: JQuery): JQuery; + + find(selector: string): JQuery; + find(element: any): JQuery; + find(obj: JQuery): JQuery; + + first(): JQuery; + + has(selector: string): JQuery; + has(contained: Element): JQuery; + + is(selector: string): bool; + is(func: (index: any) =>any): bool; + is(element: any): bool; + is(obj: JQuery): bool; + + last(): JQuery; + + map(callback: (index: any, domElement: Element) =>any): JQuery; + + next(selector?: string): JQuery; + + nextAll(selector?: string): JQuery; + + nextUntil(selector?: string, filter?: string): JQuery; + nextUntil(element?: Element, filter?: string): JQuery; + + not(selector: string): JQuery; + not(func: (index: any) =>any): JQuery; + not(element: any): JQuery; + not(obj: JQuery): JQuery; + + offsetParent(): JQuery; + + parent(selector?: string): JQuery; + + parents(selector?: string): JQuery; + + parentsUntil(selector?: string, filter?: string): JQuery; + parentsUntil(element?: Element, filter?: string): JQuery; + + prev(selector?: string): JQuery; + + prevAll(selector?: string): JQuery; + + prevUntil(selector?: string, filter?:string): JQuery; + prevUntil(element?: Element, filter?:string): JQuery; + + siblings(selector?: string): JQuery; + + slice(start: number, end?: number): JQuery; + + /********* + UTILITIES + **********/ + + queue(queueName?: string): any[]; + queue(queueName: string, newQueueOrCallback: any): JQuery; + queue(newQueueOrCallback: any): JQuery; +} + +declare var jQuery: JQueryStatic; +declare var $: JQueryStatic; diff --git a/i18next/lib/mocha.d.ts b/i18next/lib/mocha.d.ts new file mode 100644 index 0000000000..ee31e689d3 --- /dev/null +++ b/i18next/lib/mocha.d.ts @@ -0,0 +1,44 @@ +// BDD +declare function describe(cb: () => void); +declare function describe(cb: (done:() => void) => void); +declare function describe(title: string, cb: () => void); +declare function describe(title: string, cb: (done:() => void) => void); + +declare function it(cb: () => void); +declare function it(cb: (done:() => void) => void); +declare function it(title: string, cb: () => void); +declare function it(title: string, cb: (done:() => void) => void); + +declare function before(cb: () => void); +declare function before(cb: (done:() => void) => void); +declare function before(title: string, cb: () => void); +declare function before(title: string, cb: (done:() => void) => void); + +declare function after(cb: () => void); +declare function after(cb: (done:() => void) => void); +declare function after(title: string, cb: () => void); +declare function after(title: string, cb: (done:() => void) => void); + +declare function beforeEach(cb: () => void); +declare function beforeEach(cb: (done:() => void) => void); +declare function beforeEach(title: string, cb: () => void); +declare function beforeEach(title: string, cb: (done:() => void) => void); + +declare function afterEach(cb: () => void); +declare function afterEach(cb: (done:() => void) => void); +declare function afterEach(title: string, cb: () => void); +declare function afterEach(title: string, cb: (done:() => void) => void); + + +// TDD +declare function suite(title: string, cb: () => void); +declare function test(title: string, cb: () => void); +declare function test(title: string, cb: (done:() => void) => void); +declare function setup(title: string, cb: () => void); +declare function teardown(title: string, cb: () => void); + +declare function suite(cb: () => void); +declare function test(cb: () => void); +declare function test(cb: (done:() => void) => void); +declare function setup(cb: () => void); +declare function teardown(cb: () => void); diff --git a/i18next/lib/sinon.d.ts b/i18next/lib/sinon.d.ts new file mode 100644 index 0000000000..25198e3b36 --- /dev/null +++ b/i18next/lib/sinon.d.ts @@ -0,0 +1,33 @@ +/// + +interface spy { + called: bool; + getCall(x: number): any; + fakeServer: ISinonFakeServer; + calledOnce: bool; + calledWith(x: any, message: string): bool; +} + +interface IJsonReponse { + responseCode: number; + responseHeaders: any; + responseString: string; +} + +interface ISinonFakeServer { + create(): any; + restore(): void; + respondWith(postType: string, relativeUrl: string, x: any): any; + respond(): any; +} + +declare module sinon { + export function spy(): spy; + export function spy(fn: Function): spy; + //export function spy(jquery: JQueryStatic , x: string): spy; + export function spy(jquery: JQueryStatic , x: any): spy; + export function spy(obj: Object , methodName: string): spy; + export var fakeServer: ISinonFakeServer; + export function stub(x: any, name: string); + export function useFakeTimers(): void; +} \ No newline at end of file diff --git a/i18next/tests/i18next.d.tests.ts b/i18next/tests/i18next.d.tests.ts new file mode 100644 index 0000000000..f4ed24349b --- /dev/null +++ b/i18next/tests/i18next.d.tests.ts @@ -0,0 +1,1359 @@ +/// +/// +/// +/// + +// declarations for expect.js +declare var expect: (actual: string) => any; +declare var expect: (actual: number) => any; + +// declarations for jsfixtures.js +declare var setFixtures: (html) => 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, + resStore: 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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) { 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) { 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; + + 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, stub; + + 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, stub; + + 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('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('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) { 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) { + setFixtures(' + +'); + + 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) { + setFixtures(' + +'); + + 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) { + setFixtures(' + +'); + + 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) { + setFixtures(' +'); + + 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) { + setFixtures(' + +'); + + 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'); + }); + + }); + + }); + + }); + + +});