Skip to content

POLPROG-TECH/LocaleSync

LocaleSync

Detect, validate, synchronize, and auto-translate missing entries in locale JSON files.

Python 3.12+ License: AGPL-3.0 CI Commands


What is LocaleSync?

LocaleSync is a Python CLI tool that keeps your i18n locale files in sync. It scans a directory of JSON translation files, detects missing keys, and fills them — optionally translating values into the correct target language automatically.

Teams maintaining en.json, pl.json, de.json, etc. no longer need to manually track which keys are missing where. Run locale-sync check in CI to catch drift early, or locale-sync translate to auto-fill gaps with real translations. Works with any project type — Angular, React, Vue, Node.js, or plain static sites.

  • Scan — discover locale files in any directory
  • Check — validate completeness, fail CI if keys are missing
  • Sync — fill missing keys with English source text (for manual translation later)
  • Translate — fill missing keys and translate values via Google Translate
  • Safe — atomic writes, dry-run mode, backup support, stable sorted output
  • Extensible — architecture supports custom translation providers, reporters, and file formats

Screenshots

Overview Dashboard

Aggregated metrics at a glance — total keys, completeness percentage, missing and empty values, warnings, and namespace completeness bars with pagination.

LocaleSync — overview dashboard with metrics and namespace completeness

Translations Table

Browse, search, and filter all translation keys across locales. Inline editing, status tracking, review workflow, and namespace grouping — with 1,000+ entries handled smoothly.

LocaleSync — translations table with search, filters, and review status

Export Wizard

Export translations to JSON or CSV with full control — choose structure (nested/flat), pretty-print, indentation, and key sorting. Live preview updates as you configure.

LocaleSync — export wizard with JSON and CSV format options

Auto-Translation in Progress

CLI-powered batch translation via Google Translate — real-time progress bar, ETA, per-language counters, and placeholder-safe output.

LocaleSync — CLI auto-translation with progress bar and language counter


Table of Contents


Quick Start

Web server (primary)

pip install -e ".[dev]"

# Start the interactive dashboard
locale-sync serve ./locales
# → Dashboard at http://127.0.0.1:8083

Corporate network (Zscaler / VPN)? If pip install fails with SSL errors or translation fails, see Corporate Network setup below.

CLI

locale-sync scan ./locales                # Discover locale files
locale-sync check ./locales               # Validate (exit code 1 if incomplete)
locale-sync sync ./locales                # Fill missing keys (copies English text)
locale-sync translate ./locales           # Fill missing keys AND translate to target language

sync vs translate: sync adds missing keys with English source text (for manual translation later). translate adds missing keys and translates them into Polish, German, French, etc.


Web Server Mode

The web server provides a FastAPI-powered interactive dashboard with Jinja2 SSR, real-time progress via Server-Sent Events, and a REST API for programmatic access.

Dashboard features

The interactive dashboard includes:

  • Overview — aggregate statistics, locale completeness, readiness grades
  • Translations — browse, filter, search, and inline-edit all translation entries
  • Quality — placeholder validation, orphan/duplicate key detection, length warnings, release-readiness matrix
  • Compare — side-by-side locale comparison with inline translation and copy tools
  • Import Wizard — 4-step guided import flow: upload → validate → review merge plan → apply
  • Export Wizard — 3-step guided export flow: configure format → select scope → preview & download
  • Internationalization — full UI localization in English and Polish, switchable at runtime

Starting the server

locale-sync serve [DIRECTORY] [OPTIONS]
Option Default Description
DIRECTORY . Directory containing locale files
--source / -s en Source locale
--host 127.0.0.1 Bind address
--port / -p 8083 Bind port
--verbose / -v Enable debug logging

The dashboard provides an overview of all locale files with completeness metrics, readiness scoring (A–F grades), and one-click scan/check/sync/translate operations with real-time progress streaming.

App factory

For programmatic embedding or ASGI deployment:

from locale_sync.web.server import create_app

app = create_app(config, root_path="/locale-sync")

API Endpoints

The server exposes 15 routes covering health monitoring, dashboard rendering, locale operations, import/export, and configuration.

Health & Status

  • GET /health/live — liveness probe
  • GET /health/ready — readiness probe
  • GET /api/status — version, uptime, and operation state

Dashboard — interactive HTML dashboard at /, raw HTML export via /api/dashboard/html, fresh JSON data via /api/dashboard/data.

Operations — trigger scan, check, sync, and translate via POST /api/{operation}. Long-running operations stream progress via SSE at GET /api/operations/stream.

Import/Export — validate uploaded files (POST /api/import/validate), compute merge plans (POST /api/import/plan), execute imports (POST /api/import/execute). Export via client-side generation with server-assisted planning.

Configuration — view and update working directory and source locale at runtime via GET/PUT /api/config.


Installation

Requirements: Python 3.12+

Method Command Best for
From source pip install -e ".[dev]" Contributing to LocaleSync
From GitHub pip install git+https://github.com/polprog-tech/LocaleSync.git CI pipelines, direct use
Via pipx pipx install git+https://github.com/polprog-tech/LocaleSync.git Developer machines (isolated CLI)
Pinned version pip install git+https://github.com/polprog-tech/LocaleSync.git@v1.1.0 Reproducible CI builds

From source (for contributors)

git clone https://github.com/polprog-tech/LocaleSync.git
cd LocaleSync
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
locale-sync --version

Why pip install -e ".[dev]" works: The repository root contains a PEP 621 pyproject.toml with a complete package definition. The [dev] extra includes pytest, pytest-cov, and ruff. The -e flag enables editable mode.

For non-Python projects (Angular, React, Node, etc.)

Use pipx for an isolated system-wide install — no virtual environment needed:

pipx install git+https://github.com/polprog-tech/LocaleSync.git
locale-sync --version

See Cross-Project Usage for npm integration and CI setup.

Corporate Network (Zscaler / VPN / Proxy)

If you're behind a corporate proxy that intercepts HTTPS (e.g. Zscaler, Netskope), you need to export the corporate CA bundle before installing dependencies or using the translate command.

macOS / Linux
# 1. Export corporate CA certificates (macOS)
security find-certificate -a -p \
  /Library/Keychains/System.keychain \
  /System/Library/Keychains/SystemRootCertificates.keychain \
  > ~/combined-ca-bundle.pem

# On Linux, the CA bundle is usually already available:
#   /etc/ssl/certs/ca-certificates.crt          (Debian/Ubuntu)
#   /etc/pki/tls/certs/ca-bundle.crt            (RHEL/Fedora)
# If your proxy adds its own CA, ask your IT department for the .pem file
# and append it: cat corporate-ca.pem >> ~/combined-ca-bundle.pem

# 2. Configure SSL trust (add to ~/.zshrc or ~/.bashrc to persist)
export SSL_CERT_FILE=~/combined-ca-bundle.pem
export REQUESTS_CA_BUNDLE=~/combined-ca-bundle.pem

# 3. Install and use
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
locale-sync sync --source en --translate --target de,fr locales/
Windows (PowerShell)
# 1. Export corporate CA certificate
# Ask your IT department for the corporate CA .pem file, or export it from
# certmgr.msc → Trusted Root Certification Authorities → Certificates
# Right-click → All Tasks → Export → Base-64 encoded X.509 (.CER)
# Save as: %USERPROFILE%\corporate-ca-bundle.pem

# 2. Configure SSL trust (add to your PowerShell profile to persist)
$env:SSL_CERT_FILE = "$env:USERPROFILE\corporate-ca-bundle.pem"
$env:REQUESTS_CA_BUNDLE = "$env:USERPROFILE\corporate-ca-bundle.pem"

# 3. Install and use
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
locale-sync sync --source en --translate --target de,fr locales/

Tip: To make permanent: [System.Environment]::SetEnvironmentVariable("SSL_CERT_FILE", "$env:USERPROFILE\corporate-ca-bundle.pem", "User")


Commands

scan — Discover locale files

locale-sync scan ./locales
locale-sync scan ./locales --format json
locale-sync scan                          # auto-discovers locale directories from CWD

If the specified directory doesn't exist or contains no locale files, LocaleSync automatically searches subdirectories to find locale file groups. Files are recognized as locale files only if their name matches a valid locale code pattern (e.g., en.json, pl.json, zh-Hans.json). Non-locale JSON files like manifest.json or package.json are ignored.

check — Validate locale completeness

locale-sync check ./locales
locale-sync check ./locales --source en.json
locale-sync check ./locales --target pl.json --target de.json
locale-sync check ./locales --format json

sync — Fill missing keys (English text, no translation)

locale-sync sync ./locales
locale-sync sync ./locales --strategy fill_empty
locale-sync sync ./locales --strategy force_overwrite
locale-sync sync ./locales --dry-run
locale-sync sync ./locales --backup
locale-sync sync ./locales --sort-keys       # always sort alphabetically
locale-sync sync ./locales --no-sort-keys    # never sort, new keys at end
locale-sync sync ./locales --indent 4

By default, key ordering is automatic: files with ≤200 keys are sorted alphabetically, larger files preserve insertion order with new keys appended at the end. Use --sort-keys or --no-sort-keys to override.

translate — Fill and translate missing keys into target language

locale-sync translate ./locales
locale-sync translate ./locales --provider demo
locale-sync translate ./locales --dry-run
locale-sync translate ./locales --strategy fill_empty

Uses Google Translate by default. A built-in DemoTranslator is available for offline/testing use (--provider demo). Phrases the demo translator can't handle fall back to source text.

locale-sync translate ./locales                     # Google Translate (default)
locale-sync translate ./locales --provider demo     # Offline dictionary (5 languages)
locale-sync translate ./locales --dry-run           # Preview without writing

sync vs translate:

sync translate
Adds missing keys
Translates values ❌ (copies English) ✅ (language-specific)
Preserves existing

All commands accept --source, --target, --format, and --verbose flags. Run locale-sync <command> --help for full details.


Update Strategies

Strategy Behavior
fill_missing Only add keys that don't exist in target (default — safe)
fill_empty Add missing keys AND fill empty string values
force_overwrite Overwrite all values from source — use with caution

Key Features

Nested JSON support

Fully supports deeply nested locale structures. Keys are compared as dot-paths internally (auth.login.title) and reconstructed as nested JSON on write.

{
  "auth": {
    "login": { "title": "Sign In", "subtitle": "Welcome back" },
    "logout": "Sign Out"
  }
}

Placeholder safety

Preserves placeholders during translation: {name}, {{count}}, ${value}, %s, %d, {0}. Dedicated detection, protection, restoration, and validation pipeline.

Dry run

Preview all changes without modifying files:

locale-sync sync ./locales --dry-run

Safe writes

Atomic file writes (temp file + os.replace), optional .bak backups, UTF-8 encoding with human-readable non-ASCII output.

Stable diffs

Consistent formatting produces minimal, predictable diffs — ideal for PR review workflows. Small files (≤200 keys) are sorted by default; large files preserve order to avoid noisy diffs.


CI/CD Integration

LocaleSync is fully non-interactive when invoked with CLI arguments: no prompts, deterministic output, meaningful exit codes.

Exit codes

Code Meaning
0 Success — all locale files are complete
1 Validation failure — missing keys detected
2 Input error — bad path, malformed JSON, missing source
3 Runtime error — unexpected failure

GitHub Actions

- uses: actions/setup-python@v5
  with:
    python-version: '3.12'
- run: pip install git+https://github.com/polprog-tech/LocaleSync.git
- run: locale-sync check ./locales --source en.json

For full CI workflow examples, see docs/usage.md and docs/integration.md.


Cross-Project Usage

LocaleSync works with any repository that has JSON locale files. It makes no assumptions about the surrounding project structure, framework, or build system.

Angular / Node.js — package.json scripts

{
  "scripts": {
    "locales:check": "locale-sync check src/assets/i18n --source en.json",
    "locales:sync": "locale-sync sync src/assets/i18n --source en.json",
    "locales:translate": "locale-sync translate src/assets/i18n --source en.json",
    "locales:sync:preview": "locale-sync sync src/assets/i18n --source en.json --dry-run"
  }
}

React — package.json scripts

{
  "scripts": {
    "locales:check": "locale-sync check public/locales",
    "locales:sync": "locale-sync sync public/locales",
    "locales:translate": "locale-sync translate public/locales",
    "locales:scan": "locale-sync scan public/locales"
  }
}
npm run locales:check
npm run locales:translate

LocaleSync is not an npm package. These scripts invoke it as an external CLI command. Install it separately via pip or pipx before running npm scripts.

CI for non-Python projects

# GitHub Actions — works in any repository
- uses: actions/setup-python@v5
  with:
    python-version: '3.12'
- run: pip install git+https://github.com/polprog-tech/LocaleSync.git
- run: locale-sync check src/assets/i18n --source en.json

Integration examples

The examples/ directory contains ready-to-use integration templates:

Example Description
examples/angular-project/ Angular app with package.json scripts and CI workflow
examples/react-project/ React app with react-i18next, package.json scripts, and CI workflow
examples/generic-project/ Generic non-Python project with Makefile and CI workflow
# Try them directly
locale-sync check examples/angular-project/src/assets/i18n --source en.json
locale-sync check examples/react-project/public/locales --source en.json
locale-sync check examples/generic-project/locales --source en.json

Full guides

Guide Covers
Cross-Project Integration Installation models, npm integration, standalone vs embedded, frontend team onboarding
Angular Guide Angular i18n setup, package.json scripts, CI workflows, team conventions
React Guide React i18next setup, package.json scripts, CI workflow, Vite/Next.js notes
Best Practices Design rationale, trade-offs, architectural decisions

Playground

The playground/ directory provides a hands-on demo environment with realistic locale files:

locale-sync scan playground/locales                # Discover 4 locale files
locale-sync check playground/locales               # Find missing keys across targets
locale-sync sync playground/locales --dry-run      # Preview sync changes (English fill)
locale-sync translate playground/locales --dry-run  # Preview translated output
locale-sync translate playground/locales            # Actually translate to pl/de/fr
bash playground/scripts/demo.sh                    # Run interactive demo
git checkout -- playground/locales/                # Reset after experimenting

Includes 4 locale files (en.json, pl.json, de.json, fr.json) with nested structures, placeholder patterns ({name}, {{count}}, ${amount}, %d), and varying completeness levels. The translate command fills missing keys with real language-specific translations — Polish in pl.json, German in de.json, French in fr.json.

See playground/README.md for full details.


OpsPortal Integration

LocaleSync integrates with OpsPortal as a managed web service:

  • Auto-started on port 8083 via locale-sync serve --port 8083
  • Health monitoring — OpsPortal polls GET /health/live
  • Embedded in the OpsPortal portal UI via iframe
  • Framing enabled automatically via LOCALESYNC_ALLOW_FRAMING=true

No additional configuration is needed — OpsPortal manages the lifecycle automatically.


Architecture

LocaleSync uses a four-layer architecture with strict separation of concerns:

src/locale_sync/
├── domain/          # Core models, contracts (Protocols), policies, comparator, placeholder
├── application/     # Use cases — scan, check, sync orchestration
├── infrastructure/  # File I/O, JSON parsing/writing, translators, reporters, i18n catalogs
├── web/             # FastAPI server, REST API, dashboard
└── cli/             # Typer commands, formatters, interactive prompts

Key design choices:

  • Protocol-based contracts — structural subtyping, no import dependencies between layers
  • Dependency injection — use cases accept any implementation satisfying the protocol
  • Strategy pattern — enum-backed update policies, no scattered conditionals
  • Decorator pattern — placeholder-aware translator wraps any translation provider
  • Atomic writes — temp file + os.replace for crash-safe file operations
  • Generic core — no project-type assumptions; Angular/React/Vue awareness lives only in documentation

See docs/architecture.md for the full architectural overview.


Project Structure

LocaleSync/
├── pyproject.toml                        # Package configuration (PEP 621)
├── Makefile                              # Convenience commands
├── README.md                             # This file
├── LICENSE                               # AGPL-3.0 license
├── CONTRIBUTING.md                       # Contributor guide
├── CODE_OF_CONDUCT.md                    # Community standards
├── .gitignore
│
├── .github/
│   ├── workflows/ci.yml                  # CI pipeline (test + lint)
│   ├── ISSUE_TEMPLATE/                   # Bug report, feature request
│   └── pull_request_template.md
│
├── src/locale_sync/                      # Source package
│   ├── domain/                           # Models, contracts, policies, exceptions
│   ├── application/                      # Use cases (scan, check, sync)
│   ├── infrastructure/                   # Parsers, writers, translators, reporters, i18n
│   ├── web/                              # FastAPI server, REST API, SSE, dashboard
│   └── cli/                              # Typer commands, formatters
│
├── tests/                                # pytest suite (900+ tests)
│   ├── unit/{domain,infrastructure,application,web}/
│   └── integration/
│
├── playground/                           # Demo environment with sample locales
│   ├── locales/                          # en.json, pl.json, de.json, fr.json
│   └── scripts/demo.sh
│
├── examples/                             # Integration examples
│   ├── angular-project/                  # Angular + package.json + CI
│   ├── react-project/                    # React + react-i18next + CI
│   └── generic-project/                  # Generic project + Makefile + CI
│
└── docs/                                 # Documentation
    ├── architecture.md                   # Layered architecture overview
    ├── usage.md                          # Detailed usage guide
    ├── extensibility.md                  # Adding translators, parsers, formats
    ├── testing.md                        # Test strategy and instructions
    ├── integration.md                    # Cross-project integration
    ├── angular-guide.md                  # Angular-specific guide
    ├── react-guide.md                    # React-specific guide
    └── best-practices.md                 # Design rationale

Development

Step-by-step setup (recommended)

git clone https://github.com/polprog-tech/LocaleSync.git
cd LocaleSync
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
locale-sync --version          # locale-sync 1.1.0
pytest                         # 900+ passed

One-command setup (convenience only)

make quickstart

⚠️ This shortcut may not work in every environment due to differences in shell, OS, Python installation, or local configuration. If it fails, use the step-by-step instructions above.

Common tasks

make test              # Run tests
make test-cov          # Run tests with coverage
make lint              # Run ruff linter
make format            # Auto-format code
make playground-demo   # Run interactive demo
make playground-reset  # Reset playground files
make clean             # Remove build artifacts
make help              # Show all available commands

Manual equivalents

pytest
pytest --cov=locale_sync --cov-report=term-missing
ruff check src/ tests/
ruff format src/ tests/

Pre-commit Hook

A pre-commit hook is provided that runs lint (with auto-fix), format check, and the full test suite before each commit:

cp scripts/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit

The hook will:

  1. Auto-fix lint issues on staged files (ruff check --fix)
  2. Check formatting — if issues are found, it auto-formats and exits so you can review and re-stage
  3. Run the test suite — commit is blocked if any test fails

See CONTRIBUTING.md for the full contributor guide.


Testing Philosophy

All tests follow the GIVEN / WHEN / THEN structure with explicit docstring markers:

def test_sync_fills_missing_keys(self, tmp_path: Path) -> None:
    """GIVEN source with keys, target missing some"""
    (tmp_path / "en.json").write_text('{"a": "A", "b": "B"}')
    (tmp_path / "pl.json").write_text('{"a": "X"}')

    """WHEN sync is executed"""
    self._make_use_case().execute(config)

    """THEN target contains both keys with existing value preserved"""
    pl = json.loads((tmp_path / "pl.json").read_text())
    assert pl["a"] == "X"
    assert pl["b"] == "B"

This structure is applied consistently across the entire test suite (900+ tests) to ensure:

  • Readability — any engineer can immediately understand what a test does.
  • Traceability — preconditions, actions, and expectations are explicitly separated.
  • Review quality — reviewers can validate each section independently.

See docs/testing.md for the full testing strategy.


Documentation

Document Description
Usage Guide Detailed command reference, source/target selection, output formats
Architecture Layer responsibilities, design decisions, extension points
Extensibility Adding translators, parsers, file formats, reporters
Testing Test strategy, running tests, writing new tests
Integration Cross-project usage, npm scripts, CI for non-Python repos
Troubleshooting SSL errors, corporate network, proxy, translation failures
Angular Guide Angular-specific setup, workflows, team conventions
React Guide React i18next setup, CI workflow, Vite/Next.js notes
Best Practices Design rationale, trade-offs, engineering decisions
Dashboard Web dashboard features, tabs, import/export wizards

Troubleshooting

For detailed solutions to common issues, see docs/troubleshooting.md.

Problem Quick Fix
SSL errors during translation or pip install Export corporate CA bundle: export SSL_CERT_FILE=~/combined-ca-bundle.pem — see Corporate Network setup
Translation fails with RequestError after retries Check internet, proxy settings, wait for rate-limit window
Port already in use lsof -i :8083 -t | xargs kill -9 or use --port 9083

Author

Created and maintained by POLPROG (@POLPROG).


License

AGPL-3.0 — see LICENSE