Localization (L10n)

Excusez-nous — cette page est actuellement disponible en anglais uniquement.

La traduction française n'est pas encore prête. Le contenu ci-dessous est la version anglaise la plus récente.

Track translation coverage across Ren’Py tl/ directories and run a full XLSX round-trip workflow: export untranslated strings, translate them externally, validate, and apply back to your project.

What Localization Coverage answers

  • What percent of each locale’s strings are translated right now?
  • Which strings are missing, stale, or orphaned?
  • Are there placeholder mismatches or drift issues to review before applying a batch?
  • Did a translation batch improve coverage, and by how much?

Typical workflows

  • Coverage check only: Run bpy l10n audit to get current numbers — nothing is written.
  • Full round-trip: Audit → Export → Translate (spreadsheet or translator) → Import & Validate → Review Preview Panel → Apply → Re-audit.
  • Safe validation pass: Run bpy l10n import <file> --validate-only to inspect a workbook without touching any project files.

How to run (VS Code)

  1. Open the Control Center and scroll to the Localization section.
  2. Click Export Translations to XLSX — a save dialog opens; a toast follows with “Open File” / “Copy Path”.
  3. Edit the workbook in Excel (fill the translation column; add notes if needed).
  4. Click Import & Validate Translations (XLSX) — a file picker opens, validation runs, and the Import Preview Panel opens.
  5. Review the summary bar and any red (rejected) or amber (warning) rows, then click Apply.

Localization panel in the Control Center

Run via CLI

Coverage audit

bpy l10n audit --project path/to/game

Sample output:

Locale Coverage Report
──────────────────────────────────────────────────
  french         112 / 148  (75.7%)  ██████████████░░░░░░
  italian         67 / 148  (45.3%)  █████████░░░░░░░░░░░
  spanish-latin    0 / 148   ( 0.0%)  ░░░░░░░░░░░░░░░░░░░░
──────────────────────────────────────────────────
Run `bpy l10n trend` for history.

Add --format json --output report.json to write a machine-readable report for CI.

Export to XLSX

bpy l10n export --project path/to/game --output translations.xlsx --json-summary

Export a single locale or filter by status:

bpy l10n export --project path/to/game --locale fr --status missing --output fr_missing.xlsx

Exported XLSX workbook open in Excel

Validate a workbook (no writes)

bpy l10n import translations.xlsx --project path/to/game --validate-only --json-summary

Exit code 0 = clean, 1 = has rejections, 10 = error. Safe to run in CI or before handing off to a reviewer.

Apply translations

bpy l10n import translations.xlsx --project path/to/game --apply --json-summary

Preview what would be written without touching files:

bpy l10n import translations.xlsx --project path/to/game --apply --dry-run

Sample --json-summary output after apply:

{
  "applied": 58,
  "skipped": 3,
  "locale_coverage_delta": {
    "french":  [75.7, 92.1],
    "italian": [45.3, 61.2]
  }
}

The XLSX workbook

Column Editable? Purpose
locale No Locale identifier (fr, italian, …)
key No Round-trip anchor — do not edit
source_text No Source string at export time
translation Yes Fill in the translated string here
status No missing / translated / orphaned
source_file No Relative .rpy path
context No Label or screen name, if resolvable
source_hash No Drift-detection hash — do not edit
notes Yes Free-text translator notes (not written to project)

For multi-locale workbooks, filter the locale column in Excel to work on one language at a time. The notes column is not preserved across exports — archive the XLSX to retain notes between sessions.

Import validation codes

Code Outcome When it triggers
MALFORMED_ROW Rejection key or locale is empty
INVALID_LOCALE Rejection locale is not a recognised identifier
PLACEHOLDER_MISMATCH Rejection Translation is missing source placeholders
DUPLICATE_KEY Rejection Same (locale, key) appears more than once
UNKNOWN_LOCALE Skip Locale not present in project tl/ dirs
UNKNOWN_KEY Skip (locale, key) does not exist in project index
SOURCE_DRIFT Warning source_hash no longer matches current project
EMPTY_TRANSLATION Warning Translation cell is empty for a missing-status row

Rejection rows are always blocked from apply. Skip rows are silently omitted (stale export or new locale). Warning rows proceed to apply but may need translator review.

The Import Preview Panel

After Import & Validate completes, the panel shows:

  • Summary bar — 6 count cards: total rows, to update, to create, warnings, rejected, skipped.
  • Rows to Update / Create — collapsible by locale; shows source text, translation, and warning badges.
  • Rejected Rows — red-highlighted; rejection code with full detail on hover.
  • Warnings — amber-highlighted rows; warning code shown inline.
  • Apply button — disabled with a 🔒 label when any rejected rows exist; a confirmation modal appears if warnings are present.

Import Preview Panel — summary bar and locale groups

Import Preview Panel — rejected and warned rows

After a successful apply, a toast shows per-locale coverage deltas:

✅ L10n apply complete  |  French: 75% → 92%  |  Italian: 45% → 61%  |  View Report

Apply rules

  • Backup first: every apply creates .branchpy/l10n/backups/apply_<YYYYMMDD_HHMMSS>/ before writing.
  • Atomic per file: writes to each .rpy file are accumulated in memory, then committed atomically via write-to-temp + replace.
  • SOURCE_DRIFT rows: auto-skipped in CI / VS Code; use --accept-drift or --skip-drift to override.
  • Dry-run: --dry-run runs the full apply logic and reports what would change without writing any files.

When to re-run audit

  • After applying a translation batch to confirm new coverage numbers.
  • Before a release to set a baseline in version control.
  • In CI via bpy l10n audit --format json --output l10n_report.json after each merge.

Learn more: Localization feature overview