chrome-devtools-frontend
Version:
Chrome DevTools UI
168 lines (142 loc) • 6.03 kB
text/typescript
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Platform from '../platform/platform.js';
// eslint-disable-next-line
import i18nBundle from '../third_party/i18n/i18n-bundle.js';
import * as i18nTypes from './i18nTypes.js';
/**
* The locale that DevTools displays
*/
export const registerLocaleData = i18nBundle.registerLocaleData;
/**
* The locale that DevTools displays
*/
export let registeredLocale: string|undefined;
/**
* The strings from the module.json file
*/
let moduleJSONStrings: Object|undefined;
/**
* Returns an instance of an object of formatted strings based on locale. If the instance is not
* set at the time of calling, it is created.
*/
function getOrSetModuleJSONStrings(): Object {
if (!registeredLocale) {
throw new Error(`Unsupported locale '${registeredLocale}'`);
}
moduleJSONStrings = moduleJSONStrings || i18nBundle.getRendererFormattedStrings(registeredLocale);
return moduleJSONStrings;
}
/**
* Take the locale passed in from the browser(host), run through the fallback logic (example: es-419 -> es)
* to find the DevTools supported locale and register it.
*/
export function registerLocale(locale: string): void {
registeredLocale = i18nBundle.lookupLocale(locale);
}
/**
* Returns an anonymous function that wraps a call to retrieve a localized string.
* This is introduced so that localized strings can be declared in environments where
* the i18n system has not been configured and so, cannot be directly invoked. Instead,
* strings are lazily localized when they are used. This is used for instance in the
* meta files used to register module extensions.
*/
export function getLazilyComputedLocalizedString(
// eslint-disable-next-line @typescript-eslint/naming-convention
str_: (id: string, values: Object) => Platform.UIString.LocalizedString, id: string, values: Object = {}): () =>
Platform.UIString.LocalizedString {
return (): Platform.UIString.LocalizedString => getLocalizedString(str_, id, values);
}
/**
* Retrieve the localized string.
*/
export function getLocalizedString(
// eslint-disable-next-line @typescript-eslint/naming-convention
str_: (id: string, values: Object) => Platform.UIString.LocalizedString, id: string,
values: Object = {}): Platform.UIString.LocalizedString {
if (!registeredLocale) {
throw new Error(`Unsupported locale '${registeredLocale}'`);
}
const icuMessage = str_(id, values);
return i18nBundle.getFormatted(icuMessage, registeredLocale) as Platform.UIString.LocalizedString;
}
/**
* Register a file's UIStrings with i18n, return function to generate the string ids.
*/
export function registerUIStrings(path: string, stringStructure: Object): (id: string, values: Object) =>
Platform.UIString.LocalizedString {
/**
* Convert a message string & replacement values into an
* indexed id value in the form '{messageid} | # {index}'.
* */
const str: (id: string, value: Object) => Platform.UIString.LocalizedString = (id: string, value: Object) => {
try {
const i18nInstance = i18nBundle.createMessageInstanceIdFn(path, stringStructure) as (
id: string, values: Object) => Platform.UIString.LocalizedString;
return i18nInstance(id, value);
} catch (e) {
// ID was not in the main file search for module.json strings
if (e instanceof i18nBundle.idNotInMainDictionaryException) {
const stringMappingArray = Object.getOwnPropertyNames(getOrSetModuleJSONStrings());
const index = stringMappingArray.indexOf(id);
if (index >= 0) {
return stringMappingArray[index] as Platform.UIString.LocalizedString;
}
}
return id as Platform.UIString.LocalizedString;
}
};
return str;
}
/**
* Returns a span element that may contains other DOM element as placeholders
*/
export function getFormatLocalizedString(
// eslint-disable-next-line @typescript-eslint/naming-convention
str_: (id: string, values: Object) => Platform.UIString.LocalizedString, stringId: string,
placeholders: Record<string, Object>): Element {
if (!registeredLocale) {
throw new Error(`Unsupported locale '${registeredLocale}'`);
}
const icuMessage = str_(stringId, placeholders);
const formatter = i18nBundle.getFormatter(icuMessage, registeredLocale);
const icuElements = formatter.getAst().elements;
const args: Array<Object> = [];
let formattedString = '';
for (const element of icuElements) {
if (element.type === 'argumentElement') {
const placeholderValue = placeholders[element.id];
if (placeholderValue) {
args.push(placeholderValue);
element.value = '%s'; // convert the {PH} back to %s to use Platform.UIString
}
}
formattedString += element.value;
}
return formatLocalized(formattedString, args);
}
export function formatLocalized(formattedString: string, args: Array<Object>): Element {
const substitution: Platform.StringUtilities.FormatterFunction<Object> = substitution => {
return substitution;
};
function append(a: Element, b: undefined|string|Node): Element {
if (b) {
a.appendChild(typeof b === 'string' ? document.createTextNode(b) : b);
}
return a;
}
const formatters = {s: substitution};
return Platform.StringUtilities.format(formattedString, args, formatters, document.createElement('span'), append)
.formattedResult;
}
export function serializeUIString(string: string, values: Record<string, Object> = {}): string {
const serializedMessage = {string, values};
return JSON.stringify(serializedMessage);
}
export function deserializeUIString(serializedMessage: string): i18nTypes.SerializedMessage {
if (!serializedMessage) {
return {string: '', values: {}} as i18nTypes.SerializedMessage;
}
return JSON.parse(serializedMessage) as i18nTypes.SerializedMessage;
}