wallet-core/packages/taler-util/src/i18n.ts

163 lines
3.9 KiB
TypeScript
Raw Normal View History

2021-06-08 20:56:27 +02:00
// @ts-ignore: no type decl for this library
import * as jedLib from "jed";
2021-06-14 16:08:58 +02:00
import { Logger } from "./logging.js";
2021-06-08 20:56:27 +02:00
const logger = new Logger("i18n/index.ts");
export let jed: any = undefined;
/**
* Set up jed library for internationalization,
* based on browser language settings.
*/
export function setupI18n(lang: string, strings: { [s: string]: any }): void {
2021-06-08 20:56:27 +02:00
lang = lang.replace("_", "-");
if (!strings[lang]) {
2022-09-21 20:43:35 +02:00
strings[lang] = {};
2022-04-26 04:07:46 +02:00
// logger.warn(`language ${lang} not found, defaulting to source strings`);
2021-06-08 20:56:27 +02:00
}
jed = new jedLib.Jed(strings[lang]);
}
/**
* Use different translations for testing. Should not be used outside
* of test cases.
*/
export function internalSetStrings(langStrings: any): void {
jed = new jedLib.Jed(langStrings);
}
declare const __translated: unique symbol;
export type TranslatedString = string & { [__translated]: true };
2021-06-08 20:56:27 +02:00
/**
* Convert template strings to a msgid
*/
function toI18nString(stringSeq: ReadonlyArray<string>): TranslatedString {
2021-06-08 20:56:27 +02:00
let s = "";
for (let i = 0; i < stringSeq.length; i++) {
s += stringSeq[i];
if (i < stringSeq.length - 1) {
s += `%${i + 1}$s`;
}
}
return s as TranslatedString;
2021-06-08 20:56:27 +02:00
}
/**
* Internationalize a string template with arbitrary serialized values.
*/
2022-09-21 20:43:35 +02:00
export function singular(
stringSeq: TemplateStringsArray,
...values: any[]
): TranslatedString {
2021-06-08 20:56:27 +02:00
const s = toI18nString(stringSeq);
const tr = jed
.translate(s)
.ifPlural(1, s)
.fetch(...values);
return tr;
}
/**
* Internationalize a string template without serializing
*/
2021-06-09 15:26:18 +02:00
export function translate(
stringSeq: TemplateStringsArray,
...values: any[]
): TranslatedString[] {
2021-06-08 20:56:27 +02:00
const s = toI18nString(stringSeq);
2021-06-09 15:26:18 +02:00
if (!s) return [];
const translation: TranslatedString = jed.ngettext(s, s, 1);
2021-06-09 15:26:18 +02:00
return replacePlaceholderWithValues(translation, values);
2021-06-08 20:56:27 +02:00
}
/**
* Internationalize a string template without serializing
*/
2022-09-21 20:43:35 +02:00
export function Translate({
children,
debug,
}: {
children: any;
debug?: boolean;
}): any {
2021-06-08 20:56:27 +02:00
const c = [].concat(children);
const s = stringifyArray(c);
2021-06-09 15:26:18 +02:00
if (!s) return [];
const translation: TranslatedString = jed.ngettext(s, s, 1);
if (debug) {
2022-09-21 20:43:35 +02:00
console.log("looking for ", s, "got", translation);
}
2021-06-09 15:26:18 +02:00
return replacePlaceholderWithValues(translation, c);
2021-06-08 20:56:27 +02:00
}
/**
* Get an internationalized string (based on the globally set, current language)
* from a JSON object. Fall back to the default language of the JSON object
* if no match exists.
*/
export function getJsonI18n<K extends string>(
obj: Record<K, string>,
key: K,
): string {
return obj[key];
}
export function getTranslatedArray(array: Array<any>) {
const s = stringifyArray(array);
const translation: TranslatedString = jed.ngettext(s, s, 1);
2021-06-08 20:56:27 +02:00
return replacePlaceholderWithValues(translation, array);
}
function replacePlaceholderWithValues(
translation: TranslatedString,
2021-06-08 20:56:27 +02:00
childArray: Array<any>,
): Array<any> {
const tr = translation.split(/%(\d+)\$s/);
// const childArray = toChildArray(children);
// Merge consecutive string children.
const placeholderChildren = [];
for (let i = 0; i < childArray.length; i++) {
const x = childArray[i];
if (x === undefined) {
continue;
} else if (typeof x === "string") {
continue;
} else {
placeholderChildren.push(x);
}
}
const result = [];
for (let i = 0; i < tr.length; i++) {
if (i % 2 == 0) {
// Text
result.push(tr[i]);
} else {
const childIdx = Number.parseInt(tr[i]) - 1;
result.push(placeholderChildren[childIdx]);
}
}
return result;
}
function stringifyArray(children: Array<any>): string {
let n = 1;
const ss = children.map((c) => {
if (typeof c === "string") {
return c;
}
return `%${n++}$s`;
});
const s = ss.join("").replace(/ +/g, " ").trim();
return s;
}
export const i18n = {
2021-07-26 16:27:56 +02:00
str: singular,
singular,
2021-06-08 20:56:27 +02:00
Translate,
2021-06-09 15:26:18 +02:00
translate,
};