Created
August 2, 2023 15:54
-
-
Save Chigozie-Gerald/12692ac47f4a63ca0890d13fb275dad5 to your computer and use it in GitHub Desktop.
A typescript snippet I use in supporting multi-lang functionalities for not so big websites
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Example json containing translate strings and variables */ | |
const json = { | |
"The house costs {{amount}} and not {{amount}}": { | |
en: "The house costs {{amount}} and not {{amount}}", | |
fr: "La maison coûte {{amount}} et non {{amount}}", | |
}, | |
}; | |
type locale = "en" | "fr"; | |
type translation_variables = "{{amount}}" | "{{...whatever}}"; | |
type translate_options = { | |
[key in translation_variables]?: (string | number) | (string | number)[]; | |
}; | |
type json_key = keyof typeof json; | |
const defaultLocale = "fr"; // can be any locale of your choice | |
const current_locale = (process.env.REACT_APP_LOCALE || | |
defaultLocale) as locale; | |
/** @returns An object containing the parsed json and the locale used during parsing */ | |
const getTranslateJson = () => { | |
const res: Partial<{ [key in json_key]: string }> = {}; | |
Object.keys(json).forEach((k) => { | |
const key = k as json_key; | |
const translate_obj = json[key]; | |
res[key] = translate_obj[current_locale]; | |
}); | |
return { json: res, locale: current_locale }; | |
}; | |
let translate_json = getTranslateJson(); | |
/** @returns translated text */ | |
const translate = ( | |
originalText: json_key, | |
options: translate_options = {} | |
): string => { | |
const { locale } = translate_json; | |
if (current_locale !== locale) { | |
translate_json = getTranslateJson(); | |
} | |
const text = translate_json.json[originalText] || ""; | |
return text_replace(text, options); | |
}; | |
/** @returns Translated tring with variables properly replaced */ | |
const text_replace = ( | |
originalText: string, | |
options: { | |
[key in translation_variables]?: (string | number) | (string | number)[]; | |
} | |
) => { | |
let count: Partial<{ [key in translation_variables]: number }> = {}; | |
const replacedText = originalText.replace(/\{\{([^}]+)\}\}/g, (v) => { | |
// regex used here tries to find variables (i.e strings wrapped in double curly braces) | |
const value = v as translation_variables; | |
const count_value = count[value]; | |
const new_count = typeof count_value === "number" ? count_value + 1 : 0; // Based on "0" indexing | |
count[value] = new_count; | |
const replace_value = options[value]; | |
if (!replace_value) { | |
return value; | |
} else { | |
const str = Array.isArray(replace_value) | |
? replace_value[new_count] || "-" | |
: replace_value || "-"; | |
// If the appropriate variable value isn't sent, use a fallback "-" | |
return `${str}`; // Replace with the desired values | |
} | |
}); | |
return replacedText; | |
}; | |
/** | |
* Do well to check my LinkedIn page (https://www.linkedin.com/in/chigozie-ijomah) I have a post on the JS Intl Object | |
* @param value Amount to internationalize | |
* @returns Amount in specified locale format | |
*/ | |
export const currency = (value: string | number) => { | |
value = Number(value); | |
const getTagValue = (locale: locale) => (locale === "fr" ? "fr-FR" : "en-US"); | |
const tagValue = getTagValue(current_locale); | |
const amount = new Intl.NumberFormat(tagValue, { | |
style: "currency", | |
currency: "EUR", | |
}).format(value); | |
return amount; | |
}; | |
translate("The house costs {{amount}} and not {{amount}}", { | |
"{{amount}}": [currency(1000), currency(750)], | |
}); | |
// returns "La maison coûte 1 000,00 € et non 750,00 €" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment