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" });
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
| Key | English default | Where it appears |
|---|---|---|
error.network.title | Connection error | toast when the backend is unreachable |
error.network.message | The backend is unreachable. Please check the connection and try again. | |
error.http.title | Error | toast when a request came back with an error status |
error.http.message | The 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.titleon 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
suiI18nis 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.
suiI18nis a browser-side module; the desktop renderer has its own chrome strings and does not read this catalog.