diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index dd4e31e8a8416ea6234b73a3f66ebe422123bb78..92462013f634e7ec6f954d77d07203e3369794f6 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -433,8 +433,6 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe this.setForm(this.formulaireService.getFormulaireFromId(uid)); this.resultsComponent.formulaire = this._formulaire; this._calculatorNameComponent.model = this._formulaire; - // reload localisation in all cases - this.formulaireService.loadUpdateFormulaireLocalisation(this._formulaire); // call Form init hook this._formulaire.onCalculatorInit(); break; diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts index 140741bebf22d2d630cff6942ff6947b4ba42524..e0c346cf8ad5a72a4a242cb85cc4a5cf8bd5b0e9 100644 --- a/src/app/formulaire/definition/form-definition.ts +++ b/src/app/formulaire/definition/form-definition.ts @@ -52,12 +52,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs /** fichier de configuration */ private _jsonConfig: {}; - /** clé-valeurs du fichier de localisation spécifique à ce module */ - private _specificLocalisation: StringMap; - - /** ISO 639-1 language code of the current language (to avoid unnecessary localisation reload) */ - private _currentLanguage: string; - /** copy of options.resultsHelp read by FormDefinition.parseOptions() */ public helpLinks: { [key: string]: string }; @@ -79,14 +73,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs return this._calculateDisabled; } - public get specificLocalisation() { - return this._specificLocalisation; - } - - public get currentLanguage() { - return this._currentLanguage; - } - public get calculatorType(): CalculatorType { const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props; return props["calcType"]; @@ -424,11 +410,9 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs } } - public updateLocalisation(localisation: StringMap, lang: string) { - this._specificLocalisation = localisation; - this._currentLanguage = lang; + public updateLocalisation(lang: string) { for (const fe of this.topFormElements) { - fe.updateLocalisation(localisation); + fe.updateLocalisation(); } } diff --git a/src/app/formulaire/elements/fieldset-container.ts b/src/app/formulaire/elements/fieldset-container.ts index 1c31212daed733bd6a8a84e360f6b4a9ed09b5c0..96f719fcf0dd192ee0f7af1bf613bb9b69309b48 100644 --- a/src/app/formulaire/elements/fieldset-container.ts +++ b/src/app/formulaire/elements/fieldset-container.ts @@ -1,15 +1,12 @@ import { FormulaireElement } from "./formulaire-element"; import { FieldSet } from "./fieldset"; import { FieldsetTemplate } from "./fieldset-template"; -import { StringMap } from "../../stringmap"; import { FormulaireNode } from "./formulaire-node"; import { Nub } from "jalhyd"; export class FieldsetContainer extends FormulaireElement { private _templates: FieldsetTemplate[]; - private _localisation: StringMap; - public title: string; constructor(parent: FormulaireNode) { @@ -109,11 +106,4 @@ export class FieldsetContainer extends FormulaireElement { } } } - - public updateLocalisation(loc: StringMap = this._localisation) { - this._localisation = loc; - if (loc !== undefined) { - super.updateLocalisation(loc); - } - } } diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index f9063cb45285821b85b4a7fedcd8eb35095560b1..dce1e17d48ec85a85578f333ccbf908aaca69413 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -11,7 +11,6 @@ import { FormulaireElement } from "./formulaire-element"; import { Field } from "./field"; import { SelectField } from "./select-field"; import { NgParameter, ParamRadioConfig } from "./ngparam"; -import { StringMap } from "../../stringmap"; import { FieldsetContainer } from "./fieldset-container"; import { SelectFieldCustom } from "./select-field-custom"; import { FormulaireFixedVar } from "../definition/form-fixedvar"; @@ -22,9 +21,6 @@ export class FieldSet extends FormulaireElement implements Observer { /** Nub associé */ private _nub: Nub; - /** dictionnaire de traduction */ - private _localisation: StringMap; - /** fichier de configuration */ private _jsonConfig: {}; @@ -203,18 +199,6 @@ export class FieldSet extends FormulaireElement implements Observer { this.clearKids(); } - public updateLocalisation(loc?: StringMap) { - if (! loc) { - loc = this._localisation; - } else { - this._localisation = loc; - } - - if (loc) { - super.updateLocalisation(loc); - } - } - /** * Reloads the model values and properties, and reloads localisation strings */ diff --git a/src/app/formulaire/elements/formulaire-element.ts b/src/app/formulaire/elements/formulaire-element.ts index 95c14c76d51a5ad2004d2468b5557b649ae66407..79a4899ea702d5c7f964ca0b5124d242bf4290c9 100644 --- a/src/app/formulaire/elements/formulaire-element.ts +++ b/src/app/formulaire/elements/formulaire-element.ts @@ -71,13 +71,13 @@ export abstract class FormulaireElement extends FormulaireNode { * @param loc calculator-specific localised messages map * @param key Element label key */ - public updateLocalisation(loc: StringMap, key?: string) { + public updateLocalisation(key?: string) { if (!key) { key = this._confId; } - this._label = this.intlService.localizeText(key, loc); + this._label = this.intlService.localizeText(key); for (const f of this.getKids()) { - f.updateLocalisation(loc); + f.updateLocalisation(); } } diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts index 9be231395892bab31c6003d5ac62774a64acedbb..4f7196cf6b8b8ab4d78cca767a28c99e36913ea5 100644 --- a/src/app/formulaire/elements/select-field.ts +++ b/src/app/formulaire/elements/select-field.ts @@ -110,13 +110,13 @@ export class SelectField extends Field { }, this); } - public updateLocalisation(loc: StringMap) { - super.updateLocalisation(loc); + public updateLocalisation() { + super.updateLocalisation(); for (const e of this._entries) { // some Select fields already have a translated label at this time; translate others if (e.label === undefined) { const aId = e.id.split("_"); - e.label = ServiceFactory.i18nService.localizeText(`${aId[1].toUpperCase()}_${aId[2]}`, loc); + e.label = ServiceFactory.i18nService.localizeText(`${aId[1].toUpperCase()}_${aId[2]}`); } } } diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts index d4cdb6ef29af0b04ac60d3991cf1a3ea151bde0e..78c74c8a7e8545eccb75eb90242fb160a7782f0d 100644 --- a/src/app/services/formulaire.service.ts +++ b/src/app/services/formulaire.service.ts @@ -26,7 +26,6 @@ import { FormulaireDefinition } from "../formulaire/definition/form-definition"; import { FormulaireElement } from "../formulaire/elements/formulaire-element"; import { InputField } from "../formulaire/elements/input-field"; import { SelectField } from "../formulaire/elements/select-field"; -import { StringMap } from "../stringmap"; import { FormulaireSectionParametree } from "../formulaire/definition/form-section-parametree"; import { FormulaireCourbeRemous } from "../formulaire/definition/form-courbe-remous"; import { FormulaireParallelStructure } from "../formulaire/definition/form-parallel-structures"; @@ -52,8 +51,10 @@ export class FormulaireService extends Observable { private _currentFormId: string = null; - /** to avoid loading language files multiple times */ - private _languageCache = {}; + public static getConfigPathPrefix(ct: CalculatorType): string { + const ctName = CalculatorType[ct].toLowerCase(); + return "app/calculators/" + ctName + "/"; + } constructor( private i18nService: I18nService, @@ -66,84 +67,16 @@ export class FormulaireService extends Observable { this._formulaires = []; } - private get _intlService(): I18nService { - return this.i18nService; - } - - private get _httpService(): HttpService { - return this.httpService; - } - public get formulaires(): FormulaireDefinition[] { return this._formulaires; } - public get languageCache() { - return this._languageCache; - } - - /** - * Loads the localisation file dedicated to calculator type ct; tries the current - * language then the fallback language; uses cache if available - */ - public loadLocalisation(calc: CalculatorType): Promise<any> { - const lang = this._intlService.currentLanguage; - return this.loadLocalisationForLang(calc, lang).then((localisation) => { - return localisation as StringMap; - }).catch((e) => { - console.error(e); - // try default lang (the one in the config file) ? - const fallbackLang = this.appSetupService.fallbackLanguage; - if (lang !== fallbackLang) { - console.error(`trying fallback language: ${fallbackLang}`); - return this.loadLocalisationForLang(calc, fallbackLang); - } - }); - } - - /** - * Loads the localisation file dedicated to calculator type ct for language lang; - * keeps it in cache for subsequent calls () - */ - private loadLocalisationForLang(calc: CalculatorType, lang: string): Promise<any> { - const ct = String(calc); - // already in cache ? - if (Object.keys(this._languageCache).includes(ct) && Object.keys(this._languageCache[calc]).includes(lang)) { - return new Promise((resolve) => { - resolve(this._languageCache[ct][lang]); - }); - } else { - const f: string = this.getConfigPathPrefix(calc) + lang + ".json"; - return this._httpService.httpGetRequestPromise(f).then((localisation) => { - this._languageCache[ct] = this._languageCache[ct] || {}; - this._languageCache[ct][lang] = localisation; - return localisation as StringMap; - }).catch((e) => { - throw new Error(`LOCALISATION_FILE_NOT_FOUND "${f}"`); - }); - } - } - - /** - * Loads localisation file corresponding to current language then updates all form strings, - * only if form language was not already set to current language - */ - public loadUpdateFormulaireLocalisation(f: FormulaireDefinition): Promise<FormulaireDefinition> { - const requiredLang = this._intlService.currentLanguage; - if (requiredLang !== f.currentLanguage) { - return this.loadLocalisation(f.calculatorType).then(localisation => { - f.updateLocalisation(localisation, requiredLang); - return f; - }); - } - } - /** * Retourne le titre complet du type de module de calcul, dans la langue en cours */ public getLocalisedTitleFromCalculatorType(type: CalculatorType) { const sCalculator: string = CalculatorType[type].toUpperCase(); - return this._intlService.localizeText(`INFO_${sCalculator}_TITRE`); + return this.intlService.localizeText(`INFO_${sCalculator}_TITRE`); } /** @@ -163,7 +96,7 @@ export class FormulaireService extends Observable { type = CalculatorType[type]; } const sCalculator: string = type.toUpperCase(); - return this._intlService.localizeText(`INFO_${sCalculator}_TITRE_COURT`); + return this.intlService.localizeText(`INFO_${sCalculator}_TITRE_COURT`); } /** @@ -174,7 +107,7 @@ export class FormulaireService extends Observable { public expandVariableName(calcType: CalculatorType, symbol: string): string { let s = ""; // language cache… - let langCache = this.languageCache; + let langCache = this.i18nService.languageCache; if (langCache && langCache[calcType]) { langCache = langCache[calcType]; // …for target Nub type } @@ -207,7 +140,7 @@ export class FormulaireService extends Observable { */ public expandVariableNameAndUnit(calcType: CalculatorType, symbol: string, forceUnit?: string): string { let s = this.expandVariableName(calcType, symbol); - let langCache = this.languageCache; // language cache… + let langCache = this.i18nService.languageCache; // language cache… if (langCache && langCache[calcType]) { langCache = langCache[calcType]; // …for target Nub type } @@ -282,8 +215,8 @@ export class FormulaireService extends Observable { } public loadConfig(ct: CalculatorType): Promise<any> { - const f: string = this.getConfigPathPrefix(ct) + "config.json"; - return this._httpService.httpGetRequestPromise(f); + const f: string = FormulaireService.getConfigPathPrefix(ct) + "config.json"; + return this.httpService.httpGetRequestPromise(f); } private newFormulaire(ct: CalculatorType): FormulaireDefinition { @@ -530,11 +463,6 @@ export class FormulaireService extends Observable { } } - public getConfigPathPrefix(ct: CalculatorType): string { - const ctName = CalculatorType[ct].toLowerCase(); - return "app/calculators/" + ctName + "/"; - } - /** * Supprime le formulaire ciblé, et demande à JaLHyd d'effacer son Nub de la Session * @param uid formulaire à supprimer @@ -632,8 +560,6 @@ export class FormulaireService extends Observable { if (nn.meta && nn.meta.title) { title = nn.meta.title; } - // pre-fill language cache (for LinkedValues labels for ex.) - await this.loadLocalisation(nn.nub.calcType); await this.createFormulaire(nn.nub.calcType, nn.nub, title); // await guarantees loading order } // apply settings diff --git a/src/app/services/internationalisation.service.ts b/src/app/services/internationalisation.service.ts index 14df039699075e1d427e1cd84958c0f914f7fcd4..26d2cecce0c2e8490055f851a0df7d184916838e 100644 --- a/src/app/services/internationalisation.service.ts +++ b/src/app/services/internationalisation.service.ts @@ -7,6 +7,7 @@ import { ApplicationSetupService } from "./app-setup.service"; import { HttpService } from "./http.service"; import { fv, decodeHtml } from "../util"; import { ServiceFactory } from "./service-factory"; +import { FormulaireService } from "./formulaire.service"; @Injectable() export class I18nService extends Observable implements Observer { @@ -23,6 +24,9 @@ export class I18nService extends Observable implements Observer { /** localized messages in fallback language (the one in the config file) */ private _fallbackMessages: StringMap; + /** to avoid loading language files multiple times */ + private _languageCache = {}; + constructor( private applicationSetupService: ApplicationSetupService, private httpService: HttpService @@ -52,6 +56,10 @@ export class I18nService extends Observable implements Observer { return this._Messages; } + public get languageCache() { + return this._languageCache; + } + /** * Defines the current language code from its ISO 639-1 code (2 characters) or locale code * (ex: "fr", "en", "fr_FR", "en-US") @@ -69,12 +77,64 @@ export class I18nService extends Observable implements Observer { if (this._currentLanguage !== code) { this._currentLanguage = code; this._Messages = undefined; - // reload all messages + // reload all messages: global lang files, plus lang files for all calculators ! const that = this; - this.httpGetMessages(code).then((res: any) => { - that._Messages = res; - // propagate language change to all application - that.notifyObservers(undefined); + console.log("> promise.all !"); + const promisesList: Promise<any>[] = []; + for (const ct in CalculatorType) { + const calcType = Number(ct); + if (!isNaN(calcType)) { + promisesList.push(this.loadLocalisation(calcType).catch((err) => { /* silent fail */ })); + } + } + Promise.all(promisesList).then(() => { + console.log(">> get global messages !"); + this.httpGetMessages(code).then((res: any) => { + that._Messages = res; + // propagate language change to all application + that.notifyObservers(undefined); + }); + }); + } + } + + /** + * Loads the localisation file dedicated to calculator type ct; tries the current + * language then the fallback language; uses cache if available + */ + public loadLocalisation(calc: CalculatorType): Promise<any> { + const lang = this.currentLanguage; + return this.loadLocalisationForLang(calc, lang).then((localisation) => { + return localisation as StringMap; + }).catch((e) => { + // try default lang (the one in the config file) ? + const fallbackLang = this.applicationSetupService.fallbackLanguage; + if (lang !== fallbackLang) { + console.error(`localisation for ${CalculatorType[calc]} not found, trying fallback language: ${fallbackLang}`); + return this.loadLocalisationForLang(calc, fallbackLang); + } + }); + } + + /** + * Loads the localisation file dedicated to calculator type ct for language lang; + * keeps it in cache for subsequent calls () + */ + private loadLocalisationForLang(calc: CalculatorType, lang: string): Promise<any> { + const ct = String(calc); + // already in cache ? + if (Object.keys(this._languageCache).includes(ct) && Object.keys(this._languageCache[calc]).includes(lang)) { + return new Promise((resolve) => { + resolve(this._languageCache[ct][lang]); + }); + } else { + const f: string = FormulaireService.getConfigPathPrefix(calc) + lang + ".json"; + return this.httpService.httpGetRequestPromise(f).then((localisation) => { + this._languageCache[ct] = this._languageCache[ct] || {}; + this._languageCache[ct][lang] = localisation; + return localisation as StringMap; + }).catch((e) => { + throw new Error(`LOCALISATION_FILE_NOT_FOUND "${f}"`); }); } } @@ -285,7 +345,8 @@ export class I18nService extends Observable implements Observer { // interface Observer /** - * Should only be triggered once at app startup, when setup service tries loading language + * Should only be triggered once at app startup, when setup service tries loading language, + * then everytime language is changed through Preferences screen * @param sender should always be ApplicationSetupService * @param data object { * action: should always be "languagePreferenceChanged"