mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
ci(crowdin): convert Android escaping to Compose escaping during the sync
Both entries in crowdin.yml are declared `type: android`, so Crowdin's Android serializer escapes apostrophes on the way down: `l'URL` comes back as `l\'URL`. That is right for amethyst/src/main/res/, which aapt un-escapes at build time, and wrong for commons/.../composeResources/, where Compose resolves only \uXXXX, \n and \t and leaves \' \" \? \@ alone -- so the backslash reaches the screen. Nothing prevented this, so every sync reopened the same regression and CI's compose_escaping_check.py failed on the bot's own PR. It happened three times (f9baab0e,1685d7c0,e223d505), most recently 2,888 occurrences across 40 locale files, each time repaired by hand after the fact. Convert on the way in instead, so the PR is born clean. Two steps, placed after the ownership fix (the Crowdin container writes as root, so the tree is not writable before it) and before the PR is opened: - Convert: runs the documented repair over the Compose catalog only, so the Android res tree keeps the escaping it needs. --no-unwrap-quotes is mandatory -- escape conversion is idempotent, quote-unwrapping is not, and a second unwrap would strip the real display quotes from values like import_follows_tips. - Verify: re-runs the check that guards main, so a case the converter cannot repair fails the sync loudly here instead of opening a red PR. Verified by replaying both steps against the real Crowdin output on l10n_crowdin_translations (df930817): the check reproduces the failure at 2,888 occurrences, the convert step fixes 1,996 entries across 40 files, the verify step then exits 0, amethyst/src/main/res/ is left untouched, and the resulting catalog is byte-identical to main -- so with this in place that sync would have carried no string changes at all. Known gap, documented inline on the verify step: fix_escapes.py only rewrites text inside <string>/<item> elements while the check scans the whole file, so an escape in an XML comment (comments do propagate into the locale files) would fail the gate without the converter being able to repair it. No such comment exists today; it has to be fixed at the source string by hand if one ever appears. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVrW3p8NGWHgLbN673Fet2
This commit is contained in:
@@ -50,6 +50,35 @@ jobs:
|
||||
- name: Fix ownership after Crowdin Docker action
|
||||
run: sudo chown -R "$(id -u):$(id -g)" "$GITHUB_WORKSPACE"
|
||||
|
||||
# Both files in crowdin.yml are declared `type: android`, so Crowdin's Android
|
||||
# serializer escapes apostrophes on the way down: `l'URL` comes back as `l\'URL`.
|
||||
# That is correct for amethyst/src/main/res/, which aapt un-escapes at build time,
|
||||
# and WRONG for commons/.../composeResources/, where Compose resolves only \uXXXX,
|
||||
# \n and \t and leaves \' \" \? \@ alone -- so the backslash reaches the screen.
|
||||
#
|
||||
# Without this step every sync reopens the same regression and CI's
|
||||
# compose_escaping_check.py fails on the bot's own PR. It happened three times
|
||||
# (f9baab0e, 1685d7c0, e223d505 -- 2,888 occurrences across 40 locales the last
|
||||
# time) before this step existed. Convert on the way in, so the PR is born clean.
|
||||
#
|
||||
# Only the Compose catalog is passed in; the Android res tree keeps its escaping.
|
||||
# --no-unwrap-quotes is mandatory here: escape conversion is idempotent but
|
||||
# quote-unwrapping is not, and a second unwrap would strip the real display quotes
|
||||
# from values like import_follows_tips.
|
||||
- name: Convert Android escaping to Compose escaping in the shared catalog
|
||||
run: |
|
||||
python3 tools/strings-migrate/fix_escapes.py --no-unwrap-quotes \
|
||||
commons/src/commonMain/composeResources
|
||||
|
||||
# Assert the conversion actually satisfied the check that guards main, so a case
|
||||
# the converter cannot repair fails the sync loudly here instead of opening a red
|
||||
# PR. Known gap if this ever trips: fix_escapes.py only rewrites text inside
|
||||
# <string>/<item> elements, while the check scans the whole file -- an escape in an
|
||||
# XML comment (comments do propagate into the locale files) has to be fixed at the
|
||||
# source string in commons/.../composeResources/values/strings.xml by hand.
|
||||
- name: Verify the shared catalog is free of Android-only escaping
|
||||
run: .claude/hooks/compose_escaping_check.py
|
||||
|
||||
# Keep docs/changelog/translators.json seeded with everyone who has translated
|
||||
# recently, so the per-release `## Translations` credits (scripts/translators.sh)
|
||||
# can resolve them to npubs. Only adds rows when a genuinely new contributor
|
||||
|
||||
Reference in New Issue
Block a user