Files
clash-verge-rev/docs/CONTRIBUTING_i18n.md
Sline c8aa72186e chore: i18n (#5276)
* chore: notice i18n

* feat: add script to clean up unused i18n keys

* chore: cleanup i18n keys

* refactor(i18n/proxies): migrate proxies UI to structured locale keys

* chore: i18n for rule module

* chore: i18n for profile module

* chore: i18n for connections module

* chore: i18n for settings module

* chore: i18n for verge settings

* chore: i18n for theme settings

* chore: i18n for theme

* chore(i18n): components.home.*

* chore(i18n): remove unused i18n keys

* chore(i18n): components.profile.*

* chore(i18n): components.connection

* chore(i18n): pages.logs.*

* chore(i18n): pages.*.provider

* chore(i18n): components.settings.externalCors.*

* chore(i18n): components.settings.clash.*

* chore(i18n): components.settings.liteMode.*

* chore(i18n): components.settings.backup.*

* chore(i18n): components.settings.clash.port.*

* chore(i18n): components.settings.misc.*

* chore(i18n): components.settings.update.*

* chore(i18n): components.settings.sysproxy.*

* chore(i18n): components.settings.sysproxy.*

* chore(i18n): pages.profiles.notices/components.providers.notices

* refactor(notice): unify showNotice usage

* refactor(notice): add typed showNotice shortcuts, centralize defaults, and simplify subscriptions

* refactor: unify showNotice usage

* refactor(notice): unify showNotice API

* refactor(notice): unify showNotice usage

* chore(i18n): components.test.*

* chore(i18n): components.settings.dns.*

* chore(i18n): components.home.clashInfo.*

* chore(i18n): components.home.systemInfo.*

* chore(i18n): components.home.ipInfo/traffic.*

* chore(i18n): navigation.*

* refactor(i18n): remove pages.* namespace and migrate route texts under module-level page keys

* chore(i18n): common.*

* chore(i18n): common.*

* fix: change error handling in patch_profiles_config to return false when a switch is in progress

* fix: improve error handling in patch_profiles_config to prevent requests during profile switching

* fix: change error handling in patch_profiles_config to return false when a switch is in progress

fix: ensure CURRENT_SWITCHING_PROFILE is reset after config updates in perform_config_update and patch_profiles_config

* chore(i18n): restructure root-level locale keys into namespaces

* chore(i18n): add missing i18n keys

* docs: i18n guide

* chore: adjust i18n

* refactor(i18n): align UI actions and status labels with common keys

* refactor(i18n): unify two-name locale namespaces

* refactor(i18n/components): unify locale keys and update component references

* chore(i18n): add shared and entities namespaces to all locale files

* refactor(i18n): consolidate shared and entity namespaces across features

* chore(deps): update npm dependencies to ^7.3.5 (#5310)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* refactor(i18n): migrate shared editor modes and consolidate entities namespaces

* tmp

* refactor(i18n): flatten locales and move theme/validation strings

* docs: CONTRIBUTING_i18n.md

* refactor(i18n): restructure feedback and profile namespaces for better organization

* refactor(i18n): unify settings locale structure and update references

* refactor(i18n): reorganize locale keys for home, proxies, rules, connections, logs, unlock, and tests

* refactor(i18n/feedback/layout): unify shared toasts & normalize layout namespace

* refactor(i18n): centralize common UI strings in shared

* refactor(i18n): flatten headers and unify locale schema

* refactor(i18n): consolidate duplicate per-feature translations into shared namespace

* refactor(i18n): split locales into per-namespace files

* style: lint

* refactor(i18n): unify unlock UI translations under tests namespace

* feat(i18n): add type-checked translation keys

* style: eslint import order

* feat(i18n): replace ad-hoc loader with rust-i18n backend bundles

* chore(prebuild): remove locale-copy step

* fix(i18n, notice): propagate runtime params and update cleanup script path

* fix(i18n,notice): make locale formatting idempotent and guard early notice translations

* fix(i18n): resolve locale aliases and match OS codes correctly

* fix(unlock): use i18next-compatible double-brace interpolation in failure notice

* fix(i18n): route unlock error notices through translation keys

* fix(i18n): i18n types

* feat(i18n): localize upgrade notice for Clash core viewer

* fix(notice): ensure runtime overrides apply to prefix translations

* chore(i18n): replace literal notices with translation keys

* chore(i18n): types

* chore(i18n): regen typings before formatting to keep keys in sync

* chore(i18n): simply labels

* chore(i18n): adjust translation

* chore: remove eslint-plugin-i18next

* chore(i18n): add/refine Korean translations across frontend scopes and Rust backend (#5341)

* chore(i18n): translate settings.json (missed in previous pass) (#5343)

* chore(i18n): add/refine Korean translations across frontend scopes and Rust backend

* chore(i18n): add/refine Korean translations across frontend scopes and Rust backend

* fix(i18n-tauri): quote placeholder-leading value in ko.yml to prevent rust_i18n parse panic

* chore(i18n): translate settings.json (forgot to include previously)

---------

Co-authored-by: rozan <34974262+thelojan@users.noreply.github.com>
2025-11-08 19:40:38 +08:00

5.4 KiB
Raw Blame History

CONTRIBUTING — i18n

Thanks for helping localize Clash Verge Rev. This guide reflects the current architecture, where the React frontend and the Tauri backend keep their translation bundles separate. Follow the steps below to keep both sides in sync without stepping on each other.

Quick workflow

  • Update the language folder under src/locales/<lang>/; use src/locales/en/ as the canonical reference for keys and intent.
  • Run pnpm format:i18n to align structure and pnpm i18n:types to refresh generated typings.
  • If you touch backend copy, edit the matching YAML file in src-tauri/locales/<lang>.yml.
  • Preview UI changes with pnpm dev (desktop shell) or pnpm web:dev (web only).
  • Keep PRs focused and add screenshots whenever layout could be affected by text length.

Frontend locale structure

Each locale folder mirrors the namespaces under src/locales/en/:

src/locales/
  en/
    connections.json
    home.json
    shared.json
    ...
    index.ts
  zh/
    ...
  • JSON files map to namespaces (for example home.jsonhome.*). Keep keys scoped to the file they belong to.
  • shared.json stores reusable vocabulary (buttons, validations, etc.); feature-specific wording should live in the relevant namespace.
  • index.ts re-exports a resources object that aggregates the namespace JSON files. When adding or removing namespaces, mirror the pattern from src/locales/en/index.ts.
  • Frontend bundles are lazy-loaded by src/services/i18n.ts. Only languages listed in supportedLanguages are fetched at runtime, so append new codes there when you add a locale.

Because backend translations now live in their own directory, you no longer need to run pnpm prebuild just to sync locales—the frontend folder is the sole source of truth for web bundles.

Tooling for frontend contributors

  • pnpm format:i18nnode scripts/cleanup-unused-i18n.mjs --align --apply. It aligns key ordering, removes unused entries, and keeps all locales in lock-step with English.
  • pnpm node scripts/cleanup-unused-i18n.mjs (without flags) performs a dry-run audit. Use it to inspect missing or extra keys before committing.
  • pnpm i18n:types regenerates src/types/generated/i18n-keys.ts and src/types/generated/i18n-resources.ts, ensuring TypeScript catches invalid key usage.
  • For dynamic keys that the analyzer cannot statically detect, add explicit references in code or update the script whitelist to avoid false positives.

Backend (Tauri) locale bundles

Native UI strings (tray menu, notifications, dialogs) use rust-i18n with YAML bundles stored in src-tauri/locales/<lang>.yml. These files are completely independent from the frontend JSON modules.

  • Keep en.yml semantically aligned with the Simplified Chinese baseline (zh.yml). Other locales may temporarily copy English if no translation is available yet.
  • When a backend feature introduces new strings, update every YAML file to keep the key set consistent. Missing keys fall back to the default language (zh), so catching gaps early avoids mixed-language output.
  • Rust code resolves the active language through src-tauri/src/utils/i18n.rs. No additional build step is required after editing YAML files; tauri dev and tauri build pick them up automatically.

Adding a new language

  1. Duplicate src/locales/en/ into src/locales/<new-lang>/ and translate the JSON files while preserving key structure.
  2. Update the locales index.ts to import every namespace. Matching the English file is the easiest way to avoid missing exports.
  3. Append the language code to supportedLanguages in src/services/i18n.ts.
  4. If the backend should expose the language, create src-tauri/locales/<new-lang>.yml and translate the keys used in existing YAML files.
  5. Adjust crowdin.yml if the locale requires a special mapping for Crowdin.
  6. Run pnpm format:i18n, pnpm i18n:types, and (optionally) pnpm node scripts/cleanup-unused-i18n.mjs in dry-run mode to confirm structure.

Authoring guidelines

  • Reuse shared vocabulary before introducing new phrases—check shared.json for common actions, statuses, and labels.
  • Prefer semantic keys (systemProxy, updateInterval, autoRefresh) over positional ones (item1, dialogTitle2).
  • Document placeholders using {{placeholder}} and ensure components supply the required values.
  • Group keys by UI responsibility inside each namespace (page, sections, forms, actions, tooltips, notifications, errors, tables, statuses, etc.).
  • Keep strings concise to avoid layout issues. If a translation needs more context, leave a PR note so reviewers can verify the UI.

Testing & QA

  • Launch the desktop shell with pnpm dev (or pnpm web:dev) and navigate through the affected views to confirm translations load and layouts behave.
  • Run pnpm test if you touched code that consumes translations or adjusts formatting logic.
  • For backend changes, trigger the relevant tray actions or notifications to verify the updated copy.
  • Note any remaining untranslated sections or layout concerns in your PR description so maintainers can follow up.

Feedback & support

  • File an issue for missing context, tooling bugs, or localization gaps so we can track them.
  • PRs that touch UI should include screenshots or GIFs whenever text length may affect layout.
  • Mention the commands you ran (formatting, type generation, tests) in the PR checklist. If you need extra context or review help, request it via a PR comment.