From 9f5bf52dc6ebdaab0fadcdeccdb8f482131f68a4 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Tue, 25 Jul 2017 09:53:08 +0200
Subject: [PATCH] =?UTF-8?q?d=C3=A9but=20de=20prise=20en=20charge=20de=20l'?=
 =?UTF-8?q?internationalisation?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                                     |  9 +++
 package.json                                  | 59 ++++++++++---------
 src/app/i18n-providers.ts                     | 34 +++++++++++
 .../param-input/param-input.component.html    |  8 ++-
 src/app/param-input/param-input.component.ts  | 26 ++++++--
 src/index.html                                | 12 ++++
 src/locale/messages.en.xlf                    | 10 ++++
 src/main.ts                                   |  7 ++-
 src/systemjs-text-plugin.js                   | 20 +++++++
 9 files changed, 149 insertions(+), 36 deletions(-)
 create mode 100644 src/app/i18n-providers.ts
 create mode 100644 src/locale/messages.en.xlf
 create mode 100644 src/systemjs-text-plugin.js

diff --git a/README.md b/README.md
index dbf6b6701..8f60da8dd 100644
--- a/README.md
+++ b/README.md
@@ -36,3 +36,12 @@ and then :
 ### To flag suspicious language usage
 
 `npm run lint`
+
+### To generate translation file
+
+`npm run i18n`
+
+This creates a _src/messages.xlf_ file. Move it to _src/locale/messages.<locale>.xlf_
+
+
+!!!! comment fait on pour mettre à jour un fichier messages.<locale>.xlf_ existant ? !!!!
diff --git a/package.json b/package.json
index 825abcde4..b2d55b18d 100644
--- a/package.json
+++ b/package.json
@@ -18,44 +18,47 @@
     "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
     "pretest:once": "npm run build",
     "test:once": "karma start karma.conf.js --single-run",
-    "lint": "tslint ./src/**/*.ts -t verbose"
+    "lint": "tslint ./src/**/*.ts -t verbose",
+    "i18n": "ng-xi18n --i18nFormat=xlf -p src/tsconfig.json"
   },
   "keywords": [],
   "author": "",
   "license": "MIT",
   "dependencies": {
-    "@angular/animations": "^4.2.5",
-    "@angular/common": "^4.2.5",
-    "@angular/compiler": "^4.2.5",
-    "@angular/core": "^4.2.5",
-    "@angular/forms": "^4.2.5",
-    "@angular/http": "^4.2.5",
-    "@angular/material": "^2.0.0-beta.7",
-    "@angular/platform-browser": "^4.2.5",
-    "@angular/platform-browser-dynamic": "^4.2.5",
-    "@angular/router": "^4.2.5",
+    "@angular/animations": "4.2.5",
+    "@angular/common": "4.2.5",
+    "@angular/compiler": "4.2.5",
+    "@angular/compiler-cli": "4.2.5",
+    "@angular/core": "4.2.5",
+    "@angular/forms": "4.2.5",
+    "@angular/http": "4.2.5",
+    "@angular/material": "2.0.0-beta.7",
+    "@angular/platform-browser": "4.2.5",
+    "@angular/platform-browser-dynamic": "4.2.5",
+    "@angular/router": "4.2.5",
+    "@angular/platform-server": "4.2.5",
     "systemjs": "0.19.40",
-    "core-js": "^2.4.1",
+    "core-js": "2.4.1",
     "rxjs": "5.0.1",
-    "zone.js": "^0.8.4",
-    "jalhyd": "^1.0.0"
+    "zone.js": "0.8.4",
+    "jalhyd": "1.0.0"
   },
   "devDependencies": {
-    "concurrently": "^3.2.0",
-    "lite-server": "^2.2.2",
-    "typescript": "^2.2.2",
+    "concurrently": "3.2.0",
+    "lite-server": "2.2.2",
+    "typescript": "2.2.2",
     "canonical-path": "0.0.2",
-    "tslint": "^3.15.1",
-    "lodash": "^4.16.4",
-    "jasmine-core": "~2.4.1",
-    "karma": "^1.3.0",
-    "karma-chrome-launcher": "^2.0.0",
-    "karma-cli": "^1.0.1",
-    "karma-jasmine": "^1.0.2",
-    "karma-jasmine-html-reporter": "^0.2.2",
-    "protractor": "~4.0.14",
-    "rimraf": "^2.5.4",
-    "@types/node": "^6.0.46",
+    "tslint": "3.15.1",
+    "lodash": "4.16.4",
+    "jasmine-core": "2.4.1",
+    "karma": "1.3.0",
+    "karma-chrome-launcher": "2.0.0",
+    "karma-cli": "1.0.1",
+    "karma-jasmine": "1.0.2",
+    "karma-jasmine-html-reporter": "0.2.2",
+    "protractor": "4.0.14",
+    "rimraf": "2.5.4",
+    "@types/node": "6.0.46",
     "@types/jasmine": "2.5.36"
   },
   "repository": {}
diff --git a/src/app/i18n-providers.ts b/src/app/i18n-providers.ts
new file mode 100644
index 000000000..76ee311c5
--- /dev/null
+++ b/src/app/i18n-providers.ts
@@ -0,0 +1,34 @@
+import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, MissingTranslationStrategy } from '@angular/core';
+import { CompilerConfig } from '@angular/compiler';
+
+export function getTranslationProviders(): Promise<Object[]> {
+
+    // Get the locale id from the global
+    const locale = document['locale'] as string;
+
+    // return no providers if fail to get translation file for locale
+    const noProviders: Object[] = [];
+
+    // No locale or French: no translation providers
+    if (!locale || locale === 'fr-FR') {
+        return Promise.resolve(noProviders);
+    }
+
+    // Ex: 'locale/messages.es.xlf`
+    const translationFile = `./locale/messages.${locale}.xlf`;
+
+    return getTranslationsWithSystemJs(translationFile)
+        .then((translations: string) => [
+            { provide: TRANSLATIONS, useValue: translations },
+            { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
+            { provide: LOCALE_ID, useValue: locale },
+            { provide: CompilerConfig, useValue: new CompilerConfig({ missingTranslation: MissingTranslationStrategy.Error }) }
+        ])
+        .catch(() => noProviders); // ignore if file not found
+}
+
+declare var System: any;
+
+function getTranslationsWithSystemJs(file: string) {
+    return System.import(file + '!text'); // relies on text plugin
+}
diff --git a/src/app/param-input/param-input.component.html b/src/app/param-input/param-input.component.html
index 265cb5a83..87e6d7b2e 100644
--- a/src/app/param-input/param-input.component.html
+++ b/src/app/param-input/param-input.component.html
@@ -1,5 +1,11 @@
+<!--
+format de l'attribut i18n :
+i18n="<meaning>|<description>@@<custom id>"
+<p i18n="titre saisie|Titre du contrôle de saisie de paramètre@@titre_saisie_param">Saisie de paramètre</p>
+-->
+<p i18n="@@titre_saisie_param">Saisie de paramètre</p>
 <md-input-container>
-    <input mdInput placeholder="{{_paramDef.symbol}}" [ngModel]="_uiValue.uncheckValueString" (ngModelChange)="setValue($event)"
+    <input mdInput placeholder="{{_paramDef.symbol}}" [ngModel]="_uiValue.uncheckedValueString" (ngModelChange)="setValue($event)"
     />
     <md-hint>{{_message}}</md-hint>
 </md-input-container>
diff --git a/src/app/param-input/param-input.component.ts b/src/app/param-input/param-input.component.ts
index ead9e0285..447b8a6ea 100644
--- a/src/app/param-input/param-input.component.ts
+++ b/src/app/param-input/param-input.component.ts
@@ -3,7 +3,7 @@
 import { Component, Input, forwardRef, OnInit, DoCheck, ChangeDetectorRef } from '@angular/core';
 import { ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl } from '@angular/forms';
 
-import { ParamDefinition, NumericalString } from 'jalhyd';
+import { ParamDefinition, NumericalString, Internationalisation, Language, ErrorMessage } from 'jalhyd';
 
 import { ParamService } from '../param-service/param.service';
 
@@ -55,7 +55,6 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
     /**
      * valeur dans le contrôle (saisie par l'utilisateur)
      */
-    // private _uiValue: string;
     private _uiValue: NumericalString;
 
     constructor(private paramService: ParamService, private changeDetector: ChangeDetectorRef) {
@@ -93,6 +92,10 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
     ngOnInit() {
         // retrieve parameter from symbol
         this._paramDef = this.paramService.getParameter(this._paramSymbol);
+
+        let docLocale: string = document['locale'] as string;
+        Internationalisation.getInstance().setLocale(docLocale);
+        console.log("doc locale " + docLocale);
     }
 
     // private getValue() {
@@ -146,11 +149,22 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
                 this._paramDef.checkValue(v.numericalValue);
             }
             catch (e) {
-                this._message = e;
+                if (e instanceof ErrorMessage)
+                    this._message = Internationalisation.getInstance().localizeErrorMessage(e);
+                else
+                    this._message = "invalid value";
+            }
+        }
+        else {
+            switch (Internationalisation.getInstance().lang) {
+                case Language.FRENCH:
+                    this._message = "Veuillez entrer une valeur numérique";
+                    break;
+
+                default:
+                    this._message = "Please enter a numerical value";
             }
         }
-        else
-            this._message = "Please enter a numerical value";
 
         this.log("updateMessage end :" + this.getSParam() + this.getSfromUI() + this.getSUIvalue(v) + "  message=" + this._message);
     }
@@ -192,7 +206,7 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
 
     private log(m: string) {
         let t: number = new Date().getTime() - ParamInputComponent._startTime;
-        console.log("ParamInputComponent(" + this._id + ") " + t + " : " + m);
+        //   console.log("ParamInputComponent(" + this._id + ") " + t + " : " + m);
     }
 
     // ControlValueAccessor interface
diff --git a/src/index.html b/src/index.html
index ca397ac50..132635677 100644
--- a/src/index.html
+++ b/src/index.html
@@ -16,6 +16,18 @@
 
   <script src="systemjs.config.js"></script>
   <script>
+    // Get the locale id somehow
+    document.locale = 'fr-FR';
+    // document.locale = 'en';
+
+    // Map to the text plugin
+    System.config({
+      map: {
+        text: 'systemjs-text-plugin.js'
+      }
+    });
+
+    // Launch the app
     System.import('main.js').catch(function (err) { console.error(err); });
   </script>
 
diff --git a/src/locale/messages.en.xlf b/src/locale/messages.en.xlf
new file mode 100644
index 000000000..9c90b3e35
--- /dev/null
+++ b/src/locale/messages.en.xlf
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
+  <file source-language="en" datatype="plaintext" original="ng2.template">
+    <body>
+      <trans-unit id="titre_saisie_param" datatype="html">
+        <target>Parameter input</target>
+      </trans-unit>
+    </body>
+  </file>
+</xliff>
diff --git a/src/main.ts b/src/main.ts
index 311c44b76..d58d8c33d 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,5 +1,10 @@
 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { getTranslationProviders } from './app/i18n-providers';
 
 import { AppModule } from './app/app.module';
 
-platformBrowserDynamic().bootstrapModule(AppModule);
+//platformBrowserDynamic().bootstrapModule(AppModule);
+getTranslationProviders().then(providers => {
+    const options = { providers };
+    platformBrowserDynamic().bootstrapModule(AppModule, options);
+});
diff --git a/src/systemjs-text-plugin.js b/src/systemjs-text-plugin.js
new file mode 100644
index 000000000..fb7224a63
--- /dev/null
+++ b/src/systemjs-text-plugin.js
@@ -0,0 +1,20 @@
+/*
+  SystemJS Text plugin from
+  https://github.com/systemjs/plugin-text/blob/master/text.js
+*/
+exports.translate = function (load) {
+  if (this.builder && this.transpiler) {
+    load.metadata.format = 'esm';
+    return 'exp' + 'ort var __useDefault = true; exp' + 'ort default ' + JSON.stringify(load.source) + ';';
+  }
+
+  load.metadata.format = 'amd';
+  return 'def' + 'ine(function() {\nreturn ' + JSON.stringify(load.source) + ';\n});';
+}
+
+
+/*
+Copyright 2017 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
-- 
GitLab