Skip to content

Commit

Permalink
STRF-9124 Create an endpoint for precaching lang helper function
Browse files Browse the repository at this point in the history
  • Loading branch information
jairo-bc committed May 18, 2021
1 parent e75dac2 commit 42055bd
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 8 deletions.
9 changes: 9 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@ class Paper {
addTemplates(templates) {
this.renderer.addTemplates(templates);
}

/**
* Precompiles translations to string representations of translation function source code
*
* @param {Object} translations transformed translations object
*/
precompileTranslations(translations) {
return Translator.precompileTranslations(translations);
}
}

module.exports = Paper;
2 changes: 1 addition & 1 deletion lib/translator/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function filterByKey(language, keyFilter) {
result[key][subKey] = language[key][subKey];
}
}
} else {
} else if (key !== 'compiledTranslations') {
result[key] = language[key];
}
}
Expand Down
71 changes: 64 additions & 7 deletions lib/translator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,16 @@ const DEFAULT_LOCALE = 'en';
*/
function Translator(acceptLanguage, allTranslations, logger = console, omitTransforming = false) {
this.logger = logger;
this.omitTransforming = omitTransforming;

const languages = omitTransforming ? allTranslations : Transformer.transform(allTranslations, DEFAULT_LOCALE, this.logger);
const languages = this.omitTransforming ? allTranslations : Transformer.transform(allTranslations, DEFAULT_LOCALE, this.logger);
/**
* @private
* @type {string}
*/
this._locale = LocaleParser.getPreferredLocale(acceptLanguage, languages, DEFAULT_LOCALE);

/**
* @private
* @type {Object.<string, string>}
*/
this._language = languages[this._locale] || {};
this.setLanguage(languages);

/**
* @private
Expand Down Expand Up @@ -66,6 +63,53 @@ Translator.create = function (acceptLanguage, allTranslations, logger = console,
return new Translator(acceptLanguage, allTranslations, logger, omitTransforming);
};

/**
* Precompile translation functions
* @param {Object} translations
* @returns {Object}
*/
Translator.precompileTranslations = function (translations) {
const compiled = {};

Object.keys(translations).forEach(language => {
compiled[language] = {}
Object.keys(translations[language]).forEach(categoryKey => {
compiled[language][categoryKey] = translations[language][categoryKey];
if (categoryKey === 'translations') {
compiled[language].compiledTranslations = {};
Object.keys(translations[language][categoryKey]).forEach(key => {
compiled[language].compiledTranslations[key] = Translator.compileFormatterFunction(translations[language], key);
})
}
});
});

return compiled;
}

/**
* Precompile translation functions
* @param {Object} language
* @param {String} key
* @returns {Object}
*/
Translator.compileFormatterFunction = function (language, key) {
const locale = language.locales[key];
const formatter = new MessageFormat(locale)

try {
return formatter.compile(language.translations[key]).toString();
} catch (err) {
if (err.name === 'SyntaxError') {
this.logger.error(`Syntax Error during Formatter function precompilation: ${err.message} for key "${key}"`, err.expected);

return () => '';
}

throw err;
}
}

/**
* Get translated string
* @param {string} key
Expand All @@ -78,11 +122,16 @@ Translator.prototype.translate = function (key, parameters) {
return key;
}

if (typeof this._formatFunctions[key] === 'undefined') {
if (!this.omitTransforming && typeof this._formatFunctions[key] === 'undefined') {
this._formatFunctions[key] = this._compileTemplate(key);
}

try {
if (this.omitTransforming) {
const fn = new Function(`return ${language.compiledTranslations[key]}`)()
return fn(parameters);
}

return this._formatFunctions[key](parameters);
} catch (err) {
this.logger.error(err);
Expand Down Expand Up @@ -112,6 +161,14 @@ Translator.prototype.getLanguage = function (keyFilter) {
return this._language;
};

/**
* Set language object
* @param {Object} [languages] object
*/
Translator.prototype.setLanguage = function (languages) {
this._language = languages[this._locale] || {};
};

/**
* Get formatter
* @private
Expand Down
2 changes: 2 additions & 0 deletions spec/lib/translator.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ describe('Translator', () => {
it('should successfully translate en language without transforming translations', done => {
const locale = 'en';
const translator = Translator.create(locale, flattenedLanguages, console, true);
const precompiledTranslations = Translator.precompileTranslations(flattenedLanguages);
translator.setLanguage(precompiledTranslations)
expect(translator.translate('hello', {name: 'User'})).to.equal('Hello User');

const key = 'level1.level2';
Expand Down

0 comments on commit 42055bd

Please sign in to comment.