From 402b56e5b1436292cab21ab62aad066bec1f8967 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Sun, 3 Oct 2021 20:07:28 +0200 Subject: [PATCH] Introduce i18n-bundles to remove circular import There was a circular import i18n.ts <-> i18n-translate.ts --- ts/lib/genfluent.py | 4 +--- ts/lib/i18n-bundles.ts | 40 +++++++++++++++++++++++++++++++++++ ts/lib/i18n.ts | 48 +++++++++--------------------------------- 3 files changed, 51 insertions(+), 41 deletions(-) create mode 100644 ts/lib/i18n-bundles.ts diff --git a/ts/lib/genfluent.py b/ts/lib/genfluent.py index de8d8e146..bdbf779e6 100644 --- a/ts/lib/genfluent.py +++ b/ts/lib/genfluent.py @@ -17,9 +17,7 @@ class Variable(TypedDict): def methods() -> str: - out = [ - 'import { translate } from "./i18n";', - ] + out = [ 'import { translate } from "./i18n-bundles";' ] for module in modules: for translation in module["translations"]: key = stringcase.camelcase(translation["key"].replace("-", "_")) diff --git a/ts/lib/i18n-bundles.ts b/ts/lib/i18n-bundles.ts new file mode 100644 index 000000000..cdf62d1a3 --- /dev/null +++ b/ts/lib/i18n-bundles.ts @@ -0,0 +1,40 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +import { FluentNumber } from "@fluent/bundle"; +import type { FluentBundle } from "@fluent/bundle"; +type RecordVal = number | string | FluentNumber; + +let bundles: FluentBundle[] = []; + +export function setBundles(...newBundles: FluentBundle[]): void { + bundles.splice(0, bundles.length, ...newBundles); +} + +export function firstLanguage(): string { + return bundles[0].locales[0]; +} + +function formatNumbers(args: Record): void { + for (const key of Object.keys(args)) { + if (typeof args[key] === "number") { + args[key] = new FluentNumber(args[key] as number, { + maximumFractionDigits: 2, + }); + } + } +} + +export function translate(key: string, args?: Record): string { + if (args) { + formatNumbers(args); + } + + for (const bundle of bundles) { + const msg = bundle.getMessage(key); + if (msg && msg.value) { + return bundle.formatPattern(msg.value, args); + } + } + return `missing key: ${key}`; +} diff --git a/ts/lib/i18n.ts b/ts/lib/i18n.ts index bfbd5b44b..d3bcd692c 100644 --- a/ts/lib/i18n.ts +++ b/ts/lib/i18n.ts @@ -1,43 +1,14 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -// An i18n singleton and setupI18n is re-exported via the generated i18n.ts file, -// so you should not need to access this file directly. - import "intl-pluralrules"; -import { FluentBundle, FluentResource, FluentNumber } from "@fluent/bundle"; +import { FluentBundle, FluentResource } from "@fluent/bundle"; + +import { firstLanguage, setBundles } from "./i18n-bundles"; import type { ModuleName } from "./i18n-modules"; -type RecordVal = number | string | FluentNumber; - -function formatNumbers(args: Record): void { - for (const key of Object.keys(args)) { - if (typeof args[key] === "number") { - args[key] = new FluentNumber(args[key] as number, { - maximumFractionDigits: 2, - }); - } - } -} - -let bundles: FluentBundle[] = []; - -export function translate(key: string, args?: Record): string { - if (args) { - formatNumbers(args); - } - - for (const bundle of bundles) { - const msg = bundle.getMessage(key); - if (msg && msg.value) { - return bundle.formatPattern(msg.value, args); - } - } - return `missing key: ${key}`; -} - export function supportsVerticalText(): boolean { - const firstLang = bundles[0].locales[0]; + const firstLang = firstLanguage(); return ( firstLang.startsWith("ja") || firstLang.startsWith("zh") || @@ -46,7 +17,7 @@ export function supportsVerticalText(): boolean { } export function direction(): string { - const firstLang = bundles[0].locales[0]; + const firstLang = firstLanguage(); if ( firstLang.startsWith("ar") || firstLang.startsWith("he") || @@ -59,7 +30,7 @@ export function direction(): string { } export function weekdayLabel(n: number): string { - const firstLang = bundles[0].locales[0]; + const firstLang = firstLanguage(); const now = new Date(); const daysFromToday = -now.getDay() + n; const desiredDay = new Date(now.getTime() + daysFromToday * 86_400_000); @@ -95,17 +66,18 @@ export async function setupI18n(args: { modules: ModuleName[] }): Promise } const json = await resp.json(); - bundles = []; + const newBundles: FluentBundle[] = []; for (const i in json.resources) { const text = json.resources[i]; const lang = json.langs[i]; const bundle = new FluentBundle([lang, "en-US"]); const resource = new FluentResource(text); bundle.addResource(resource); - bundles.push(bundle); + newBundles.push(bundle); } - langs = json.langs; + setBundles(...newBundles); + langs.splice(0, langs.length, ...json.langs); } export { ModuleName } from "./i18n-modules";