0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00
ghost/core/frontend/services/theme-engine/i18n.js
Hannah Wolfe 9614d71e1f Moved theme i18n to new theme engine service
refs: bf0823c9a2

- continuing the work of splitting up the theme service into logical components

- This one is a little more involved, as the i18n initialisation was unnecessarily spread over several locations.
- I moved it into being part of the ActiveTheme class and called in the constructor, meaning we don't need the services.theme.activated event anymore as the constructor is called in the same cases.
- Also moved the event listener for locales into the bridge, as I don't want that inside of theme-engine, and we don't want circular dependencies. We'll figure out a wayto refactor this soon too.
2021-04-26 12:29:55 +01:00

98 lines
3.3 KiB
JavaScript

const errors = require('@tryghost/errors');
const {i18n} = require('../../../server/lib/common');
const logging = require('../../../shared/logging');
const settingsCache = require('../../../server/services/settings/cache');
const config = require('../../../shared/config');
const jp = require('jsonpath');
const isNil = require('lodash/isNil');
class ThemeI18n extends i18n.I18n {
constructor(locale) {
super(locale);
}
/**
* Setup i18n support for themes:
* - Load correct language file into memory
*
* @param {String} activeTheme - name of the currently loaded theme
*/
init(activeTheme) {
// This function is called during theme initialization, and when switching language or theme.
const currentLocale = this._loadLocale();
// Reading file for current locale and active theme and keeping its content in memory
if (activeTheme) {
// Reading translation file for theme .hbs templates.
// Compatibility with both old themes and i18n-capable themes.
// Preventing missing files.
this._strings = this._tryGetLocale(activeTheme, currentLocale);
if (!this._strings && currentLocale !== this.defaultLocale()) {
logging.warn(`Falling back to locales/${this.defaultLocale()}.json.`);
this._strings = this._tryGetLocale(activeTheme, this.defaultLocale());
}
}
if (isNil(this._strings)) {
// even if empty, themeStrings must be an object for jp.value
this._strings = {};
}
this._initializeIntl();
}
/**
* Attempt to load a local file and parse the contents
*
* @param {String} activeTheme
* @param {String} locale
*/
_tryGetLocale(activeTheme, locale) {
try {
return this._readStringsFile(config.getContentPath('themes'), activeTheme, 'locales', `${locale}.json`);
} catch (err) {
if (err.code === 'ENOENT') {
if (locale !== this.defaultLocale()) {
logging.warn(`Theme's file locales/${locale}.json not found.`);
}
} else if (err instanceof SyntaxError) {
logging.error(new errors.IncorrectUsageError({
err,
message: `Unable to parse locales/${locale}.json. Please check that it is valid JSON.`
}));
} else {
throw err;
}
}
}
/**
* Load the current locale out of the settings cache
*/
_loadLocale() {
this._locale = settingsCache.get('lang');
return this._locale;
}
/**
* Do the lookup with JSON path
*
* @param {String} msgPath
*/
_getCandidateString(msgPath) {
// Both jsonpath's dot-notation and bracket-notation start with '$'
// E.g.: $.store.book.title or $['store']['book']['title']
// The {{t}} translation helper passes the default English text
// The full Unicode jsonpath with '$' is built here
// jp.stringify and jp.value are jsonpath methods
// Info: https://www.npmjs.com/package/jsonpath
let path = jp.stringify(['$', msgPath]);
return jp.value(this._strings, path) || msgPath;
}
}
let themeI18n = new ThemeI18n();
module.exports = themeI18n;