diff --git a/src/app/services/internationalisation/internationalisation.service.ts b/src/app/services/internationalisation/internationalisation.service.ts index 9700324cae9e628aa393af5d6579db3d3640b681..fe7c6dc3e0328979325f2b54c4d2ad8a6d8369dc 100644 --- a/src/app/services/internationalisation/internationalisation.service.ts +++ b/src/app/services/internationalisation/internationalisation.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@angular/core"; +import { Injectable, isDevMode } from "@angular/core"; import { Message, MessageCode, Observable, Observer } from "jalhyd"; @@ -18,6 +18,9 @@ export class I18nService extends Observable implements Observer { /** localized messages */ private _Messages: StringMap; + /** localized messages in fallback language (the one in the config file) */ + private _fallbackMessages: StringMap; + constructor( private applicationSetupService: ApplicationSetupService, private httpService: HttpService @@ -27,6 +30,10 @@ export class I18nService extends Observable implements Observer { fr: "Français", en: "English" }; + // load fallback language messages once for all + this.httpGetMessages(this.applicationSetupService.fallbackLanguage).then((res: any) => { + this._fallbackMessages = res; + }); // add language preferences observer this.applicationSetupService.addObserver(this); } @@ -53,7 +60,7 @@ export class I18nService extends Observable implements Observer { public setLanguage(code: string) { // is language supported ? if (! Object.keys(this._availableLanguages).includes(code)) { - throw new Error(`ERROR_LANGUAGE_UNSUPPORTED "${code}"`); + throw new Error(`LANGUAGE_UNSUPPORTED "${code}"`); } // did language change ? if (this._currentLanguage !== code) { @@ -62,7 +69,8 @@ export class I18nService extends Observable implements Observer { this._Messages = undefined; // reload all messages const that = this; - this.httpGetMessages().then((res) => { + this.httpGetMessages(code).then((res: any) => { + that._Messages = res; // propagate language change to all application that.notifyObservers(undefined); }); @@ -70,39 +78,73 @@ export class I18nService extends Observable implements Observer { } /** - * Loads localized messages from JSON files, for the current language - * (general message file, not calculator-specific ones) + * Loads localized messages from JSON files for the given language + * (general messages files, not calculator-specific ones) */ - private httpGetMessages(): Promise<void> { - const that = this; - const fileName = "messages." + this._currentLanguage + ".json"; - return this.httpService.httpGetRequestPromise("locale/" + fileName).then( - (res: any) => { that._Messages = res; } - ); + private httpGetMessages(lang: string): Promise<void> { + const fileName = "messages." + lang + ".json"; + const filePath = "locale/" + fileName; + return this.httpService.httpGetRequestPromise(filePath).then((res: any) => { + return res; + }); } private getMessageFromCode(c: MessageCode): string { if (! this._Messages) { - return `*** Messages not loaded yet ***`; + return `*** messages not loaded yet ***`; } if (this._Messages[MessageCode[c]] === undefined) { - return `*** Message ${MessageCode[c]} non traduit ***`; + return `*** message not found ${MessageCode[c]} ***`; } return this._Messages[MessageCode[c]]; } /** - * Traduit un texte défini dans un fichier de langue, à partir de sa clé + * Translates a text from its key. + * + * In production mode, looks in different messages collections : + * 1. ${msg} if provided + * 2. messages for current language + * 3. messages for fallback language + * + * In dev mode, looks only in 1. if provided, else only in 2. which makes missing + * translations easier to detect + * * @param textKey id du texte (ex: "ERROR_PARAM_NULL") */ - public localizeText(textKey: string, messages = this._Messages) { - if (messages === undefined) { - return `*** messages not loaded: ${this._currentLanguage} ***`; - } - if (messages[textKey] === undefined) { - return `*** message not found: ${textKey} ***`; + public localizeText(textKey: string, msg?: StringMap) { + if (isDevMode()) { + // expose missing translations + if (msg) { + if (msg[textKey] === undefined) { + return `*** message not found: ${textKey} ***`; + } + return msg[textKey]; + } else { + if (! this._Messages) { + return `*** messages not loaded: ${this._currentLanguage} ***`; + } + if (this._Messages[textKey] === undefined) { + return `*** message not found: ${textKey} ***`; + } + return this._Messages[textKey]; + } + } else { + const messages = msg || this._Messages; + if (! messages) { + return `*** messages not loaded: ${this._currentLanguage} ***`; + } + if (messages[textKey] === undefined) { + // try fallback language before giving up + if (this._fallbackMessages[textKey] === undefined) { + return `*** message not found: ${textKey} ***`; + } else { + return this._fallbackMessages[textKey]; + } + } else { + return messages[textKey]; + } } - return messages[textKey]; } /**