Translations
============

The Gridcoin project supports multiple localisations. For managing all
application translations, Gridcoin uses the
[Transifex](https://www.transifex.com/gridcoin/gridcoin/) online translation
management tool.

## Helping to translate (using Transifex)

Transifex monitors the GitHub repo for updates. When code containing new
translations is merged, Transifex picks up the changes (this may take several
hours). Translators work on the Transifex web interface; updated translations
are pulled back into the repo periodically by maintainers.

See the [Transifex Gridcoin project](https://www.transifex.com/gridcoin/gridcoin/)
to assist in translations.

## Writing code with translations

See [translation_strings_policy.md](translation_strings_policy.md) for
guidelines on marking strings as translatable.

Summary:

- **Qt GUI code**: use `tr("...")` (the Qt translation macro).
- **Non-GUI code** (init, RPC, validation, etc.): use `_("...")`.

## Translation update pipeline

A single script handles the entire update process:

```bash
./contrib/devtools/update-translations.sh
```

### What the script does

| Step | Action | Detail |
|------|--------|--------|
| 1 | **extract** | Runs `share/qt/extract_strings_qt.py` to extract `_("...")` strings from non-Qt source files into `src/qt/bitcoinstrings.cpp`. |
| 2 | **lupdate** | Runs Qt `lupdate` to scan all source code (`.cpp`, `.h`, `.ui`) and update `src/qt/locale/bitcoin_en.ts` with current translatable strings. |
| 3 | **tx-pull** | Pulls all translation files from Transifex (`tx pull --translations --force --all`). Files arrive in XLIFF (`.xlf`) format. |
| 4 | **postprocess** | Converts `.xlf` to Qt `.ts` format using `lconvert`, then sanitizes: removes invalid control characters, strips translations with broken format specifiers, drops languages with fewer than 10 translated messages. Uses `contrib/devtools/postprocess-translations.py` (derived from Bitcoin Core's [bitcoin-maintainer-tools](https://github.com/bitcoin-core/bitcoin-maintainer-tools)). |
| 5 | **lupdate** (again) | Re-runs `lupdate` to merge new source strings into the freshly-pulled translation files. |
| 6 | **update-build** | Regenerates `src/qt/bitcoin_locale.qrc` and the `TS_FILES` list in `src/qt/locale/CMakeLists.txt` to match the current set of `.ts` files. |
| 7 | **tx-push** | Pushes the updated `bitcoin_en.ts` source to Transifex via the REST API so translators can see new/changed strings. |
| 8 | **cleanup** | Removes temporary `.xlf` files and any Autotools artifacts generated by upstream `update-translations.py`. |

### Script modes

```bash
# Full pipeline (default) — all 8 steps
./contrib/devtools/update-translations.sh

# Local only — extract + lupdate, no network access needed
./contrib/devtools/update-translations.sh --no-transifex

# Individual steps
./contrib/devtools/update-translations.sh extract    # Step 1 only
./contrib/devtools/update-translations.sh lupdate    # Step 2 only
./contrib/devtools/update-translations.sh tx-pull    # Steps 3-6 + 8
./contrib/devtools/update-translations.sh tx-push    # Step 7 only
```

### Prerequisites

| Tool | Package | Purpose |
|------|---------|---------|
| `python3` | python3 | String extraction, post-processing |
| `xgettext` | gettext | Extracts `_("...")` strings |
| `lupdate` | qt6-l10n-tools | Scans source for `tr("...")` strings |
| `lconvert` | qt6-l10n-tools | Converts XLIFF to Qt TS format |
| `tx` | [Transifex CLI](https://github.com/transifex/cli) v1.x | Pulls/pushes translations |

The script auto-detects Qt tool names (`lupdate6`/`lupdate-qt6`/`lupdate`).

### Installing the Transifex CLI

Install the Go-based Transifex CLI v1.x (not the old Python `transifex-client`):

```bash
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
# Move binary to a permanent location:
mv ./tx ~/.local/bin/tx
```

### Transifex authentication

Create `~/.transifexrc` with your API token:

```ini
[https://www.transifex.com]
rest_hostname = https://rest.api.transifex.com
token         = YOUR_API_TOKEN
```

Generate a token at https://app.transifex.com/user/settings/api/.

### Post-processing script provenance

The post-processing step uses `contrib/devtools/postprocess-translations.py`,
which is derived from Bitcoin Core's
[bitcoin-maintainer-tools](https://github.com/bitcoin-core/bitcoin-maintainer-tools)
`update-translations.py`. The script is vendored in-repo so there are no
external dependencies beyond the tools listed above.

Gridcoin-specific changes from the upstream version:
- Self-contained with CLI argument parsing (no module-level globals)
- Auto-detects `lconvert` binary name (`lconvert-qt6`, `lconvert6`, `lconvert`)
- Removed Autotools `Makefile.qt_locale.include` generation
- Removed `ts_files.cmake` generation
- Configurable minimum message threshold (default: 10, upstream uses 120)

## Transifex configuration

The `.tx/config` file maps the Transifex resource to local files:

```ini
[o:gridcoin:p:gridcoin:r:src-qt-locale-bitcoin-en-ts--development]
file_filter = src/qt/locale/bitcoin_<lang>.xlf
source_file = src/qt/locale/bitcoin_en.xlf
source_lang = en
```

Note: The resource type on Transifex is QT (`.ts`), but the CLI uses XLIFF
(`.xlf`) as a wire format. The `lconvert` step in the pipeline handles the
conversion. Source pushes use the REST API with the `.ts` file directly
because `tx push --source` does not handle this format mismatch correctly.

## File overview

| File | Purpose |
|------|---------|
| `src/qt/locale/bitcoin_en.ts` | English source strings (master for all translations) |
| `src/qt/locale/bitcoin_*.ts` | Per-language translation files |
| `src/qt/bitcoinstrings.cpp` | Auto-generated: non-Qt `_("...")` strings wrapped in `QT_TRANSLATE_NOOP` |
| `src/qt/bitcoin_locale.qrc` | Qt resource file listing all compiled `.qm` translations |
| `src/qt/locale/CMakeLists.txt` | CMake translation build rules and `TS_FILES` list |
| `share/qt/extract_strings_qt.py` | Extracts non-Qt translatable strings |
| `contrib/devtools/update-translations.sh` | Complete translation update pipeline script |
| `contrib/devtools/postprocess-translations.py` | Sanitizes and converts Transifex translation files |
| `.tx/config` | Transifex CLI resource mapping |

## When to update translations

- **Before a release**: run the full pipeline to pick up any new translations.
- **After adding translatable strings**: run `--no-transifex` to update the
  English source, then push to Transifex so translators can work on it.
- **General PRs**: do not include translation file updates. These are done
  separately to avoid merge conflicts and to give translators time.

## Handling plurals (in source files)

When new plurals are added to the source file:

1. Open `bitcoin_en.ts` in Qt Linguist (included in the Qt SDK)
2. Search for `%n`, which will take you to the parts that use plurals
3. Look for empty `English Translation (Singular)` and `English Translation (Plural)` fields
4. Add the appropriate strings for the singular and plural forms
5. Mark the item as done (green arrow in the toolbar)
6. Save the source file

## Adding a new language

To add a new language:

1. Add the language on the Transifex project page
2. Run the full pipeline — the script will automatically:
   - Pull the new language file
   - Add it to `bitcoin_locale.qrc`
   - Add it to the `TS_FILES` list in `CMakeLists.txt`
3. Commit the result
