From b9ae50a0392fdc780a6c99211199d93c7927739c Mon Sep 17 00:00:00 2001 From: Patrick Riley Date: Wed, 24 Jul 2019 17:29:00 -0400 Subject: [PATCH] feat(locale): use cookie to determine current locale (#55) * use rh_locale cookie to set i18n locale if it's available * use env var as a fallback if we can't find a supported locale * gitignore, added en-US locale --- .env | 3 +- .gitignore | 2 +- package.json | 2 + public/locales/en-US.json | 8 ++++ public/locales/en.json | 9 +---- public/locales/locales.json | 2 +- .../__tests__/__snapshots__/i18n.test.js.snap | 2 +- .../__snapshots__/userServices.test.js.snap | 28 ++++++++++++++ src/services/__tests__/userServices.test.js | 24 ++++++++++++ src/services/userServices.js | 26 +++++++------ tests/__snapshots__/dist.test.js.snap | 1 + tests/i18n.test.js | 2 +- yarn.lock | 37 +++++++++++++++++++ 13 files changed, 122 insertions(+), 24 deletions(-) create mode 100644 public/locales/en-US.json create mode 100644 src/services/__tests__/__snapshots__/userServices.test.js.snap diff --git a/.env b/.env index 5c459d28e..7c2095a43 100644 --- a/.env +++ b/.env @@ -5,7 +5,8 @@ PUBLIC_URL=${UI_DEPLOY_PATH_PREFIX}/apps/subscription-reporting/ REACT_APP_AJAX_TIMEOUT=60000 -REACT_APP_CONFIG_SERVICE_LOCALES_DEFAULT_LNG=en +REACT_APP_CONFIG_SERVICE_LOCALES_COOKIE=rh_locale +REACT_APP_CONFIG_SERVICE_LOCALES_DEFAULT_LNG=en-US REACT_APP_CONFIG_SERVICE_LOCALES_DEFAULT_LNG_DESC=English REACT_APP_CONFIG_SERVICE_LOCALES=${UI_DEPLOY_PATH_PREFIX}/apps/subscription-reporting/locales/locales.json REACT_APP_CONFIG_SERVICE_LOCALES_PATH=${UI_DEPLOY_PATH_PREFIX}/apps/subscription-reporting/locales/{{lng}}.json diff --git a/.gitignore b/.gitignore index a295ba19d..abd0bc0e0 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ build public/apps public/locales/*.json !public/locales/locales.json -!public/locales/en.json +!public/locales/en*.json !.env .env*.local .chrome diff --git a/package.json b/package.json index d98bf7cdd..0725cfc6f 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,8 @@ "axios": "^0.19.0", "i18next": "^17.0.6", "i18next-xhr-backend": "^3.0.0", + "js-cookie": "^2.2.0", + "locale-code": "^2.0.2", "lodash": "^4.17.15", "moment": "^2.24.0", "node-sass": "^4.12.0", diff --git a/public/locales/en-US.json b/public/locales/en-US.json new file mode 100644 index 000000000..1cdf714f2 --- /dev/null +++ b/public/locales/en-US.json @@ -0,0 +1,8 @@ +{ + "curiosity-graph": { + "heading": "Daily CPU socket usage", + "dropdownDefault": "Last 30 Days", + "tooltipLabel": "sockets on", + "tooltipPreviousLabel": "from previous day" + } +} diff --git a/public/locales/en.json b/public/locales/en.json index 1cdf714f2..0967ef424 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -1,8 +1 @@ -{ - "curiosity-graph": { - "heading": "Daily CPU socket usage", - "dropdownDefault": "Last 30 Days", - "tooltipLabel": "sockets on", - "tooltipPreviousLabel": "from previous day" - } -} +{} diff --git a/public/locales/locales.json b/public/locales/locales.json index 0668c1376..7c531e424 100644 --- a/public/locales/locales.json +++ b/public/locales/locales.json @@ -1,6 +1,6 @@ [ { "key": "English", - "value": "en" + "value": "en-US" } ] diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap index c806ecb0c..b224ce8d5 100644 --- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap +++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap @@ -4,7 +4,7 @@ exports[`I18n Component should pass children: children 1`] = `"lorem ipsum"`; exports[`I18n Component should render a basic component: basic 1`] = ` diff --git a/src/services/__tests__/__snapshots__/userServices.test.js.snap b/src/services/__tests__/__snapshots__/userServices.test.js.snap new file mode 100644 index 000000000..9ec57c334 --- /dev/null +++ b/src/services/__tests__/__snapshots__/userServices.test.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UserServices should return a specific locale cookie value 1`] = ` +Object { + "data": Object { + "key": "English", + "value": "en-US", + }, +} +`; + +exports[`UserServices should return default locale if no locale cookie is present 1`] = ` +Object { + "data": Object { + "key": "English", + "value": "en-US", + }, +} +`; + +exports[`UserServices should return the default locale with an invalid ISO_639 code 1`] = ` +Object { + "data": Object { + "key": "English", + "value": "en-US", + }, +} +`; diff --git a/src/services/__tests__/userServices.test.js b/src/services/__tests__/userServices.test.js index 22184c684..2fab6cb04 100644 --- a/src/services/__tests__/userServices.test.js +++ b/src/services/__tests__/userServices.test.js @@ -1,3 +1,4 @@ +import Cookies from 'js-cookie'; import userServices from '../userServices'; describe('UserServices', () => { @@ -19,4 +20,27 @@ describe('UserServices', () => { done(); }); }); + + it('should return default locale if no locale cookie is present', done => { + userServices.getLocale().then(locale => { + expect(locale).toMatchSnapshot(); + done(); + }); + }); + + it('should return a specific locale cookie value', done => { + Cookies.get = jest.fn().mockImplementation(() => 'en_US'); + userServices.getLocale().then(locale => { + expect(locale).toMatchSnapshot(); + done(); + }); + }); + + it('should return the default locale with an invalid ISO_639 code', done => { + Cookies.get = jest.fn().mockImplementation(() => 'test_US'); + userServices.getLocale().then(locale => { + expect(locale).toMatchSnapshot(); + done(); + }); + }); }); diff --git a/src/services/userServices.js b/src/services/userServices.js index 030f1e19d..0434509c3 100644 --- a/src/services/userServices.js +++ b/src/services/userServices.js @@ -1,3 +1,5 @@ +import Cookies from 'js-cookie'; +import LocaleCode from 'locale-code'; import { helpers } from '../common/helpers'; const authorizeUser = () => { @@ -14,21 +16,23 @@ const authorizeUser = () => { return returnMethod; }; +const getLocaleFromCookie = () => { + const value = (Cookies.get(process.env.REACT_APP_CONFIG_SERVICE_LOCALES_COOKIE) || '').replace('_', '-'); + const key = (value && LocaleCode.getLanguageName(value)) || null; + + return (key && { value, key }) || null; +}; + const getLocale = () => { - const locale = { + const defaultLocale = { value: process.env.REACT_APP_CONFIG_SERVICE_LOCALES_DEFAULT_LNG, key: process.env.REACT_APP_CONFIG_SERVICE_LOCALES_DEFAULT_LNG_DESC }; - - return new Promise(resolve => { - if (locale) { - return resolve({ - data: locale - }); - } - - return resolve({}); - }); + return new Promise(resolve => + resolve({ + data: getLocaleFromCookie() || defaultLocale + }) + ); }; const logoutUser = () => diff --git a/tests/__snapshots__/dist.test.js.snap b/tests/__snapshots__/dist.test.js.snap index 4a5efe89e..130c0dc97 100644 --- a/tests/__snapshots__/dist.test.js.snap +++ b/tests/__snapshots__/dist.test.js.snap @@ -4,6 +4,7 @@ exports[`Build distribution should match a specific file output 1`] = ` Array [ "", "./build/index.html", + "./build/locales/en-US.json", "./build/locales/en.json", "./build/locales/locales.json", "./build/static/css/2*chunk*map", diff --git a/tests/i18n.test.js b/tests/i18n.test.js index b2405a493..c3dfdc61f 100644 --- a/tests/i18n.test.js +++ b/tests/i18n.test.js @@ -1,6 +1,6 @@ const get = require('lodash/get'); const { GettextExtractor, JsExtractors } = require('gettext-extractor'); -const enLocales = require('../public/locales/en'); +const enLocales = require('../public/locales/en-US'); const textExtractor = () => { const extractor = new GettextExtractor(); diff --git a/yarn.lock b/yarn.lock index 67c294b28..75c5b250a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7049,6 +7049,25 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +iso-3166-1-alpha-2@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/iso-3166-1-alpha-2/-/iso-3166-1-alpha-2-1.0.0.tgz#bc9e0bb94e584df5468a932997a28552e26f97ac" + integrity sha1-vJ4LuU5YTfVGipMpl6KFUuJvl6w= + dependencies: + mout "^0.11.0" + +iso-639-1-zh@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/iso-639-1-zh/-/iso-639-1-zh-2.0.4.tgz#61b577d14ee8b0c2c8e73697a3c894fe02dbd541" + integrity sha1-YbV30U7osMLI5zaXo8iU/gLb1UE= + dependencies: + iso-639-1 "^2.0.0" + +iso-639-1@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.0.5.tgz#a72ad3de139a96c4c4420b97b60b0af4cec4d7a3" + integrity sha512-2TcJ8AcsqM4AXLi92eFZX3xa7X6Eno/chq9yOR0AvSgb15Smmoh1miXyYJVWCkSmbzDimds3Ix2M4efhnOuxOg== + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -7508,6 +7527,11 @@ js-base64@^2.1.8: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== +js-cookie@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb" + integrity sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s= + js-levenshtein@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" @@ -7927,6 +7951,14 @@ loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1. emojis-list "^2.0.0" json5 "^1.0.1" +locale-code@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/locale-code/-/locale-code-2.0.2.tgz#660d80c5825d8fe9f3ba4a72de5716833ec7d0ed" + integrity sha512-wNcUMwk6Nlc10pnZZXWtKArAOZHhH8p2vohPEIENg7ImwMrib/CwKSvyV4g9Wm7KjylyHzXnEMz4i/W3w57wlw== + dependencies: + iso-3166-1-alpha-2 "~1.0.0" + iso-639-1-zh "^2.0.4" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -8443,6 +8475,11 @@ moo@^0.4.3: resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e" integrity sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw== +mout@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/mout/-/mout-0.11.1.tgz#ba3611df5f0e5b1ffbfd01166b8f02d1f5fa2b99" + integrity sha1-ujYR318OWx/7/QEWa48C0fX6K5k= + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"