Skip to content

Commit ab72cba

Browse files
committed
chore(i18n): enforce pot sync in hooks and CI
1 parent 778c776 commit ab72cba

3 files changed

Lines changed: 111 additions & 0 deletions

File tree

.githooks/pre-commit

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ mapfile -t po_files < <(
1111
grep -E '^i18n/.+\.po$' || true
1212
)
1313

14+
mapfile -t i18n_sync_trigger_files < <(
15+
git diff --cached --name-only --diff-filter=ACMR |
16+
grep -E '^src/.*\.(c|cc|cpp|cxx|h|hh|hpp|hxx)$|^i18n/opengothicstarter\.pot$' || true
17+
)
18+
1419
if [ "${#files[@]}" -gt 0 ]; then
1520
./scripts/format.sh "${files[@]}"
1621
git add "${files[@]}"
@@ -21,3 +26,7 @@ fi
2126
if [ "${#po_files[@]}" -gt 0 ]; then
2227
./scripts/check_i18n.sh "${po_files[@]}"
2328
fi
29+
30+
if [ "${#i18n_sync_trigger_files[@]}" -gt 0 ]; then
31+
./scripts/check_pot_sync.sh
32+
fi

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ jobs:
5757
- name: Validate localization catalogs
5858
run: ./scripts/check_i18n.sh
5959

60+
- name: Validate POT template sync
61+
run: ./scripts/check_pot_sync.sh
62+
6063
tidy:
6164
needs: [format, i18n]
6265
runs-on: ubuntu-24.04

scripts/check_pot_sync.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
pot_file="i18n/opengothicstarter.pot"
5+
6+
if ! command -v xgettext >/dev/null 2>&1; then
7+
echo "xgettext is required to validate ${pot_file}." >&2
8+
exit 1
9+
fi
10+
11+
if ! command -v msgcat >/dev/null 2>&1; then
12+
echo "msgcat is required to validate ${pot_file}." >&2
13+
exit 1
14+
fi
15+
16+
if [ ! -f "${pot_file}" ]; then
17+
echo "Expected POT file not found: ${pot_file}" >&2
18+
exit 1
19+
fi
20+
21+
mapfile -t source_files < <(find src -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.cxx' -o -name '*.h' -o -name '*.hh' -o -name '*.hpp' -o -name '*.hxx' \) | sort)
22+
23+
if [ "${#source_files[@]}" -eq 0 ]; then
24+
echo "No source files found under src/."
25+
exit 0
26+
fi
27+
28+
expected_tmp=$(mktemp)
29+
current_tmp=$(mktemp)
30+
expected_normalized_tmp=$(mktemp)
31+
current_normalized_tmp=$(mktemp)
32+
cleanup() {
33+
rm -f "${expected_tmp}" "${current_tmp}" "${expected_normalized_tmp}" "${current_normalized_tmp}"
34+
}
35+
trap cleanup EXIT
36+
37+
xgettext \
38+
--from-code=UTF-8 \
39+
--language=C++ \
40+
--keyword=_ \
41+
--omit-header \
42+
--no-location \
43+
-o "${expected_tmp}" \
44+
"${source_files[@]}"
45+
46+
msgcat --sort-output --no-location -o "${expected_tmp}" "${expected_tmp}"
47+
msgcat --sort-output --no-location -o "${current_tmp}" "${pot_file}"
48+
49+
strip_header_entry() {
50+
local input_file="$1"
51+
local output_file="$2"
52+
awk '
53+
BEGIN { skipping_preamble = 1; skipping_header = 0; }
54+
{
55+
if (skipping_preamble) {
56+
if ($0 ~ /^#/ || $0 == "") {
57+
next;
58+
}
59+
60+
if ($0 ~ /^msgid ""$/) {
61+
skipping_preamble = 0;
62+
skipping_header = 1;
63+
next;
64+
}
65+
66+
skipping_preamble = 0;
67+
}
68+
69+
if (skipping_header) {
70+
if ($0 == "") {
71+
skipping_header = 0;
72+
}
73+
next;
74+
}
75+
76+
if ($0 ~ /^#/) {
77+
next;
78+
}
79+
80+
if ($0 ~ /^msgid ""$/) {
81+
skipping_header = 1;
82+
next;
83+
}
84+
85+
print;
86+
}' "${input_file}" > "${output_file}"
87+
}
88+
89+
strip_header_entry "${expected_tmp}" "${expected_normalized_tmp}"
90+
strip_header_entry "${current_tmp}" "${current_normalized_tmp}"
91+
92+
if ! diff -u "${current_normalized_tmp}" "${expected_normalized_tmp}" >/dev/null; then
93+
echo "${pot_file} is out of sync with translatable source strings." >&2
94+
echo "Regenerate ${pot_file} from current sources before committing." >&2
95+
diff -u "${current_normalized_tmp}" "${expected_normalized_tmp}" || true
96+
exit 1
97+
fi
98+
99+
echo "POT template is in sync with source strings."

0 commit comments

Comments
 (0)