UNPKG

scribe-translator

Version:

Lightweight translator for javascript

122 lines (103 loc) 4.01 kB
export interface Replacements { [key: string]: string | string[]; } class Scribe { /** * @param translations Container for all translation messages. * @param placeholderIdentifier Special identifier to idicate the block of text * to right is a placeholder. */ constructor(private translations, private placeholderIdentifier: string = ':') {} /** * Check to see if the translation exists. * @param translation The dot notation location of the require translation. */ has(translation: string): boolean { return this.get(translation) === translation; } /** * Get a translation by key. * @param translation The dot notation location of the required translation. * @param replacements If replacements are passed we will get the translation and then * try to replace any placeholders with the value from the corresponding key on the replacements. */ get(translation: string, replacements?: Replacements): string { const line = this.getLine(translation); if (!line) { return translation; } if (!replacements) { return line; } return this.makeReplacements(line, replacements); } /** * If the count is greator than 1 then use the plural form of the string. * @param translation @see get * @param count The amount of items. * @param replacements @see get */ choice(translation: string, count: number, replacements?: Replacements): string { const lines = this.get(translation, replacements).split('|'); if (lines[0] === translation) { return translation; } if (lines.length === 1 || count <= 1) { return lines[0]; } return lines[1]; } /** * Gets the translation line, using the translationNotation passed. * @param translationNotation The dot notation location of the required translation. */ protected getLine(translationNotation: string): string { const translationKeyParts: string[] = translationNotation.split('.'); return translationKeyParts.reduce((translationSegment, key) => { if (translationSegment) { return translationSegment[key]; } }, this.translations); } /** * Replace all placeholder * @param line A string containing placeholders to replace. * @param replacements An object with keys that correspond to the placeholders * in the line. */ protected makeReplacements(line: string, replacements: Replacements): string { const sortedReplacementKeys = this.getSortedReplacementKeys(replacements); sortedReplacementKeys.forEach((key) => { const replacementValue = replacements[key]; // If it is an array then we will go over the line with each item in the array // replacing each occurence of the placeholder with the current array item. if (Array.isArray(replacementValue)) { line = this.makeArrayReplacements(line, key, replacementValue); } else { line = line.replace(new RegExp(`${this.placeholderIdentifier}${key}`, "g"), replacementValue); } }); return line; } /** * @param line A string containing placeholders to replace. * @param key The placeholder. * @param replacements An array of string values. */ protected makeArrayReplacements(line: string, key: string, replacements: string[]) { return replacements.reduce((line: string, val: string) => { return line.replace(new RegExp(`${this.placeholderIdentifier}${key}`), val); }, line); } /** * Sort the replacements by length first, so that we don't replace part on another placeholder first. For example * if we did not do this the placeholder ":foo" would also replace the placeholder ":foobar" * @param replacements The end of the specified portion of the array. */ protected getSortedReplacementKeys(replacements: Replacements): string[] { return Object.keys(replacements).sort((a, b) => { return b.length - a.length; }); } } export default Scribe;