Skip to content

Write the store copy ahead of the release, and translate the app again - #593

Merged
andiwand merged 8 commits into
mainfrom
translate-the-app-and-write-the-store-copy
Aug 16, 2026
Merged

Write the store copy ahead of the release, and translate the app again#593
andiwand merged 8 commits into
mainfrom
translate-the-app-and-write-the-store-copy

Conversation

@andiwand

@andiwand andiwand commented Aug 16, 2026

Copy link
Copy Markdown
Member

The Android half of OpenDocument.ios#162. Same two problems, and one that repo did not have.

What was different here

The listing in this repository was behind the Play Console, not ahead of it. Play has been serving a full translation of the current English in all fifteen locales for some time; the copies checked in here were one or two generations older - six of them around 1700 characters against the console's 3500, Japanese and Chinese under 1000. Even the English had drifted by a line.

So skip_upload_metadata could not simply be turned off. Doing that would have pushed the old copies over fifteen locales of current translation. The first commit takes the live listing back into the repository unchanged, so the second one is a diff of what changes rather than of what was already true.

The store copy

scripts/store-copy.py v4.15.0 writes the "What's new" text for every locale before the release, instead of it being typed into the promotion box.

The English comes from the CHANGELOG.md section of that version, or from Unreleased while the heading is still open. Every other locale is translated by an agent of its own, given that locale's own description and the release before it, then read back by a second agent of the same language. Output is checked mechanically and a language that comes back wrong is retried, then named so it can be redone with --locales.

Play takes 500 characters where the App Store takes 4000, and that is the whole difference. 4.15.0's English was written at 497 and there is no translation of it that fits - German came back a fifth longer, French a quarter. The English is rewritten inside a 400-character budget, the check is hard at 500, and both prompts say so. The longest of the fifteen is French at 491.

scripts/store-listing.py owns the layout and stages what supply uploads. The release run checks before it builds, so a missing translation fails in seconds rather than after both bundles are up.

The app

No language had more than 44 of the 75 strings. German was missing 42 - the whole landing screen, every document action, all of the house ad, the unsaved-changes dialog, and OK and Cancel. Catalan had 15. Anything added after September 2023 was English everywhere, and that is most of what the app now shows.

Beyond the missing strings:

  • thirty of the sixty-six values- directories held nothing but <resources></resources>
  • Crowdin wrote values-de-rDE beside the older values-de and the two drifted, so which strings a user saw depended on their phone's region. All 43 Korean strings were in values-ko-rKR and values-ko was empty, so a Korean speaker outside Korea got an entirely English app.
  • every translated locale carried a dead toast_error_generic
  • crouton_remove_ads still offered to remove ads "via the menu" - it is a snackbar whose OK button makes the purchase, and there has been no menu since the options menu went

All nineteen languages are now complete, written by scripts/translate-app.py and each read back by a second agent of that language - over the whole file, not only the new strings, since a string translated three years ago beside one translated today is where the two stop agreeing on what "document" is called. Estonian and Swedish are translated for the first time, though the store has sold the app in both for years.

crowdin.yml is gone. Nothing came back from it after September 2023, and a source of translations that no longer delivers is worse than none: it says the gap is somebody else's to close.

The listing

Two things it claimed had stopped being true, in all fifteen languages: the app has had no file browser of its own since scoped storage, and ads have not been removable from a menu since there stopped being a menu. Each listing now also says plainly that a document is opened on the device and never uploaded - which is what the worst-rated review on the store says the app does, and it stopped being true of the app when the online loader went.

Title, and the two apps

fastlane/metadata/android is what both apps share; fastlane/metadata-pro and -lite hold the rest, read over it. Two things differ.

The title. Play has been serving OpenDocument Reader Pro in all fifteen storefronts already, and lite OpenDocument Reader - view ODT. The titles checked in here were never what Play showed, and eleven of the fifteen were 36 to 49 characters - written when the limit was 50 rather than today's 30, so supply would have refused every one of them.

Settled rather than guessed, and no longer translated:

title
Pro OpenDocument Reader Pro
Lite OpenDocument Reader

OpenDocument is the format's own name and one name is one app people can pass to each other. Nothing is lost to search - Play indexes the title, the short description and the full description alike, so LibreOffice and the local words live in the short description, which has 80 characters for them. app_title in strings.xml is marked untranslatable for the same reason.

Advertising. Pro links no ad SDK and shows none, but every description said ads were shown, in all fifteen languages, on both apps. The shared description holds ${ads} and each app fills it in from its own ads.txt - lite has fifteen, pro has none, and a fill-in nobody answers leaves nothing behind, the space in front of it included.

The listing is uploaded now

The release uploads the listing with the bundle: title, both descriptions and that version's release notes, per app, in fifteen locales. listingPro / listingLite send it without a bundle, which is how a typo is fixed - Play refuses a version code twice, so repairing words should not need a version to carry them.

Graphics are not uploaded. The four screenshots checked in here predate the 4.14 redesign, and sending them would put the old ones back over the current.

The first run overwrites what the console says for those fields, on both apps, in all fifteen locales. That is the point - the copy is written here now - but it is worth knowing before the run rather than after.

Checked

  • every values-*/strings.xml parses, holds all 75 keys in source order, none extra, apostrophes escaped
  • spotlessCheck, assembleDebug (all three flavors), lintProDebug and testProDebugUnitTest pass
  • every locale's release notes are four paragraphs, in the English's order, under Play's 500
  • every staged title is within 30 characters, every short description within 80, every description within 4000
  • both upload lanes run end to end locally as far as the credentials, each staging its own full listing for fifteen locales
  • staged side by side, Pro and Lite differ in exactly two files per locale: title.txt, and one sentence of full_description.txt
  • no ${...} survives staging, and no double space is left where one was filled in empty
  • the recovered en-US description round-trips against what Play serves, byte for byte apart from the one line the console had edited

The Play Store call itself needs the repository secrets, so the first real release run is its own proof.

🤖 Generated with Claude Code

andiwand and others added 7 commits August 16, 2026 11:20
Every listing but the English one in this repository was a translation of an
older, shorter English listing: six of the fifteen were around 1700 characters
against the 3500 the console serves, and the Japanese and Chinese ones under
1000. The console has had a full translation of the current English in all
fifteen locales for some time; none of it was ever written down here.

The English had drifted too, by one line: LibreOffice, OpenOffice and Libre
Office are no longer named in the list of office suites that use the format.

Nothing is reworded here. This is what play serves today, so that the next
commit is a diff of what changes rather than of what was already true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
The listing claimed two things that stopped being true. The app has no file
browser of its own since scoped storage - documents come through Android's own
picker - and ads have not been removable from a menu since there stopped being
a menu; that is a row in the settings on the landing screen now. Both are
corrected in all fifteen languages, and each listing now says plainly that a
document is opened on the device and never uploaded, which is the thing the
worst-rated review on the store says the app does.

fastlane/metadata/android is what pro and lite share. fastlane/metadata-pro and
-lite hold the rest, read over it. Two things differ: the title, and the
sentences about advertising, which pro has been carrying in every locale
without linking an ad SDK. That one sentence is a ${ads} in the shared
description rather than a second copy of it.

The title is no longer translated. Play has been serving OpenDocument Reader
Pro in all fifteen storefronts already, and the titles checked in here were
never what play showed: eleven of the fifteen were 36 to 49 characters, written
when the limit was 50 rather than today's 30, so supply would have refused
every one of them. LibreOffice and the local words live in the short
description, which play indexes just as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
The "What's new" text was typed into the play console at promotion and never
translated: only en-US was kept here, and play fell back to the listing's own
language everywhere else. scripts/store-copy.py now writes it from the
changelog, one agent per language and a second one of that language reading
each draft back, and scripts/store-listing.py checks a version has copy in
every locale and stages it for supply.

Play takes 500 characters where the App Store takes 4000, so the limit is the
interesting part. 4.15.0's English was written at 497 and no translation of it
fits - German came back a fifth longer and French a quarter. The English is
rewritten inside a 400 character budget, the check is hard at 500, and both
prompts say so; the longest of the fifteen is French at 491.

OpenDocument.ios has the same two scripts against App Store Connect's shape.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
Crowdin wrote values-de-rDE beside the older values-de and the two drifted, so
which strings a user saw depended on the region their phone was set to. Korean
was the sharp end of it: all 43 strings were in values-ko-rKR and values-ko was
empty, so a Korean speaker outside Korea got an entirely English app. Nothing
here differs by region, so the region qualifier is gone and values-de answers
for every German-speaking one.

Thirty of the sixty-six directories held nothing but <resources></resources> -
fifteen languages that shipped a file and no words. They are removed. Estonian
and Swedish are kept though they were two of them, because the play listing
sells the app in both.

crowdin.yml goes with them. Nothing has come back from it since September 2023,
which is before the redesign that added most of what is missing, and a source
of translations that no longer delivers is worse than none: it says the gap is
somebody else's to close.

app_title is marked untranslatable rather than left to fall back, for the same
reason the store title is not translated. crouton_remove_ads was still offering
to remove ads "via the menu"; it is a snackbar whose OK button makes the
purchase, and there has been no menu since the options menu went.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
No language had more than 44 of the 75 strings, and most had far fewer: German
was missing 42 of them - the whole landing screen, every document action, all
of the house ad, the unsaved-changes dialog, and OK and Cancel. Catalan had 15.
Whatever was added after September 2023, when the last translation arrived, was
English in every language, and that is most of what the app now shows.

All nineteen languages are complete. Estonian and Swedish are translated for
the first time, though the store has been selling the app in both for years.

scripts/translate-app.py writes them, one agent per language and a second one
of that language reading the whole file back - not only the new strings, since
a string translated three years ago beside one translated today is where the
two stop agreeing on what "document" is called. values/strings.xml is the
source: the keys it has, in its order, and nothing else, so a string that
leaves it leaves every translation with it. The values come back as plain text
and the escaping is put on here, so an agent cannot write an apostrophe that
stops the resources compiling.

OpenDocument.ios did the same for its .strings files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
supply was told to skip metadata, changelogs and images, so nothing under
fastlane/metadata ever reached play - the console was the only copy of the
listing and this repository held an older one. The release now uploads the
listing with the bundle, which is what makes the text checked in here the
text the store shows.

scripts/store-listing.py stages what goes up rather than supply being pointed
at fastlane/metadata directly: the two apps say almost the same thing, and the
places they differ have to be read over the shared text before either is sent.
The release run stages it a second time before it builds, so a locale missing
its notes stops the run in seconds.

listingPro and listingLite upload the listing without a bundle, for a typo or
a locale that came out wrong - play refuses a version code twice, so repairing
the words should not need a version to carry them.

Images stay skipped. The four screenshots checked in here predate the 4.14
redesign, and uploading them would put the old ones back over the current.

**The first run overwrites what the console says** for the title, both
descriptions and the release notes, on both apps, in all fifteen locales. That
is the point, but it is worth knowing before the run rather than after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
The README pointed at a Crowdin project that has not delivered since 2023. It
now says what writes each of the three - the app's strings, the listing, the
release notes - and that a pull request correcting any of them is welcome.

CHANGELOG.md said its sections were pasted into the Play Console at promotion.
They are what the store copy is written from now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2780b05b62

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread scripts/store-listing.py Outdated
Comment thread scripts/store-listing.py Outdated
`locales()` read the tree and believed it: a directory deleted, or one that lost
its full_description.txt, simply left the set, and the pre-build check passed with
fourteen locales instead of fifteen. That storefront would then keep the listing of
whatever version last reached it, and nothing would say so. The fifteen are written
down in `LOCALES` now, with the language each is written in, and the tree is checked
against the list both ways round - a locale gone missing fails the release, and one
beside them the list does not name fails it too rather than be translated and never
uploaded.

That is the same table `store-copy.py` kept as `LANGUAGES` to name the language it
hands the translator, so it now reads it from here. One list, in the place the
release consults.

Staging had the same silence one file down: a `title.txt`, `short_description.txt` or
`full_description.txt` that no layer held was left out of the staged tree, and supply
uploads what it is handed and leaves the rest of the console alone - so the result is
not a blank listing but the old one still standing, which is the arrangement this
branch replaces. Those three are required per locale now and name the three
directories they were looked for in; `video.txt` stays optional, since a listing
without a trailer is a listing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9iTwwgnYcYkC9jEUvUEgN
andiwand added a commit to opendocument-app/OpenDocument.ios that referenced this pull request Aug 16, 2026
Both were counted up from what was on disk. A locale that lost its
directory, or only its description, simply stopped being a locale: the
check passed with ten, and that storefront kept whatever the console
said. The eleven are written down now.

Same for the listing itself. A field found nowhere was left out of what
is staged, and App Store Connect reads a field it was not given as
"leave this be" - so the run meant to replace the old words would have
kept them instead. The name is the easiest to lose, since each app says
it in one file for all eleven languages.

Both come from the review of the Android half, opendocument-app/OpenDocument.droid#593.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xryx81PvamT674wzzQujjg
@andiwand
andiwand merged commit 7d46cb5 into main Aug 16, 2026
7 checks passed
@andiwand
andiwand deleted the translate-the-app-and-write-the-store-copy branch August 16, 2026 15:02
andiwand added a commit that referenced this pull request Aug 16, 2026
andiwand added a commit to opendocument-app/OpenDocument.ios that referenced this pull request Aug 16, 2026
#162)

* Write the store copy before the release, not during it

The "What's New" text was typed into App Store Connect at submission and
translated by hand. scripts/store-copy.py now writes it from the changelog,
one agent per language and a second one reading each draft back, and the
release run uploads it and refuses a version any locale is missing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Translate the app again

Every language but English showed English for the onboarding buttons, the
privacy screen and the banner - nineteen of the forty-four strings. Danish,
Catalan, Turkish and Czech showed it for most of the rest, and the Chinese
introduction named a different app.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Translate the store listing from what it says now

Every listing but the English one was a translation of an older, shorter
listing: six of the nine features and the whole list of formats the app opens
were missing, and so were the notes about ads and where to send feedback. The
Swedish one called an office suite office supplies.

The 1.41 notes say PDFs fit the screen and take a password like everything
else, rather than which engine draws them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Name the app in its own language, and let the release write the listing

Eight of the ten storefronts showed an English name and subtitle, both saying
the app only reads. Every one showed the same English keywords, so nobody
searching in their own language found it. Each listing now leads with
LibreOffice, says somewhere that it edits, and spends its keywords on words
people there actually type.

The release run uploads all of it, not just the release notes, so the store
says what is written here. Lite still takes the notes alone: a name has to be
unique in the store, and only Pro's listing is checked in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Say the same about both apps, except where they differ

fastlane/metadata is what Pro and Lite share. fastlane/metadata-pro and
-lite hold the rest, read over it. Two things differ: the name, because
the store wants a unique one, and the sentence about ads, which Pro has
been carrying for years without showing any. That one sentence is a
${ads} in the shared description rather than a second copy of it.

The name is no longer translated. OpenDocument is the format's own name,
and the App Store indexes the subtitle just as well, so the local words
and LibreOffice moved down there.

Nothing sells the app as an editor now. It edits text, but not well
enough to promise.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fail the release when a language or a field goes missing

Both were counted up from what was on disk. A locale that lost its
directory, or only its description, simply stopped being a locale: the
check passed with ten, and that storefront kept whatever the console
said. The eleven are written down now.

Same for the listing itself. A field found nowhere was left out of what
is staged, and App Store Connect reads a field it was not given as
"leave this be" - so the run meant to replace the old words would have
kept them instead. The name is the easiest to lose, since each app says
it in one file for all eleven languages.

Both come from the review of the Android half, opendocument-app/OpenDocument.droid#593.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant