Standard: Multilingual strings
Applies to
Every sentence a person sees. This covers the page (HTML and JS for the yard and the overlay), error and status messages the backend returns to the page, window titles and the tray menu, and file dialog titles. Supported languages are Korean (ko), English (en), Japanese (ja), and Simplified Chinese (zh-hans).
Not covered:
- Sentences the app's CLI mode writes for the terminal and coding agents (usage, errors, MCP tool descriptions). These are fixed in English.
- The template sentences of prompts sent to the AI (
chat/prompt.rs). These are written in English, and the prompt sets the reply language. - Words sent by an agent or a person (
say, AI replies). These are shown as they are, without translation. - Test code, comments, and developer docs (
docs/), which are written in English. Dated design records and decision records stay as they are.
Rules
- Page strings live in
src/core/strings/<language>.jsand backend strings insrc-tauri/src/i18n/<language>.rs. The Korean file is the reference; other languages have the same keys in the same order. No other module or markup contains Korean sentences. The steps for adding a language are in Add a language. - Every language has the same keys, and the sentences for one key have the same placeholders (
{name}). Lists contain nonempty localized lines with the same placeholders. Do not copy English sentences into another table to make a missing translation pass structural checks; review meaning and terminology in every language. - Every key the code calls (
t('…'),list('…'),data-i18n,data-title,i18n::t("…")) exists in the table. A missing key shows the key name itself on screen. - Key names use lowercase and dots, with the area first (
invite.open_folder,error.pet_missing). When the same sentence repeats, reuse the key. - Korean uses the friendly, polite style, English uses short sentences (only the first letter capitalized), and Japanese page strings use the です・ます style. Simplified Chinese uses plain, friendly 你 (never 您) with full-width punctuation. A friend's own spoken lines (speech bubbles, what it says on its own, at a new closeness level, about an event) are casual in every language: informal speech in Korean, casual speech in Japanese and Chinese, contractions in English. Everything else follows its language's UI tone above.
- The English tables (
en.js,en.rs) use American spelling (color, favorite). - In Korean, the particle after a name is attached to the placeholder (using
{name:<consonant-form>/<vowel-form>}). The particle that matches whether the name ends in a final consonant is filled in automatically. - Coding agent status is sent as codes (
@thinking,@tool Bash,@done). The app receives them and turns them intoagent.*keys. When you add a new status, add the code and the key together. - Keep the terms below consistent. Their localized spellings are the corresponding keys in each language table; use those keys as the glossary instead of adding new synonyms. A named Mini pet is distinct from the mini window mode. Appearance changes never select a relationship.
| Term | Meaning |
|---|---|
| Pet | A character file (pet.json and the sprite sheet) |
| Friend | Someone invited into the yard |
| Import | Bringing in pet files |
| Invite | Adding a friend to the yard from a pet |
| AI connection | The AI a friend uses to chat (Claude Code, Codex, Ollama, OpenAI-compatible) |
| Agent integration | Hook and MCP settings for coding agents |
| Yard, mini mode, desktop | The main window, the small window mode, the desktop overlay |
| Closeness | How close a friend has grown to the person, in five levels (Just met, At ease, Warm, Very close, Dearest) |
| Relationship | Who a friend is to the person (friend, partner, mentor, younger sibling), which sets how it talks |
| Tag | The chasing game |
| Send away | Taking a friend out of the yard |
| Type | The pet filter on the Invite tab (invite.kind_label) |
This is how the page uses it.
import { t } from '../core/i18n.js';
// The Korean table supplies the particle form along with its localized sentence.
await confirmAction({ title: t('friend.send_away_confirm', { name: pet.name }) }); // "Send Frieren away from the yard?"<button id="update-button" data-i18n="settings.update_check"></button>
<input data-i18n-placeholder="chat.placeholder">This is how the backend uses it.
return Err(i18n::tr("error.pets_limit", &[("limit", &LIMIT.to_string())]));Recommendations
Follow these when you can. When you cannot, say why in the PR.
- Spell out development terms (config, provider, sprite) in sentences people see.
- Error messages say what failed and what the person can do (“Check your internet connection”).
Exceptions
| When | How |
|---|---|
Code that handles Korean itself, such as particle handling (src/core/words.js) | Allowed. It is already in the guard test's exception list |
| Proper nouns and language names (the language choices in Settings) | Allowed. They are not translated |
| You cannot fill every language at once | Do not leave them empty in English; split the PR. Tests block empty strings |
Rationale
When strings are scattered through the code, they cannot be translated and the terms drift. Gathering them into two tables lets tests catch missing and mismatched entries. Agent hooks run in a different process from the app and do not know the app's language, so they send codes. Based on: decision “Strings live in two per-language tables, one for the page and one for the backend, and agent status is sent as codes”
Automated checks
tests/i18n.test.mjs— matching keys, placeholders and nonempty list lines across every language, English-only current developer guidance, Korean in page code and markup, comments included (onlystrings/ko.js,words.jsandi18n.jsmay show it), and that the keys the page calls exist.- Rust
i18n::tests— matching keys and placeholders across every language, Korean in everysrc/module, comments included (test modules may use Korean input data), that the keys the backend calls exist, and agent code conversion.
Change history
- 2026-10-01 First version
- 2026-10-06 Simplified Chinese added; the guard tests also look at comments
- 2026-10-10 Friends' own lines are casual in every language; American spelling in English; closeness, relationship, tag, send away and Type added to the terms