diff --git a/packages/editor-ui/src/components/CredentialEdit/CredentialConfig.vue b/packages/editor-ui/src/components/CredentialEdit/CredentialConfig.vue index a1c742493d..def0127225 100644 --- a/packages/editor-ui/src/components/CredentialEdit/CredentialConfig.vue +++ b/packages/editor-ui/src/components/CredentialEdit/CredentialConfig.vue @@ -81,7 +81,7 @@ import CopyInput from '../CopyInput.vue'; import CredentialInputs from './CredentialInputs.vue'; import OauthButton from './OauthButton.vue'; import { restApi } from '@/components/mixins/restApi'; -import { addNodeTranslation } from '@/i18n'; +import { addNodeTranslation } from '@/plugins/i18n'; import mixins from 'vue-typed-mixins'; export default mixins(restApi).extend({ diff --git a/packages/editor-ui/src/i18n/index.ts b/packages/editor-ui/src/i18n/index.ts deleted file mode 100644 index 5ba7f5634a..0000000000 --- a/packages/editor-ui/src/i18n/index.ts +++ /dev/null @@ -1,75 +0,0 @@ -import Vue from 'vue'; -import VueI18n from 'vue-i18n'; -const englishBaseText = require('./locales/en'); -import axios from 'axios'; -import { INodeTranslationHeaders } from '@/Interface'; - -Vue.use(VueI18n); - -export const i18n = new VueI18n({ - locale: 'en', - fallbackLocale: 'en', - messages: { en: englishBaseText }, - silentTranslationWarn: true, -}); - -const loadedLanguages = ['en']; - -function setLanguage(language: string) { - i18n.locale = language; - axios.defaults.headers.common['Accept-Language'] = language; - document!.querySelector('html')!.setAttribute('lang', language); - - return language; -} - -export async function loadLanguage(language?: string) { - if (!language) return Promise.resolve(); - - if (i18n.locale === language) { - return Promise.resolve(setLanguage(language)); - } - - if (loadedLanguages.includes(language)) { - return Promise.resolve(setLanguage(language)); - } - - const { numberFormats, ...rest } = require(`./locales/${language}.json`); - - i18n.setLocaleMessage(language, rest); - - if (numberFormats) { - i18n.setNumberFormat(language, numberFormats); - } - - loadedLanguages.push(language); - - setLanguage(language); -} - -export function addNodeTranslation( - nodeTranslation: { [key: string]: object }, - language: string, -) { - const newNodesBase = { - 'n8n-nodes-base': Object.assign( - i18n.messages[language]['n8n-nodes-base'] || {}, - nodeTranslation, - ), - }; - - i18n.setLocaleMessage( - language, - Object.assign(i18n.messages[language], newNodesBase), - ); -} - -export function addHeaders( - headers: INodeTranslationHeaders, - language: string, -) { - i18n.setLocaleMessage( - language, - Object.assign(i18n.messages[language], { headers }), - ); -} \ No newline at end of file diff --git a/packages/editor-ui/src/i18n/README.md b/packages/editor-ui/src/plugins/i18n/docs/img/README.md similarity index 95% rename from packages/editor-ui/src/i18n/README.md rename to packages/editor-ui/src/plugins/i18n/docs/img/README.md index 39fa32884d..2c1eca0d8c 100644 --- a/packages/editor-ui/src/i18n/README.md +++ b/packages/editor-ui/src/plugins/i18n/docs/img/README.md @@ -31,7 +31,7 @@ Base text is directly rendered with no dependencies. Base text is supplied by th ### Locating base text -Each base text file is located at `/packages/editor-ui/src/i18n/locales/{localeIdentifier}.json` and exports an object where keys are Vue component names (and their containing dirs if any) and references to parts of those Vue components. +Each base text file is located at `/packages/editor-ui/src/plugins/i18n/locales/{localeIdentifier}.json` and exports an object where keys are Vue component names (and their containing dirs if any) and references to parts of those Vue components. ```json "nodeCreator": { @@ -46,7 +46,7 @@ Each base text file is located at `/packages/editor-ui/src/i18n/locales/{localeI 1. For the new locale identifier, e.g. `de`, copy the `en` base text and rename it: ```sh -cp ./packages/editor-ui/src/i18n/locales/en.json ./packages/editor-ui/src/i18n/locales/de.json +cp ./packages/editor-ui/src/plugins/i18n/locales/en.json ./packages/editor-ui/src/plugins/i18n/locales/de.json ``` 2. Check in the UI for a base text string to translate, and find it in the newly created base text file. @@ -213,14 +213,14 @@ export class Github implements INodeType { Header text is used wherever the node's display name and description are needed:

- - - + + +

- - + +

#### `credentialsModal` section @@ -322,7 +322,7 @@ The object for each node credential parameter allows for the keys `displayName`, ```

- +

#### `nodeView` section @@ -393,7 +393,7 @@ Allowed keys: `displayName`, `description`, and `placeholder`. ```

- +

#### `options` parameter @@ -446,7 +446,7 @@ Allowed subkeys: `options.{optionName}.displayName` and `options.{optionName}.de ```

- +

#### `collection` and `fixedCollection` parameters @@ -523,7 +523,7 @@ To reduce nesting and to share translations, a parameter inside a collection's o ```

- +

> **Note**: In case of deep nesting, i.e. a child of a child of a `collection` and `fixedCollection` parameter, the deeply nested child in principle should be translatable at the same level of nesting as the `collection` and `fixedCollection` parameter, but this has not been fully tested for this first release. @@ -546,7 +546,7 @@ Currently only the keys `oauth.clientId` and `oauth.clientSecret` are supported ## Base text -When translating a base text file at `/packages/editor-ui/src/i18n/locales/{localeIdentifier}.json`: +When translating a base text file at `/packages/editor-ui/src/plugins/i18n/locales/{localeIdentifier}.json`: 1. Open a terminal: diff --git a/packages/editor-ui/src/i18n/img/cred.png b/packages/editor-ui/src/plugins/i18n/docs/img/cred.png similarity index 100% rename from packages/editor-ui/src/i18n/img/cred.png rename to packages/editor-ui/src/plugins/i18n/docs/img/cred.png diff --git a/packages/editor-ui/src/i18n/img/header1.png b/packages/editor-ui/src/plugins/i18n/docs/img/header1.png similarity index 100% rename from packages/editor-ui/src/i18n/img/header1.png rename to packages/editor-ui/src/plugins/i18n/docs/img/header1.png diff --git a/packages/editor-ui/src/i18n/img/header2.png b/packages/editor-ui/src/plugins/i18n/docs/img/header2.png similarity index 100% rename from packages/editor-ui/src/i18n/img/header2.png rename to packages/editor-ui/src/plugins/i18n/docs/img/header2.png diff --git a/packages/editor-ui/src/i18n/img/header3.png b/packages/editor-ui/src/plugins/i18n/docs/img/header3.png similarity index 100% rename from packages/editor-ui/src/i18n/img/header3.png rename to packages/editor-ui/src/plugins/i18n/docs/img/header3.png diff --git a/packages/editor-ui/src/i18n/img/header4.png b/packages/editor-ui/src/plugins/i18n/docs/img/header4.png similarity index 100% rename from packages/editor-ui/src/i18n/img/header4.png rename to packages/editor-ui/src/plugins/i18n/docs/img/header4.png diff --git a/packages/editor-ui/src/i18n/img/header5.png b/packages/editor-ui/src/plugins/i18n/docs/img/header5.png similarity index 100% rename from packages/editor-ui/src/i18n/img/header5.png rename to packages/editor-ui/src/plugins/i18n/docs/img/header5.png diff --git a/packages/editor-ui/src/i18n/img/node1.png b/packages/editor-ui/src/plugins/i18n/docs/img/node1.png similarity index 100% rename from packages/editor-ui/src/i18n/img/node1.png rename to packages/editor-ui/src/plugins/i18n/docs/img/node1.png diff --git a/packages/editor-ui/src/i18n/img/node2.png b/packages/editor-ui/src/plugins/i18n/docs/img/node2.png similarity index 100% rename from packages/editor-ui/src/i18n/img/node2.png rename to packages/editor-ui/src/plugins/i18n/docs/img/node2.png diff --git a/packages/editor-ui/src/i18n/img/node4.png b/packages/editor-ui/src/plugins/i18n/docs/img/node4.png similarity index 100% rename from packages/editor-ui/src/i18n/img/node4.png rename to packages/editor-ui/src/plugins/i18n/docs/img/node4.png diff --git a/packages/editor-ui/src/plugins/i18n/index.ts b/packages/editor-ui/src/plugins/i18n/index.ts index 90f052f114..384ba44fb5 100644 --- a/packages/editor-ui/src/plugins/i18n/index.ts +++ b/packages/editor-ui/src/plugins/i18n/index.ts @@ -1,8 +1,12 @@ import _Vue from "vue"; -import { IRootState } from '@/Interface'; +import axios from 'axios'; import VueI18n from 'vue-i18n'; -import { i18n as i18nLib } from '../../i18n'; import { Store } from "vuex"; +import Vue from 'vue'; +import { INodeTranslationHeaders, IRootState } from '@/Interface'; +const englishBaseText = require('./locales/en'); + +Vue.use(VueI18n); const REUSABLE_DYNAMIC_TEXT_KEY = 'reusableDynamicText'; const CREDENTIALS_MODAL_KEY = 'credentialsModal'; @@ -28,20 +32,11 @@ export class I18nClass { } private get i18n(): VueI18n { - return i18nLib; - } - - /** - * Render a string of dynamic text, i.e. a string with a constructed path to the localized value in the node text object, in the credentials modal, in the node view, or in the headers. Unlike in `baseText`, the fallback has to be set manually for dynamic text. - */ - private dynamicRender( - { key, fallback }: { key: string; fallback: string; }, - ) { - return this.i18n.te(key) ? this.i18n.t(key).toString() : fallback; + return i18nInstance; } // ---------------------------------- - // template helpers + // helper methods // ---------------------------------- exists(key: string) { @@ -56,6 +51,10 @@ export class I18nClass { return longNodeType.replace('n8n-nodes-base.', ''); } + // ---------------------------------- + // render methods + // ---------------------------------- + /** * Render a string of base text, i.e. a string with a fixed path to the localized value in the base text object. Optionally allows for [interpolation](https://kazupon.github.io/vue-i18n/guide/formatting.html#named-formatting) when the localized value contains a string between curly braces. */ @@ -65,6 +64,15 @@ export class I18nClass { return this.i18n.t(key, options && options.interpolate).toString(); } + /** + * Render a string of dynamic text, i.e. a string with a constructed path to the localized value in the node text object, in the credentials modal, in the node view, or in the headers. Unlike in `baseText`, the fallback has to be set manually for dynamic text. + */ + private dynamicRender( + { key, fallback }: { key: string; fallback: string; }, + ) { + return this.i18n.te(key) ? this.i18n.t(key).toString() : fallback; + } + /** * Render a string of dynamic header text, used in the nodes panel and in the node view. */ @@ -252,3 +260,71 @@ export class I18nClass { }; } } + +const i18nInstance = new VueI18n({ + locale: 'en', + fallbackLocale: 'en', + messages: { en: englishBaseText }, + silentTranslationWarn: true, +}); + +const loadedLanguages = ['en']; + +function setLanguage(language: string) { + i18nInstance.locale = language; + axios.defaults.headers.common['Accept-Language'] = language; + document!.querySelector('html')!.setAttribute('lang', language); + + return language; +} + +export async function loadLanguage(language?: string) { + if (!language) return Promise.resolve(); + + if (i18nInstance.locale === language) { + return Promise.resolve(setLanguage(language)); + } + + if (loadedLanguages.includes(language)) { + return Promise.resolve(setLanguage(language)); + } + + const { numberFormats, ...rest } = require(`./locales/${language}.json`); + + i18nInstance.setLocaleMessage(language, rest); + + if (numberFormats) { + i18nInstance.setNumberFormat(language, numberFormats); + } + + loadedLanguages.push(language); + + setLanguage(language); +} + +export function addNodeTranslation( + nodeTranslation: { [key: string]: object }, + language: string, +) { + const newNodesBase = { + 'n8n-nodes-base': Object.assign( + i18nInstance.messages[language]['n8n-nodes-base'] || {}, + nodeTranslation, + ), + }; + + i18nInstance.setLocaleMessage( + language, + Object.assign(i18nInstance.messages[language], newNodesBase), + ); +} + +export function addHeaders( + headers: INodeTranslationHeaders, + language: string, +) { + i18nInstance.setLocaleMessage( + language, + Object.assign(i18nInstance.messages[language], { headers }), + ); +} \ No newline at end of file diff --git a/packages/editor-ui/src/i18n/locales/de.json b/packages/editor-ui/src/plugins/i18n/locales/de.json similarity index 100% rename from packages/editor-ui/src/i18n/locales/de.json rename to packages/editor-ui/src/plugins/i18n/locales/de.json diff --git a/packages/editor-ui/src/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json similarity index 100% rename from packages/editor-ui/src/i18n/locales/en.json rename to packages/editor-ui/src/plugins/i18n/locales/en.json diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index e88ce2b6a2..a76bd6c872 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -175,7 +175,7 @@ import { loadLanguage, addNodeTranslation, addHeaders, -} from '@/i18n'; +} from '@/plugins/i18n'; import '../plugins/N8nCustomConnectorType'; import '../plugins/PlusEndpointType';