From 5f24887535bc23ca4809596fc34ca0f5c62e08cc Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Tue, 22 Sep 2026 16:38:30 -0500 Subject: [PATCH] api strings --- packages/core/src/api/fetchJSON.ts | 5 ++ .../core/src/{protobuf => api}/fetchPB.ts | 2 +- packages/core/src/{protobuf => api}/index.ts | 0 .../src/blitzkit/api/{base.ts => abstract.ts} | 5 +- packages/core/src/blitzkit/api/client.ts | 18 +++-- packages/core/src/blitzkit/api/dynamic.ts | 4 +- packages/core/src/blitzkit/api/index.ts | 2 +- .../core/src/blitzkit/api/server/0_base.ts | 11 ++- .../src/blitzkit/api/server/11_scripts.ts | 2 + .../src/blitzkit/api/server/12_strings.ts | 25 +++++++ .../core/src/blitzkit/api/server/index.ts | 4 +- .../src/blitzkit/averageDefinitions/index.ts | 2 +- packages/core/src/blitzkit/popularTanks.ts | 2 +- packages/core/src/blitzkit/reviews.ts | 2 +- packages/core/src/index.ts | 4 +- packages/core/src/protobuf/pbMap.ts | 1 - packages/i18n/locales.json | 49 +++++++++++--- packages/i18n/src/strings.ts | 67 +------------------ .../components/TankopediaLoadout/index.tsx | 2 + packages/website/src/core/i18n/getStrings.ts | 6 -- packages/website/src/hooks/useLocale.tsx | 14 +--- packages/website/src/hooks/useStrings.ts | 9 +++ .../[...chunk_api]/strings/[locale].json.ts | 14 ++++ 23 files changed, 132 insertions(+), 118 deletions(-) create mode 100644 packages/core/src/api/fetchJSON.ts rename packages/core/src/{protobuf => api}/fetchPB.ts (78%) rename packages/core/src/{protobuf => api}/index.ts (100%) rename packages/core/src/blitzkit/api/{base.ts => abstract.ts} (88%) create mode 100644 packages/core/src/blitzkit/api/server/12_strings.ts delete mode 100644 packages/core/src/protobuf/pbMap.ts delete mode 100644 packages/website/src/core/i18n/getStrings.ts create mode 100644 packages/website/src/hooks/useStrings.ts create mode 100644 packages/website/src/pages/[...chunk_api]/strings/[locale].json.ts diff --git a/packages/core/src/api/fetchJSON.ts b/packages/core/src/api/fetchJSON.ts new file mode 100644 index 000000000..5c3cead47 --- /dev/null +++ b/packages/core/src/api/fetchJSON.ts @@ -0,0 +1,5 @@ +export async function fetchJSON(url: string) { + const response = await fetch(url); + const json = await response.json(); + return json as Type; +} diff --git a/packages/core/src/protobuf/fetchPB.ts b/packages/core/src/api/fetchPB.ts similarity index 78% rename from packages/core/src/protobuf/fetchPB.ts rename to packages/core/src/api/fetchPB.ts index 286b0aa9b..d9891f60d 100644 --- a/packages/core/src/protobuf/fetchPB.ts +++ b/packages/core/src/api/fetchPB.ts @@ -1,4 +1,4 @@ -import type { MessageFns } from '../../../protos/src/blitzkit'; +import type { MessageFns } from "@blitzkit/protos/src/blitzkit"; export async function fetchPB(url: string, message: MessageFns) { const response = await fetch(url); diff --git a/packages/core/src/protobuf/index.ts b/packages/core/src/api/index.ts similarity index 100% rename from packages/core/src/protobuf/index.ts rename to packages/core/src/api/index.ts diff --git a/packages/core/src/blitzkit/api/base.ts b/packages/core/src/blitzkit/api/abstract.ts similarity index 88% rename from packages/core/src/blitzkit/api/base.ts rename to packages/core/src/blitzkit/api/abstract.ts index b8a6ad860..b4654ef45 100644 --- a/packages/core/src/blitzkit/api/base.ts +++ b/packages/core/src/blitzkit/api/abstract.ts @@ -10,9 +10,10 @@ import { SkillDefinitions, TankDefinitions, } from "@blitzkit/core"; +import { Strings } from "@blitzkit/i18n"; import { BlitzScripts } from "../../types/blitzScripts"; -export abstract class BlitzKitAPI { +export abstract class AbstractBlitzKitAPI { abstract skills(): Promise; abstract provisions(): Promise; abstract consumables(): Promise; @@ -25,6 +26,8 @@ export abstract class BlitzKitAPI { abstract gallery(): Promise; abstract scripts(): Promise; + abstract strings(locale: string): Promise; + async tank(id: number) { const tanks = await this.tanks(); return tanks.tanks[id]; diff --git a/packages/core/src/blitzkit/api/client.ts b/packages/core/src/blitzkit/api/client.ts index 880d150e9..72491bfb7 100644 --- a/packages/core/src/blitzkit/api/client.ts +++ b/packages/core/src/blitzkit/api/client.ts @@ -1,4 +1,5 @@ import { alias } from "@blitzkit/core"; +import { BlitzKitStrings } from "@blitzkit/i18n"; import { CamouflageDefinitions, ConsumableDefinitions, @@ -11,11 +12,12 @@ import { SkillDefinitions, TankDefinitions, } from "@blitzkit/protos"; -import { fetchPB } from "../../protobuf"; +import { fetchPB } from "../../api"; +import { fetchJSON } from "../../api/fetchJSON"; import { BlitzScripts } from "../../types/blitzScripts"; -import { BlitzKitAPI } from "./base"; +import { AbstractBlitzKitAPI } from "./abstract"; -export class ClientBlitzKitAPI extends BlitzKitAPI { +export class ClientBlitzKitAPI extends AbstractBlitzKitAPI { game() { return fetchPB(alias("api", "/definitions/game.pb"), GameDefinitions); } @@ -68,9 +70,11 @@ export class ClientBlitzKitAPI extends BlitzKitAPI { return fetchPB(alias("api", "/definitions/maps.pb"), MapDefinitions); } - async scripts() { - const response = await fetch(alias("api", "/definitions/scripts.json")); - const json = await response.json(); - return json as BlitzScripts; + scripts() { + return fetchJSON(alias("api", "/definitions/scripts.json")); + } + + strings(locale: string) { + return fetchJSON(alias("api", `/strings/${locale}.json`)); } } diff --git a/packages/core/src/blitzkit/api/dynamic.ts b/packages/core/src/blitzkit/api/dynamic.ts index 2dcb96d19..27104581b 100644 --- a/packages/core/src/blitzkit/api/dynamic.ts +++ b/packages/core/src/blitzkit/api/dynamic.ts @@ -1,7 +1,7 @@ -import { AbstractVFS, BlitzKitAPI } from "@blitzkit/core"; +import { AbstractBlitzKitAPI, AbstractVFS } from "@blitzkit/core"; export async function createDynamicAPI(vfs: () => Promise) { - let _api: BlitzKitAPI; + let _api: AbstractBlitzKitAPI; if (import.meta.env.SSR) { const { ServerBlitzKitAPI } = await import( diff --git a/packages/core/src/blitzkit/api/index.ts b/packages/core/src/blitzkit/api/index.ts index b39160477..6a5626a6a 100644 --- a/packages/core/src/blitzkit/api/index.ts +++ b/packages/core/src/blitzkit/api/index.ts @@ -1,4 +1,4 @@ -export * from "./base"; +export * from "./abstract"; export * from "./client"; export * from "./dynamic"; export * from "./server"; diff --git a/packages/core/src/blitzkit/api/server/0_base.ts b/packages/core/src/blitzkit/api/server/0_base.ts index 77b00ab6f..08f5a368f 100644 --- a/packages/core/src/blitzkit/api/server/0_base.ts +++ b/packages/core/src/blitzkit/api/server/0_base.ts @@ -25,13 +25,12 @@ import { VehicleDefinitionList, } from "@blitzkit/core"; import { AbstractVFS } from "@blitzkit/core/src/blitzkit/vfs/abstract"; -import { SUPPORTED_LOCALE_BLITZ_MAP } from "@blitzkit/i18n"; import locales from "@blitzkit/i18n/locales.json"; import type { extname, parse } from "node:path"; import { parse as parseYaml } from "yaml"; -import { BlitzKitAPI } from "../base"; +import { AbstractBlitzKitAPI } from "../abstract"; -export abstract class ServerBlitzKitAPI0 extends BlitzKitAPI { +export abstract class ServerBlitzKitAPI0 extends AbstractBlitzKitAPI { protected vfs: AbstractVFS; protected parsePath?: typeof parse; protected extname?: typeof extname; @@ -171,8 +170,8 @@ export abstract class ServerBlitzKitAPI0 extends BlitzKitAPI { let fetchedLocalizations = 0; await Promise.all( - locales.supported.map(async ({ locale }) => { - const blitzLocale = SUPPORTED_LOCALE_BLITZ_MAP[locale]; + locales.supported.map(async (locale) => { + const blitzLocale = locale.variant_blitz_cdn ?? locale.locale; const cache = await fetch( `https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`, ) @@ -182,7 +181,7 @@ export abstract class ServerBlitzKitAPI0 extends BlitzKitAPI { `Data/Strings/${blitzLocale}.yaml`, ); - this.stringsI18n[locale] = { + this.stringsI18n[locale.locale] = { ...cache, ...preInstalled, }; diff --git a/packages/core/src/blitzkit/api/server/11_scripts.ts b/packages/core/src/blitzkit/api/server/11_scripts.ts index 6acc89ca4..f2dee6def 100644 --- a/packages/core/src/blitzkit/api/server/11_scripts.ts +++ b/packages/core/src/blitzkit/api/server/11_scripts.ts @@ -1,9 +1,11 @@ import { ConsumablesCommon, OptionalDevices } from "../../../types"; import { BlitzScripts } from "../../../types/blitzScripts"; import { AbstractVFS } from "../../vfs"; +import { Cache } from "./0_base"; import { ServerBlitzKitAPI10 } from "./10_avatars"; export abstract class ServerBlitzKitAPI11 extends ServerBlitzKitAPI10 { + @Cache() async scripts() { const scripts: BlitzScripts = { consumables: {}, diff --git a/packages/core/src/blitzkit/api/server/12_strings.ts b/packages/core/src/blitzkit/api/server/12_strings.ts new file mode 100644 index 000000000..1b6374e7d --- /dev/null +++ b/packages/core/src/blitzkit/api/server/12_strings.ts @@ -0,0 +1,25 @@ +import { Strings } from "@blitzkit/i18n"; +import locales from "@blitzkit/i18n/locales.json"; +import { DeepPartial } from "@blitzkit/protos"; +import { merge } from "lodash-es"; +import { Cache } from "./0_base"; +import { ServerBlitzKitAPI11 } from "./11_scripts"; + +const globbedStrings = import.meta.glob("../../../../../i18n/strings/*.json", { + import: "default", +}); + +export abstract class ServerBlitzKitAPI12 extends ServerBlitzKitAPI11 { + @Cache() + async strings(locale: string) { + const localized = (await globbedStrings[ + `../../../../../i18n/strings/${locale}.json` + ]()) as DeepPartial; + const defaults = (await globbedStrings[ + `../../../../../i18n/strings/${locales.default}.json` + ]()) as Strings; + const strings = merge({}, defaults, localized); + + return strings; + } +} diff --git a/packages/core/src/blitzkit/api/server/index.ts b/packages/core/src/blitzkit/api/server/index.ts index 87f38443f..8a571d236 100644 --- a/packages/core/src/blitzkit/api/server/index.ts +++ b/packages/core/src/blitzkit/api/server/index.ts @@ -1,3 +1,3 @@ -import { ServerBlitzKitAPI11 } from "./11_scripts"; +import { ServerBlitzKitAPI12 } from "./12_strings"; -export class ServerBlitzKitAPI extends ServerBlitzKitAPI11 {} +export class ServerBlitzKitAPI extends ServerBlitzKitAPI12 {} diff --git a/packages/core/src/blitzkit/averageDefinitions/index.ts b/packages/core/src/blitzkit/averageDefinitions/index.ts index 03d560a6f..9ac6e401a 100644 --- a/packages/core/src/blitzkit/averageDefinitions/index.ts +++ b/packages/core/src/blitzkit/averageDefinitions/index.ts @@ -1,6 +1,6 @@ import { staticAsset } from "@blitzkit/core"; -import { fetchPB } from "../../protobuf"; import { AverageDefinitions } from "../../../../protos/src/blitzkit"; +import { fetchPB } from "../../api"; export interface AverageDefinitionsManifest { version: 1; diff --git a/packages/core/src/blitzkit/popularTanks.ts b/packages/core/src/blitzkit/popularTanks.ts index c77f3eb04..be4795fae 100644 --- a/packages/core/src/blitzkit/popularTanks.ts +++ b/packages/core/src/blitzkit/popularTanks.ts @@ -1,6 +1,6 @@ import { staticAsset } from "@blitzkit/core"; -import { fetchPB } from "../protobuf"; import { PopularTanks } from "../../../protos/src/blitzkit"; +import { fetchPB } from "../api"; export function fetchPopularTanks() { return fetchPB(staticAsset("definitions/popular-tanks.pb"), PopularTanks); diff --git a/packages/core/src/blitzkit/reviews.ts b/packages/core/src/blitzkit/reviews.ts index dc66a6bad..785861fdc 100644 --- a/packages/core/src/blitzkit/reviews.ts +++ b/packages/core/src/blitzkit/reviews.ts @@ -1,6 +1,6 @@ import { staticAsset } from "@blitzkit/core"; -import { fetchPB } from "../protobuf"; import { Reviews } from "../../../protos/src/blitzkit"; +import { fetchPB } from "../api"; export function fetchReviews() { return fetchPB(staticAsset("definitions/reviews.pb"), Reviews); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index f8d8b2160..8c62596e9 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,10 +1,10 @@ +export * from "../../protos/src/blitzkit"; +export * from "./api"; export * from "./blitz"; export * from "./blitzkit"; export * from "./imgur"; export * from "./math"; export * from "./patreon"; -export * from "./protobuf"; -export * from "../../protos/src/blitzkit"; export * from "./statistics"; export * from "./streams"; export * from "./types"; diff --git a/packages/core/src/protobuf/pbMap.ts b/packages/core/src/protobuf/pbMap.ts deleted file mode 100644 index 74e031394..000000000 --- a/packages/core/src/protobuf/pbMap.ts +++ /dev/null @@ -1 +0,0 @@ -export type PBMap = T[keyof T] extends number ? T[keyof T] : never; diff --git a/packages/i18n/locales.json b/packages/i18n/locales.json index 488c43563..413d3a2c3 100644 --- a/packages/i18n/locales.json +++ b/packages/i18n/locales.json @@ -1,14 +1,45 @@ { "default": "en", "supported": [ - { "locale": "en" }, - { "locale": "es" }, - { "locale": "fr" }, - { "locale": "ja" }, - { "locale": "pl" }, - { "locale": "pt" }, - { "locale": "ru" }, - { "locale": "uk" }, - { "locale": "zh", "blitz": "zh_Hans_SG" } + { + "locale": "en", + "flag": "πŸ‡ΊπŸ‡Έ" + }, + { + "locale": "es", + "flag": "πŸ‡ͺπŸ‡Έ" + }, + { + "locale": "fr", + "flag": "πŸ‡«πŸ‡·" + }, + { + "locale": "ja", + "flag": "πŸ‡―πŸ‡΅" + }, + { + "locale": "pl", + "flag": "πŸ‡΅πŸ‡±" + }, + { + "locale": "pt", + "flag": "πŸ‡΅πŸ‡Ή" + }, + { + "locale": "ru", + "flag": "πŸ‡·πŸ‡Ί" + }, + { + "locale": "uk", + "flag": "πŸ‡ΊπŸ‡¦" + }, + { + "locale": "zh", + + "variant_blitz_local": "zh_Hans_SG", + "variant_blitz_cdn": "zh-Hans", + + "flag": "πŸ‡¨πŸ‡³" + } ] } diff --git a/packages/i18n/src/strings.ts b/packages/i18n/src/strings.ts index ace172be0..d4fc3fb8e 100644 --- a/packages/i18n/src/strings.ts +++ b/packages/i18n/src/strings.ts @@ -1,68 +1,3 @@ -import { merge } from "ts-deepmerge"; -import locales from "../locales.json"; import en from "../strings/en.json"; -import es from "../strings/es.json"; -import fr from "../strings/fr.json"; -import ja from "../strings/ja.json"; -import pl from "../strings/pl.json"; -import pt from "../strings/pt.json"; -import ru from "../strings/ru.json"; -import uk from "../strings/uk.json"; -import zh from "../strings/zh.json"; -export type BlitzKitStrings = typeof en; - -const stringsRaw: Record = { - en, - es, - fr, - ja, - pl, - pt, - ru, - uk, - zh, -}; - -export const STRINGS: Record = {}; - -for (const locale in stringsRaw) { - if (locale === locales.default) { - STRINGS[locales.default] = stringsRaw[locales.default] as BlitzKitStrings; - continue; - } - - const localeStrings = stringsRaw[locale]; - STRINGS[locale] = merge( - stringsRaw[locales.default], - localeStrings, - ) as BlitzKitStrings; -} - -export const SUPPORTED_LOCALE_BLITZ_MAP: Record = { - en: "en", - es: "es", - fr: "fr", - ja: "ja", - pt: "pt", - ru: "ru", - uk: "uk", - zh: "zh-Hans", - pl: "pl", -}; - -export const SUPPORTED_LOCALE_FLAGS: Record = { - en: "πŸ‡ΊπŸ‡Έ", - es: "πŸ‡ͺπŸ‡Έ", - fr: "πŸ‡«πŸ‡·", - ja: "πŸ‡―πŸ‡΅", - pt: "πŸ‡΅πŸ‡Ή", - ru: "πŸ‡·πŸ‡Ί", - uk: "πŸ‡ΊπŸ‡¦", - zh: "πŸ‡¨πŸ‡³", - pl: "πŸ‡΅πŸ‡±", -}; - -export type TranslationTree = { [key: string]: TranslationNode }; - -export type TranslationNode = string | TranslationTree; +export type Strings = typeof en; diff --git a/packages/website/src/components/TankopediaLoadout/index.tsx b/packages/website/src/components/TankopediaLoadout/index.tsx index c31f29da8..a5797daf9 100644 --- a/packages/website/src/components/TankopediaLoadout/index.tsx +++ b/packages/website/src/components/TankopediaLoadout/index.tsx @@ -1,4 +1,6 @@ import { useProtagonist } from "../../hooks/useProtagonist"; +import { useStrings } from "../../hooks/useStrings"; +import { Tankopedia } from "../../stores/tankopedia"; import { hasUpgrades } from "../../tankopedia/hasUpgrades"; import type { ComputedCharacteristics } from "../../types/characteristics"; diff --git a/packages/website/src/core/i18n/getStrings.ts b/packages/website/src/core/i18n/getStrings.ts deleted file mode 100644 index b787fea5a..000000000 --- a/packages/website/src/core/i18n/getStrings.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { STRINGS } from "@blitzkit/i18n"; - -export function getStrings(locale: string) { - if (locale in STRINGS) return STRINGS[locale]; - throw new Error(`Unsupported locale: ${locale}`); -} diff --git a/packages/website/src/hooks/useLocale.tsx b/packages/website/src/hooks/useLocale.tsx index 86e274cb8..4fcff19b2 100644 --- a/packages/website/src/hooks/useLocale.tsx +++ b/packages/website/src/hooks/useLocale.tsx @@ -1,11 +1,8 @@ -import { unwrapper } from "@blitzkit/i18n"; import locales from "@blitzkit/i18n/locales.json"; import { createContext, useContext, type ReactNode } from "react"; -import { getStrings } from "../core/i18n/getStrings"; const LocaleContext = createContext<{ locale: string; - localeRaw: string | undefined; } | null>(null); interface LocaleProviderProps extends LocaleAcceptorProps { @@ -14,9 +11,7 @@ interface LocaleProviderProps extends LocaleAcceptorProps { export function LocaleProvider({ locale, children }: LocaleProviderProps) { return ( - + {children} ); @@ -29,12 +24,9 @@ export function useLocale() { throw new Error("useLocale must be used within a LocaleProvider"); } - const strings = getStrings(context.locale); - const unwrap = unwrapper(context.locale); - - return { locale: context.locale, strings, unwrap }; + return context.locale; } export interface LocaleAcceptorProps { - locale: string | undefined; + locale: string; } diff --git a/packages/website/src/hooks/useStrings.ts b/packages/website/src/hooks/useStrings.ts new file mode 100644 index 000000000..4c188e157 --- /dev/null +++ b/packages/website/src/hooks/useStrings.ts @@ -0,0 +1,9 @@ +import { api } from "../blitzkit/api"; +import { useAwait } from "./useAwait"; +import { useLocale } from "./useLocale"; + +export function useStrings() { + const locale = useLocale(); + const strings = useAwait(() => api.strings(locale), `strings-${locale}`); + return strings; +} diff --git a/packages/website/src/pages/[...chunk_api]/strings/[locale].json.ts b/packages/website/src/pages/[...chunk_api]/strings/[locale].json.ts new file mode 100644 index 000000000..0cd08c1e2 --- /dev/null +++ b/packages/website/src/pages/[...chunk_api]/strings/[locale].json.ts @@ -0,0 +1,14 @@ +import locales from "@blitzkit/i18n/locales.json"; +import type { APIContext } from "astro"; +import { mixStaticPaths } from "../../../astro/mixStaticPaths"; +import { api } from "../../../blitzkit/api"; +import { getStaticPaths as _getStaticPaths } from "../_index"; + +export const getStaticPaths = mixStaticPaths(_getStaticPaths, () => { + return locales.supported.map(({ locale }) => ({ params: { locale } })); +}); + +export async function GET({ params }: APIContext) { + const strings = await api.strings(params.locale); + return Response.json(strings); +}