UNPKG

stem-core

Version:

Frontend and core-library framework

133 lines (112 loc) 4.29 kB
import {UI} from "./UIBase"; // This is the object that will be used to translate text let translationMap = null; // Keep a set of all UI Element that need to be updated when the language changes // Can't use a weak set here unfortunately because we need iteration // That's why we must make sure to remove all nodes from the set when destroying them UI.TranslationElements = new Set(); UI.TranslationTextElement = class TranslationTextElement extends UI.TextElement { constructor(value) { if (arguments.length === 1) { super(value); } else { super(""); this.setValue(...arguments); } } setValue(value) { if (arguments.length > 1) { this.value = Array.from(arguments); } else { this.value = value; } if (this.node) { this.redraw(); } } // args[0] is a string where the "%[number]" block will be replaced by the args[number] evaluateSprintf(...args) { let str = translationMap && translationMap.get(args[0]); if (!str) { return ""; } for (let index = 1; index < args.length; index += 1) { str = str.replace("%" + index, args[index]); } return str; } evaluate(strings, ...values) { if (!Array.isArray(strings)) { return this.evaluateSprintf(...arguments); // This means strings is a string with the sprintf pattern } else { // Using template literals https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals if (arguments.length !== strings.length) { console.error("Invalid arguments to evaluate ", Array.from(arguments)); } let result = strings[0]; for (let i = 1; i < arguments.length; i++) { result += arguments[i]; result += strings[i]; } return result; } } getValue() { let value = this.value; if (Array.isArray(this.value)) { value = this.evaluate(...value); } else { // TODO: if translationMap.get() returns "", keep, skip only if returning null value = (translationMap && translationMap.get(value)) || value; } return value; } toString() { return this.getValue(); } onMount() { UI.TranslationElements.add(this); } onUnmount() { UI.TranslationElements.delete(this); } }; // This method is a shorthand notation to create a new translatable text element // TODO: should also support being used as a string template UI.T = (str) => { return new UI.TranslationTextElement(str); }; // TODO @mciucu this should be wrapped in a way that previous requests that arrive later don't get processed // TODO: should this be done with promises? // Function to be called with a translation map // The translationMap object needs to implement .get(value) to return the translation for value function setTranslationMap(_translationMap) { if (translationMap === _translationMap) { return; } translationMap = _translationMap; for (let textElement of UI.TranslationElements.values()) { textElement.redraw(); } } let languageStore = null; // This function should be called to set the language store to watch for changes // The languageStore argumenent needs to implement .getLocale(), addListener("localChange", (language) =>{}) // The language objects need to implement .buildTranslation(callback), where callback should be called with a translationMap function setLanguageStore(_languageStore) { languageStore = _languageStore; let currentLocale = languageStore.getLocale(); // If there's a default language already set, build the translation table for it if (currentLocale) { currentLocale.buildTranslation(setTranslationMap); } // Add a listener for whenever the language changes languageStore.addListener("localeChange", (language) => { language.buildTranslation(setTranslationMap); }); } function getTranslationMap() { return translationMap; } export {setLanguageStore, setTranslationMap, getTranslationMap};