Content and localization
Sets interface wording and the formats of numbers and dates.
Principles
- Use one term for each thing. An action, state, or object keeps its name on every screen, so two words never seem to mean two things.
- Lead with the outcome, then the next step. Readers act on the first words they see, so keep error codes and internal terms in details.
- Translate whole sentences. Word order and plurals differ by language, so never build a sentence from fragments.
- Format values in the reader's locale and time zone. Pass both to Intl explicitly, with the same values on the server and the client, so the first render matches.
Interface text
A recoverable error names the cause and the fix, and keeps what the reader entered. Report success only when the work is done. Accessibility covers where results stay and how they are announced.
Korean copy describes with -합니다 and instructs with -하세요, attaches a counter to its numeral (검사 2개), and avoids translationese such as -에 대한 and -을 통해.
Numbers, dates, and time zones
The locale sets number and date formats, and the time zone sets an instant's local time. Change both below, and compare the times around a DST change with the UTC source. Currency stays USD.
- Recorded runs
- 1 recorded run
- Estimated cost (USD)
- $1,234.50
- Utilization
- 87.5%
- Occurred at
- Time zone
- Asia/Seoul
- Last change
- 5 minutes ago
- Actual zero
- 0
- Missing value
- Not available yet
Relative time uses a fixed preview reference. The absolute time is shown too.
Source: 2026-03-08T06:30:00Z. The relative time uses a fixed reference, not the current time.
Validate invalid dates, NaN, and unsupported locales at the data boundary, and treat them as errors. Don't show zero or the current time for a missing value. Never parse a display string back into a value.
Language and direction
lang sets the language, and dir sets the reading direction. Isolate names that readers enter with dir="auto", and Latin identifiers with bdi dir="ltr". The RTL preview checks layout only.
Try a long name, Korean or Arabic text, or text that looks like HTML. It shows as text and is never sent.
Project: 프로젝트 / مشروع / platform-api-production-release-archive
Resource ID: demo-e2e-42/platform-api-production
المشروع: demo-e2e-42
Wrap text instead of truncating it, and use start and end spacing. Where like items keep one height, such as the last message on each card of a collection, Text lines={2} clamps it, and the whole text shows where the item opens. Don't hide names, amounts, or identifiers behind an ellipsis in errors and confirmations.
Component labels
Components write some text of their own: the names of close and copy buttons, the announcements of an upload, a chart's data table. Translate it once for the app with LabelsProvider, instead of on every instance. KoreanLabels from @surflane/ui/labels-ko writes all of it in Korean.
A component's own props win over the provider's labels, and those over the component's English defaults. A provider inside another changes the groups it names and keeps the rest.
KoreanLabels takes no functions, so a Server Component can render it. Breadcrumbs and Spinner render on the server and take their names as props.