fix(l10n): give Play the locale codes it actually accepts (#7225)

This commit is contained in:
James Rich authored and GitHub committed 2026-09-18 18:21:19 -07:00
1 parent ce70ac5f8e
commit f166a165ff
72 files changed
+169 -72

No files matched your search

+5
View File
@@ -305,6 +305,11 @@ jobs:
run: ./scripts/verify-abi-parity-selftest.sh
- name: Validate store listing metadata lengths
run: python3 scripts/check-metadata-length.py
# supply uploads every locale directory it finds and neither it nor the Crowdin CLI
# validates the names, so an unmapped code is only rejected by the Play API, partway
# through an upload. Catch it here instead.
- name: Validate store listing locale codes
run: python3 scripts/check-play-locales.py
# Compose Multiplatform does not strip Android-style \" / \' escapes, so a
# backslash written before a quote renders literally in the UI (PR #6357).
# Guards the English source strings; locale mirrors are cleaned upstream by
+4
View File
@@ -294,6 +294,10 @@ jobs:
continue-on-error: true
run: python3 scripts/check-metadata-length.py
- name: Check store locale codes
continue-on-error: true
run: python3 scripts/check-play-locales.py
- name: Build PR body
id: pr_body
env:
+36
View File
@@ -10,10 +10,46 @@ files:
escape_quotes: 0
escape_special_characters: 0
type: android
# Crowdin's %locale% is not Google Play's language set: it renders regions Play rejects
# (ar-SA), `srp` for Serbian, and the modern Hebrew code where Play wants the legacy one.
# Nothing validates this - supply uploads every directory it finds and fastlane documents
# no behaviour for unknown ones - so a bad code is rejected by the Play API mid-upload,
# after earlier locales have already been written.
- source: /fastlane/metadata/android/en-US/*.txt
translation: /fastlane/metadata/android/%locale%/%original_file_name%
languages_mapping: &play_locales
locale:
# Keys are Crowdin language ids, not the locale %locale% renders. Play takes the
# bare language for these; %locale% would render a region it rejects.
ar: ar
be: be
bg: bg
ca: ca
et: et
hr: hr
lt: lt
ro: ro
sk: sk
sl: sl
sq: sq
uk: uk
# Play still uses the pre-1989 ISO code for Hebrew; %locale% renders he-IL.
he: iw-IL
# Crowdin renders Serbian as `srp`, which Play does not accept in any form.
sr: sr
# Play publishes no slot for these. Irish and Haitian Creole are absent from its
# supported-languages list entirely, and it lists Serbian only as `sr` with no script
# variant - mapping sr-Latn there too would point two languages at one directory and
# silently lose whichever wrote first. They keep translating the app's own strings;
# only the store listing is out of reach.
excluded_target_languages: &play_unsupported
- ga
- ht
- sr-Latn
- source: /fastlane/metadata/android/en-US/changelogs/default.txt
translation: /fastlane/metadata/android/%locale%/changelogs/%original_file_name%
languages_mapping: *play_locales
excluded_target_languages: *play_unsupported
# In-app docs — user guide only (developer guide is English-only)
# English sources live under docs/en/; translations land at docs/{android_code}/
# Uses %android_code% to output Android/CMP qualifier format directly (pt-rBR, zh-rCN, fr)
@@ -1 +0,0 @@
For detailed release notes, please visit: https://github.com/meshtastic/Meshtastic-Android/releases/
@@ -1,21 +0,0 @@
Meshtastic is a tool for using Android devices with open-source, off-grid mesh radios. This app is the main client for the Meshtastic project, allowing you to manage your mesh devices and communicate with other users.
For more information about the Meshtastic project, please visit our website: <a href="https://www.meshtastic.org">meshtastic.org</a>. The firmware that runs on the radio devices is a separate open-source project, which you can find here: <a href="https://github.com/meshtastic/Meshtastic-device">https://github.com/meshtastic/Meshtastic-device</a>.
<b>Community and Support</b>
This project is currently in beta. We would love to hear from you! If you have questions, feedback, or encounter any problems, please join our friendly and active community:
• <b>Discussion Forum:</b> <a href="https://github.com/orgs/meshtastic/discussions">https://github.com/orgs/meshtastic/discussions</a>
• <b>Discord:</b> <a href="https://discord.gg/meshtastic">https://discord.gg/meshtastic</a>
• <b>Report an Issue:</b> <a href="https://github.com/meshtastic/Meshtastic-Android/issues">https://github.com/meshtastic/Meshtastic-Android/issues</a>
<b>Documentation</b>
To learn more about the features and capabilities of this app and Meshtastic, please view our official documentation:
<a href="https://meshtastic.org/docs/">View Documentation</a>
<b>Translations</b>
You can help translate the app into your native language using Crowdin:
<a href="https://crowdin.meshtastic.org/android">https://crowdin.meshtastic.org/android</a>
@@ -1 +0,0 @@
The official app for Meshtastic, an open-source, off-grid, mesh radio.
@@ -1 +0,0 @@
For detailed release notes, please visit: https://github.com/meshtastic/Meshtastic-Android/releases/
@@ -1,21 +0,0 @@
Meshtastic is a tool for using Android devices with open-source, off-grid mesh radios. This app is the main client for the Meshtastic project, allowing you to manage your mesh devices and communicate with other users.
For more information about the Meshtastic project, please visit our website: <a href="https://www.meshtastic.org">meshtastic.org</a>. The firmware that runs on the radio devices is a separate open-source project, which you can find here: <a href="https://github.com/meshtastic/Meshtastic-device">https://github.com/meshtastic/Meshtastic-device</a>.
<b>Community and Support</b>
This project is currently in beta. We would love to hear from you! If you have questions, feedback, or encounter any problems, please join our friendly and active community:
• <b>Discussion Forum:</b> <a href="https://github.com/orgs/meshtastic/discussions">https://github.com/orgs/meshtastic/discussions</a>
• <b>Discord:</b> <a href="https://discord.gg/meshtastic">https://discord.gg/meshtastic</a>
• <b>Report an Issue:</b> <a href="https://github.com/meshtastic/Meshtastic-Android/issues">https://github.com/meshtastic/Meshtastic-Android/issues</a>
<b>Documentation</b>
To learn more about the features and capabilities of this app and Meshtastic, please view our official documentation:
<a href="https://meshtastic.org/docs/">View Documentation</a>
<b>Translations</b>
You can help translate the app into your native language using Crowdin:
<a href="https://crowdin.meshtastic.org/android">https://crowdin.meshtastic.org/android</a>
@@ -1 +0,0 @@
The official app for Meshtastic, an open-source, off-grid, mesh radio.
@@ -1 +0,0 @@
Meshtastic
@@ -1 +0,0 @@
For detailed release notes, please visit: https://github.com/meshtastic/Meshtastic-Android/releases/
@@ -1,21 +0,0 @@
Meshtastic is a tool for using Android devices with open-source, off-grid mesh radios. This app is the main client for the Meshtastic project, allowing you to manage your mesh devices and communicate with other users.
For more information about the Meshtastic project, please visit our website: <a href="https://www.meshtastic.org">meshtastic.org</a>. The firmware that runs on the radio devices is a separate open-source project, which you can find here: <a href="https://github.com/meshtastic/Meshtastic-device">https://github.com/meshtastic/Meshtastic-device</a>.
<b>Community and Support</b>
This project is currently in beta. We would love to hear from you! If you have questions, feedback, or encounter any problems, please join our friendly and active community:
• <b>Discussion Forum:</b> <a href="https://github.com/orgs/meshtastic/discussions">https://github.com/orgs/meshtastic/discussions</a>
• <b>Discord:</b> <a href="https://discord.gg/meshtastic">https://discord.gg/meshtastic</a>
• <b>Report an Issue:</b> <a href="https://github.com/meshtastic/Meshtastic-Android/issues">https://github.com/meshtastic/Meshtastic-Android/issues</a>
<b>Documentation</b>
To learn more about the features and capabilities of this app and Meshtastic, please view our official documentation:
<a href="https://meshtastic.org/docs/">View Documentation</a>
<b>Translations</b>
You can help translate the app into your native language using Crowdin:
<a href="https://crowdin.meshtastic.org/android">https://crowdin.meshtastic.org/android</a>
@@ -1 +0,0 @@
The official app for Meshtastic, an open-source, off-grid, mesh radio.
-1
View File
@@ -1 +0,0 @@
Meshtastic
@@ -1 +0,0 @@
Meshtastic
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""Fail when a fastlane locale directory is not a language Google Play accepts.
Nothing else checks this. Crowdin's locale placeholder renders Crowdin's own codes, and
the Crowdin CLI silently ignores config keys it does not recognise, so a mapping typo is
invisible there. On the other side, supply uploads every directory it finds - uploader.rb's
all_languages is a bare Dir.entries with no reference to Supply::Languages::ALL_LANGUAGES -
and fastlane documents no behaviour for unknown folders. The rejection therefore arrives
from the Play API mid-upload, after earlier locales have already been written.
The list below is Play's published set (Play Console Help, "Add your own translations"),
not fastlane's ALL_LANGUAGES. They disagree: fastlane omits Albanian, which Play lists.
Play is the authority here, because Play is what rejects the upload.
"""
import sys
from pathlib import Path
METADATA = Path(__file__).resolve().parent.parent / "fastlane/metadata/android"
PLAY_LANGUAGES = {
"af",
"am",
"ar",
"az-AZ",
"be",
"bg",
"bn-BD",
"ca",
"cs-CZ",
"da-DK",
"de-DE",
"el-GR",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-SG",
"en-US",
"en-ZA",
"es-419",
"es-ES",
"es-US",
"et",
"eu-ES",
"fa",
"fi-FI",
"fil",
"fr-CA",
"fr-FR",
"gl-ES",
"hi-IN",
"hr",
"hu-HU",
"hy-AM",
"id",
"is-IS",
"it-IT",
"iw-IL",
"ja-JP",
"ka-GE",
"km-KH",
"kn-IN",
"ko-KR",
"ky-KG",
"lo-LA",
"lt",
"lv",
"mk-MK",
"ml-IN",
"mn-MN",
"mr-IN",
"ms",
"ms-MY",
"my-MM",
"ne-NP",
"nl-NL",
"no-NO",
"pl-PL",
"pt-BR",
"pt-PT",
"rm",
"ro",
"ru-RU",
"si-LK",
"sk",
"sl",
"sq",
"sr",
"sv-SE",
"sw",
"ta-IN",
"te-IN",
"th",
"tr-TR",
"uk",
"vi",
"zh-CN",
"zh-HK",
"zh-TW",
"zu",
}
def main() -> int:
if not METADATA.is_dir():
print(f"error: {METADATA} not found", file=sys.stderr)
return 2
dirs = sorted(p.name for p in METADATA.iterdir() if p.is_dir() and not p.name.startswith("."))
bad = [d for d in dirs if d not in PLAY_LANGUAGES]
if not bad:
print(f"All {len(dirs)} fastlane locale directories are languages Google Play accepts.")
return 0
for d in bad:
print(
f"::error file=fastlane/metadata/android/{d}::'{d}' is not a Play language code. "
"Map it in crowdin.yml languages_mapping, or exclude it there.",
file=sys.stderr,
)
print(f"\n{len(bad)} of {len(dirs)} locale directories would be rejected by Play.", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())