A library "My loans" page written in plain TypeScript against the DOM — no framework,
no runtime i18n library. Just the saykit core runtime and
unplugin-saykit wired into Vite.
This is the smallest complete picture of how SayKit works, and the best example to read first.
| API | Where |
|---|---|
new Say({ locales, messages }) |
src/i18n.ts |
say.match(navigator.languages) — locale detection |
src/main.ts |
say.activate(locale) — runtime locale switching |
src/main.ts (the language picker) |
say`…` with interpolation |
src/main.ts |
say({ context }) to disambiguate identical source text |
src/main.ts (My loans) |
say.plural with CLDR categories and an exact 0 case |
renderSummary |
say.ordinal, nested inside a say`…` template |
renderSummary |
say.select over a union type |
statusLabel |
// Translators: comments carried into the catalogue |
dueLabel, renderSummary |
say.locale fed to Intl.NumberFormat / Intl.DisplayNames |
renderSummary, renderLocalePicker |
The locale set is deliberate: en (source), fr, pl (four plural categories, so
one/few/many/other all matter), and ja (no plural distinction at all). A catalogue that
reads correctly in all four is a catalogue that is actually internationalised.
pnpm install
pnpm --filter vanilla-example devEdit a message in src/main.ts, then re-extract:
pnpm --filter vanilla-example extractExtraction rewrites src/locales/en.po (the source locale) and leaves fr, pl, and ja
untouched, adding only the new empty entries. Untranslated keys fall back to the source string at
build time, so the app never renders a raw message id. Use saykit clean to prune entries that no
longer exist in the source.
unplugin-saykit/vite does two things (see vite.config.ts):
- transform — rewrites
say`Due in ${n} days`into asay.call({ id, … })with a stable hashed id. The macro bodies in the runtime throw if this step is missing, so a misconfigured build fails loudly rather than silently shipping English. - load — turns
import en from './locales/en.po'into a plain JS object. No PO parser reaches the browser bundle.
Further reading: core concepts and the Vite integration docs.