# How the OpenLogi Crowdin i18n Workflow Maintains Key Parity During Locale Synchronization

> Learn how the OpenLogi Crowdin i18n workflow ensures perfect key parity by preserving all English source keys during locale synchronization. Understand the snapshot-download-merge pipeline.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-08-26

---

**The OpenLogi repository guarantees perfect key parity across all locale files by implementing a snapshot-download-merge pipeline that preserves every key from the English source ([`en.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/en.yml)) regardless of the completeness of Crowdin's export.**

The OpenLogi project manages its internationalization (i18n) infrastructure through a robust Crowdin i18n workflow that ensures `crates/openlogi-ui/locales/*.yml` files never drift from the canonical English key set. This system handles sparse or incomplete Crowdin exports by treating the English source as the single source of truth and overlaying only validated translations.

## The Three-Step Key Parity Pipeline

The workflow operates as a deterministic pipeline that runs in the CI environment defined in [`.github/workflows/crowdin.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/.github/workflows/crowdin.yml). Each step is designed to prevent key loss during the synchronization process.

### Step 1: Snapshot Current Catalogs

Before contacting Crowdin, the CI job creates a complete backup of the existing locale files. The workflow copies the current contents of `crates/openlogi-ui/locales/*.yml` into a temporary directory (e.g., `/tmp/before`). As documented in [`docs/DEVELOPMENT.md`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/DEVELOPMENT.md) (lines 40-43), this snapshot represents the *complete* set of keys that must remain present after the merge, protecting against sparse downloads that might omit certain keys.

### Step 2: Download Sparse Translations

The workflow configures Crowdin to export only translations that have actually changed by enabling `skip_untranslated_strings`. According to [`docs/DEVELOPMENT.md`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/DEVELOPMENT.md) (lines 32-34), this export may be sparse—missing keys entirely—or may contain untranslated strings that simply echo the English key (e.g., `"Key": "Key"`). This optimization reduces bandwidth but creates a structural risk that the subsequent merge step must resolve.

### Step 3: Merge with Parity Enforcement

The Python script [`merge_crowdin_download.py`](https://github.com/AprilNEA/OpenLogi/blob/main/merge_crowdin_download.py) reconciles the snapshot (`before`) with the newly downloaded files (`after`). The script performs three critical operations to enforce parity:

- **Preserves the canonical key order** (`en_order`) from [`crates/openlogi-ui/locales/en.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ui/locales/en.yml), ensuring every locale file contains exactly the same keys as the English source.
- **Retains headers and metadata**, keeping original header lines and `_version` fields or injecting default headers if missing (lines 66-97).
- **Selectively applies translations**, replacing a key's value **only** when the Crowdin value differs from the English source, effectively ignoring untranslated fallback strings (lines 98-107).

```bash
python .github/scripts/i18n/merge_crowdin_download.py \
  --before /tmp/before \
  --locales crates/openlogi-ui/locales \
  --en crates/openlogi-ui/locales/en.yml

```

The script outputs a summary indicating successful parity maintenance, such as:

```

fr.yml: applied 3 Crowdin improvement(s); kept 42 keys for parity

```

## Configuration and Source Files

The integrity of the Crowdin i18n workflow depends on several configuration artifacts:

- **[`.config/crowdin.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/.config/crowdin.yml)** – Defines the Crowdin project settings, source locale (`en`), and file path patterns for the translation bundles.
- **[`.github/workflows/crowdin.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/.github/workflows/crowdin.yml)** – Orchestrates the snapshot, upload, download, and merge phases in CI.
- **[`docs/DEVELOPMENT.md`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/DEVELOPMENT.md)** – Documents the parity guarantees and workflow steps, including the requirement that a `crowdin/i18n` pull request is created only when at least one non-English value actually improved (lines 24-28).

## Summary

- The OpenLogi Crowdin i18n workflow uses a **snapshot-download-merge** strategy to prevent key loss during locale synchronization.
- The **[`merge_crowdin_download.py`](https://github.com/AprilNEA/OpenLogi/blob/main/merge_crowdin_download.py)** script enforces parity by overlaying Crowdin changes onto the full English key structure without ever removing keys.
- Sparse exports from Crowdin are handled safely because the merge process references **[`en.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/en.yml)** as the canonical key list, ensuring every locale file maintains 1:1 key parity with the source.
- The CI validates structural integrity before opening pull requests, preventing incomplete translation files from entering the repository.

## Frequently Asked Questions

### What happens if Crowdin returns a file with missing keys?

The merge script resolves this by using the pre-download snapshot as the base structure. Since the script reads [`en.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/en.yml) to establish the canonical key order (`en_order`), it regenerates any missing keys in the final output, ensuring no keys are lost even when Crowdin omits them from the export.

### How does the workflow handle untranslated strings that export as English duplicates?

The Python merging logic explicitly compares values against the English source. According to lines 98-107 in [`merge_crowdin_download.py`](https://github.com/AprilNEA/OpenLogi/blob/main/merge_crowdin_download.py), a key's value is replaced **only** when the Crowdin value differs from the English source. This prevents untranslated placeholder strings (where `"Key": "Key"`) from overwriting existing valid translations.

### Which file defines the canonical set of keys for the parity check?

The **[`crates/openlogi-ui/locales/en.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ui/locales/en.yml)** file serves as the single source of truth for the entire i18n system. The merge script uses this file to determine the `en_order`, and the CI pipeline validates that every locale file contains exactly the keys present in this English source.

### Where is the Crowdin CLI configuration stored?

The Crowdin project configuration resides in **[`.config/crowdin.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/.config/crowdin.yml)**, which specifies source locale settings and file patterns. The CI workflow defined in [`.github/workflows/crowdin.yml`](https://github.com/AprilNEA/OpenLogi/blob/main/.github/workflows/crowdin.yml) consumes this configuration during the upload and download phases to ensure consistent file mapping.