Add a language
The app speaks Korean (ko), English (en), Japanese (ja) and Simplified Chinese (zh-hans). Codes are lowercase BCP 47; a language with two writing systems uses the full code, like zh-hans (when the system says only zh-CN, the region tells which writing system it is). Start with two strings files and their registrations, then update the site and installer language lists below. The Korean file is the reference: copy its key order and placeholders ({name}) as they are, and the tests tell you what is missing. The language list has two sources: MODULES in src/core/strings.js on the page side and ALL in src-tauri/src/i18n/mod.rs on the backend side. The list in the Settings tab, the capture script and the site tests read from those.
1. Page strings
- Copy
src/core/strings/ko.jstosrc/core/strings/<code>.jsand translate the sentences. The file exports three required things and one optional one.name: what the language calls itself (shown in the list in the Settings tab).sentence: a regular expression that recognizes a sentence in that language (text.jsuses it to tell error sentences from codes). Use a character range if the writing system gives it away, otherwise punctuation.strings: key → sentence. Keys whose value is a list (greetings, chatter) stay lists.listSeparator(optional): the separator used when listing names. The default is', '; Japanese uses'、'.
- Add one
importline and one entry toMODULESinsrc/core/strings.js. The language list in the Settings tab comes from here. words.jsattaches Korean particles (a placeholder with the two particle forms after a colon) only for Korean. Other languages use plain placeholders. When listing names,joinListpicks that language's comma.- If the writing system is different, add a font stack for the language in
src/styles/base.css, like:root:lang(ja)(Chinese drawn with Japanese fonts gets different glyph shapes).
2. Backend strings
- Copy
src-tauri/src/i18n/ko.rstosrc-tauri/src/i18n/<module>.rs. The module name is the code with-turned into_, since a Rust module name cannot contain a hyphen:zh-hansiszh_hans.rs. Rows have to stay in the same order asko.rs(the test checks the order too, so the files can be edited side by side). Put the code and the English name inSPECat the top of the file. The English name is used when telling the AI "answer in this language". - In
src-tauri/src/i18n/mod.rs, addmod <module>;(for examplemod zh_hans;), add&<module>::SPECtoALL, and increase the array length in its type ([&Spec; 4]) by one. That is all;Langrefers to a language by its position inALL.
3. Other places
Site:
localesinwebsite/.vitepress/config.mtsand the docs inwebsite/<code>/guide/. The site picks its languages separately, so it can have fewer than the app (today the landing page, user guide and release pages are in Korean, English, Japanese and Simplified Chinese, and the developer docs are in English only). Register the locale inscripts/site-content.mjs, addtheme/landing-<code>.tsand its active copy contract, and updatetheme/words.tsand the creator components.Landing.vuecomposes those modules; publishing, captures and release validation share the locale registry. Add an Open Graph card, guide pages and release notes, then test canonical and alternate links.Captures: add the language's names, personalities and sample conversation to
scriptinscripts/shots.mjs, andnpm run shotscaptures screens in that language too (it reads the language list fromstrings.js). You can choose languages, likeSHOT_LANGS=ko,en. Once the site has docs in that language,tests/website.test.mjslooks for the captures used bywebsite/<code>/in that language's folder.The supported-languages line in the doc
docs/standards/i18n.md.OG images:
scripts/make-og.mjsmakes one image per language the site has. Add the language once the site has it.The language line in
README.mdand the first line of this doc.Windows installer: add the NSIS language name to
bundle.windows.nsis.languagesinsrc-tauri/tauri.conf.jsonand the locale topackaging/windows/msix/AppxManifest.xml. Keep the language selector enabled. NSIS uses names such asEnglish,Korean,JapaneseandSimpChinese, while MSIX uses locale tags. Update the expected mappings intests/repository-config.test.mjsand inspect the installer and uninstaller on Windows.
4. Check
npm testtests/i18n.test.mjs checks that every language file has the same keys and placeholders, that no Korean is left in a module, and that every key the code asks for is in the table. i18n::tests in cargo test checks the backend side the same way. Then run the app with PLAYPETS_LANG=<code> and pick the language in the Settings tab.