Repository navigation
EN Create Translations
Français · Type: how-to + reference · Audience: author · Context: engine repository, created project · Status: ready · Applies from: 4.3.0
The content stays written in one language (lang in game.ts, en when absent). Translating is a table, not keys
in the content: one JSON file per language, { "<path>": "<text>" }, made and kept up to date by the i18n tool.
This page is the procedure, then the reference of the paths and of how the player picks a language.
locales/<lang>.json beside the game, every text of the game translated, a game that offers the language in its
Settings and picks it from the browser, and i18n status at ✔ for every language.
The engine repository and a created project alike; only the command and the folder differ. True from 4.3.0: text
switches kept by a translation and i18n.same are checked by status since then.
- A game that loads (
validatepasses). - Stable ids on the lines you will voice or reorder:
ids --lines --write(see Voices). Without one, a line is keyed by its position.
| Context | Folder | Command | Files |
|---|---|---|---|
| Engine repository | its root |
npm run i18n -- <sub> (the game: GAME=<id>, else the one npm run game chose, else config.game) |
games/<id>/locales/ |
| Created project | its root | npx quest-n-click i18n <sub> |
game/locales/ |
-
Write the reference file, every text of the game with its path, in the game's own language:
npm run i18n -- extract # games/<id>/locales/en.json: every text with its path (the reference) npm run i18n -- extract --lang fr # locales/fr.json: keeps what is translated, follows moved texts, adds the missing ones npm run i18n -- status # coverage of every language, stale paths, long lines
These three run in the engine repository; in a created project they are
npx quest-n-click i18n extract,npx quest-n-click i18n extract --lang frandnpx quest-n-click i18n status.
-
Create or update the language file with
extract --lang fr. The missing paths are added with the source text, to translate; the file's_entry says so. It prints how many texts are to translate, followed a moved text, came back, or were parked as_stale.
-
Translate the values, never the keys. Keep the text switches of the source (
{form?m=him|f=her}): a translation must keep each choice its source makes, and may add its own (a French agreement English writes alike,Prêt{form?f=e|*=}). The syntax is on Heroes.
-
Check with
status. For each language: translated / total, missing, stale, long (more than 140 characters), with other text switches, and the texts identical to the source. It exits 1 while a language has a missing or stale path, a dropped switch, or an identical text thati18n.samedoes not list.
-
Ship. The game's
index.tspicks up everylocales/*.json(the template's and the sample games' do); build as usual. Commit the reference file with the translations.
A path looks like room:house/look.pantry[1], item:key/name, char:grandma/refuse, ui/newGame,
rules/fallbacks.look[2], start/intro[0].say, credits[3], map/places.house.name, objectives/key.title. A line
with an id is keyed by it: room:house/look.pantry.<id>, rules/fallbacks.look.<id> (lists take { id, text }
lines; see Upgrade notes v3). The file is { "<path>": "<text>" }.
Paths follow the structure, so a refactor moves them; extract --lang xx copes. It compares the game with the
reference file (refreshed at the same time):
- a text that moved (a reordered list, a rule moved up) keeps its translation, because its source text is the same;
- a text that disappeared is parked under
_stale:<old path>: ignored in play, listed bystatus, deleted by hand when you are sure; it comes back with its translation if the path returns; - a text whose source changed is offered again to translate.
Rule of thumb: run extract --lang xx after every refactor, before translating anything new, and commit the reference
file with the translations.
Guarantee ·
i18n-moved-texts· referenced · scope self-checked by the author (AI), not reviewedextract --langkeeps the translation of a text that moved, parks the one that disappeared under_stale:, and brings it back with its translation when its path returns.
The language is chosen when the page loads, the first that applies:
-
?lang=frin the address; - the player's choice in Settings (kept in the browser as
<game id>.lang): withsettings: true, the Settings menu shows a Language row (ui.language) when the game ships another language; each tap moves to the next language and reloads the page; - the browser's language, when the game ships it (
fr-CApicksfr); - otherwise the game's own language.
A text a file lacks stays as written. The voices follow the language: Voices.
Limit ·
lang-not-shipped?lang=xxfor a language the game does not ship shows the texts as written, with no message.
A text identical to the source is an untranslated line, and fails status, unless i18n.same in game.ts lists its
path: a name, OK, ▲, a word French borrowed.
i18n: { same: ['char:hero/name', 'ui/ok'] },status also lists the ui keys the game leaves to the engine's English defaults: a player sees those in English in
every language.
npm run validate -- --report (npx quest-n-click validate --report) and the Studio's Check tab show the coverage
per language. verify, build and release in a created project run i18n status and stop on its failure.
status prints ✔ fr: <n>/<n> translated for every language and exits 0; ?lang=fr shows the game in French.
| Symptom | Cause | Fix |
|---|---|---|
… fr: 120/131 translated, 11 missing |
New texts since the last extract |
extract --lang fr, translate |
stale room:house/look.pantry[3] |
A text that no longer exists | Delete it once sure, or let it come back |
switch <path> (source: …; translation: …) |
The translation drops a choice of the source's switches | Put the switch back in the translation |
same <path> (translate it, or list it in i18n.same) |
A text left as the source | Translate it, or list it in i18n.same
|
[<id>] no locales |
No language file yet | extract --lang <xx> |
| The page stays in English |
?lang= misspelt, a choice stored for another language, or the file not shipped |
Check the address and Settings; rebuild |
locales/<base>.json (the reference) and locales/<lang>.json; nothing else. ids --write (a prerequisite) renames
the keys of the locale files to id-based paths.
Both files are in Git: git checkout -- <file> undoes an extract. Nothing is lost by extract: a disappeared text
goes to _stale:, never deleted.
-
tools/i18n.ts,src/engine/tools/i18n.ts(textPaths,mergeLocale,localeStatus,switchesKept),src/engine/boot.ts(pickLanguage) - Voices, Heroes, Languages, for the player
Generated publication · publication générée — current documentation · documentation courante: quest'n'click 4.4.0 r1, documentation revision · révision de la documentation 8dc717c69acb62c4742b69c54a7e7dfb620f75d8.
Earlier versions and permalinks · versions précédentes et liens permanents: https://wanoo.github.io/quest-n-click/docs/
An edit made in this wiki is overwritten at the next publication · une modification faite dans ce wiki est écrasée à la publication suivante.
Edit the source · Modifier la source · Report an error · Signaler une erreur
Index (6)
Start (6)
Play (9)
Install (17)
- Requirements
- Install from the release archive
- Install from npm, once published
- Install from the repository to work on the engine
- doctor: checking your machine
- Image toolchain
- Audio toolchain: ffmpeg, fluidsynth, Furnace, uv
- Upgrade
- Upgrade notes: 4.4
- Upgrade notes: 4.3
- Upgrade notes: 4.2
- Upgrade notes: 4.1
- Upgrade notes: v3
- Upgrade notes: v2 to v3
- Coming from web-scumm
- Package reference
- Install troubleshooting
Create a game (55)
- Your first game
- Layout of a created project and of the engine repository
- The working loop
- Content principles and the identity contract
- Rooms
- Geometry: placement, walk zones, masks, layers, camera
- Something is visible but unreachable
- Reactions
- Game commands
- Conditions
- Flags, variables and events: which to use
- Custom code
- Characters
- Items and inventory
- World map
- Dialogues
- Scripts and events
- Moving characters: patrols and walks
- Exits
- Chapters and objectives
- State and saves: persistent or temporary, renaming an id, migrations
- Staging: wide rooms and animations
- The stage: lights, particles, floors
- Skin and fonts
- Title and credits
- Heroes: several characters and hero choice
- Built-in minigames
- A custom minigame
- Translations
- Music in stems
- Sound effects
- Voices: per language and per hero
- Images: prompts, cutting sheets, transparency, scale
- Asset provenance
- The storyboard, source of truth
- Puzzle design
- Classic mechanics
- Review pages
- DSL reference
- Checking your game
- What the solver proves
- Solver options
- Playtests
- Remix
- Speedrun for authors
- The sealed ending
- Production template
- Example games
- Working with an AI
- Build and release a game
- Publish on GitHub Pages
- The static game on Clever Cloud
- Other static hosts
- Sub-path, cache and service worker, incomplete deploys, going back
- Testing on a phone over the LAN
Local Studio (24)
- The local Studio: overview and launch
- Edit a room
- Placement and stage
- Preview, apply, undo
- Storyboard
- Assets and cutting
- Check: validator, solver, critical path, heat, health, coverage
- Before and after captures
- Semantic diff
- Play and replay a session
- Rule explainer
- Language and objectives
- Voices and the heroes × languages matrix
- Map
- Notes
- Remix in the Studio
- Music
- The Assistant: bring your own key
- Demo mode and studio-apply
- Local and LAN security
- Studio API
- Local MCP: setting up each client
- MCP tools
- Studio troubleshooting
Team Studio (21)
- What runs where
- Concepts: revision, transaction, span, lease, preview, build
- Starting as an invited dev
- Working together day to day
- Roles and actions: the full matrix
- Invitations
- Managing members
- Write refused on the hosted Studio: stale base revision (409)
- Write refused on the hosted Studio: span locked (423)
- Recovering after a lost lease, a disconnection or a stale preview
- Comments
- Map and semantic diff
- Publishing builds
- Remote MCP
- The game in Git
- Upgrading the engine of a hosted game
- Hosted assets
- The server's command line
- Health and metrics routes
- Trying it locally with compose.yml
- Known limits
Clever Cloud (23)
- Clever Cloud: overview, cost and prerequisites
- Apps and add-ons
- Domains and TLS
- Keycloak
- Generic OIDC and GitLab
- Configuration
- First deployment
- Backups
- RPO and RTO
- Restore the Studio on a fresh installation
- Redeploys
- Upgrading the server and checking state after a migration
- Limits of going back
- Monitoring
- Security
- Rotating keys
- Recovering admin access
- Changing domain or OIDC provider
- Worker, PostgreSQL or Cellar down
- Exporting the game and leaving the installation
- Retention
- Clever Cloud troubleshooting
- Costs and teardown
Reality Bridge and connectors (16)
- The Reality Bridge: what it is
- Quick start
- Guarantees
- Install and run the Bridge
- Backup and restore
- Several tenants
- Signals and the manifest
- The Bridge's command line
- Connectors overview
- Email connector
- Telnet connector
- SSH connector
- Open Badges connector
- The connector SDK
- Security: Biscuit and signatures
- Bridge and connector troubleshooting
Contribute (25)
- Welcome
- Developer setup
- The dev loop
- Before a pull request
- Conventions
- Writing documentation
- Architecture
- Code tour
- Import boundaries
- Which tests run when
- Mutation testing
- The coverage ratchet
- The quality baseline
- CI explained
- Field passes
- Benchmarks
- Releasing
- npm packages
- Decisions and ADRs
- Governance
- Bot pull requests
- Contributing with AI agents
- Security policy
- Code of conduct
- Licences and credits