UNPKG

@eclipse-scout/core

Version:
247 lines (221 loc) 8.53 kB
/* * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ import {App, arrays, Session, TextMap} from '../index'; import $ from 'jquery'; export type TextMapType = Record<string, TextMap>; export const texts = { /** * This default language is used whenever a new text is registered. */ defaultLanguage: 'en', TEXT_KEY_REGEX: /^\${textKey:([^}]+)}$/, textsByLocale: {} as TextMapType, bootstrap(url: string | string[]): JQuery.Promise<any> { if (!url) { return $.resolvedPromise({}); } let promises = []; let urls = arrays.ensure(url); urls.forEach(url => promises.push( $.ajaxJson(url).then(texts._handleBootstrapResponse.bind(this, url))) ); return $.promiseAll(promises); }, /** @internal */ _setTextsByLocale(val: TextMapType) { texts.textsByLocale = val; }, /** @internal */ _handleBootstrapResponse(url: string, data: any) { App.handleJsonError(url, data); texts.init(data); }, init(model: Record<string, Record<string, string>>) { Object.keys(model).forEach(languageTag => { let textMap = model[languageTag]; texts.get(languageTag).addAll(textMap); }); }, /** * Links the texts of the given languageTag to make parent lookup possible (e.g. look first in de-CH, then in de, then in default). */ link(languageTag: string) { let tags = texts.createOrderedLanguageTags(languageTag); let child: TextMap; tags.forEach(tag => { let textMap: TextMap = texts._get(tag); if (!textMap) { // If there are no texts for the given tag, create an empty Texts object for linking purpose textMap = new TextMap(); texts._put(tag, textMap); } if (child) { child.setParent(textMap); } child = textMap; }); }, /** * Creates an array containing all relevant tags. * * Examples: * - 'de-CH' generates the array: ['de-CH', 'de', 'default'] * - 'de' generates the array: ['de', 'default'] * - 'default' generates the array: ['default'] */ createOrderedLanguageTags(languageTag: string): string[] { let tags = [languageTag]; let i = languageTag.lastIndexOf('-'); while (i >= 0) { languageTag = languageTag.substring(0, i); tags.push(languageTag); i = languageTag.lastIndexOf('-'); } if (languageTag !== 'default') { tags.push('default'); } return tags; }, /** * Returns the (modifiable) TextMap for the given language tag. * If no TextMap exists for the languageTag given, a new empty map is created. * @returns the TextMap for the given languageTag. Never returns null or undefined. */ get(languageTag: string): TextMap { let textMap = texts._get(languageTag); if (textMap) { return textMap; } texts.link(languageTag); textMap = texts._get(languageTag); if (!textMap) { throw new Error('Texts missing for the language tag ' + languageTag); } return textMap; }, /** @internal */ _get(languageTag: string): TextMap { return texts.textsByLocale[languageTag]; }, /** * Registers the text map for the given locale. * If there already is a text map registered for that locale, it will be replaced, meaning existing texts for that locale are deleted. * @internal */ _put(languageTag: string, textMap: TextMap) { texts.textsByLocale[languageTag] = textMap; }, /** * Extracts NLS texts from the DOM tree. Texts are expected in the following format: * * `<scout-text data-key="..." data-value="..." />` * * This method returns a map with all found texts. It must be called before scout.prepareDOM() * is called, as that method removes all <scout-text> tags. */ readFromDOM(): Record<string, string> { let textMap = {}; $('scout-text').each(function() { // No need to unescape strings (the browser did this already) let key = $(this).data('key'); // noinspection UnnecessaryLocalVariableJS let value = $(this).data('value'); textMap[key] = value; }); return textMap; }, /** * Returns the given text key in the form `'${textKey:AKey}'`. * * @param key the text key to convert (e.g. `'AKey'`) * @returns the given text key in the form `'${textKey:AKey}'` */ buildKey(key: string): string { return '${textKey:' + key + '}'; }, /** * Returns the text key (e.g. `'AKey'`) if the given text has the form `'${textKey:AKey}'`. Otherwise, * the input is returned unchanged. * * @param value either an arbitrary text or a special string of the form `'${textKey:AKey}'` * @returns the resolved text key or the unchanged value if the text key could not be extracted. */ resolveKey(value: string): string { let match = texts.TEXT_KEY_REGEX.exec(value); if (match) { return match[1]; } return value; }, /** * If the given text has the form `'${textKey:AKey}'`, the key is extracted and the text for this * key in the given languages is resolved and returned. Otherwise, the input is returned unchanged. * * @param value either an arbitrary text or a special string of the form `'${textKey:AKey}'` * @param languageTag the languageTag to use for the text lookup with the resolved key. * @returns the resolved text in the given language or the unchanged text if the text key could not be extracted. */ resolveText(value: string, languageTag: string): string { let key = texts.resolveKey(value); if (key !== value) { return texts.get(languageTag).get(key); } return value; }, /** * Converts the value of the specified property from the form `'${textKey:...}'` into a resolved text. * The value remains unchanged if it does not match the {@linkplain texts#resolveText supported format}. * * @param object non-null object having a text property which may contain a text key (must not be null) * @param textProperty name of the property on the given object which may contain a text key. By default, 'text' is used as property name. * @param session session defining the locale to be used when resolving a text. Can be undefined when the given `object` has a session property, otherwise mandatory. */ resolveTextProperty(object: any, textProperty?: string, session?: Session) { textProperty = textProperty || 'text'; session = object.session || session; let value = object[textProperty]; let text = texts.resolveText(value, session.locale.languageTag); if (text !== value) { object[textProperty] = text; } }, /** * Converts the values of the specified properties from the form `'${textKey:...}'` into a resolved text. * A value remains unchanged if it does not match the {@linkplain texts#resolveText supported format}. * * @param object non-null object having a text property which may contain a text key (must not be null) * @param textProperties names of the properties on the given object which may contain a text key. * @param session session defining the locale to be used when resolving a text. Can be undefined when the given `object` has a session property, otherwise mandatory. */ resolveTextProperties(object: any, textProperties: string[], session?: Session) { arrays.ensure(textProperties).forEach(property => { texts.resolveTextProperty(object, property, session); }); }, /** * Registers a texts map for a text key. * The texts for the default language specified by {@link texts.defaultLanguage} are registered as default texts. * * @param key the text key under which the given textsArg map will be registered. * @param textsArg an object with the languageTag as key and the translated text as value */ registerTexts(key: string, textsArg: Record<string, string>) { // In case of changed defaultLanguage clear the 'default' entry texts.get('default').remove(key); for (let languageTag in textsArg) { let text = textsArg[languageTag]; // Use defaultLanguage as default, if specified (maybe changed or set to null by the app). if (languageTag && languageTag === texts.defaultLanguage) { languageTag = 'default'; } texts.get(languageTag).add(key, text); } } };