endfield-mcp
Version:
MCP Server for Arknights: Endfield (TypeScript / stdio + Streamable HTTP)
87 lines (86 loc) • 4.07 kB
TypeScript
/**
* Localization (i18n) resolution layer.
*
* Endfield separates values from strings: most tables store `{id, text}`
* objects where `text` is empty and `id` is an int64 hash. The actual
* string lives in `I18nTextTable_<LANG>.json` under that hash, and looks
* like `{"key": "-7078064683023630592", "value": "管理员"}`.
*
* This module owns that lookup. It lazily loads one or more language
* tables (default CN), builds an in-memory `Map<string, string>` index,
* and exposes `resolveText()` for readers to call without knowing which
* language is active.
*
* ## Key format
*
* I18n keys are stored as strings in the upstream JSON even though they
* look like int64 numbers. JS `number` can't represent int64 exactly
* (Number.MAX_SAFE_INTEGER is 2^53-1), so we keep them as strings
* end-to-end. The `{id, text}` objects in game tables also store `id`
* as a number, so callers convert via `String(loc.id)` before resolving.
*/
import { SUPPORTED_LANGUAGES } from "./datasets.js";
import type { JsonStore } from "./stores.js";
/**
* The `{id, text}` shape embedded in nearly every Endfield table.
*
* `id` is a string, not a number: Endfield's localization ids are int64
* hashes that exceed JS Number.MAX_SAFE_INTEGER, so tables must be parsed
* with `JsonStore.readJsonInt64Safe()` (which wraps large integer literals
* in quotes). `text` is conventionally empty upstream; the real string is
* keyed by `id` in the i18n table.
*/
export interface LocalizedText {
id: string;
text: string;
}
/** Supported language codes (CN, EN, JP, TC, KR). */
export type LanguageCode = (typeof SUPPORTED_LANGUAGES)[number];
export declare function bindTextStore(store: JsonStore): void;
/**
* Set the default language used when `resolveText()` is called without an
* explicit language. Must be one of SUPPORTED_LANGUAGES.
*/
export declare function setDefaultLanguage(lang: string): void;
export declare function getDefaultLanguage(): LanguageCode;
/** Drop all loaded language indices. Called by startupSync after refresh. */
export declare function clearTextCaches(): void;
/**
* Load (and cache) one language's i18n index.
*
* The i18n file is a flat object: `{ "-7078064683023630592": "管理员", ... }`.
* Keys are int64 hash values stored as strings (because JS number can't
* represent int64 exactly — see notes on CharacterTable id handling).
* Values are the localized strings.
*
* We build an in-memory `Map<string, string>` eagerly on first access.
* With ~50k entries per language this takes a few hundred ms — acceptable
* because it happens once per language per process lifetime.
*/
export declare function loadLanguageIndex(lang: LanguageCode): Map<string, string>;
/**
* Resolve a `{id, text}` object to an actual string.
*
* Behaviour:
* - If `text` is non-empty, return it directly (some tables pre-fill it).
* - Otherwise look up `String(id)` in the requested (or default) language.
* - On miss, return the fallback string (default: the id itself, so the
* caller can see something went wrong without a crash).
*
* Callers pass an explicit `lang` only when they need a non-default
* language (e.g. a future "get this in English" tool option). The vast
* majority of reads use the process default.
*/
export declare function resolveText(loc: LocalizedText | undefined | null, lang?: LanguageCode, fallback?: string): string;
/**
* Resolve in a specific language, returning null on miss (vs resolveText
* which returns a fallback). Used when callers want to distinguish
* "found" from "not found" without ambiguity.
*/
export declare function tryResolveText(loc: LocalizedText | undefined | null, lang: LanguageCode): string | null;
/**
* Convenience: resolve the same localization across all supported
* languages. Returns `{CN: "...", EN: "...", ...}` with null for misses.
* Useful for tools that want to show multilingual names at once.
*/
export declare function resolveTextAllLanguages(loc: LocalizedText | undefined | null): Record<LanguageCode, string | null>;