From 3d6b821a1521c532eab8843e587ac501d7622f0b Mon Sep 17 00:00:00 2001 From: Norwin Roosen Date: Sat, 16 Feb 2019 22:07:44 +0100 Subject: [PATCH] add i18n infrastructure (#1) --- package-lock.json | 106 ++++++++++++++++++++++------------- package.json | 2 + src/app/app.component.ts | 32 +++++++---- src/app/app.html | 6 +- src/app/app.module.ts | 22 ++++++-- src/assets/i18n/de.json | 16 ++++++ src/assets/i18n/en.json | 16 ++++++ src/constants.ts | 4 ++ src/pages/blockly/blockly.ts | 3 - 9 files changed, 145 insertions(+), 62 deletions(-) create mode 100644 src/assets/i18n/de.json create mode 100644 src/assets/i18n/en.json create mode 100644 src/constants.ts diff --git a/package-lock.json b/package-lock.json index 5725683..d8a78ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1050,6 +1050,16 @@ "tslib": "^1.7.1" } }, + "@ngx-translate/core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-9.1.1.tgz", + "integrity": "sha1-rhA5KINrip4Gn9Li52+iGYzH5ig=" + }, + "@ngx-translate/http-loader": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-2.0.1.tgz", + "integrity": "sha1-qmd4jmS/qGUmkad7Ais7QDEgkRM=" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1245,7 +1255,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -1304,7 +1314,7 @@ }, "autoprefixer": { "version": "7.2.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "resolved": "http://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", "dev": true, "requires": { @@ -1347,7 +1357,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -1572,7 +1582,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -1609,7 +1619,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -1653,7 +1663,7 @@ }, "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -1722,7 +1732,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -2877,7 +2887,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -2890,7 +2900,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -2943,7 +2953,7 @@ }, "d": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { @@ -3073,7 +3083,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -3546,7 +3556,7 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "dev": true, "requires": { @@ -3653,7 +3663,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3690,7 +3701,8 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -3699,7 +3711,8 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3802,7 +3815,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3812,6 +3826,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3837,6 +3852,7 @@ "minipass": { "version": "2.2.4", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3853,6 +3869,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3925,7 +3942,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3935,6 +3953,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4010,7 +4029,8 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4040,6 +4060,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4057,6 +4078,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4095,11 +4117,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.2", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -4154,7 +4178,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -4349,7 +4373,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -4775,7 +4799,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -4895,7 +4919,7 @@ }, "magic-string": { "version": "0.22.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "dev": true, "requires": { @@ -4939,7 +4963,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, @@ -4964,7 +4988,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -5168,7 +5192,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -5194,7 +5218,7 @@ "dependencies": { "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "dev": true } @@ -5274,7 +5298,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -5474,7 +5498,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -5673,7 +5697,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -6788,7 +6812,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -7105,7 +7129,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -7123,7 +7147,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -7473,7 +7497,7 @@ }, "yargs": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "requires": { @@ -7972,7 +7996,8 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", @@ -7997,7 +8022,8 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -8657,7 +8683,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -8866,7 +8892,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -8903,7 +8929,7 @@ }, "xmlbuilder": { "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "dev": true }, diff --git a/package.json b/package.json index e6c6804..e3253c1 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,8 @@ "@ionic-native/splash-screen": "~4.15.0", "@ionic-native/status-bar": "~4.15.0", "@ionic/storage": "2.2.0", + "@ngx-translate/core": "^9.1.1", + "@ngx-translate/http-loader": "^2.0.1", "cordova-android": "7.1.1", "cordova-browser": "5.0.4", "cordova-plugin-device": "^2.0.2", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index b215d29..4ffe894 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,8 +2,9 @@ import { Component, ViewChild } from '@angular/core'; import { Nav, Platform } from 'ionic-angular'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; +import { TranslateService } from '@ngx-translate/core'; -import { BlocklyPage } from '../pages/Blockly/blockly'; +import { COLORS, DEFAULT_LANG } from '../constants'; import { BlocklyPage } from '../pages/blockly/blockly'; @Component({ @@ -16,17 +17,27 @@ export class openSenseApp { rootPage:any = BlocklyPage; pages: Array<{title: string, component: any}> = [ - { title:'Blockly', component:'BlocklyPage' }, - { title: 'About', component: 'AboutPage' }, + { title: 'MENU.BLOCKLY', component: 'BlocklyPage' }, + { title: 'MENU.ABOUT', component: 'AboutPage' }, ]; - constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) { - platform.ready().then(() => { - // Okay, so the platform is ready and our plugins are available. - // Here you can do any higher level native things you might need. - statusBar.styleDefault(); - splashScreen.hide(); - }); + constructor( + public translate: TranslateService, + platform: Platform, + statusBar: StatusBar, + splashScreen: SplashScreen, + ) { + platform.ready() + .then(() => { + this.translate.setDefaultLang(DEFAULT_LANG) + this.translate.use(this.translate.getBrowserLang()) // @TODO: check if this works on all platforms! + // @TODO: also pass language to blockly (if possible?) + + statusBar.styleDefault(); + splashScreen.hide(); + + splashScreen.hide() + }) } openPage(page) { @@ -35,4 +46,3 @@ export class openSenseApp { this.nav.setRoot(page.component); } } - diff --git a/src/app/app.html b/src/app/app.html index d1a04fd..51c722b 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -1,20 +1,18 @@ - Menu + {{ 'MENU.TITLE' | translate }} - - diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8859de4..9900050 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,15 +1,22 @@ import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; +import { HttpClientModule, HttpClient } from '@angular/common/http'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { SplashScreen } from '@ionic-native/splash-screen'; import { StatusBar } from '@ionic-native/status-bar'; +import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; +import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { openSenseApp } from './app.component'; -import { HttpClientModule } from '@angular/common/http'; -import { OtaWizardPage } from '../pages/ota-wizard/ota-wizard'; import { OtaWizardPageModule } from '../pages/ota-wizard/ota-wizard.module'; import { BlocklyPageModule } from '../pages/blockly/blockly.module'; -import { BlocklyPageModule } from '../pages/Blockly/blockly.module'; + +// For AoT compilation (production builds) we need to have a factory for the loader of translation files. +// @TODO: we possibly could optimize this by using a static loader in combination with webpack: +// https://github.com/ngx-translate/http-loader#angular-cliwebpack-translateloader-example +export function createTranslateLoader(http: HttpClient) { + return new TranslateHttpLoader(http, './assets/i18n/', '.json'); +} @NgModule({ declarations: [ @@ -20,7 +27,14 @@ import { BlocklyPageModule } from '../pages/Blockly/blockly.module'; BrowserModule, OtaWizardPageModule, BlocklyPageModule, - IonicModule.forRoot(openSenseApp) + IonicModule.forRoot(openSenseApp), + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: createTranslateLoader, + deps: [HttpClient] + } + }), ], bootstrap: [IonicApp], entryComponents: [ diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json new file mode 100644 index 0000000..3236c03 --- /dev/null +++ b/src/assets/i18n/de.json @@ -0,0 +1,16 @@ +{ + "MENU": { + "TITLE": "Menü", + "BLOCKLY": "Blockly", + "ABOUT": "Über" + }, + "ABOUT": { + + }, + "BLOCKLY": { + "TITLE": "Blockly für senseBox" + }, + "OTAWIZARD": { + + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json new file mode 100644 index 0000000..c6fc678 --- /dev/null +++ b/src/assets/i18n/en.json @@ -0,0 +1,16 @@ +{ + "MENU": { + "TITLE": "Menu", + "ABOUT": "About", + "BLOCKLY": "Blockly" + }, + "ABOUT": { + + }, + "BLOCKLY": { + "TITLE": "Blockly for senseBox" + }, + "OTAWIZARD": { + + } +} diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..f9f861d --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,4 @@ +export const COLORS = { + PRIMARY: '#4EAF47', // sensebox green +} +export const DEFAULT_LANG = 'en' diff --git a/src/pages/blockly/blockly.ts b/src/pages/blockly/blockly.ts index 126cf95..17d1512 100644 --- a/src/pages/blockly/blockly.ts +++ b/src/pages/blockly/blockly.ts @@ -1,7 +1,5 @@ import { Component, ViewChild, ElementRef } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; -import { TranslateService } from '@ngx-translate/core'; - import { OtaWizardPage } from '../ota-wizard/ota-wizard'; @IonicPage() @@ -17,7 +15,6 @@ export class BlocklyPage { constructor( public navCtrl: NavController, public navParams: NavParams, - public translate: TranslateService, ) { // need to assign it here to keep the function reference for unsubscribing again // and to maintain the this scope properly