Languages
Job Radar keeps every user-visible text in messages/<id>.json, one file per interface language (English and Chinese
ship with it). Which language is used where is set in language.yaml (Settings → Interface → Languages).
language.yaml
Section titled “language.yaml”| Key | Default | Meaning |
|---|---|---|
ui.default_locale |
en |
Interface language of a browser that never picked one. The language button in the top bar remembers a choice per browser (cookie). Must be one of the messages files. |
ai.output |
en |
The language of everything the AI writes: fit reasons, gaps, the one-line summary, the job breakdown, suggestion reasons. Any language code (en, zh, de, fr, pt-BR …). |
ai.summary_also |
[] |
The one-line summary is also written in these languages, so another interface language still shows one. |
translation.target |
en |
Job ads are translated into this language. Ads already written in it get no translation tab and no translate button, and the automatic translation skips them. |
notify.locale |
null |
Language of Telegram messages, buttons and alerts; null = ui.default_locale. |
cli.locale |
null |
Language of pnpm run doctor and pnpm sources:list; null = ui.default_locale. Both commands also take `–lang en |
Language codes are BCP 47 tags (en, zh, de, pt-BR, zh-Hant); an invalid one is refused when saving and by
pnpm config:check.
An install from before languages were configurable gets a language.yaml written on its first start with what it did
until then: Chinese interface, AI texts, Telegram and command line, English one-line summaries next to the Chinese
ones, translations into Chinese. A new install gets the English defaults above.
What changes when you change a language
Section titled “What changes when you change a language”- Interface: at the next page load (the web app reads
language.yamlfresh). A browser that picked a language with the button keeps it. - AI output: new results are written in the new language. Earlier scores, breakdowns and suggestions are not
rewritten (that would cost an AI call per job): they keep their language, and the job page marks text that is not in
the interface language with a small language tag (for example
中文) and the rightlangattribute. Nothing is translated automatically. - Translation target: translations are stored per language, so switching back shows the earlier ones again.
- Telegram / command line: the next message or run.
The one-line summary shown is the one in the interface language, else in the AI output language, else English, else any language there is; a summary in another language than the interface carries a language tag.
Command-line output
Section titled “Command-line output”- User commands follow
cli.locale(or--lang):pnpm run doctor,pnpm sources:list,pnpm traps:scan, and the Telegram test message ofpnpm telegram:test(Telegram language). Their--jsonoutput carries codes only (ids, statuses, reason keys); the doctor’s JSON also says whichlocaleits texts are in. - Developer and maintenance commands (
config:check,*:migrate,db:*,smoke:*,score:*,simhash:*,auth:linkedin, the e2e tools, logs) are in English.
Adding an interface language
Section titled “Adding an interface language”- Copy
messages/en.jsontomessages/<id>.json(for examplefr.json; the file name is the language code). - Fill in
meta:name(the language’s own name, shown in the language menu),intl(the tag for dates and numbers,fr-FR),promptName(how a prompt names the language to an AI,French),wide(truefor CJK scripts). Translateformat(relative times, duration units, salary words) and as many other keys as you like: a key that is missing shows the English text. - Run
pnpm i18n:catalog(it also runs beforepnpm dev,pnpm buildandpnpm build:runner) and commit the regeneratedsrc/i18n/catalog.generated.tsandsrc/i18n/messages.generated.ts.pnpm i18n:check(part ofscripts/validate.shand CI) fails when a messages file is invalid or the generated files are stale.
No hand-written code changes. With more than two languages the language button becomes a menu that lists every
language by its own name. Rules the check enforces: English and Chinese have every key; other languages have no key
English lacks; every message uses the same ICU placeholders as the English one; meta is valid.
For contributors
Section titled “For contributors”- User-visible text goes into
messages/*.json, never into components, Telegram messages, doctor checks or CLI output meant for users.tests/i18n/no-hardcoded-cjk.test.tsscans every string literal and JSX text ofsrc/andscripts/for Han characters (comments are fine); the allow-list holds only demo data and migration templates. - Outside React, use
translatorFor(locale, namespace)orgetTranslator(namespace, "notify" | "cli")fromsrc/lib/i18n/node.ts; Telegram formatting gets aNotifyText, doctor checks usectx.t. - Format numbers, times and salaries only through
src/lib/format/*with an explicit locale.
Synced from docs/ in Joevonlong/job-radar@2947f47. Job Radar is not affiliated with any job board. Code under AGPL-3.0-only.