Interface localization¶
Typsastra's interface uses a small built-in locale layer. There is no runtime localization dependency. English is the source locale, and English source text is also the message key, so authored labels stay readable and translators can work from extracted strings.
Translate a string¶
import { t } from "../i18n";
element.textContent = t("Save");
element.title = t`Downloading ${percent}%`;
section.textContent = t("Hello {name}", { name });
t("Save")looks the exact source text up in the active catalog.t\Downloading ${percent}%`becomes the keyDownloading {0}%` and interpolates the value after translation.- Named values use
{name}placeholders. Numbered values from tagged templates use{0},{1}, and so on. Unknown placeholders are preserved. - Missing translations fall back to English.
For count-aware wording, choose the source phrase before translating:
Translate authored markup¶
Static text and the title, placeholder, aria-label, and alt attributes
are translated by source text when the app starts:
Dynamic HTML that contains authored text should be installed with
setLocalizedHtml instead of a direct innerHTML assignment:
Explicit keys are available when the authored text is ambiguous or assembled from fragments:
<div data-i18n="Clear recent projects">Clear recent projects</div>
<input data-i18n-placeholder="Search languages..." />
<button data-i18n-title="Open settings" title="Settings"></button>
Use data-i18n-skip on a subtree that must never be translated, such as
generated user content. The localizer already skips code, pre, editable
regions, shortcut labels, and editor widgets.
Add a locale¶
A ready-to-copy template with every currently extracted English key is checked
in at src/i18n/locales/locale.template.ts. Copy it to a new file, rename the
export, set id and label, and translate the values.
Refresh the template after UI strings change:
The template maps each English key to itself, so it is safe to register while translations are incomplete. Remove entries you do not plan to translate; missing keys fall back to English.
- Copy
src/i18n/locales/locale.template.tstosrc/i18n/locales/km.ts. - Rename
localeTemplatetokhmerLocale. - Set
id: "km"andlabel: "ខ្មែរ". - Translate the catalog values.
- Register the locale in
src/i18n/locales/index.ts:
import type { LocaleDefinition } from "../types";
import { englishLocale } from "./en";
import { khmerLocale } from "./km";
export const builtinLocales: readonly LocaleDefinition[] = [
englishLocale,
khmerLocale,
];
export { englishLocale };
- Open Settings → Language → Interface language and choose the locale.
The choice is stored in
localStorageundertypsastra.ui-locale.
setLocale("km") is also available from code. The settings panel re-renders
after a change; other surfaces that build labels with t() pick up the new
locale the next time they render.
For a JSON key list instead of the TypeScript template, run
bun run i18n:extract.
Notes¶
- English text remains in the templates, just as with gettext-style catalogs. This keeps diffs small and preserves useful source context.
- Static markup is matched after whitespace normalization. Mixed-content
paragraphs may need
data-i18nor a small markup adjustment before translation reads naturally. - Do not translate user document text, file paths, compiler diagnostics, or generated code. Those values flow through the UI untouched.