feat(errors): dynamic fallback locale
This commit is contained in:
committed by
Benedikt Rötsch
parent
92fcbdf4d8
commit
3c9089af98
6
app.js
6
app.js
@@ -11,7 +11,7 @@ const helmet = require('helmet')
|
|||||||
require('dotenv').config({ path: 'variables.env' })
|
require('dotenv').config({ path: 'variables.env' })
|
||||||
|
|
||||||
const helpers = require('./helpers')
|
const helpers = require('./helpers')
|
||||||
const { translate, initializeTranslations } = require('./i18n/i18n')
|
const { translate, initializeTranslations, setFallbackLocale } = require('./i18n/i18n')
|
||||||
const breadcrumb = require('./lib/breadcrumb')
|
const breadcrumb = require('./lib/breadcrumb')
|
||||||
const { updateCookie } = require('./lib/cookies')
|
const { updateCookie } = require('./lib/cookies')
|
||||||
const settings = require('./lib/settings')
|
const settings = require('./lib/settings')
|
||||||
@@ -110,6 +110,10 @@ app.use(catchErrors(async function (request, response, next) {
|
|||||||
response.locals.currentLocale = defaultLocale
|
response.locals.currentLocale = defaultLocale
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.locals.fallbackCode) {
|
||||||
|
setFallbackLocale(response.locals.fallbackCode)
|
||||||
|
}
|
||||||
|
|
||||||
// Creates a query string which adds the current credentials to links
|
// Creates a query string which adds the current credentials to links
|
||||||
// To other implementations of this app in the about modal
|
// To other implementations of this app in the about modal
|
||||||
helpers.updateSettingsQuery(request, response, response.locals.settings)
|
helpers.updateSettingsQuery(request, response, response.locals.settings)
|
||||||
|
|||||||
44
i18n/i18n.js
44
i18n/i18n.js
@@ -2,12 +2,19 @@ const fs = require('fs')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
let translations = null
|
let translations = null
|
||||||
// Initializes translation dictionary with contents from /public/locales
|
let fallbackLocale = null
|
||||||
module.exports.initializeTranslations = () => {
|
|
||||||
|
/**
|
||||||
|
* Initializes translation dictionary with contents from /public/locales
|
||||||
|
*/
|
||||||
|
function initializeTranslations () {
|
||||||
if (translations) {
|
if (translations) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default fallbock locale is english
|
||||||
|
setFallbackLocale('en-US')
|
||||||
|
|
||||||
translations = {}
|
translations = {}
|
||||||
|
|
||||||
const localesPath = path.join(__dirname, 'locales')
|
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
|
* Translate a static string
|
||||||
* @param symbol string Identifier for static text
|
* @param symbol string Identifier for static text
|
||||||
@@ -33,14 +48,20 @@ module.exports.initializeTranslations = () => {
|
|||||||
*
|
*
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
module.exports.translate = (symbol, locale = 'en-US') => {
|
function translate (symbol, locale = 'en-US') {
|
||||||
const localeDict = translations[locale]
|
const localeDict = translations[locale]
|
||||||
if (!localeDict) {
|
let translatedValue
|
||||||
return `Localization file for ${locale} is not available`
|
|
||||||
|
if (localeDict) {
|
||||||
|
translatedValue = localeDict[symbol]
|
||||||
}
|
}
|
||||||
const translatedValue = localeDict[symbol]
|
|
||||||
if (!translatedValue) {
|
if (!translatedValue) {
|
||||||
return `Translation not found for ${symbol} in ${locale}`
|
translatedValue = translations[fallbackLocale][symbol]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!translatedValue) {
|
||||||
|
return `Translation not found for ${symbol}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return translatedValue
|
return translatedValue
|
||||||
@@ -53,6 +74,11 @@ module.exports.translate = (symbol, locale = 'en-US') => {
|
|||||||
*
|
*
|
||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
module.exports.translationAvaliable = (symbol, locale = 'en-US') => {
|
function translationAvaliable (symbol, locale = 'en-US') {
|
||||||
return !!(translations[locale] || {})[symbol]
|
return !!(translations[locale] || translations[fallbackLocale] || {})[symbol]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.initializeTranslations = initializeTranslations
|
||||||
|
module.exports.setFallbackLocale = setFallbackLocale
|
||||||
|
module.exports.translate = translate
|
||||||
|
module.exports.translationAvaliable = translationAvaliable
|
||||||
|
|||||||
@@ -99,12 +99,12 @@ describe('Settings', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('i18n', () => {
|
describe('i18n', () => {
|
||||||
test('It returns an error when locale file is not found', () => {
|
test('It returns the fallback value when locale file is not found', () => {
|
||||||
expect(translate('foo', 'bar-locale')).toBe('Localization file for bar-locale is not available')
|
expect(translate('defaultTitle', 'not-existing-locale-file')).toBe('The Example App')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('It returns an error when symbol is not found on locale file', () => {
|
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', () => {
|
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', () => {
|
test('It returns true if string is found for locale', () => {
|
||||||
expect(translationAvaliable('coursesLabel', 'en-US')).toBe(true)
|
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', () => {
|
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)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user