diff --git a/src/lib/app-state-hoc.jsx b/src/lib/app-state-hoc.jsx index 20e2852a131c5ad70a878d4d0d4b3038df6c8548..2f70b44d251f52d5ccec5fb08ae6eb786bf79794 100644 --- a/src/lib/app-state-hoc.jsx +++ b/src/lib/app-state-hoc.jsx @@ -9,6 +9,9 @@ import localesReducer, {initLocale, localesInitialState} from '../reducers/local import {setPlayer, setFullScreen} from '../reducers/mode.js'; +import locales from 'scratch-l10n'; +import {detectLocale} from './detect-locale'; + import {ScratchPaintReducer} from 'scratch-paint'; const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; @@ -33,9 +36,8 @@ const AppStateHOC = function (WrappedComponent) { } let initializedLocales = localesInitialState; - if (window.location.search.indexOf('locale=') !== -1 || - window.location.search.indexOf('lang=') !== -1) { - const locale = window.location.search.match(/(?:locale|lang)=([\w]+)/)[1]; + const locale = detectLocale(Object.keys(locales)); + if (locale !== 'en') { initializedLocales = initLocale(initializedLocales, locale); } diff --git a/src/lib/detect-locale.js b/src/lib/detect-locale.js new file mode 100644 index 0000000000000000000000000000000000000000..c9eaf5feccd6fb362f12288c1ac712029563140b --- /dev/null +++ b/src/lib/detect-locale.js @@ -0,0 +1,38 @@ +/** + * @fileoverview + * Utility function to detect locale from the browser setting or paramenter on the URL. + */ + +/** + * look for language setting in the browser. Check against supported locales. + * If there's a parameter in the URL, override the browser setting + * @param {Array.string} supportedLocales An array of supported locale codes. + * @return {string} the preferred locale + */ +const detectLocale = supportedLocales => { + let locale = 'en'; // default + let browserLocale = window.navigator.userLanguage || window.navigator.language; + browserLocale = browserLocale.toLowerCase(); + // try to set locale from browserLocale + if (supportedLocales.includes(browserLocale)) { + locale = browserLocale; + } else { + browserLocale = browserLocale.split('-')[0]; + if (supportedLocales.includes(browserLocale)) { + locale = browserLocale; + } + } + + if (window.location.search.indexOf('locale=') !== -1 || + window.location.search.indexOf('lang=') !== -1) { + const urlLocale = window.location.search.match(/(?:locale|lang)=([\w-]+)/)[1].toLowerCase(); + if (supportedLocales.includes(urlLocale)) { + locale = urlLocale; + } + } + return locale; +}; + +export { + detectLocale +}; diff --git a/test/unit/util/detect-locale.test.js b/test/unit/util/detect-locale.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a7a699c414900b4a42c9b0cf452ac95f06bc65e0 --- /dev/null +++ b/test/unit/util/detect-locale.test.js @@ -0,0 +1,70 @@ +import {detectLocale} from '../../../src/lib/detect-locale.js'; + +const supportedLocales = ['en', 'es', 'pt-br', 'de', 'it']; + +Object.defineProperty(window.location, + 'search', + {value: '?name=val', configurable: true} +); +Object.defineProperty(window.navigator, + 'language', + {value: 'en-US', configurable: true} +); + +describe('detectLocale', () => { + test('uses locale from the URL when present', () => { + Object.defineProperty(window.location, + 'search', + {value: '?locale=pt-br'} + ); + expect(detectLocale(supportedLocales)).toEqual('pt-br'); + }); + + test('is case insensitive', () => { + Object.defineProperty(window.location, + 'search', + {value: '?locale=pt-BR'} + ); + expect(detectLocale(supportedLocales)).toEqual('pt-br'); + }); + + test('also accepts lang from the URL when present', () => { + Object.defineProperty(window.location, + 'search', + {value: '?lang=it'} + ); + expect(detectLocale(supportedLocales)).toEqual('it'); + }); + + test('ignores unsupported locales', () => { + Object.defineProperty(window.location, + 'search', + {value: '?lang=sv'} + ); + expect(detectLocale(supportedLocales)).toEqual('en'); + }); + + test('ignores other parameters', () => { + Object.defineProperty(window.location, + 'search', + {value: '?enable=language'} + ); + expect(detectLocale(supportedLocales)).toEqual('en'); + }); + + test('uses navigator language property for default if supported', () => { + Object.defineProperty(window.navigator, + 'language', + {value: 'pt-BR'} + ); + expect(detectLocale(supportedLocales)).toEqual('pt-br'); + }); + + test('ignores navigator language property if unsupported', () => { + Object.defineProperty(window.navigator, + 'language', + {value: 'da'} + ); + expect(detectLocale(supportedLocales)).toEqual('en'); + }); +});