@fabioguelfi/angular-translate
Version:
A lightweight internationalization library for Angular applications
460 lines (448 loc) • 13.6 kB
JavaScript
import { InjectionToken, Inject, Injectable, Directive, ElementRef, Input, Pipe, NgModule } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { BehaviorSubject, Subject, of, from, combineLatest } from 'rxjs';
import { filter, switchMap, switchMapTo, take, takeUntil } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
const /** @type {?} */ CONFIG = new InjectionToken('config');
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class LoaderService {
/**
* @param {?} http
* @param {?} config
*/
constructor(http, config) {
this.http = http;
this.config = config;
this.path = '/assets/languages/';
this.extension = '.json';
this.path = config.path ? config.path : this.path;
}
/**
* @param {?} fileName
* @return {?}
*/
getFile(fileName) {
return this.http.get(this.path + fileName + this.extension);
}
}
LoaderService.decorators = [
{ type: Injectable }
];
/** @nocollapse */
LoaderService.ctorParameters = () => [
{ type: HttpClient, },
{ type: undefined, decorators: [{ type: Inject, args: [CONFIG,] },] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/** @enum {string} */
const CONSTANTS = {
EXIT: 'EXIT',
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class TranslateService {
/**
* @param {?} http
* @param {?} config
*/
constructor(http, config) {
this.http = http;
this.config = config;
this.translations = {};
this.translationsLoaded = new BehaviorSubject(false);
this.matcher = key => new RegExp('{{\\s?[\\b' + key + '\\b]*\\s?}}', 'gm');
this.loaderService = new LoaderService(http, config);
}
/**
* @return {?}
*/
getBrowserLanguage() {
let /** @type {?} */ browserLanguage = window.navigator.languages
? window.navigator.languages[0]
: window.navigator.language;
if (browserLanguage.indexOf('-') !== -1) {
browserLanguage = browserLanguage.split('-')[0];
}
if (browserLanguage.indexOf('_') !== -1) {
browserLanguage = browserLanguage.split('_')[0];
}
return browserLanguage;
}
/**
* @param {?} fileName
* @return {?}
*/
setDefault(fileName) {
this.defaultKey = fileName;
this.defaultPrefix = fileName.split('-')[0];
if (this.translations[this.defaultKey]) {
this.translationsLoaded.next(true);
}
else {
this.translationsLoaded.next(false);
this.loaderService.getFile(fileName)
.subscribe(translations => {
this.translations[this.defaultKey] = translations;
this.translationsLoaded.next(true);
});
}
}
/**
* @param {?} fileName
* @return {?}
*/
setOverride(fileName) {
this.overrideKey = fileName;
if (this.translations[this.overrideKey]) {
this.translationsLoaded.next(true);
}
else {
this.loaderService.getFile(fileName)
.subscribe(translations => {
this.translations[this.overrideKey] = translations;
this.translationsLoaded.next(true);
});
}
}
/**
* @param {?} keyPaths
* @return {?}
*/
get(keyPaths) {
return this.translationsLoaded.pipe(filter(Boolean), switchMapTo(keyPaths instanceof Array
? this.getAll(keyPaths)
: this.getOne(keyPaths)));
}
/**
* @param {?} keyPaths
* @param {?} fileName
* @return {?}
*/
getByFileName(keyPaths, fileName) {
const /** @type {?} */ translationLoaded = new Subject();
const /** @type {?} */ defaultFileName = `${this.defaultPrefix}-${fileName.split('-')[1]}`;
this.loaderService.getFile(fileName).pipe(file => combineLatest(file, this.loaderService.getFile(defaultFileName)), filter(([file, defaultFile]) => [file, defaultFile].indexOf(undefined) === -1), take(1)).subscribe(([translations, defaultTranslations]) => {
this.translations[fileName] = translations;
this.translations[defaultFileName] = defaultTranslations;
translationLoaded.next(fileName);
}, () => {
this.loaderService.getFile(defaultFileName)
.pipe(take(1))
.subscribe(translations => {
this.translations[defaultFileName] = translations;
translationLoaded.next(defaultFileName);
});
});
return translationLoaded.pipe(switchMap(overrideFileName => keyPaths instanceof Array
? this.getAll(keyPaths, overrideFileName, defaultFileName)
: this.getOne(keyPaths, overrideFileName, defaultFileName)));
}
/**
* @param {?} keyPath
* @param {?=} fileName
* @param {?=} defaultKey
* @return {?}
*/
getOne(keyPath, fileName = this.overrideKey, defaultKey = this.defaultKey) {
return from([this.read(keyPath, {}, fileName, defaultKey)]);
}
/**
* @param {?} keyPaths
* @param {?=} fileName
* @param {?=} defaultKey
* @return {?}
*/
getAll(keyPaths, fileName = this.overrideKey, defaultKey = this.defaultKey) {
return of(keyPaths.reduce((acc, keyPath) => (Object.assign({}, acc, { [keyPath]: this.read(keyPath, {}, fileName, defaultKey) })), {}));
}
/**
* @param {?} keyPath
* @param {?=} params
* @param {?=} overrideKey
* @param {?=} defaultKey
* @return {?}
*/
read(keyPath, params = {}, overrideKey = this.overrideKey, defaultKey = this.defaultKey) {
let /** @type {?} */ value = CONSTANTS.EXIT;
const /** @type {?} */ path = keyPath.split('.');
if (this.translations[overrideKey]) {
value = this.readValue(path, this.translations[overrideKey]);
if (value === CONSTANTS.EXIT) {
value = this.readValue(path, this.translations[defaultKey]);
}
}
else if (this.translations[defaultKey]) {
value = this.readValue(path, this.translations[defaultKey]);
}
if (Boolean(params) && params !== {}) {
value = Object.keys(params)
.reduce((final, key) => final.replace(this.matcher(key), params[key]), value);
}
if (value === CONSTANTS.EXIT) {
console.warn('Unknown Key: ', keyPath);
return keyPath;
}
return value;
}
/**
* @param {?} path
* @param {?} translation
* @return {?}
*/
readValue(path, translation) {
const /** @type {?} */ length = path.length;
for (let /** @type {?} */ i = 0; i < length; i++) {
translation = translation && translation[path[i]] ? translation[path[i]] : CONSTANTS.EXIT;
if (translation === CONSTANTS.EXIT) {
break;
}
}
return translation;
}
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
isEquivalent(a, b) {
if (!Boolean(a) || !Boolean(b)) {
return false;
}
const /** @type {?} */ aProps = Object.getOwnPropertyNames(a);
const /** @type {?} */ bProps = Object.getOwnPropertyNames(b);
if (aProps.length !== bProps.length) {
return false;
}
for (let /** @type {?} */ i = 0; i < aProps.length; i++) {
const /** @type {?} */ propName = aProps[i];
if (a[propName] !== b[propName]) {
return false;
}
}
return true;
}
}
TranslateService.decorators = [
{ type: Injectable }
];
/** @nocollapse */
TranslateService.ctorParameters = () => [
{ type: HttpClient, },
{ type: undefined, decorators: [{ type: Inject, args: [CONFIG,] },] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class TranslateDirective {
/**
* @param {?} element
* @param {?} translateService
*/
constructor(element, translateService) {
this.element = element;
this.translateService = translateService;
this.unsubscribe = new Subject();
this.translationLoaded$ = this.translateService.translationsLoaded
.pipe(takeUntil(this.unsubscribe));
}
/**
* @param {?} params
* @return {?}
*/
set params(params) {
if (!this.translateService.isEquivalent(this.translateParams, params)) {
this.translateParams = params;
if (this.translateParams) {
this.runOneCheck(this.keyPath, this.translateParams);
}
}
}
;
/**
* @return {?}
*/
ngAfterViewInit() {
this.keyPath = this.element.nativeElement.textContent ? this.element.nativeElement.textContent.trim() : '';
this.element.nativeElement.textContent = '';
this.registerKeyChecker(this.keyPath);
}
/**
* @return {?}
*/
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
/**
* @param {?} keyPath
* @return {?}
*/
registerKeyChecker(keyPath) {
this.translationLoaded$
.subscribe(isLoaded => this.doCheck(isLoaded, keyPath, this.translateParams));
}
/**
* @param {?} keyPath
* @param {?} params
* @return {?}
*/
runOneCheck(keyPath, params) {
if (keyPath) {
this.translationLoaded$
.pipe(take(1))
.subscribe(isLoaded => this.doCheck(isLoaded, keyPath, params));
}
}
/**
* @param {?} isLoaded
* @param {?} keyPath
* @param {?} params
* @return {?}
*/
doCheck(isLoaded, keyPath, params) {
if (isLoaded) {
const /** @type {?} */ readValue = keyPath !== '' ? this.translateService.read(keyPath, params) : '';
this.element.nativeElement.textContent = readValue === keyPath ? '' : readValue;
}
}
}
TranslateDirective.decorators = [
{ type: Directive, args: [{
selector: '[translate]'
},] }
];
/** @nocollapse */
TranslateDirective.ctorParameters = () => [
{ type: ElementRef, },
{ type: TranslateService, },
];
TranslateDirective.propDecorators = {
"params": [{ type: Input, args: ['translate',] },],
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class TranslatePipe {
/**
* @param {?} translateService
*/
constructor(translateService) {
this.translateService = translateService;
this.translation = '';
this.unsubscribe = new Subject();
this.translationLoaded$ = translateService.translationsLoaded.pipe(filter(Boolean), takeUntil(this.unsubscribe));
}
/**
* @param {?} val
* @param {?} args
* @return {?}
*/
transform(val, args) {
this.translationLoaded$.subscribe(() => {
const /** @type {?} */ readValue = val ? this.translateService.read(val, args) : '';
this.translation = readValue === val ? this.translation : readValue;
});
return this.translation;
}
/**
* @return {?}
*/
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
}
TranslatePipe.decorators = [
{ type: Pipe, args: [{
name: 'translate',
pure: false
},] }
];
/** @nocollapse */
TranslatePipe.ctorParameters = () => [
{ type: TranslateService, },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
class TranslateModule {
/**
* @param {?=} config
* @return {?}
*/
static forRoot(config = {}) {
return {
ngModule: TranslateModule,
providers: [
TranslateService,
LoaderService,
{ provide: CONFIG, useValue: config }
]
};
}
;
/**
* @return {?}
*/
static forChild() {
return {
ngModule: TranslateModule
};
}
;
}
TranslateModule.decorators = [
{ type: NgModule, args: [{
imports: [HttpClientModule],
declarations: [
TranslateDirective,
TranslatePipe
],
exports: [
TranslateDirective,
TranslatePipe
]
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
const /** @type {?} */ translations = {
'default-en': {
'BODY': {
'KNOWN_KEY': 'Known key example'
}
}
};
const /** @type {?} */ LoaderServiceMock = {
path: '/assets/language',
extension: '.json',
http: null,
config: null,
getFile: (key) => of(translations[key])
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
export { TranslateModule, TranslateService, TranslateDirective, TranslatePipe, LoaderService, LoaderServiceMock, CONFIG as ɵa };
//# sourceMappingURL=angular-translate.js.map