#!/usr/bin/env python3 """Regenerate app/utils/languages.py from ISO 639-1 and CLDR. Every ISO 639-1 alpha-2 code becomes an entry. The display name is the CLDR endonym where CLDR knows the language, and the English ISO name for the remainder. Writing direction comes from CLDR's character order. Needs the dev extra: pip install -e ".[dev]" """ import subprocess import sys from pathlib import Path import pycountry from babel import Locale from babel.localedata import locale_identifiers TARGET = Path(__file__).resolve().parents[1] / "app" / "utils" / "languages.py" HEADER = '''"""ISO 639-1 languages, their display names and writing direction. Generated by utils/generate_languages.py — edit that script, not this file. Display names are CLDR endonyms where CLDR covers the language and the English ISO 639-1 name for the {fallback} codes it does not. """ LANGUAGES = {{ ''' FOOTER = """}} RTL_LANGUAGES = frozenset({rtl}) """ def collect(): """Return (code -> display name) and the set of right-to-left codes.""" cldr = {code for code in locale_identifiers() if len(code) == 2 and code.isalpha()} names, rtl, fallbacks = {}, set(), 0 for language in sorted( pycountry.languages, key=lambda item: getattr(item, "alpha_2", "") ): code = getattr(language, "alpha_2", None) if not code: continue if code in cldr: locale = Locale.parse(code) names[code] = locale.get_display_name(code) if locale.character_order == "right-to-left": rtl.add(code) else: names[code] = language.name fallbacks += 1 return names, rtl, fallbacks def render(names, rtl, fallbacks): """Return the module source, English first and the rest by code.""" ordered = ["en"] + [code for code in sorted(names) if code != "en"] body = "".join(f' "{code}": "{names[code]}",\n' for code in ordered) listed = ", ".join(f'"{code}"' for code in sorted(rtl)) return ( HEADER.format(fallback=fallbacks) + body + FOOTER.format(rtl="{" + listed + "}") ) def main(): names, rtl, fallbacks = collect() TARGET.write_text(render(names, rtl, fallbacks), encoding="utf-8") subprocess.run([sys.executable, "-m", "ruff", "format", str(TARGET)], check=False) print( f"{len(names)} languages, {len(rtl)} right-to-left, " f"{fallbacks} without a CLDR endonym" ) return 0 if __name__ == "__main__": raise SystemExit(main())