From 6d8ca23625ccb5ee87bdea62e21ff1c323f2d692 Mon Sep 17 00:00:00 2001 From: Daniel Lockyer Date: Wed, 1 Mar 2023 09:10:11 +0100 Subject: [PATCH] Added support for namespaces to i18n package refs https://github.com/TryGhost/Ghost/issues/15502 - this adds support for namespaces to the i18n package so we can separate translations for different packages --- ghost/i18n/i18next-parser.config.js | 4 +- ghost/i18n/lib/i18n.js | 27 +++++++----- .../i18n/locales/{en.json => en/portal.json} | 1 - ghost/i18n/locales/en/test.json | 4 ++ .../i18n/locales/{nl.json => nl/portal.json} | 3 +- ghost/i18n/locales/nl/test.json | 4 ++ ghost/i18n/package.json | 7 +-- ghost/i18n/test/i18n.test.js | 44 +++++++++++++------ ghost/portal/src/App.js | 2 +- 9 files changed, 62 insertions(+), 34 deletions(-) rename ghost/i18n/locales/{en.json => en/portal.json} (99%) create mode 100644 ghost/i18n/locales/en/test.json rename ghost/i18n/locales/{nl.json => nl/portal.json} (98%) create mode 100644 ghost/i18n/locales/nl/test.json diff --git a/ghost/i18n/i18next-parser.config.js b/ghost/i18n/i18next-parser.config.js index 3a19f8cbd0..02be8944ce 100644 --- a/ghost/i18n/i18next-parser.config.js +++ b/ghost/i18n/i18next-parser.config.js @@ -9,11 +9,13 @@ module.exports = { keySeparator: false, namespaceSeparator: false, + defaultNamespace: process.env.NAMESPACE || 'translation', + createOldCatalogs: false, indentation: 4, sort: true, failOnUpdate: process.env.CI, - output: 'locales/$LOCALE.json' + output: 'locales/$LOCALE/$NAMESPACE.json' }; diff --git a/ghost/i18n/lib/i18n.js b/ghost/i18n/lib/i18n.js index 7f8a1d3c12..f9853006e7 100644 --- a/ghost/i18n/lib/i18n.js +++ b/ghost/i18n/lib/i18n.js @@ -1,17 +1,12 @@ const i18next = require('i18next'); -const RESOURCES = { - en: { - translation: require('../locales/en.json') - }, - nl: { - translation: require('../locales/nl.json') - } -}; +const SUPPORTED_LOCALES = ['en', 'nl']; -const SUPPORTED_LOCALES = Object.keys(RESOURCES); - -module.exports = (lng = 'en') => { +/** + * @param {string} [lng] + * @param {'portal'|'test'} ns + */ +module.exports = (lng = 'en', ns = 'portal') => { const i18nextInstance = i18next.createInstance(); i18nextInstance.init({ lng, @@ -27,7 +22,15 @@ module.exports = (lng = 'en') => { // do not load a fallback fallbackLng: false, - resources: RESOURCES + ns: ns, + defaultNS: ns, + + resources: SUPPORTED_LOCALES.reduce((acc, lng) => { + acc[lng] = { + [ns]: require(`../locales/${lng}/${ns}.json`) + } + return acc; + }, {}) }); return i18nextInstance; diff --git a/ghost/i18n/locales/en.json b/ghost/i18n/locales/en/portal.json similarity index 99% rename from ghost/i18n/locales/en.json rename to ghost/i18n/locales/en/portal.json index 91f7e2dd3a..2d816e8f4e 100644 --- a/ghost/i18n/locales/en.json +++ b/ghost/i18n/locales/en/portal.json @@ -26,7 +26,6 @@ "Get help": "", "Get notified when someone replies to your comment": "", "Give feedback on this post": "", - "Hello": "", "Less like this": "", "Manage": "", "Monthly": "", diff --git a/ghost/i18n/locales/en/test.json b/ghost/i18n/locales/en/test.json new file mode 100644 index 0000000000..e736f21808 --- /dev/null +++ b/ghost/i18n/locales/en/test.json @@ -0,0 +1,4 @@ +{ + "Hello": "Hello Test", + "Name": "" +} diff --git a/ghost/i18n/locales/nl.json b/ghost/i18n/locales/nl/portal.json similarity index 98% rename from ghost/i18n/locales/nl.json rename to ghost/i18n/locales/nl/portal.json index 499c8f6821..b1ec4d95fd 100644 --- a/ghost/i18n/locales/nl.json +++ b/ghost/i18n/locales/nl/portal.json @@ -26,12 +26,11 @@ "Get help": "", "Get notified when someone replies to your comment": "", "Give feedback on this post": "", - "Hello": "Hallo", "Less like this": "", "Manage": "", "Monthly": "", "More like this": "", - "Name": "", + "Name": "Naam", "Not receiving emails?": "", "Now check your email!": "", "Powered by Ghost": "", diff --git a/ghost/i18n/locales/nl/test.json b/ghost/i18n/locales/nl/test.json new file mode 100644 index 0000000000..06dec3f83a --- /dev/null +++ b/ghost/i18n/locales/nl/test.json @@ -0,0 +1,4 @@ +{ + "Hello": "Hallo Test", + "Name": "" +} diff --git a/ghost/i18n/package.json b/ghost/i18n/package.json index 519ed93fc3..5f184377c6 100644 --- a/ghost/i18n/package.json +++ b/ghost/i18n/package.json @@ -8,12 +8,13 @@ "scripts": { "dev": "echo \"Implement me!\"", "test:unit": "NODE_ENV=testing c8 --include index.js --include lib --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", - "test": "yarn test:unit && yarn test:translate", - "test:translate": "yarn translate:generate", + "test": "yarn test:unit && yarn translate", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache", - "translate:generate": "i18next '../portal/src/**/*.{js,jsx}' './test/**/*.js'" + "translate": "yarn translate:portal && yarn translate:test", + "translate:portal": "NAMESPACE=portal i18next '../portal/src/**/*.{js,jsx}'", + "translate:test": "NAMESPACE=test i18next './test/**/*.js'" }, "files": [ "index.js", diff --git a/ghost/i18n/test/i18n.test.js b/ghost/i18n/test/i18n.test.js index 9fe36ec484..abb705d9f8 100644 --- a/ghost/i18n/test/i18n.test.js +++ b/ghost/i18n/test/i18n.test.js @@ -2,28 +2,44 @@ const assert = require('assert'); const i18n = require('../'); -describe('Can translate', function () { - describe('Dutch', function () { - let t; +describe('i18n', function () { + describe('Can use Portal resources', function () { + describe('English', function () { + let t; - before(function () { - t = i18n('nl').t; - }); + before(function () { + t = i18n('nl', 'portal').t; + }); - it('can translate Dutch', function () { - assert.equal(t('Hello'), 'Hallo'); + it('can translate `Name`', function () { + assert.equal(t('Name'), 'Naam'); + }); }); }); - describe('English', function () { - let t; + describe('Can translate', function () { + describe('Dutch', function () { + let t; - before(function () { - t = i18n('en').t; + before(function () { + t = i18n('nl', 'test').t; + }); + + it('can translate Dutch', function () { + assert.equal(t('Hello'), 'Hallo Test'); + }); }); - it('can translate English', function () { - assert.equal(t('Hello'), 'Hello'); + describe('English', function () { + let t; + + before(function () { + t = i18n('en', 'test').t; + }); + + it('can translate English', function () { + assert.equal(t('Hello'), 'Hello Test'); + }); }); }); }); diff --git a/ghost/portal/src/App.js b/ghost/portal/src/App.js index fc54e9269a..37afefdfb4 100644 --- a/ghost/portal/src/App.js +++ b/ghost/portal/src/App.js @@ -156,7 +156,7 @@ export default class App extends React.Component { try { // Fetch data from API, links, preview, dev sources const {site, member, page, showPopup, popupNotification, lastPage, pageQuery, pageData} = await this.fetchData(); - const i18n = require('@tryghost/i18n')(/*site.locale || */ 'en'); // TODO: uncomment when you want to enable i18n translations + const i18n = require('@tryghost/i18n')(/*site.locale || */ 'en', 'portal'); // TODO: uncomment when you want to enable i18n translations const state = { site, member,