diff --git a/app.js b/app.js index 54396b6..593aaaa 100644 --- a/app.js +++ b/app.js @@ -11,7 +11,7 @@ const helmet = require('helmet') require('dotenv').config({ path: 'variables.env' }) const helpers = require('./helpers') -const { translate, initializeTranslations } = require('./i18n/i18n') +const { translate, initializeTranslations, setFallbackLocale } = require('./i18n/i18n') const breadcrumb = require('./lib/breadcrumb') const { updateCookie } = require('./lib/cookies') const settings = require('./lib/settings') @@ -110,6 +110,10 @@ app.use(catchErrors(async function (request, response, next) { response.locals.currentLocale = defaultLocale } + if (response.locals.fallbackCode) { + setFallbackLocale(response.locals.fallbackCode) + } + // Creates a query string which adds the current credentials to links // To other implementations of this app in the about modal helpers.updateSettingsQuery(request, response, response.locals.settings) diff --git a/i18n/i18n.js b/i18n/i18n.js index 0e5ba2a..eb36f8d 100644 --- a/i18n/i18n.js +++ b/i18n/i18n.js @@ -2,12 +2,19 @@ const fs = require('fs') const path = require('path') let translations = null -// Initializes translation dictionary with contents from /public/locales -module.exports.initializeTranslations = () => { +let fallbackLocale = null + +/** + * Initializes translation dictionary with contents from /public/locales + */ +function initializeTranslations () { if (translations) { return } + // Default fallbock locale is english + setFallbackLocale('en-US') + translations = {} const localesPath = path.join(__dirname, 'locales') @@ -26,6 +33,14 @@ module.exports.initializeTranslations = () => { } } +/** + * Sets the fallback locale + * @param locale string Locale code + */ +function setFallbackLocale (locale) { + fallbackLocale = locale +} + /** * Translate a static string * @param symbol string Identifier for static text @@ -33,14 +48,20 @@ module.exports.initializeTranslations = () => { * * @returns string */ -module.exports.translate = (symbol, locale = 'en-US') => { +function translate (symbol, locale = 'en-US') { const localeDict = translations[locale] - if (!localeDict) { - return `Localization file for ${locale} is not available` + let translatedValue + + if (localeDict) { + translatedValue = localeDict[symbol] } - const translatedValue = localeDict[symbol] + if (!translatedValue) { - return `Translation not found for ${symbol} in ${locale}` + translatedValue = translations[fallbackLocale][symbol] + } + + if (!translatedValue) { + return `Translation not found for ${symbol}` } return translatedValue @@ -53,6 +74,11 @@ module.exports.translate = (symbol, locale = 'en-US') => { * * @returns boolean */ -module.exports.translationAvaliable = (symbol, locale = 'en-US') => { - return !!(translations[locale] || {})[symbol] +function translationAvaliable (symbol, locale = 'en-US') { + return !!(translations[locale] || translations[fallbackLocale] || {})[symbol] } + +module.exports.initializeTranslations = initializeTranslations +module.exports.setFallbackLocale = setFallbackLocale +module.exports.translate = translate +module.exports.translationAvaliable = translationAvaliable diff --git a/test/unit/index.test.js b/test/unit/index.test.js index 55caa0c..dd068bc 100644 --- a/test/unit/index.test.js +++ b/test/unit/index.test.js @@ -99,12 +99,12 @@ describe('Settings', () => { }) describe('i18n', () => { - test('It returns an error when locale file is not found', () => { - expect(translate('foo', 'bar-locale')).toBe('Localization file for bar-locale is not available') + test('It returns the fallback value when locale file is not found', () => { + expect(translate('defaultTitle', 'not-existing-locale-file')).toBe('The Example App') }) test('It returns an error when symbol is not found on locale file', () => { - expect(translate('foo', 'en-US')).toBe('Translation not found for foo in en-US') + expect(translate('foo', 'en-US')).toBe('Translation not found for foo') }) test('It returns the translated string when symbol is found on locale file', () => { @@ -113,10 +113,8 @@ describe('i18n', () => { test('It returns true if string is found for locale', () => { expect(translationAvaliable('coursesLabel', 'en-US')).toBe(true) }) - test('It returns false if string is not found for locale', () => { - expect(translationAvaliable('foo-symbol', 'en-US')).toBe(false) - }) test('It returns false if locale is not found', () => { - expect(translationAvaliable('coursesLabel', 'foo-locale')).toBe(false) + expect(translationAvaliable('foo-symbol', 'en-US')).toBe(false) + expect(translationAvaliable('foo-symbol', 'not-existing-locale')).toBe(false) }) })