ember-intl
Version:
A internationalization toolbox for ambitious applications.
77 lines (70 loc) • 2.45 kB
text/typescript
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore We don't want to bring along extra baggage, when installed in a
// host project.
import omit from 'lodash.omit';
/**
* Takes an object and stringifies it in a deterministic way. It will also only
* include top-level entries.
*
* @private
* @function
* @param {object} obj
* @return {string}
*/
const stringifyDeterministically = (obj: Record<string, unknown>) => JSON.stringify(obj, Object.keys(obj).sort());
/**
* Replaces the `{` and `}` characters with `(` and `)` in order for those to
* not be interpreted as variables.
* Replaces the `\"` characters with `"` in order for the additional escape to work.
* For more details, refer: https://github.com/ember-intl/ember-intl/issues/1035
*
* @private
* @function
* @param {string} subject
* @return {string}
*/
const replaceInterpolators = (subject: string) =>
String(subject).replace(/\{/g, '(').replace(/\}/g, ')').replace(/\\"/g, '"');
/**
* A list of internal options that should not be serialized.
*/
const INTERNAL_OPTIONS = 'resilient default htmlSafe'.split(' ');
/**
* Takes a translation options object and stringifies it in a deterministic way.
* It will also only include top-level entries and filter out irrelevant,
* internal entries.
*
* @private
* @function
* @param {object} options
* @return {string}
*/
const stringifyOptions = (options: Record<string, unknown> = {}) =>
replaceInterpolators(stringifyDeterministically(omit(options, INTERNAL_OPTIONS)));
/**
* Serializes a translation invocation deterministically.
*
* @private
* @function
* @param {string} key translation key
* @param {object} [options] options and variables passed along
* @return {string}
* @hide
*/
export const serializeTranslation = (key: string, options: Record<string, unknown>) =>
`t:${key}:${stringifyOptions(options)}`;
/**
* Used to overwrite the default `intl/missing-message` implementation in order
* to display a deterministic serialization of the translation for easier
* assertions in the tests.
*
* @private
* @function
* @param {string} key translation key
* @param {string[]} locales list of locales to search through
* @param {object} [options] options and variables passed along
* @return {string}
* @hide
*/
export const missingMessage = (key: string, _locales: string[], options: Record<string, unknown>) =>
serializeTranslation(key, options);