0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Improved i18n to use DI for logging + config

- final preparation for moving i18n out of Ghost core
- logging is passed in via DI
- theme i18n needs a config value, but no need to pass all of config for one parameter, a better pattern is to pass the one value needed
This commit is contained in:
Hannah Wolfe 2021-05-06 10:38:56 +01:00
parent e1699afc77
commit ad9b18e00f
No known key found for this signature in database
GPG key ID: 9F8C7532D0A6BA55
5 changed files with 47 additions and 26 deletions

View file

@ -1,17 +1,31 @@
const errors = require('@tryghost/errors'); const errors = require('@tryghost/errors');
const i18n = require('../../../../shared/i18n'); const i18n = require('../../../../shared/i18n');
const logging = require('../../../../shared/logging');
const config = require('../../../../shared/config');
class ThemeI18n extends i18n.I18n { class ThemeI18n extends i18n.I18n {
/** /**
* @param {objec} [options] * @param {objec} [options]
* @param {string} basePath - the base path for the translation directory (e.g. where themes live)
* @param {string} [locale] - a locale string * @param {string} [locale] - a locale string
*/ */
constructor(options = {}) { constructor(options = {}) {
super(options); super(options);
// We don't care what gets passed in, themes use fulltext mode // We don't care what gets passed in, themes use fulltext mode
this._stringMode = 'fulltext'; this._stringMode = 'fulltext';
this._basePath = options.basePath;
}
/**
* BasePath getter & setter used for testing
*/
set basePath(basePath) {
this._basePath = basePath;
}
/**
* Need to call init after this
*/
get basePath() {
return this._basePath;
} }
/** /**
@ -23,36 +37,36 @@ class ThemeI18n extends i18n.I18n {
* @param {String} options.locale - name of the currently loaded locale * @param {String} options.locale - name of the currently loaded locale
* *
*/ */
init({activeTheme, locale}) { init({activeTheme, locale} = {}) {
// This function is called during theme initialization, and when switching language or theme. // This function is called during theme initialization, and when switching language or theme.
this._locale = locale || this._locale; this._locale = locale || this._locale;
this._activetheme = activeTheme || 'casper'; this._activetheme = activeTheme || this._activetheme;
super.init(); super.init();
} }
_translationFileDirs() { _translationFileDirs() {
return [config.getContentPath('themes'), this._activetheme, 'locales']; return [this.basePath, this._activetheme, 'locales'];
} }
_handleFallbackToDefault() { _handleFallbackToDefault() {
logging.warn(`Theme translations falling back to locales/${this.defaultLocale()}.json.`); this._logging.warn(`Theme translations falling back to locales/${this.defaultLocale()}.json.`);
} }
_handleMissingFileError(locale) { _handleMissingFileError(locale) {
if (locale !== this.defaultLocale()) { if (locale !== this.defaultLocale()) {
logging.warn(`Theme translations file locales/${locale}.json not found.`); this._logging.warn(`Theme translations file locales/${locale}.json not found.`);
} }
} }
_handleInvalidFileError(locale, err) { _handleInvalidFileError(locale, err) {
logging.error(new errors.IncorrectUsageError({ this._logging.error(new errors.IncorrectUsageError({
err, err,
message: `Theme translations unable to parse locales/${locale}.json. Please check that it is valid JSON.` message: `Theme translations unable to parse locales/${locale}.json. Please check that it is valid JSON.`
})); }));
} }
_handleEmptyKeyError() { _handleEmptyKeyError() {
logging.warn('Theme translations {{t}} helper called without a translation key.'); this._logging.warn('Theme translations {{t}} helper called without a translation key.');
} }
_handleMissingKeyError() { _handleMissingKeyError() {

View file

@ -1,5 +1,7 @@
const ThemeI18n = require('./i18n'); const config = require('../../../../shared/config');
const themeI18n = new ThemeI18n(); const logging = require('../../../../shared/logging');
module.exports = themeI18n; const ThemeI18n = require('./i18n');
module.exports = new ThemeI18n({logging, basePath: config.getContentPath('themes')});
module.exports.ThemeI18n = ThemeI18n; module.exports.ThemeI18n = ThemeI18n;

View file

@ -1,3 +1,4 @@
const errors = require('@tryghost/errors');
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const MessageFormat = require('intl-messageformat'); const MessageFormat = require('intl-messageformat');
@ -8,18 +9,19 @@ const isEqual = require('lodash/isEqual');
const isNil = require('lodash/isNil'); const isNil = require('lodash/isNil');
const merge = require('lodash/merge'); const merge = require('lodash/merge');
const get = require('lodash/get'); const get = require('lodash/get');
const errors = require('@tryghost/errors');
const logging = require('../logging');
class I18n { class I18n {
/** /**
* @param {objec} [options] * @param {objec} [options]
* @param {string} [locale] - a locale string * @param {string} [locale] - a locale string
* @param {{dot|fulltext}} [stringMode] - which mode our translation keys use * @param {{dot|fulltext}} [stringMode] - which mode our translation keys use
* @param {{object}} [logging] - logging method
*/ */
constructor(options = {}) { constructor(options = {}) {
this._locale = options.locale || this.defaultLocale(); this._locale = options.locale || this.defaultLocale();
this._stringMode = options.stringMode || 'dot'; this._stringMode = options.stringMode || 'dot';
this._logging = options.logging || console;
this._strings = null; this._strings = null;
} }
@ -257,29 +259,29 @@ class I18n {
} }
_handleFormatError(err) { _handleFormatError(err) {
logging.error(err.message); this._logging.error(err.message);
} }
_handleFallbackToDefault() { _handleFallbackToDefault() {
logging.warn(`i18n is falling back to ${this.defaultLocale()}.json.`); this._logging.warn(`i18n is falling back to ${this.defaultLocale()}.json.`);
} }
_handleMissingFileError(locale) { _handleMissingFileError(locale) {
logging.warn(`i18n was unable to find ${locale}.json.`); this._logging.warn(`i18n was unable to find ${locale}.json.`);
} }
_handleInvalidFileError(locale, err) { _handleInvalidFileError(locale, err) {
logging.error(new errors.IncorrectUsageError({ this._logging.error(new errors.IncorrectUsageError({
err, err,
message: `i18n was unable to parse ${locale}.json. Please check that it is valid JSON.` message: `i18n was unable to parse ${locale}.json. Please check that it is valid JSON.`
})); }));
} }
_handleEmptyKeyError() { _handleEmptyKeyError() {
logging.warn('i18n.t() was called without a key'); this._logging.warn('i18n.t() was called without a key');
} }
_handleMissingKeyError(key) { _handleMissingKeyError(key) {
logging.error(new errors.IncorrectUsageError({ this._logging.error(new errors.IncorrectUsageError({
message: `i18n.t() was called with a key that could not be found: ${key}` message: `i18n.t() was called with a key that could not be found: ${key}`
})); }));
} }

View file

@ -1,4 +1,6 @@
const logging = require('../logging');
const I18n = require('./i18n'); const I18n = require('./i18n');
module.exports = new I18n(); module.exports = new I18n({logging});
module.exports.I18n = I18n; module.exports.I18n = I18n;

View file

@ -2,15 +2,16 @@ const should = require('should');
const path = require('path'); const path = require('path');
const helpers = require('../../../core/frontend/helpers'); const helpers = require('../../../core/frontend/helpers');
const themeI18n = require('../../../core/frontend/services/theme-engine/i18n'); const themeI18n = require('../../../core/frontend/services/theme-engine/i18n');
const configUtils = require('../../utils/configUtils');
describe('{{t}} helper', function () { describe('{{t}} helper', function () {
beforeEach(function () { let ogBasePath = themeI18n.basePath;
configUtils.set('paths:contentPath', path.join(__dirname, '../../utils/fixtures/'));
before(function () {
themeI18n.basePath = path.join(__dirname, '../../utils/fixtures/themes/');
}); });
afterEach(function () { after(function () {
configUtils.restore(); themeI18n.basePath = ogBasePath;
}); });
it('theme translation is DE', function () { it('theme translation is DE', function () {