Files
clash-proxy/docs/CONTRIBUTING_i18n.md
2025-11-05 16:40:23 +08:00

5.5 KiB
Raw Blame History

CONTRIBUTING — i18n

Thank you for considering contributing to our localization work — your help is appreciated.

Quick workflow

  • Start small: fix typos, improve phrasing, or refine tone and consistency.
  • Use scripts/cleanup-unused-i18n.mjs (see below) to keep locale files aligned and free of dead keys.
  • Prefer incremental PRs or draft PRs; leave a comment on the issue if you want guidance.
  • Open an issue to report missing strings, UI context, or localization bugs.
  • Add or improve docs and tests to make future contributions easier.

Locale maintenance script

The repository ships with scripts/cleanup-unused-i18n.mjs, a TypeScript-aware analyzer that:

  • Scans src/ and src-tauri/ for t("...") usages (including dynamic prefixes) to identify which locale keys are referenced.
  • Reports unused keys per locale and optionally removes them.
  • Compares every locale against the baseline (default: en.json) to produce missing/extra key lists.
  • Aligns locale structure/order with the baseline so diffs stay predictable.
  • Emits optional JSON reports for CI or manual review.

Typical commands

# Dry-run audit (recommended before opening a PR)
pnpm node scripts/cleanup-unused-i18n.mjs

# Apply removals and align to the baseline structure (same as pnpm format:i18n)
pnpm node scripts/cleanup-unused-i18n.mjs --apply --align

# Generate a machine-readable report
pnpm node scripts/cleanup-unused-i18n.mjs --report ./i18n-report.json

Shorthand task runner aliases:

  • pnpm format:i18nnode scripts/cleanup-unused-i18n.mjs --align --apply
  • pnpm node scripts/cleanup-unused-i18n.mjs -- --help — view all flags (--baseline, --src, --keep-extra, --no-backup, --report, --apply, --align).
  1. Run the script in dry-run mode to review unused/missing key output.
  2. Apply removals/alignment locally if your changes introduce new keys or delete UI.
  3. Inspect .bak backups (created by default) when applying changes to confirm nothing important disappeared.
  4. For dynamic key patterns, add explicit references or update the whitelist if the script misidentifies usage.

PR checklist

  • Keep JSON files UTF-8 encoded.
  • Follow the repos locale file structure and naming conventions.
  • Run pnpm format:i18n to align with the baseline file for minimal diffs.
  • Test translations in a local dev build before opening a PR.
  • Reference related issues and explain any context for translations or changes.

Notes

  • The script expects simple top-level JSON key/value maps in each locale file.
  • .bak snapshots are created automatically when applying fixes; remove them once you confirm the changes.
  • Alignment keeps key order stable across locales, which makes reviews easier.

Locale Key Structure Guidelines

The locale files now follow a two-namespace layout designed to mirror the React/Rust feature tree:

  • shared.* — cross-cutting vocabulary (buttons, statuses, validation hints, window chrome, etc.).
    • Buckets to prefer: actions, labels, statuses, messages, placeholders, units, validation, window, editorModes.
  • Add to shared only when the copy is used (or is expected to be reused) by two or more features. Otherwise keep it in the owning feature namespace.
  • <feature>.* — route-level or domain-level strings scoped to a single feature.
    • Top-level keys mirror folders under src/pages, src/components, or service domains (settings, proxies, profiles, home, unlock, layout, …).
    • Within a feature namespace, prefer consistent buckets like page, sections, forms, fields, actions, tooltips, notifications, errors, dialogs, tables, components. Choose the minimum depth needed to describe the UI.

Authoring guidelines

  1. Follow the shared/feature split — before inventing a new key, check whether an equivalent exists under shared.*.
  2. Use camelCase leaf keys — keep names semantic (systemProxy, updateInterval) and avoid positional names (item1, btn_ok).
  3. Group by UI responsibility — for example:
    • settings.dns.fields.listen
    • settings.dns.dialog.title
    • settings.dns.sections.general
  4. Component-specific copy — nest under components.<ComponentName> or dialogs.<DialogName> to keep implementation-specific strings organized but still discoverable.
  5. Dynamic placeholders — continue using {{placeholder}} syntax and document required params in code when possible.

Minimal example

{
  "shared": {
    "actions": {
      "save": "Save",
      "cancel": "Cancel"
    }
  },
  "profiles": {
    "page": {
      "title": "Profiles",
      "actions": {
        "import": "Import",
        "updateAll": "Update All Profiles"
      },
      "notifications": {
        "importSuccess": "Profile imported successfully"
      }
    },
    "components": {
      "batchDialog": {
        "title": "Batch Operations",
        "items": "items"
      }
    }
  }
}

Whenever you need a common verb or label, reference shared.* directly in the code (shared.actions.save, shared.labels.name, …) instead of duplicating the copy in a feature namespace.

Feedback & Contributions

  • For tool usage issues or feedback: please open an Issue in this repository so it can be tracked and addressed.
  • For localization contributions (translations, fixes, context notes, etc.): submit a PR or Issue in this repository and include examples, context, and testing instructions when possible.
  • If you need help or a review, leave a comment on your submission requesting assistance.