Localization
The Flutter client and CLI support English (en), Simplified Chinese (zh),
Japanese (ja), German (de), and French (fr). English is the fallback.
Chinese system variants resolve to the Simplified Chinese translation.
Flutter
mobile/l10n.yaml configures Flutter's official localization generator. Add
messages to mobile/lib/l10n/app_en.arb and translate the same keys in the other
four ARB files. Use descriptive keys and named placeholders for entire messages;
use ICU plurals when counts change the wording. Declare placeholder types in
the English template. Run flutter gen-l10n after editing resources.
Widgets obtain strings through context.l10n. The library state refreshes its
localization reference in didChangeDependencies, allowing asynchronous
operations to use strings without retaining a BuildContext across awaits.
flutter_localizations supplies Material/Cupertino labels and intl formats
dates and counts. Keep English first in preferred-supported-locales so unknown
system languages have a deterministic fallback. iOS declares supported languages
in Runner/Info.plist.
The language menu is available before unlock. SharedPreferences stores only
the non-secret language preference; system removes that preference. A failed
save leaves the existing selection in place and displays a localized error.
Language changes do not recreate the backend or alter the unlocked session.
With no saved preference, system language changes update both the interface and
font fallback while the app is running. A saved choice stays fixed until changed
or reset to the system default.
Local errors are translated when displayed, so an existing banner changes with
the language. Native errors use their stable codes for a translated fallback.
Do not translate protocol values, identifiers, URLs, account metadata, user
titles, bodies, tags, relationships, signed audit records, or secret values.
Protected previews must continue using the explicit field allowlist and fixed
masks in protected_cards.dart.
CLI
crates/cli/src/i18n.rs resolves the language before Clap renders help. Precedence:
--lang en|zh|ja|de|fr, supported at the top level and on subcommands.- Nonempty
MEMORIES_LANG. - The saved preference in the selected Memories home directory.
- The first nonempty
LC_ALL,LC_MESSAGES, orLANG. - Windows user locale, or English on other platforms without locale variables.
memories language zh # Save a language for subsequent commands
memories language # Show the saved choice and effective language
memories language system # Clear the choice and follow the system
The non-secret preference is saved as language.txt under --home /
MEMORIES_HOME (or the default memories data directory). Saving uses an atomic
file replacement. It works before initialization and without a running daemon.
No preference file is created just by detecting the system language. Missing,
unreadable, or invalid preferences fall back to the system; failed writes report
an error. Temporary --lang and MEMORIES_LANG overrides do not alter the file.
Locale variants such as ja_JP.UTF-8 normalize to their base language.
Unsupported environment/system languages fall back to English. Explicit invalid
--lang values are rejected by Clap. The initial scan stops at --, preserving
language-like arguments passed to captured programs.
UTF-8 catalogs in crates/cli/locales/ are embedded at compile time; installed
binaries do not need resource files alongside them. Catalog keys are the original
English messages. Keep both full and period-stripped variants of Clap doc
comments because short help removes the final period. Translate both short and
long help. Add a catalog entry for every new CLI-owned error and prompt.
Use i18n::format for named placeholders. Substitution processes the template
once, so user text containing braces cannot become another placeholder. Password
and secret capture still use hidden input. USE and APPROVE remain literal
confirmation tokens and must appear unchanged in their translated prompts.
JSON output keeps the existing version, field names, error codes, and exit status. Only human-facing messages are localized. Unmapped native/OS diagnostics retain their original text after a localized summary; Clap parsing diagnostics include a localized introduction and the original argument details. MCP schemas, tool names, and protocol messages remain stable and do not depend on CLI locale.
Validation
cargo test -p memories --locked
cd mobile
flutter gen-l10n
flutter analyze
flutter test
Rust tests cover all catalogs, help coverage, placeholder preservation, locale precedence, forwarded arguments, nested help, and localized errors with stable JSON fields. Flutter tests cover catalog parity, all five system locales, unsupported-locale fallback, preference persistence, session preservation, localized dialogs at phone widths, and masked protected-card previews.
On hosts with an HTTP proxy, exclude localhost, 127.0.0.1, and ::1 from the
proxy while running widget tests; Flutter's local test WebSocket must connect
directly. Device testing remains necessary to verify platform font fallback,
native file pickers, and OAuth browser UI, whose language is managed by the OS
or provider.