Skip to content

Instantly share code, notes, and snippets.

@Chigozie-Gerald
Created August 2, 2023 15:54
Show Gist options
  • Save Chigozie-Gerald/12692ac47f4a63ca0890d13fb275dad5 to your computer and use it in GitHub Desktop.
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
/** 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