Skip to content

Translation

LO-TEK has almost no text. Whoever renders the markup writes the text in it, in their own language and with the translation tool the app already uses. The few texts built into the package are defaults, and each of them can be replaced. They are listed in the table at the bottom.

A button, a label and a dialog are markup you write yourself, and the text in them is yours. In React with i18next, the session timeout looks like this:

import { useId } from "react"
import { useTranslation } from "react-i18next"
import { lt } from "@lo-tek/interfaces/react"
export function SessionWarning() {
const { t } = useTranslation()
const session = lt.sessionTimeout({ titleId: useId() })
return (
<lt-session-timeout {...session.host}>
<dialog {...session.dialog}>
<h2 {...session.title}>{t("session.title")}</h2>
<p {...session.text}>
{t("session.beforeCount")} <span {...session.count} /> {t("session.afterCount")}
</p>
<span {...session.live} />
<form {...session.actions}>
<button {...session.extend}>{t("session.continue")}</button>
<button {...session.logout}>{t("session.logOut")}</button>
</form>
</dialog>
</lt-session-timeout>
)
}

On a server it is the same markup, with the text coming from the server’s own setup. In a Go template it can be a function the app has registered itself:

<h2 class="lt-session-timeout__title" id="session-title">{{ T "session.title" }}</h2>

LO-TEK does not care which tool you use, as long as it produces text. Some common choices:

Where the markup is madeCommon tools
Reacti18next with react-i18next, FormatJS (react-intl), Lingui
Other JavaScripti18next, Paraglide, FormatJS
Servergettext, go-i18n in Go, resource files in .NET, ResourceBundle in Kotlin and Java
  • The package has no dependencies, and is not getting any. An integration with i18next would make i18next part of every app that uses LO-TEK.
  • Most of the tools have a separate package per framework, such as react-i18next. An integration would tie LO-TEK to one framework again, which is what the whole system is built to avoid.
  • A server in Go or Kotlin cannot use a JavaScript library. Its text has to come from the server anyway.
  • The text belongs to the markup, and the markup comes from whoever renders it. See Markup and behaviour.

The components format numbers and durations with the browser’s own Intl, following lang on the page. The announcement in Session Timeout says “1 minute and 30 seconds” on an English page and “1 minutt og 30 sekunder” on a Norwegian one, without anyone having translated it. Suggestion picks the plural form with Intl.PluralRules, so Polish gets all four of its forms.

Set lang on <html>, therefore, and on any element in a different language from the rest of the page. Without lang, the browser’s own language is used.

These are all the texts LO-TEK writes into the page itself. A guard in the build fails on a new text that is not listed here, on a text in CSS that is not read from a variable, and on a text written directly in a component.

ComponentDefault textHow to replace it
Toast, the regionNotificationslabel on <lt-toast>, or label in lt.toast()
Toast, the close buttonClose messageclose-label on <lt-toast>, closeLabel in lt.toast(), or closeLabel in show() for a single message
Connection Status, no connectionNo connection. What you type is not being saved.offline-text
Connection Status, backConnection restored.online-text
Suggestion, no matchesNo matchescount-none
Suggestion, one matchOne matchcount-one
Suggestion, several matches{n} matchescount-other, and count-zero, count-two, count-few and count-many for languages that have them
Label and Fieldset, required with a symbol*--lt-label-required-symbol
Label and Fieldset, required with text(required)--lt-label-required-text
Label and Fieldset, optional(optional)--lt-label-optional-text

Session Timeout is not in the table. It has no text: you write the dialog yourself.

The texts in the stylesheets are replaced with a variable, for example by the language of the page. This example translates them into Norwegian on purpose, to show a language other than the defaults:

:root:lang(nb) {
--lt-label-required-text: " (påkrevd)";
--lt-label-optional-text: " (valgfri)";
}

In the suggestion field, {n} stands for the count. Write it in every form except count-none, including count-one: in French that form also covers 0 matches, and in Russian also 21. The Norwegian example is on purpose too:

<lt-suggestion lang="nb" count-none="Ingen treff" count-one="{n} treff" count-other="{n} treff">

If you use i18next, you can pass the translation straight in, as count-other={t("matches.other")}. i18next leaves {n} with single braces alone, so it can stay in the translation file.