UNPKG

ng2-translate

Version:

An implementation of angular translate for Angular 2

424 lines (423 loc) 15.1 kB
import { Injectable, EventEmitter, Optional } from "@angular/core"; import { Observable } from "rxjs/Observable"; import "rxjs/add/observable/of"; import "rxjs/add/operator/share"; import "rxjs/add/operator/map"; import "rxjs/add/operator/merge"; import "rxjs/add/operator/toArray"; import "rxjs/add/operator/take"; import { TranslateParser } from "./translate.parser"; import { isDefined } from "./util"; export var MissingTranslationHandler = (function () { function MissingTranslationHandler() { } return MissingTranslationHandler; }()); export var TranslateLoader = (function () { function TranslateLoader() { } return TranslateLoader; }()); export var TranslateStaticLoader = (function () { function TranslateStaticLoader(http, prefix, suffix) { if (prefix === void 0) { prefix = "i18n"; } if (suffix === void 0) { suffix = ".json"; } this.http = http; this.prefix = prefix; this.suffix = suffix; } /** * Gets the translations from the server * @param lang * @returns {any} */ TranslateStaticLoader.prototype.getTranslation = function (lang) { return this.http.get(this.prefix + "/" + lang + this.suffix) .map(function (res) { return res.json(); }); }; return TranslateStaticLoader; }()); export var TranslateService = (function () { /** * * @param currentLoader An instance of the loader currently used * @param parser An instance of the parser currently used * @param missingTranslationHandler A handler for missing translations. */ function TranslateService(currentLoader, parser, missingTranslationHandler) { this.currentLoader = currentLoader; this.parser = parser; this.missingTranslationHandler = missingTranslationHandler; /** * The lang currently used */ this.currentLang = this.defaultLang; /** * An EventEmitter to listen to translation change events * onTranslationChange.subscribe((params: TranslationChangeEvent) => { * // do something * }); * @type {EventEmitter<TranslationChangeEvent>} */ this.onTranslationChange = new EventEmitter(); /** * An EventEmitter to listen to lang change events * onLangChange.subscribe((params: LangChangeEvent) => { * // do something * }); * @type {EventEmitter<LangChangeEvent>} */ this.onLangChange = new EventEmitter(); /** * An EventEmitter to listen to default lang change events * onDefaultLangChange.subscribe((params: DefaultLangChangeEvent) => { * // do something * }); * @type {EventEmitter<DefaultLangChangeEvent>} */ this.onDefaultLangChange = new EventEmitter(); this.translations = {}; this.langs = []; } /** * Sets the default language to use as a fallback * @param lang */ TranslateService.prototype.setDefaultLang = function (lang) { var _this = this; if (lang === this.defaultLang) { return; } var pending = this.retrieveTranslations(lang); if (typeof pending !== "undefined") { // on init set the defaultLang immediately if (!this.defaultLang) { this.defaultLang = lang; } pending.take(1) .subscribe(function (res) { _this.changeDefaultLang(lang); }); } else { this.changeDefaultLang(lang); } }; /** * Gets the default language used * @returns string */ TranslateService.prototype.getDefaultLang = function () { return this.defaultLang; }; /** * Changes the lang currently used * @param lang * @returns {Observable<*>} */ TranslateService.prototype.use = function (lang) { var _this = this; var pending = this.retrieveTranslations(lang); if (typeof pending !== "undefined") { // on init set the currentLang immediately if (!this.currentLang) { this.currentLang = lang; } pending.take(1) .subscribe(function (res) { _this.changeLang(lang); }); return pending; } else { this.changeLang(lang); return Observable.of(this.translations[lang]); } }; /** * Retrieves the given translations * @param lang * @returns {Observable<*>} */ TranslateService.prototype.retrieveTranslations = function (lang) { var pending; // if this language is unavailable, ask for it if (typeof this.translations[lang] === "undefined") { pending = this.getTranslation(lang); } return pending; }; /** * Gets an object of translations for a given language with the current loader * @param lang * @returns {Observable<*>} */ TranslateService.prototype.getTranslation = function (lang) { var _this = this; this.pending = this.currentLoader.getTranslation(lang).share(); this.pending.take(1) .subscribe(function (res) { _this.translations[lang] = res; _this.updateLangs(); _this.pending = undefined; }, function (err) { _this.pending = undefined; }); return this.pending; }; /** * Manually sets an object of translations for a given language * @param lang * @param translations * @param shouldMerge */ TranslateService.prototype.setTranslation = function (lang, translations, shouldMerge) { if (shouldMerge === void 0) { shouldMerge = false; } if (shouldMerge && this.translations[lang]) { Object.assign(this.translations[lang], translations); } else { this.translations[lang] = translations; } this.updateLangs(); this.onTranslationChange.emit({ lang: lang, translations: this.translations[lang] }); }; /** * Returns an array of currently available langs * @returns {any} */ TranslateService.prototype.getLangs = function () { return this.langs; }; /** * @param langs * Add available langs */ TranslateService.prototype.addLangs = function (langs) { var _this = this; langs.forEach(function (lang) { if (_this.langs.indexOf(lang) === -1) { _this.langs.push(lang); } }); }; /** * Update the list of available langs */ TranslateService.prototype.updateLangs = function () { this.addLangs(Object.keys(this.translations)); }; /** * Returns the parsed result of the translations * @param translations * @param key * @param interpolateParams * @returns {any} */ TranslateService.prototype.getParsedResult = function (translations, key, interpolateParams) { var res; if (key instanceof Array) { var result = {}, observables = false; for (var _i = 0, key_1 = key; _i < key_1.length; _i++) { var k = key_1[_i]; result[k] = this.getParsedResult(translations, k, interpolateParams); if (typeof result[k].subscribe === "function") { observables = true; } } if (observables) { var mergedObs = void 0; for (var _a = 0, key_2 = key; _a < key_2.length; _a++) { var k = key_2[_a]; var obs = typeof result[k].subscribe === "function" ? result[k] : Observable.of(result[k]); if (typeof mergedObs === "undefined") { mergedObs = obs; } else { mergedObs = mergedObs.merge(obs); } } return mergedObs.toArray().map(function (arr) { var obj = {}; arr.forEach(function (value, index) { obj[key[index]] = value; }); return obj; }); } return result; } if (translations) { res = this.parser.interpolate(this.parser.getValue(translations, key), interpolateParams); } if (typeof res === "undefined" && this.defaultLang && this.defaultLang !== this.currentLang) { res = this.parser.interpolate(this.parser.getValue(this.translations[this.defaultLang], key), interpolateParams); } if (!res && this.missingTranslationHandler) { var params = { key: key, translateService: this }; if (typeof interpolateParams !== 'undefined') { params.interpolateParams = interpolateParams; } res = this.missingTranslationHandler.handle(params); } return typeof res !== "undefined" ? res : key; }; /** * Gets the translated value of a key (or an array of keys) * @param key * @param interpolateParams * @returns {any} the translated key, or an object of translated keys */ TranslateService.prototype.get = function (key, interpolateParams) { var _this = this; if (!isDefined(key) || !key.length) { throw new Error("Parameter \"key\" required"); } // check if we are loading a new translation to use if (this.pending) { return Observable.create(function (observer) { var onComplete = function (res) { observer.next(res); observer.complete(); }; var onError = function (err) { observer.error(err); }; _this.pending.subscribe(function (res) { res = _this.getParsedResult(res, key, interpolateParams); if (typeof res.subscribe === "function") { res.subscribe(onComplete, onError); } else { onComplete(res); } }, onError); }); } else { var res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams); if (typeof res.subscribe === "function") { return res; } else { return Observable.of(res); } } }; /** * Returns a translation instantly from the internal state of loaded translation. * All rules regarding the current language, the preferred language of even fallback languages will be used except any promise handling. * @param key * @param interpolateParams * @returns {string} */ TranslateService.prototype.instant = function (key, interpolateParams) { if (!isDefined(key) || !key.length) { throw new Error("Parameter \"key\" required"); } var res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams); if (typeof res.subscribe !== "undefined") { if (key instanceof Array) { var obj_1 = {}; key.forEach(function (value, index) { obj_1[key[index]] = key[index]; }); return obj_1; } return key; } else { return res; } }; /** * Sets the translated value of a key * @param key * @param value * @param lang */ TranslateService.prototype.set = function (key, value, lang) { if (lang === void 0) { lang = this.currentLang; } this.translations[lang][key] = value; this.updateLangs(); this.onTranslationChange.emit({ lang: lang, translations: this.translations[lang] }); }; /** * Changes the current lang * @param lang */ TranslateService.prototype.changeLang = function (lang) { this.currentLang = lang; this.onLangChange.emit({ lang: lang, translations: this.translations[lang] }); // if there is no default lang, use the one that we just set if (!this.defaultLang) { this.changeDefaultLang(lang); } }; /** * Changes the default lang * @param lang */ TranslateService.prototype.changeDefaultLang = function (lang) { this.defaultLang = lang; this.onDefaultLangChange.emit({ lang: lang, translations: this.translations[lang] }); }; /** * Allows to reload the lang file from the file * @param lang * @returns {Observable<any>} */ TranslateService.prototype.reloadLang = function (lang) { this.resetLang(lang); return this.getTranslation(lang); }; /** * Deletes inner translation * @param lang */ TranslateService.prototype.resetLang = function (lang) { this.translations[lang] = undefined; }; /** * Returns the language code name from the browser, e.g. "de" * * @returns string */ TranslateService.prototype.getBrowserLang = function () { if (typeof window === 'undefined' || typeof window.navigator === 'undefined') { return undefined; } var browserLang = window.navigator.languages ? window.navigator.languages[0] : null; browserLang = browserLang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage; if (browserLang.indexOf('-') !== -1) { browserLang = browserLang.split('-')[0]; } if (browserLang.indexOf('_') !== -1) { browserLang = browserLang.split('_')[0]; } return browserLang; }; /** * Returns the culture language code name from the browser, e.g. "de-DE" * * @returns string */ TranslateService.prototype.getBrowserCultureLang = function () { if (typeof window === 'undefined' || typeof window.navigator === 'undefined') { return undefined; } var browserCultureLang = window.navigator.languages ? window.navigator.languages[0] : null; browserCultureLang = browserCultureLang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage; return browserCultureLang; }; TranslateService.decorators = [ { type: Injectable }, ]; /** @nocollapse */ TranslateService.ctorParameters = function () { return [ { type: TranslateLoader, }, { type: TranslateParser, }, { type: MissingTranslationHandler, decorators: [{ type: Optional },] }, ]; }; return TranslateService; }());