When ES2015 came out with the template strings (as that was its name there) i cheered the old Great Lisp Macros would be on the way to go back but it was the premature overestimating. Nevertheless i quickly found a good real use of the literals besides just being handy.
The idea is to have in React:
1 |
<div>{T`Hello World,`}</div> |
and to see in a browser:
Привет, Мир
The dirty, quick, but still long living implementation is as easy as to have a JSON object with the translations like this:
src/l10n/translations.json
1 2 3 4 5 6 7 8 9 10 |
{ “en”:{ “No balance”: “Balance is not updated yet”, “No web3”: “Not connected to Ethereum” }, “ru”:{ “No balance”: “Баланс неизвестен”, “No web3”: “Нет подключения к Ethereum” } } |
and a module implementing T
src/l10n/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// default en let locale = ‘en’; // this might be useful, so let's export export const currentLocale = () => locale; // messages in the language of the current locale let messages = {}; let dictionary = {}; // Lookup helper to simplify the monster function be const translate = key => messages[key] ? messages[key] : key; // The work horse. It does all we work with the literal // template translating and will be exported as a default const l10n = (strings, …values) => trings.reduce((prevString, nextString, index) => prevString + (index > 0 ? values[index — 1] : ‘’) + nextString, ‘’); export default l10n; // Let's try to be clever an build `messages` lookup // table combining the available languages with the fallbacks // to default const init = (lc, json) => { // Uniform the locale abbreveation locale = lc.split(‘-’); const [mainlocale] = locale; locale = locale[1] ? `${locale[0]}-${locale[1].toUpperCase()}` : lc; // Create `messages` dictionary from the corresponding // langauge const locales = Object.keys(json); if (locales.length > 0) { messages = Object.assign({}, json[locales[0]]); if (mainlocale !== locale) { if (json[mainlocale]) { messages = Object.assign(messages, json[mainlocale]); } } if (json[locale]) { messages = Object.assign(messages, json[locale]); } } // also save json object in the dictionary // just it case we would nee other be current localization dictionary = json; dictionary[lc] = messages; }; // export `just in case` function to get message // a message in non-default language export const byLang = (lc, key) => dictionary[lc][key] ? dictionary[lc][key] : `L10N:${key}[${lc}]:L10N`; // Finally read the translation from json and init import translations from ‘./translations.json’; init(navigator.language, translations); |
What’s the reason to invent a wheel instead of picking up one of the miriads others l18n modules? The main reason is “miriads”. Really it is much faster to get this small module done than to waste hours if not days trying to choose “the best” from the npm pile. Another reasons are “flexibility” and “risk free” — once we in S4Y needed to have few versions of wordings in the same language and it cost us nothing to change the getting “locale” from http header to mobx observable and we are sure we will adopt this homebrew solution in countable minutes/hours in case of the unexpected requirements.
And besides all it is pretty.