From 1fdd58c38e35ef451a4e9d9f912567b8f29ad8f4 Mon Sep 17 00:00:00 2001 From: Manuel Kocher <manuel.kocher@tugraz.at> Date: Thu, 12 May 2022 14:43:04 +0200 Subject: [PATCH] Merge branch dbp-translation-component into master Squashed commit of the following: commit 21309f2c44bd42caaa753e34af26705c8715edc5 Merge: f69672e8 7a2e492e Author: Manuel Kocher <manuel.kocher@tugraz.at> Date: Thu May 12 14:16:56 2022 +0200 Merge branch 'master' into dbp-translation-component commit f69672e8322310e5eb8608e972a261af120dcda0 Author: Manuel Kocher <manuel.kocher@tugraz.at> Date: Thu May 12 13:48:10 2022 +0200 Remove unnecessary en translation text commit 6d0df9840ea4b481bc7d22a7eb3b02add943d0d6 Author: Manuel Kocher <manuel.kocher@tugraz.at> Date: Thu May 12 13:36:45 2022 +0200 Remove unnecessary imports and minor refactor commit 6496d910d9e150f0b28de2ee8b3372e880fa17af Author: Manuel Kocher <manuel.kocher@tugraz.at> Date: Thu May 12 13:24:51 2022 +0200 Add lang-File attribute to README commit 7a528144fd02b9af2197815ca931f298452c0e29 Author: Manuel Kocher <manuel.kocher@tugraz.at> Date: Thu May 12 13:17:40 2022 +0200 Add dbp-translation component and include it in showcase --- README.md | 1 + packages/app-shell/src/app-shell.js | 4 +- packages/common/components.js | 2 + packages/common/dbp-common-demo.js | 7 ++ packages/common/index.js | 3 +- packages/common/src/i18n.js | 23 +++++++ packages/common/src/i18n/de/translation.json | 3 +- packages/common/src/i18n/en/translation.json | 3 +- packages/common/src/translation.js | 67 +++++++++++++++++++ toolkit-showcase/assets/common.metadata.json | 2 +- .../assets/dbp-toolkit-showcase.html.ejs | 3 +- .../src/dbp-common-demo-activity.js | 3 + toolkit-showcase/src/i18n/de/translation.json | 3 + toolkit-showcase/src/i18n/en/translation.json | 3 + 14 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 packages/common/src/translation.js create mode 100644 toolkit-showcase/src/i18n/de/translation.json create mode 100644 toolkit-showcase/src/i18n/en/translation.json diff --git a/README.md b/README.md index 2e4043e0..2ea0ba3a 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ the version number in its `package.json` is higher than the version number on np | `unsubscribe` | Reserved for future use | | `auth` | Authentication information, set by the authentication component | | `lang` | Currently selected language, set by the language selector | +| `lang-file` | Location of the i18n language file where all required i18n translations are | | `entry-point-url` | Entry point url for all api requests | | `requested-login-status` | Used by the login buttons to trigger a login in auth components | | `initial-file-handling-state` | Used by the file-handling component to sync file source/sink at first time open | diff --git a/packages/app-shell/src/app-shell.js b/packages/app-shell/src/app-shell.js index 95ea1045..53397c4e 100644 --- a/packages/app-shell/src/app-shell.js +++ b/packages/app-shell/src/app-shell.js @@ -74,6 +74,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) { this.initateOpenMenu = false; this.auth = {}; + this.langFile = ''; } static get scopedElements() { @@ -271,6 +272,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) { buildTime: {type: String, attribute: 'build-time'}, env: {type: String}, auth: {type: Object}, + langFile: {type: String, attribute: 'lang-file'}, }; } @@ -701,7 +703,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) { background-position:center center; margin: 0 0.5% 0 1.5%; font-size:94%; - } + } */ .menu a { diff --git a/packages/common/components.js b/packages/common/components.js index 6a42c6af..ac6917b0 100644 --- a/packages/common/components.js +++ b/packages/common/components.js @@ -7,6 +7,7 @@ import { MiniSpinner, Spinner, Translated, + Translation } from './index'; commonUtils.defineCustomElement('dbp-mini-spinner', MiniSpinner); @@ -16,3 +17,4 @@ commonUtils.defineCustomElement('dbp-button', Button); commonUtils.defineCustomElement('dbp-loading-button', LoadingButton); commonUtils.defineCustomElement('dbp-inline-notification', InlineNotification); commonUtils.defineCustomElement('dbp-translated', Translated); +commonUtils.defineCustomElement('dbp-translation', Translation); diff --git a/packages/common/dbp-common-demo.js b/packages/common/dbp-common-demo.js index fad1b686..5f5b9bc0 100644 --- a/packages/common/dbp-common-demo.js +++ b/packages/common/dbp-common-demo.js @@ -12,6 +12,7 @@ import { Spinner, InlineNotification, Translated, + Translation, } from './index.js'; export class DbpCommonDemo extends ScopedElementsMixin(LitElement) { @@ -20,6 +21,7 @@ export class DbpCommonDemo extends ScopedElementsMixin(LitElement) { this._i18n = createInstance(); this.lang = this._i18n.language; this.noAuth = false; + this.langFile = ''; } static get scopedElements() { @@ -31,6 +33,7 @@ export class DbpCommonDemo extends ScopedElementsMixin(LitElement) { 'dbp-loading-button': LoadingButton, 'dbp-inline-notification': InlineNotification, 'dbp-translated': Translated, + 'dbp-translation': Translation }; if (customElements.get('dbp-auth')) { @@ -44,6 +47,7 @@ export class DbpCommonDemo extends ScopedElementsMixin(LitElement) { return { lang: {type: String}, noAuth: {type: Boolean, attribute: 'no-auth'}, + langFile: {type: String, attribute: 'lang-file'}, }; } @@ -297,6 +301,9 @@ html { </div> </dbp-translated> </div> + <div class="control" id="dbp-translation-demo"> + <dbp-translation key="toolkit-showcase" subscribe="lang, lang-file"></dbp-translation> + </div> </div> </section> `; diff --git a/packages/common/index.js b/packages/common/index.js index 0009a2f0..3d7467fc 100644 --- a/packages/common/index.js +++ b/packages/common/index.js @@ -6,6 +6,7 @@ import {Button, LoadingButton} from './src/button.js'; import {Spinner} from './src/spinner.js'; import {InlineNotification} from './src/inline-notification.js'; import {Translated} from './src/translated'; +import {Translation} from './src/translation'; import {AdapterLitElement} from './src/adapter-lit-element.js'; export {EventBus, createLinkedAbortController, createTimeoutAbortSignal}; @@ -14,7 +15,7 @@ export {MiniSpinner}; export {Button, LoadingButton}; export {Spinner}; export {InlineNotification}; -export {Translated}; +export {Translated, Translation}; export * from './src/logger.js'; export * from './src/utils.js'; export {AdapterLitElement}; diff --git a/packages/common/src/i18n.js b/packages/common/src/i18n.js index 6623ebdc..0374a825 100644 --- a/packages/common/src/i18n.js +++ b/packages/common/src/i18n.js @@ -6,3 +6,26 @@ import en from './i18n/en/translation.json'; export function createInstance() { return _createInstance({en: en, de: de}, 'de', 'en'); } + +export async function createInstanceAsync(langFile) { + // check if a path to language files is given + if(langFile) { + // request german lang file asynchronously + let result = await + fetch(langFile + 'de/translation.json', { + headers: {'Content-Type': 'application/json'}, + }); + const dynDe = await result.json(); + + // request english lang file asynchronously + result = await + fetch(langFile + 'en/translation.json', { + headers: {'Content-Type': 'application/json'}, + }); + const dynEn = await result.json(); + + return _createInstance({en: dynEn, de: dynDe}, 'de', 'en'); + } + + return _createInstance({en: en, de: de}, 'de', 'en'); +} diff --git a/packages/common/src/i18n/de/translation.json b/packages/common/src/i18n/de/translation.json index 51cf793c..b9daed00 100644 --- a/packages/common/src/i18n/de/translation.json +++ b/packages/common/src/i18n/de/translation.json @@ -7,5 +7,6 @@ "api-documentation-server": "Verbindung zum apiDocumentation API Server {{apiDocUrl}} fehlgeschlagen!", "error-api-server": "Verbindung zum API Server {{apiUrl}} fehlgeschlagen!", "error-hydra-documentation-url-not-set": "Hydra apiDocumentation URL wurden für server {{apiUrl}} nicht gesetzt!" - } + }, + "toolkit-showcase": "Dieser Text wird mithilfe von i18n Englisch wenn man die Sprache auf Englisch stellt." } diff --git a/packages/common/src/i18n/en/translation.json b/packages/common/src/i18n/en/translation.json index e1036a65..1e17839a 100644 --- a/packages/common/src/i18n/en/translation.json +++ b/packages/common/src/i18n/en/translation.json @@ -7,5 +7,6 @@ "api-documentation-server": "Connection to apiDocumentation server {{apiDocUrl}} failed!", "error-api-server": "Connection to api server {{apiUrl}} failed!", "error-hydra-documentation-url-not-set": "Hydra apiDocumentation url was not set for server {{apiUrl}}!" - } + }, + "toolkit-showcase": "This text will be translated to german using i18n when the user changes the language to german." } diff --git a/packages/common/src/translation.js b/packages/common/src/translation.js new file mode 100644 index 00000000..034978f3 --- /dev/null +++ b/packages/common/src/translation.js @@ -0,0 +1,67 @@ +import {css, html} from 'lit'; +import {until} from 'lit/directives/until.js'; +import DBPLitElement from '../dbp-lit-element'; +import {createInstanceAsync} from './i18n.js'; + +export class Translation extends DBPLitElement { + constructor() { + super(); + this.key = ''; + this.lang = ''; + this.langFile = ''; + } + + static get properties() { + return { + ...super.properties, + key: {type: String}, + lang: {type: String}, + langFile: {type: String, attribute: 'lang-file'}, + }; + } + + static get styles() { + // language=css + return css` + .hidden { + display: none; + } + `; + } + + connectedCallback() { + super.connectedCallback(); + this._i18n = createInstanceAsync(this.langFile); + } + + update(changedProperties) { + let lang = this.lang; + changedProperties.forEach((oldValue, propName) => { + switch (propName) { + case 'lang': + + this._i18n.then(function(response) { + response.changeLanguage(lang); + }); + break; + } + }); + + super.update(changedProperties); + } + + render() { + // save global key in local variable for async use + let key = this.key; + + // async request to i18n translation + const translation = this._i18n.then(function(response){ + return response.t(key); + }); + + // load translation text when available, otherweise display "Loading.." + return html` + ${until(translation, html`<span>Loading..</span>`)} + `; + } +} diff --git a/toolkit-showcase/assets/common.metadata.json b/toolkit-showcase/assets/common.metadata.json index de1f70c7..51e4892c 100644 --- a/toolkit-showcase/assets/common.metadata.json +++ b/toolkit-showcase/assets/common.metadata.json @@ -14,5 +14,5 @@ "de": "Gemeinsame Web Components", "en": "Common web components" }, - "subscribe": "lang,entry-point-url" + "subscribe": "lang,entry-point-url,lang-file" } diff --git a/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs b/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs index ef38009f..1cf3784a 100644 --- a/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs +++ b/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs @@ -11,7 +11,7 @@ <!-- PWA manifest file --> <link rel="manifest" href="<%= getUrl(name + '.manifest.json') %>"> - + <!-- PWA iphone --> <link rel="apple-touch-icon" sizes="180x180" href="<%= getPrivateUrl('apple-touch-icon.png') %>"> <link rel="icon" type="image/png" sizes="32x32" href="<%= getPrivateUrl('icon-32x32.png') %>"> @@ -113,6 +113,7 @@ <<%= name %> provider-root lang="de" + lang-file="<%= getUrl('/src/i18n/') %>" entry-point-url="<%= entryPointURL %>" nextcloud-auth-url="<%= nextcloudWebAppPasswordURL %>" nextcloud-web-dav-url="<%= nextcloudWebDavURL %>" diff --git a/toolkit-showcase/src/dbp-common-demo-activity.js b/toolkit-showcase/src/dbp-common-demo-activity.js index fc633b9d..67358455 100644 --- a/toolkit-showcase/src/dbp-common-demo-activity.js +++ b/toolkit-showcase/src/dbp-common-demo-activity.js @@ -13,6 +13,7 @@ class DbpCommonDemoActivity extends ScopedElementsMixin(AdapterLitElement) { super(); this.lang = 'en'; this.entryPointUrl = ''; + this.langFile = ''; } static get scopedElements() { @@ -25,6 +26,7 @@ class DbpCommonDemoActivity extends ScopedElementsMixin(AdapterLitElement) { return { ...super.properties, lang: {type: String}, + langFile: {type: String, attribute: 'lang-file'}, entryPointUrl: {type: String, attribute: 'entry-point-url'}, }; } @@ -63,6 +65,7 @@ class DbpCommonDemoActivity extends ScopedElementsMixin(AdapterLitElement) { <dbp-common-demo id="demo" lang="${this.lang}" + lang-file="${this.langFile}" entry-point-url="${this.entryPointUrl}"></dbp-common-demo> `; } diff --git a/toolkit-showcase/src/i18n/de/translation.json b/toolkit-showcase/src/i18n/de/translation.json new file mode 100644 index 00000000..d51b20bd --- /dev/null +++ b/toolkit-showcase/src/i18n/de/translation.json @@ -0,0 +1,3 @@ +{ + "toolkit-showcase": "Dieser Text wird mithilfe von i18n aus einer benutzerdefinierten Sprachdatei gelesen und ins Englische übersetzt wenn man die Sprache auf Englisch stellt." +} diff --git a/toolkit-showcase/src/i18n/en/translation.json b/toolkit-showcase/src/i18n/en/translation.json new file mode 100644 index 00000000..a2a41567 --- /dev/null +++ b/toolkit-showcase/src/i18n/en/translation.json @@ -0,0 +1,3 @@ +{ + "toolkit-showcase": "This text will be translated to german using i18n with a user defined language file when the language is changed to german." +} -- GitLab