Files
Piperless/tools/sync-translations.sh
T
2026-05-11 21:57:24 +02:00

109 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# sync-translations.sh — Generate / update per-locale JSON translation files
# from the master translations.json.
#
# Usage:
# ./tools/sync-translations.sh [locale...]
#
# With no arguments: syncs all known locales.
# With one or more locale codes: syncs only those (e.g. de_DE fr_FR).
#
# The master file (languages/translations.json) keys on the original English
# string. Each locale file gets a _meta block and a "strings" object.
# Existing translations are preserved; new keys from master are added with
# empty values. Removed keys are dropped.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
LANG_DIR="${PROJECT_DIR}/languages"
MASTER="${LANG_DIR}/translations.json"
# ── Known target locales ──────────────────────────────────────────────
DEFAULT_LOCALES=("de_DE" "fr_FR" "es_ES" "ja" "nl_NL")
if [[ $# -gt 0 ]]; then
LOCALES=("$@")
else
LOCALES=("${DEFAULT_LOCALES[@]}")
fi
# ── Validate master ───────────────────────────────────────────────────
if [[ ! -f "$MASTER" ]]; then
echo "Error: master translations.json not found. Run pot2json.sh first." >&2
exit 1
fi
if ! command -v jq &>/dev/null; then
echo "Error: jq is required. Install with: sudo apt install jq" >&2
exit 1
fi
TODAY=$(date +%Y-%m-%d)
# ── Count keys in master ──────────────────────────────────────────────
MASTER_COUNT=$(jq 'keys | length' "$MASTER")
for LOCALE in "${LOCALES[@]}"; do
LOCALE_FILE="${LANG_DIR}/piperless-${LOCALE}.json"
if [[ -f "$LOCALE_FILE" ]]; then
# ── Merge: keep existing translations, add new keys, drop removed ──
OLD_TRANSLATED=$(jq '._meta.translated // 0' "$LOCALE_FILE")
OLD_LOCKED=$(jq '._meta.locked // false' "$LOCALE_FILE")
# Build a new strings object: for every key in master, use the
# existing translation if present; otherwise empty string.
jq -n --slurpfile master "$MASTER" --slurpfile local "$LOCALE_FILE" '
($local[0].strings // {}) as $existing |
{
_meta: {
locale: "'"$LOCALE"'",
source: "translations.json",
generated: "'"$TODAY"'",
total_strings: ($master[0] | keys | length),
translated: 0,
locked: '"$OLD_LOCKED"'
},
strings: ($master[0] | to_entries | map({
key: .key,
value: ($existing[.key] // "")
}) | from_entries)
}
' > "${LOCALE_FILE}.tmp"
# Re-count translated (non-empty values).
NEW_TRANSLATED=$(jq '[.strings[] | select(. != "")] | length' "${LOCALE_FILE}.tmp")
jq --argjson t "$NEW_TRANSLATED" '._meta.translated = $t' "${LOCALE_FILE}.tmp" > "$LOCALE_FILE"
rm -f "${LOCALE_FILE}.tmp"
echo "Updated ${LOCALE}: ${NEW_TRANSLATED} / ${MASTER_COUNT} translated (was ${OLD_TRANSLATED})"
else
# ── Create new locale file ─────────────────────────────────────
jq -n --slurpfile master "$MASTER" '
{
_meta: {
locale: "'"$LOCALE"'",
source: "translations.json",
generated: "'"$TODAY"'",
total_strings: ($master[0] | keys | length),
translated: 0,
locked: false
},
strings: ($master[0] | to_entries | map({
key: .key,
value: .value
}) | from_entries)
}
' > "$LOCALE_FILE"
echo "Created ${LOCALE}: 0 / ${MASTER_COUNT} translated"
fi
done
echo ""
echo "Done. Locale files in ${LANG_DIR}/"