Ask Metnos with a request like this example: “What is the instance language and what is the localisation state?”
The language is selected for the whole instance during installation. A change
is administrative, global, and takes effect through a controlled restart; it
is not a preference on an individual user's record. The persistent source is
the signed request at
$METNOS_USER_STATE/i18n/localization_request.json; when valid, it
takes precedence over the bootstrap-only METNOS_LANG value.
Language is a property of the instance. The web chat, Telegram, recurring work, and paired devices consume the same value; serving two languages concurrently requires two Metnos instances.
Metnos must keep four kinds of content aligned: model instructions, tool descriptions, text shown to people, and the lexicon used to understand requests. Translating the interface alone is insufficient: a button may be in French while the planner still reads English instructions, or a response may be correctly localized while recognition of a natural French phrase still fails.
Italian and English are the languages currently registered as fully supported in code. The stores may contain other languages while translation is underway; their presence alone does not prove that the entire product is ready in those languages.
The operational contract is:
The installer normalises the BCP-47 code and records the operational language,
any requested target, and the localisation state. Once the installation key
exists, these facts are signed and replaced in one atomic write. The persistent
authority is $METNOS_USER_STATE/i18n/localization_request.json
(~/.local/state/metnos/i18n/localization_request.json by default).
When valid, this document takes precedence over METNOS_LANG, which
remains only the bootstrap value for installations not yet materialised.
On restart, the runtime verifies the signed document and defines
INSTANCE_LANG, REQUESTED_LANG, and
LOCALIZATION_STATE in one configuration module. A missing,
tampered, or malformed document does not prevent boot: it is ignored and the
fallback diagnostic remains visible.
| Source | Value used | Scope |
|---|---|---|
| Signed request | Operational language, optional target, state, date, and corpus version. | Whole instance; persistent authority. |
METNOS_LANG | Bootstrap value for installations without a valid signed request. | Whole instance at restart. |
| Built-in default | it, when the bootstrap value is also absent or invalid. | Whole instance. |
The BCP-47 code is validated structurally, without a hard-coded language list.
If the requested language is not yet certified, the instance temporarily uses
English and retains the target under bootstrap_english. The
presence of some translations does not enable the new language by itself.
| Area | Content | Runtime source | Fallback |
|---|---|---|---|
| Model prompts | Instructions for planning, judging, describing, Tutor composition, and final-answer generation. | runtime/prompts/<language>/ |
Approved target file; target candidate; approved English file; English candidate. |
| Executor manifests | The executor description and argument descriptions read by the planner. | Language tables in the corresponding manifest.toml. |
Instance language; English; first available language in deterministic order. |
| User-facing text | Deterministic messages, errors, confirmations, labels, and notifications. | i18n.sqlite |
Instance language; English; Italian; finally <missing:KEY>. |
| Input lexicon | Natural forms and mappings used to recognize intents and parameters in a request. | detection.sqlite, initialized from the runtime registry. |
Union of the current language with Italian and English; gaps are reported and queued. |
Every caller passes an explicit language code to the prompt loader. When an
approved file is absent, the loader can use a candidate from
_pending; when that candidate is also absent, it falls back to
English. A candidate does not replace an approved file that already exists:
for an existing language, the candidate must be reviewed and promoted.
The planner consists of a core, relevant sections, and a footer. If the instance language lacks the core, the whole planner falls back to English. If the core exists but one section is missing, that section can fall back to its English counterpart.
[description]
it = "Cerca file per nome, percorso e intervallo temporale."
en = "Find files by name, path, and time window."
[args.properties.patterns.description]
it = "Nomi o espressioni da cercare."
en = "Names or patterns to find."
affinity = ["cerca", "trova", "find", "search", "files"]
The loader reads these tables directly from the manifest. It does not import
descriptions into the message database. affinity is not a table
per language either: it is one mixed list of signals, because it supports
semantic routing and is not displayed to the user. The
manifest.lang_state.json file stores the hashes needed for
alignment; it does not replace the manifest's content.
Deterministic text is looked up by key in the i18n database. The
needs_translation field describes work still owed by the
translator; if a row already contains non-empty text, that text remains
usable.
The input lexicon is separate from visible text. For a new language, common phrases and mappings can be translated with assistance; regular expressions must still be authored and checked manually. When native forms are absent, Metnos continues to recognize Italian and English forms, while explicitly reporting that the target language is not fully covered.
For actions, surfaces and semantic boundaries are no longer an IT/EN table
embedded in the renderer. The versioned vocab.action_surfaces
mapping feeds recognition, while VOCAB_ACTION_*_BOUNDARY i18n keys
feed prompts. Coverage requires every canonical identity, non-empty forms, and
native boundaries; any polysemy that needs review is reported separately.
A model tends to follow the language of its instructions, but this is not a guarantee. Response language must therefore not depend on prompt language alone.
Metnos passes both the turn's language code and its readable name to prompt templates. Prompts that produce visible prose, including the final assembler, describers, and Tutor, explicitly request output in that language. An English fallback prompt can therefore still request a French answer. If the code has no registered readable name, the model receives the code itself: the turn may work, but behavior is less reliable and the language is not ready for release.
If a prompt is written in the wrong language and does not state the output language, the model may indeed answer in the prompt's language. Checks must therefore cover both conditions: the correct template was selected, and the target response language was stated explicitly. Deterministic messages do not depend on model behavior; they always follow the i18n database's fallback chain.
Prompts, manifest descriptions, and messages record a fingerprint of the current text and of the source version from which each translation was produced. When one language is edited, that version becomes the source for realigning the others.
| Resource | How a change is detected | Result |
|---|---|---|
| Prompt | Content-hash comparison; file time is used only to resolve concurrent edits. | A new candidate is written to the target language's _pending directory. |
| Manifest description | Hash comparison for every field and language. | The manifest table is updated and the manifest is signed again. |
| i18n message | Text version and row update time. | Other languages that are no longer aligned are queued for translation. |
Comparison and selection of resources are deterministic; the model is used only to produce candidate wording. A translation remains generated content that requires review, not automatic evidence of linguistic correctness.
Edit one language of a resource at a time before running alignment. For prompts, concurrent edits are resolved by file time. In a manifest, all languages share one file, so a conflict is resolved alphabetically. Do not rely on either rule to reconcile two divergent corrections.
The input lexicon follows a separate cycle: it is queued by language and verified through a coverage check. It does not participate in source selection for the other three areas.
The following command bootstraps a language; it does not declare that
language supported. Run it from the runtime directory with the
Metnos installation's Python environment:
cd <installation-directory>/runtime
../.venv/bin/python -m admin.prompts_cli add-language fr --source-lang=it
The command performs three immediate operations:
runtime/prompts/fr/ and its _pending directory;It does not immediately translate manifests, complete the input lexicon, add the code to the supported-language registries, or change the instance default.
vocab.LANGS and add the language's
readable name to the registries used by the prompt loader and translators.
Check the vocabulary sections that expose their own language-specific
forms as well.
../deploy/run_prompts_translator.sh
../.venv/bin/python cli/detection_cli.py enqueue fr
../.venv/bin/python cli/detection_cli.py translate
Repeat translation until the actionable queue is empty; author and verify
any pending regular expressions manually.
../.venv/bin/python -m admin.prompts_cli sync-status
../.venv/bin/python -m admin.prompts_cli review <role> --lang=fr
../.venv/bin/python -m admin.prompts_cli mark-synced <role> --lang=fr
METNOS_LANG remains only the
bootstrap value when no signed request exists yet.
Run the following commands from
<installation-directory>/runtime with
../.venv/bin/python.
| Command | What it checks |
|---|---|
../.venv/bin/python -m admin.prompts_cli validate | Template syntax and loading invariants. |
../.venv/bin/python -m admin.prompts_cli lint --strict | Prompt structure, metadata, and symmetry. |
../.venv/bin/python -m admin.prompts_cli validate-cross-lang | Placeholders, syntax, and proportions across language versions. |
../.venv/bin/python -m admin.i18n_cli stats | Row counts and translations still pending. |
../.venv/bin/python -m admin.i18n_cli pending | Catalog rows that still require translation. |
../.venv/bin/python -m admin.i18n_cli validate --verbose | Completeness for languages registered in vocab.LANGS. |
../.venv/bin/python cli/detection_cli.py coverage fr | Native coverage of the input lexicon. |
Every visible string in the chat, dialogs, approval requests, and Settings pages must come from the i18n catalog. A sentence written directly in a template or JavaScript violates this contract even when it happens to match the installation's default language.