From f0b61782beffe1c07c0403374980d19dfa462a1e Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Thu, 7 Oct 2021 15:31:49 +0200 Subject: [PATCH] Refactor i18n (#1405) Merging note: the typing changes were fixed in a separate PR. * Put rootDirs into subprojects - typings do not work for any ts or svelte files - if we set the 'rootDirs' in ts/tsconfig.json to '../bazel-bin/ts' and then inherit them from e.g. editor, the root will be changed to '../../bazel-bin/ts', however editor needs look in '../../bazel-bin/ts/editor' instead. * Rename i18n and i18n_helpers to i18n-generated and i18n - This way, we can restrict the awkwardness of importing files outside the ts directory within lib * Fix missing typing of i18n and backend_proto by adding back symlinks * Split up i18n-generated into i18n-{translate,modules} * Change i18n from singleton to functions * Revert "Put rootDirs into subprojects" This partially reverts commit e1d4292ce3979e7b7ee21bf3951b8a462d45c29c. It seems like this might not be necessary after all. However some other change made on this branch seems to have fixed the .svelte.d.ts imports * Introduce i18n-bundles to remove circular import There was a circular import i18n.ts <-> i18n-translate.ts * Create own directory for i18n * Move lib/i18n/translate to lib/translate * This restores tree shaking * Update tsconfig libs and module * es2018-2020 have wide support on all modern browsers including * Switch bundles and langs inside i18n to variables again * Add missing copyright header * Rename translate.ts to ftl.ts * Remove the symlinks again I added them to fix to have completion for tr, however this would have also have meant to abandon the tree shaking. As we want to have tree shaking, it's also not necessary to have the symlinks anymore * Revert "Update tsconfig libs and module" This reverts commit 0a96776a475e9901c1f9f3407c726d1d002fb9ef. * move withCollapsedWhitespace back to i18n/utils * Add back /ts as in rootDirs --- ts/.prettierignore | 3 +- ts/change-notetype/ChangeNotetypePage.svelte | 2 +- ts/change-notetype/Mapper.svelte | 2 +- ts/change-notetype/SaveButton.svelte | 2 +- ts/congrats/CongratsPage.svelte | 2 +- ts/congrats/lib.ts | 3 +- ts/deck-options/AdvancedOptions.svelte | 2 +- ts/deck-options/AudioOptions.svelte | 2 +- ts/deck-options/BuryOptions.svelte | 2 +- ts/deck-options/CardStateCustomizer.svelte | 2 +- ts/deck-options/ConfigSelector.svelte | 2 +- ts/deck-options/DailyLimits.svelte | 2 +- ts/deck-options/DisplayOrder.svelte | 2 +- ts/deck-options/LapseOptions.svelte | 2 +- ts/deck-options/NewOptions.svelte | 3 +- ts/deck-options/RevertButton.svelte | 2 +- ts/deck-options/SaveButton.svelte | 5 +- ts/deck-options/TimerOptions.svelte | 2 +- ts/deck-options/lib.ts | 6 +- ts/deck-options/strings.ts | 2 +- ts/editor/ClozeButton.svelte | 3 +- ts/editor/ColorButtons.svelte | 3 +- ts/editor/FormatBlockButtons.svelte | 3 +- ts/editor/FormatInlineButtons.svelte | 3 +- ts/editor/ImageHandleFloatButtons.svelte | 2 +- ts/editor/ImageHandleSizeSelect.svelte | 2 +- ts/editor/MathjaxHandleInlineBlock.svelte | 3 +- ts/editor/NoteTypeButtons.svelte | 2 +- ts/editor/PreviewButton.svelte | 2 +- ts/editor/TemplateButtons.svelte | 2 +- ts/editor/label-container.ts | 3 +- ts/graphs/AddedGraph.svelte | 2 +- ts/graphs/ButtonsGraph.svelte | 2 +- ts/graphs/CalendarGraph.svelte | 5 +- ts/graphs/CardCounts.svelte | 13 ++- ts/graphs/EaseGraph.svelte | 2 +- ts/graphs/FutureDue.svelte | 2 +- ts/graphs/GraphRangeRadios.svelte | 2 +- ts/graphs/HourGraph.svelte | 6 +- ts/graphs/IntervalsGraph.svelte | 12 +-- ts/graphs/NoDataOverlay.svelte | 4 +- ts/graphs/RangeBox.svelte | 5 +- ts/graphs/ReviewsGraph.svelte | 5 +- ts/graphs/TableData.svelte | 4 +- ts/graphs/added.ts | 2 +- ts/graphs/buttons.ts | 5 +- ts/graphs/calendar.ts | 8 +- ts/graphs/card-counts.ts | 3 +- ts/graphs/ease.ts | 3 +- ts/graphs/future-due.ts | 2 +- ts/graphs/hours.ts | 2 +- ts/graphs/intervals.ts | 4 +- ts/graphs/reviews.ts | 2 +- ts/graphs/today.ts | 3 +- ts/lib/BUILD.bazel | 26 +++-- ts/lib/genfluent.py | 36 ++++--- ts/lib/i18n/bundles.ts | 46 ++++++++ ts/lib/i18n/index.ts | 6 ++ ts/lib/i18n/utils.ts | 87 ++++++++++++++++ ts/lib/i18n_helpers.ts | 104 ------------------- ts/lib/keys.ts | 2 +- ts/lib/proto.ts | 1 + ts/lib/time.ts | 2 +- ts/lib/tsconfig.json | 2 +- ts/tsconfig.json | 7 +- ts/typescript.bzl | 3 +- 66 files changed, 265 insertions(+), 233 deletions(-) create mode 100644 ts/lib/i18n/bundles.ts create mode 100644 ts/lib/i18n/index.ts create mode 100644 ts/lib/i18n/utils.ts delete mode 100644 ts/lib/i18n_helpers.ts diff --git a/ts/.prettierignore b/ts/.prettierignore index ac995e48b..339fa65b6 100644 --- a/ts/.prettierignore +++ b/ts/.prettierignore @@ -1,4 +1,5 @@ licenses.json vendor -*.svelte.d.ts +lib/translate.ts +lib/i18n/modules.ts backend_proto.d.ts diff --git a/ts/change-notetype/ChangeNotetypePage.svelte b/ts/change-notetype/ChangeNotetypePage.svelte index 878114145..03dc13305 100644 --- a/ts/change-notetype/ChangeNotetypePage.svelte +++ b/ts/change-notetype/ChangeNotetypePage.svelte @@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> diff --git a/ts/graphs/EaseGraph.svelte b/ts/graphs/EaseGraph.svelte index 2a2f0ceae..de8568311 100644 --- a/ts/graphs/EaseGraph.svelte +++ b/ts/graphs/EaseGraph.svelte @@ -4,10 +4,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> diff --git a/ts/graphs/RangeBox.svelte b/ts/graphs/RangeBox.svelte index b4285beb5..10bc3e936 100644 --- a/ts/graphs/RangeBox.svelte +++ b/ts/graphs/RangeBox.svelte @@ -3,11 +3,10 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->
- +
{#each tableData as { label, value }} diff --git a/ts/graphs/added.ts b/ts/graphs/added.ts index db4877c85..dca8ad566 100644 --- a/ts/graphs/added.ts +++ b/ts/graphs/added.ts @@ -19,10 +19,10 @@ import { import type { Bin } from "d3"; import type { HistogramData } from "./histogram-graph"; +import * as tr from "../lib/ftl"; import { dayLabel } from "../lib/time"; import { GraphRange } from "./graph-helpers"; import type { TableDatum, SearchDispatch } from "./graph-helpers"; -import * as tr from "../lib/i18n"; export interface GraphData { daysAdded: number[]; diff --git a/ts/graphs/buttons.ts b/ts/graphs/buttons.ts index 3c77166e6..10ae799a9 100644 --- a/ts/graphs/buttons.ts +++ b/ts/graphs/buttons.ts @@ -6,8 +6,6 @@ @typescript-eslint/no-explicit-any: "off", */ -import { Stats } from "../lib/proto"; - import { interpolateRdYlGn, select, @@ -19,6 +17,8 @@ import { axisLeft, sum, } from "d3"; +import { Stats } from "../lib/proto"; +import * as tr from "../lib/ftl"; import { showTooltip, hideTooltip } from "./tooltip"; import { GraphBounds, @@ -26,7 +26,6 @@ import { GraphRange, millisecondCutoffForRange, } from "./graph-helpers"; -import * as tr from "../lib/i18n"; type ButtonCounts = [number, number, number, number]; diff --git a/ts/graphs/calendar.ts b/ts/graphs/calendar.ts index 3bea00fbb..4797ab0a9 100644 --- a/ts/graphs/calendar.ts +++ b/ts/graphs/calendar.ts @@ -29,8 +29,8 @@ import { SearchDispatch, } from "./graph-helpers"; import { clickableClass } from "./graph-styles"; -import { i18n } from "../lib/i18n"; -import * as tr from "../lib/i18n"; +import { weekdayLabel, toLocaleString } from "../lib/i18n"; +import * as tr from "../lib/ftl"; export interface GraphData { // indexed by day, where day is relative to today @@ -155,7 +155,7 @@ export function renderCalendar( .interpolator((n) => interpolateBlues(cappedRange(n)!)); function tooltipText(d: DayDatum): string { - const date = d.date.toLocaleString(i18n.langs, { + const date = toLocaleString(d.date, { weekday: "long", year: "numeric", month: "long", @@ -172,7 +172,7 @@ export function renderCalendar( .selectAll("text") .data(sourceData.weekdayLabels) .join("text") - .text((d: number) => i18n.weekdayLabel(d)) + .text((d: number) => weekdayLabel(d)) .attr("width", x(-1)! - 2) .attr("height", height - 2) .attr("x", x(1)! - 3) diff --git a/ts/graphs/card-counts.ts b/ts/graphs/card-counts.ts index 0d2f0faf7..7897982af 100644 --- a/ts/graphs/card-counts.ts +++ b/ts/graphs/card-counts.ts @@ -6,6 +6,7 @@ @typescript-eslint/no-explicit-any: "off", */ +import * as tr from "../lib/ftl"; import { CardQueue, CardType } from "../lib/cards"; import type { Stats, Cards } from "../lib/proto"; import { @@ -22,8 +23,6 @@ import { } from "d3"; import type { GraphBounds } from "./graph-helpers"; -import * as tr from "../lib/i18n"; - type Count = [string, number, boolean, string]; export interface GraphData { title: string; diff --git a/ts/graphs/ease.ts b/ts/graphs/ease.ts index 5b28ee58d..1ab829900 100644 --- a/ts/graphs/ease.ts +++ b/ts/graphs/ease.ts @@ -16,11 +16,10 @@ import { interpolateRdYlGn, } from "d3"; import type { Bin, ScaleLinear } from "d3"; +import * as tr from "../lib/ftl"; import { CardType } from "../lib/cards"; import type { HistogramData } from "./histogram-graph"; - import type { TableDatum, SearchDispatch } from "./graph-helpers"; -import * as tr from "../lib/i18n"; export interface GraphData { eases: number[]; diff --git a/ts/graphs/future-due.ts b/ts/graphs/future-due.ts index 67d5ba0ed..2c132fea5 100644 --- a/ts/graphs/future-due.ts +++ b/ts/graphs/future-due.ts @@ -17,13 +17,13 @@ import { interpolateGreens, } from "d3"; import type { Bin } from "d3"; +import * as tr from "../lib/ftl"; import { CardQueue } from "../lib/cards"; import type { HistogramData } from "./histogram-graph"; import { dayLabel } from "../lib/time"; import { GraphRange } from "./graph-helpers"; import type { TableDatum, SearchDispatch } from "./graph-helpers"; -import * as tr from "../lib/i18n"; export interface GraphData { dueCounts: Map; diff --git a/ts/graphs/hours.ts b/ts/graphs/hours.ts index 1508c6928..3724bb301 100644 --- a/ts/graphs/hours.ts +++ b/ts/graphs/hours.ts @@ -21,6 +21,7 @@ import { curveBasis, } from "d3"; +import * as tr from "../lib/ftl"; import { showTooltip, hideTooltip } from "./tooltip"; import { GraphBounds, @@ -29,7 +30,6 @@ import { millisecondCutoffForRange, } from "./graph-helpers"; import { oddTickClass } from "./graph-styles"; -import * as tr from "../lib/i18n"; interface Hour { hour: number; diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index 22372a03c..11c796659 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -18,12 +18,12 @@ import { interpolateBlues, } from "d3"; import type { Bin } from "d3"; +import * as tr from "../lib/ftl"; +import { timeSpan } from "../lib/time"; import { CardType } from "../lib/cards"; import type { HistogramData } from "./histogram-graph"; import type { TableDatum, SearchDispatch } from "./graph-helpers"; -import { timeSpan } from "../lib/time"; -import * as tr from "../lib/i18n"; export interface IntervalGraphData { intervals: number[]; diff --git a/ts/graphs/reviews.ts b/ts/graphs/reviews.ts index f31f7e161..00a6a2617 100644 --- a/ts/graphs/reviews.ts +++ b/ts/graphs/reviews.ts @@ -32,10 +32,10 @@ import { } from "d3"; import type { Bin } from "d3"; +import * as tr from "../lib/ftl"; import type { TableDatum } from "./graph-helpers"; import { GraphBounds, setDataAvailable, GraphRange } from "./graph-helpers"; import { showTooltip, hideTooltip } from "./tooltip"; -import * as tr from "../lib/i18n"; interface Reviews { learn: number; diff --git a/ts/graphs/today.ts b/ts/graphs/today.ts index 07e5a12e7..568e536dc 100644 --- a/ts/graphs/today.ts +++ b/ts/graphs/today.ts @@ -3,8 +3,7 @@ import { Stats } from "../lib/proto"; import { studiedToday } from "../lib/time"; - -import * as tr from "../lib/i18n"; +import * as tr from "../lib/ftl"; export interface TodayData { title: string; diff --git a/ts/lib/BUILD.bazel b/ts/lib/BUILD.bazel index 10811be31..14bb8df24 100644 --- a/ts/lib/BUILD.bazel +++ b/ts/lib/BUILD.bazel @@ -1,17 +1,11 @@ +load("@rules_python//python:defs.bzl", "py_binary") load("//ts:prettier.bzl", "prettier_test") load("//ts:eslint.bzl", "eslint_test") load("//ts:protobuf.bzl", "protobufjs_library") load("//ts:typescript.bzl", "typescript") -load("@rules_python//python:defs.bzl", "py_binary") load("@py_deps//:requirements.bzl", "requirement") load("//ts:jest.bzl", "jest_test") -protobufjs_library( - name = "backend_proto", - proto = "//proto:backend_proto_lib", - visibility = ["//visibility:public"], -) - py_binary( name = "genfluent", srcs = [ @@ -22,21 +16,33 @@ py_binary( requirement("stringcase"), ], ) +_i18n_generated = [ + "ftl.ts", + "i18n/modules.ts", +] genrule( name = "fluent_gen", - outs = ["i18n.ts"], - cmd = "$(location genfluent) $(location //rslib/i18n:strings.json) $@", + outs = _i18n_generated, + cmd = "$(location genfluent) $(location //rslib/i18n:strings.json) $(OUTS)", tools = [ "genfluent", "//rslib/i18n:strings.json", ], ) +protobufjs_library( + name = "backend_proto", + proto = "//proto:backend_proto_lib", + visibility = ["//visibility:public"], +) + typescript( name = "lib", generated = [ - ":i18n.ts", + ":backend_proto.d.ts", + ":ftl.ts", + ":i18n/modules.ts", ], deps = [ ":backend_proto", diff --git a/ts/lib/genfluent.py b/ts/lib/genfluent.py index 3944aad5f..075707ed2 100644 --- a/ts/lib/genfluent.py +++ b/ts/lib/genfluent.py @@ -7,7 +7,7 @@ from typing import List, Literal, TypedDict import stringcase -strings_json, outfile = sys.argv[1:] +strings_json, translate_out, modules_out = sys.argv[1:] modules = json.load(open(strings_json, encoding="utf8")) @@ -17,10 +17,12 @@ class Variable(TypedDict): def methods() -> str: - out = [ - 'import { i18n } from "./i18n_helpers";', - 'export { i18n, setupI18n } from "./i18n_helpers";', - ] + out = [ """import type { FluentVariable } from "@fluent/bundle"; +import { getMessage } from "./i18n"; + +function translate(key: string, args: Record = {}): string { + return getMessage(key, args) ?? `missing key: ${key}`; +}""" ] for module in modules: for translation in module["translations"]: key = stringcase.camelcase(translation["key"].replace("-", "_")) @@ -31,7 +33,7 @@ def methods() -> str: f""" /** {doc} */ export function {key}({arg_types}): string {{ - return i18n.translate("{translation["key"]}"{args}) + return translate("{translation["key"]}"{args}) }} """ ) @@ -102,17 +104,17 @@ def module_names() -> str: return buf -out = "" - -out += methods() -out += module_names() - -open(outfile, "wb").write( - ( - """// Copyright: Ankitects Pty Ltd and contributors +def write(outfile, out) -> None: + open(outfile, "wb").write( + ( + f"""// Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html """ - + out - ).encode("utf8") -) + + out + ).encode("utf8") + ) + + +write(translate_out, str(methods())) +write(modules_out, str(module_names())) diff --git a/ts/lib/i18n/bundles.ts b/ts/lib/i18n/bundles.ts new file mode 100644 index 000000000..d83860ea3 --- /dev/null +++ b/ts/lib/i18n/bundles.ts @@ -0,0 +1,46 @@ +// 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, FluentVariable } from "@fluent/bundle"; + +let bundles: FluentBundle[] = []; + +export function setBundles(newBundles: FluentBundle[]): void { + bundles = newBundles; +} + +export function firstLanguage(): string { + return bundles[0].locales[0]; +} + +function toFluentNumber(num: number): FluentNumber { + return new FluentNumber(num, { + maximumFractionDigits: 2, + }); +} + +function formatArgs( + args: Record +): Record { + return Object.fromEntries( + Object.entries(args).map(([key, value]) => [ + key, + typeof value === "number" ? toFluentNumber(value) : value, + ]) + ); +} + +export function getMessage( + key: string, + args: Record = {} +): string | null { + for (const bundle of bundles) { + const msg = bundle.getMessage(key); + if (msg && msg.value) { + return bundle.formatPattern(msg.value, formatArgs(args)); + } + } + + return null; +} diff --git a/ts/lib/i18n/index.ts b/ts/lib/i18n/index.ts new file mode 100644 index 000000000..d547a93c0 --- /dev/null +++ b/ts/lib/i18n/index.ts @@ -0,0 +1,6 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +export * from "./bundles"; +export * from "./modules"; +export * from "./utils"; diff --git a/ts/lib/i18n/utils.ts b/ts/lib/i18n/utils.ts new file mode 100644 index 000000000..9ff8d9e4f --- /dev/null +++ b/ts/lib/i18n/utils.ts @@ -0,0 +1,87 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +import "intl-pluralrules"; +import { FluentBundle, FluentResource } from "@fluent/bundle"; + +import { firstLanguage, setBundles } from "./bundles"; +import type { ModuleName } from "./modules"; + +export function supportsVerticalText(): boolean { + const firstLang = firstLanguage(); + return ( + firstLang.startsWith("ja") || + firstLang.startsWith("zh") || + firstLang.startsWith("ko") + ); +} + +export function direction(): string { + const firstLang = firstLanguage(); + if ( + firstLang.startsWith("ar") || + firstLang.startsWith("he") || + firstLang.startsWith("fa") + ) { + return "rtl"; + } else { + return "ltr"; + } +} + +export function weekdayLabel(n: number): string { + const firstLang = firstLanguage(); + const now = new Date(); + const daysFromToday = -now.getDay() + n; + const desiredDay = new Date(now.getTime() + daysFromToday * 86_400_000); + return desiredDay.toLocaleDateString(firstLang, { + weekday: "narrow", + }); +} + +let langs: string[] = []; + +export function toLocaleString( + date: Date, + options?: Intl.DateTimeFormatOptions +): string { + return date.toLocaleDateString(langs, options); +} + +export function localeCompare( + first: string, + second: string, + options?: Intl.CollatorOptions +): number { + return first.localeCompare(second, langs, options); +} + +/// Treat text like HTML, merging multiple spaces and converting +/// newlines to spaces. +export function withCollapsedWhitespace(s: string): string { + return s.replace(/\s+/g, " "); +} + +export async function setupI18n(args: { modules: ModuleName[] }): Promise { + const resp = await fetch("/_anki/i18nResources", { + method: "POST", + body: JSON.stringify(args), + }); + if (!resp.ok) { + throw Error(`unexpected reply: ${resp.statusText}`); + } + const json = await resp.json(); + + 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); + newBundles.push(bundle); + } + + setBundles(newBundles); + langs = json.langs; +} diff --git a/ts/lib/i18n_helpers.ts b/ts/lib/i18n_helpers.ts deleted file mode 100644 index 5852d6444..000000000 --- a/ts/lib/i18n_helpers.ts +++ /dev/null @@ -1,104 +0,0 @@ -// 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"; - -type RecordVal = number | string | FluentNumber; - -function formatNumbers(args?: Record): void { - if (!args) { - return; - } - for (const key of Object.keys(args)) { - if (typeof args[key] === "number") { - args[key] = new FluentNumber(args[key] as number, { - maximumFractionDigits: 2, - }); - } - } -} - -export class I18n { - bundles: FluentBundle[] = []; - langs: string[] = []; - - translate(key: string, args?: Record): string { - formatNumbers(args); - for (const bundle of this.bundles) { - const msg = bundle.getMessage(key); - if (msg && msg.value) { - return bundle.formatPattern(msg.value, args); - } - } - return `missing key: ${key}`; - } - - supportsVerticalText(): boolean { - const firstLang = this.bundles[0].locales[0]; - return ( - firstLang.startsWith("ja") || - firstLang.startsWith("zh") || - firstLang.startsWith("ko") - ); - } - - direction(): string { - const firstLang = this.bundles[0].locales[0]; - if ( - firstLang.startsWith("ar") || - firstLang.startsWith("he") || - firstLang.startsWith("fa") - ) { - return "rtl"; - } else { - return "ltr"; - } - } - - weekdayLabel(n: number): string { - const firstLang = this.bundles[0].locales[0]; - const now = new Date(); - const daysFromToday = -now.getDay() + n; - const desiredDay = new Date(now.getTime() + daysFromToday * 86_400_000); - return desiredDay.toLocaleDateString(firstLang, { - weekday: "narrow", - }); - } - - /// Treat text like HTML, merging multiple spaces and converting - /// newlines to spaces. - withCollapsedWhitespace(s: string): string { - return s.replace(/\s+/g, " "); - } -} - -// global singleton -export const i18n = new I18n(); - -import type { ModuleName } from "./i18n"; - -export async function setupI18n(args: { modules: ModuleName[] }): Promise { - const resp = await fetch("/_anki/i18nResources", { - method: "POST", - body: JSON.stringify(args), - }); - if (!resp.ok) { - throw Error(`unexpected reply: ${resp.statusText}`); - } - const json = await resp.json(); - - i18n.bundles = []; - 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); - i18n.bundles.push(bundle); - } - i18n.langs = json.langs; -} diff --git a/ts/lib/keys.ts b/ts/lib/keys.ts index ef7bcad15..8de5acd76 100644 --- a/ts/lib/keys.ts +++ b/ts/lib/keys.ts @@ -1,7 +1,7 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import * as tr from "./i18n"; +import * as tr from "./ftl"; import { isApplePlatform } from "./platform"; // those are the modifiers that Anki works with diff --git a/ts/lib/proto.ts b/ts/lib/proto.ts index 08b1a8853..e182f6c10 100644 --- a/ts/lib/proto.ts +++ b/ts/lib/proto.ts @@ -2,6 +2,7 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { anki } from "./backend_proto"; + import Cards = anki.cards; import DeckConfig = anki.deckconfig; import Notetypes = anki.notetypes; diff --git a/ts/lib/time.ts b/ts/lib/time.ts index c59e4fd8a..18d9263e8 100644 --- a/ts/lib/time.ts +++ b/ts/lib/time.ts @@ -1,7 +1,7 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import * as tr from "./i18n"; +import * as tr from "./ftl"; export const SECOND = 1.0; export const MINUTE = 60.0 * SECOND; diff --git a/ts/lib/tsconfig.json b/ts/lib/tsconfig.json index 3614760cc..39f73a570 100644 --- a/ts/lib/tsconfig.json +++ b/ts/lib/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "../tsconfig.json", - "include": ["*", "../../bazel-bin/ts/lib/*"], + "include": ["*", "i18n/*"], "references": [], "compilerOptions": { "types": ["jest"] diff --git a/ts/tsconfig.json b/ts/tsconfig.json index 7c93dc9dd..636dcbbf9 100644 --- a/ts/tsconfig.json +++ b/ts/tsconfig.json @@ -17,14 +17,15 @@ "declaration": true, "composite": true, "target": "es6", - "module": "es6", + "module": "es2020", "lib": [ "es2017", "es2018.intl", - "es2019.array", "es2018.promise", - "es2020.promise", + "es2019.array", + "es2019.object", "es2019.string", + "es2020.promise", "dom", "dom.iterable" ], diff --git a/ts/typescript.bzl b/ts/typescript.bzl index 26dce9894..69ecadc09 100644 --- a/ts/typescript.bzl +++ b/ts/typescript.bzl @@ -4,12 +4,13 @@ load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin", "js_library") def typescript( name, srcs = None, + exclude = [], generated = [], tsconfig = "tsconfig.json", visibility = ["//visibility:public"], **kwargs): if not srcs: - srcs = native.glob(["**/*.ts"]) + srcs = native.glob(["**/*.ts"], exclude = exclude) # all tsconfig files must be in the bazel-out folder copy_to_bin(
{label}: