Skip to main content

Language of the runtime

A semantic-ui app has two kinds of text in it, and only one of them is this page's business.

Your content — labels, titles, table headers, validation messages — is built on the server, in whatever language you built it in. The renderers pass it through untouched. Translating that is your application's job, with whatever you already use for it.

The runtime's own chrome is the handful of strings the client says on its own behalf, when no server told it what to say: the status toast while a stream runs, and the toasts for a request that failed. Those are the strings suiI18n covers.

It is deliberately small — a flat key-to-string map with {param} interpolation. No plurals, no number or date formatting. There are seven keys.

It usually needs no setup

At load, the runtime follows the page's declared language:

<html lang="de">

If a bundle for that language is registered, it is used. German ships built in, so a server-driven app that already sets lang gets matching chrome for nothing. English is built in as the default.

That is the whole story for most apps. The rest of this page is for when it isn't.

Choosing the language yourself

import { suiI18n } from ".../sui/i18n.js";

suiI18n.use("de"); // true — a bundle exists
suiI18n.use("de-AT"); // true — region subtags are ignored
suiI18n.use("fr"); // false — falls back to English
suiI18n.locale(); // "de"

use() returns whether it found a bundle, so a host that cares can tell the difference between "translated" and "fell back" instead of guessing from what appears on screen.

Your own language, or your own wording

Register a whole bundle:

suiI18n.register("fr", {
"error.network.title": "Erreur de connexion",
"error.network.message": "Le backend est injoignable. Vérifiez la connexion et réessayez.",
"error.http.title": "Erreur",
"error.http.message": "La requête a échoué (HTTP {status}).",
});
suiI18n.use("fr");

A bundle may be incomplete. Every key falls back to English on its own, so a half-translated bundle shows the untranslated half rather than blanks.

Or override individual strings without a bundle:

suiI18n.set({ "error.http.title": "Something went wrong" });
Order matters

use() replaces the active overrides, including anything set() put there. Call set() after use(), never before:

suiI18n.use("de");
suiI18n.set({ "error.network.title": "Keine Verbindung" }); // ✅ survives

suiI18n.set({ "error.network.title": "Keine Verbindung" });
suiI18n.use("de"); // ❌ discarded

A locale is a complete set of copy; picking one starts from that set.

The keys

KeyEnglish defaultWhere it appears
error.network.titleConnection errortoast when the backend is unreachable
error.network.messageThe backend is unreachable. Please check the connection and try again.
error.http.titleErrortoast when a request came back with an error status
error.http.messageThe request failed (HTTP {status}).

{label} is the stream's own label, from the server's Sui-Stream-Label header. {status} is the HTTP status code.

Reading a message yourself

If your own client code wants the same treatment:

import { t } from ".../sui/i18n.js";

t("error.http.message", { status: "503" });

Two things t() does on purpose:

  • An unknown key returns the key itself, not an empty string. A typo shows up as error.htpp.title on screen, which is a bug you can find.
  • An unknown placeholder is left verbatim. Calling t("error.http.message") with no params renders (HTTP {status}) — again, visibly wrong rather than silently blank.

What it does not do

  • Server-rendered content. It never passes through here. A page rendered in German by the server stays German whatever suiI18n is set to, and the two are only consistent because the host sets both.
  • Plurals and formatting. Seven fixed strings do not need a plural engine, and adding one would invite the application's own copy into a catalog that is not built for it.
  • Anything on the JavaFX renderer. suiI18n is a browser-side module; the desktop renderer has its own chrome strings and does not read this catalog.