← Documentation index Architecture guide › multilingual operation

Metnos

Language per user, prompts, and visible text
Architecture guide

Ask Metnos with a request like this example: “Which language is set for my account, and where can I change it?”

The instance administrator can change it in the web chat by opening Settings > System > Users > user name > Preferences, then selecting the lang field. A user's detail page is served at /admin/users/<user-id>. If the question is asked from Telegram, the path still belongs to the Metnos web chat; it is not a path inside Telegram.

Language is a preference of each user and is applied to one request at a time. Two users can use different languages concurrently without changing the instance-wide configuration or affecting one another.

Contents

  1. The multilingual contract
  2. How Metnos selects a request's language
  3. The four areas that must stay aligned
  4. Prompt language and response language
  5. Translation alignment
  6. Adding a language
  7. Checks and administrative tools

1. The multilingual contract

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:

2. How Metnos selects a request's language

In the web chat, the server identifies the authenticated user and reads that user's lang preference. Telegram resolves the same value through the channel-to-user binding. Recurring work performed on behalf of a person also applies its owner's language.

Metnos places the value in a context local to that request. The context remains isolated while several turns run in parallel: setting English for one user changes neither another user's language nor the process-wide default.

SourceValue usedScope
lang preferenceLanguage of the authenticated user or the user bound to the channel.One request or turn.
METNOS_LANGInstance fallback when the user has no valid preference.Process; cached on first use.
Built-in defaultit, when METNOS_LANG is also absent.Instance.

The values offered by the lang field do not come from a list written into the page. They are derived from the languages present in i18n.sqlite. Consequently, bootstrapping a new language can make it selectable before every translation is complete. Fallbacks keep the service usable, but the administrator should not offer that language to users before completing the checks described below.

3. The four areas that must stay aligned

AreaContentRuntime sourceFallback
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. Request language; English; first available language in deterministic order.
User-facing text Deterministic messages, errors, confirmations, labels, and notifications. i18n.sqlite Request 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.

Model prompts

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 requested 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.

Executor manifests

[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.

Visible text and the input lexicon

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.

4. Prompt language and response language

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.

5. Translation alignment

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.

ResourceHow a change is detectedResult
PromptContent-hash comparison; file time is used only to resolve concurrent edits.A new candidate is written to the target language's _pending directory.
Manifest descriptionHash comparison for every field and language.The manifest table is updated and the manifest is signed again.
i18n messageText 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.

6. Adding a language

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:

  1. creates runtime/prompts/fr/ and its _pending directory;
  2. creates pending French rows in the i18n database from the source language's keys;
  3. records the operation in the installation's multilingual audit log when possible.

It does not immediately translate manifests, complete the input lexicon, add the code to the supported-language registries, or change the instance default.

Release procedure

  1. Register the code in 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.
  2. Run the alignment process for prompts, manifest descriptions, and messages:
    ../deploy/run_prompts_translator.sh
  3. Prepare the target language's input lexicon and translate the forms that can be assisted:
    ../.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.
  4. Inspect every prompt candidate and promote only valid wording:
    ../.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
  5. Verify syntax, symmetry, placeholders, the database, and input-lexicon coverage with the commands in the next chapter.
  6. Perform human language review and functional tests in the web chat, dialogs, approvals, Settings, Telegram, and recurring work. Test two users with different languages at the same time. A right-to-left language also requires visual checks of direction, control order, and layout.
  7. Only then offer the language to users. The lang field derives its values from the i18n catalog automatically; the page has no separate allow-list to edit. Setting METNOS_LANG is optional and changes only the instance fallback, not individual preferences.

7. Checks and administrative tools

Run the following commands from <installation-directory>/runtime with ../.venv/bin/python.

CommandWhat it checks
../.venv/bin/python -m admin.prompts_cli validateTemplate syntax and loading invariants.
../.venv/bin/python -m admin.prompts_cli lint --strictPrompt structure, metadata, and symmetry.
../.venv/bin/python -m admin.prompts_cli validate-cross-langPlaceholders, syntax, and proportions across language versions.
../.venv/bin/python -m admin.i18n_cli statsRow counts and translations still pending.
../.venv/bin/python -m admin.i18n_cli pendingCatalog rows that still require translation.
../.venv/bin/python -m admin.i18n_cli validate --verboseCompleteness for languages registered in vocab.LANGS.
../.venv/bin/python cli/detection_cli.py coverage frNative 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.

Related documents