Skip to content

Talk to Transifex's API instead of using tx - #84

Merged
hatstand merged 1 commit into
mainfrom
claude/project-thread-l6fkzp
Nov 8, 2026
Merged

hatstand merged 1 commit into
mainfrom
claude/project-thread-l6fkzp

Conversation

@hatstand

@hatstand hatstand commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Requested by John · project thread

Since 8 November, every run of the translations workflow has failed with failed to download translation, both the nightly pull and the push, which pulls first. Transifex stopped making the String Catalog's translation files once the catalog had a string with substitutions (a plural of one of its numbers, here "Downloading %lld of %lld songs…") that nobody had translated yet. Asked directly, the API gives the reason that tx leaves out:

[{"code": "parse_error", "detail": "'NoneType' object is not iterable"}]

Every download mode fails like this except onlytranslated. The pull used onlyreviewed as well.

What changes

scripts/transifex.py replaces tx, .tx/config, pull-transifex-translations.sh and merge-transifex-translations.py:

  • pull asks for each language's translations as data (/resource_translations with their resource_strings) rather than as files, and builds each catalog entry from them, substitutions included. Transifex keeps a substitution as a string of its own, <key>.substitutions.<name>, and writes a . in a key as \.. One pass takes reviewed and unreviewed translations alike, which used to take two downloads. The placeholder check and the Xcode-style formatting are unchanged. A pull also lists any catalog strings Transifex doesn't have yet.
  • push-source and push-translations upload the catalog as tx push did, wait for Transifex to process it, and print Transifex's errors if it refuses.

The scripts run with uv. A new Python CI job, which the CI check now requires, runs ruff, ty and pytest with the same settings as the Android remote. import-android-translations.py is removed: it was the one-off import from before the app was on Transifex, and running it now would overwrite Transifex's translations.

Testing

  • 14 unit tests cover plain, plural and substitution strings, partly translated substitutions, placeholder mismatches, key escaping and paging.
  • Run against Transifex from this branch, the pull changed only the 7 translations made since the last successful pull (el 3, es 1, sv 3), and found every catalog string on Transifex. A test push-source sent the two strings that were missing because of the failures. Afterwards Transifex's per-language counts still matched the catalog.

Once this merges, the push it triggers pulls those 7 translations and pushes the catalog. The nightly pull then commits them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01R2bAq7fKGbJyhCgNr9zbNH

@hatstand hatstand self-assigned this Nov 8, 2026
@hatstand
hatstand force-pushed the claude/project-thread-l6fkzp branch 6 times, most recently from 11bda99 to 3fb73a7 Compare November 8, 2026 17:49
Transifex stopped making the String Catalog's translation files once the
catalog had a string with substitutions (a plural of one of its numbers,
here "Downloading %lld of %lld songs…") that wasn't translated yet: every
download mode but onlytranslated fails with a parse_error, "'NoneType'
object is not iterable", which tx doesn't show. So every pull failed, and
with it every push, which pulls first.

scripts/transifex.py replaces tx and the shell and merge scripts. Its
pull reads each language's translations from the API as data, with their
strings, and puts each catalog entry together itself, substitutions
included: Transifex keeps a substitution as a string of its own,
"<key>.substitutions.<name>", and writes a "." in a key as "\.". One
pass takes reviewed and unreviewed translations alike, which needed two
downloads before. The placeholder check and the catalog's formatting are
as before, and a pull lists the catalog's strings Transifex doesn't have
yet. push-source and push-translations upload the catalog as tx did, and
print Transifex's errors when it refuses one.

Run against Transifex, the pull changes only the 7 translations made since
the last one. The scripts run with uv, and a Python job in CI checks them
with ruff, ty and pytest, as in the Android remote. Also removes
import-android-translations.py, the one-off import from before the app
was on Transifex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R2bAq7fKGbJyhCgNr9zbNH
@hatstand
hatstand force-pushed the claude/project-thread-l6fkzp branch from 3fb73a7 to 0e71c14 Compare November 8, 2026 17:50
@hatstand hatstand changed the title Show why Transifex couldn't make a translations file Talk to Transifex's API instead of using tx Nov 8, 2026
@hatstand
hatstand enabled auto-merge (rebase) November 8, 2026 17:52
@hatstand
hatstand merged commit 32c2e09 into main Nov 8, 2026
4 checks passed
@hatstand
hatstand deleted the claude/project-thread-l6fkzp branch November 8, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants