halkyon/packages/halkyon_app/tool/country_names.py

77 lines
2.8 KiB
Python
Raw Normal View History

"""Writes halkyon_app's country names from a release of Unicode CLDR.
The names of countries and territories (ISO 3166-1 alpha-2) that
`AssetCountryNames` reads, in English and German, from CLDR's
`common/main/<language>.xml` (`territories`) at a tagged release, the same
release as the subdivisions' names (`subdivision_names.py`), whose licence
notice beside those covers these too:
python3 -I packages/halkyon_app/tool/country_names.py [release-48-2]
Only two-letter codes, and of those not the union (the package says it in
its own words), nor CLDR's codes for groups or test data (EZ, UN, QO, XA,
XB, ZZ). English is kept whole; German only where it differs, as the app
falls back to English. Variants (`alt`) are left out, but for the four whose
usual name says more than a label needs, which take CLDR's short one, as
Learn's world map does ("Hong Kong", not "Hong Kong SAR China"). Run it again
with a newer tag together with `subdivision_names.py`, and say the release in
`assets/countries/ATTRIBUTION.md`.
"""
import json
import re
import sys
import urllib.request
import xml.etree.ElementTree as ElementTree
from pathlib import Path
RELEASE = sys.argv[1] if len(sys.argv) > 1 else 'release-48-2'
LANGUAGES = ('en', 'de')
SOURCE = 'https://raw.githubusercontent.com/unicode-org/cldr/' + RELEASE + '/'
ASSETS = Path(__file__).resolve().parent.parent / 'assets' / 'countries'
CODE = re.compile(r'^[A-Z]{2}$')
LEFT_OUT = {'EU', 'EZ', 'UN', 'QO', 'XA', 'XB', 'ZZ'}
# CLDR's short names where its usual one says more than a label needs.
SHORT = {'HK', 'MO', 'MM', 'PS'}
def fetch(path):
with urllib.request.urlopen(SOURCE + path, timeout=60) as response:
return response.read()
def names_in(language):
root = ElementTree.fromstring(fetch('common/main/' + language + '.xml'))
names = {}
short = {}
for element in root.iter('territory'):
code = element.attrib.get('type', '')
if not (element.text or '').strip():
continue
if element.attrib.get('alt') == 'short':
short[code] = element.text.strip()
elif 'alt' not in element.attrib and CODE.match(code) and code not in LEFT_OUT:
names[code] = element.text.strip()
for code in SHORT & names.keys() & short.keys():
names[code] = short[code]
return names
def main():
english = names_in('en')
names = {'release': RELEASE, 'en': english}
for language in LANGUAGES[1:]:
names[language] = {
code: name
for code, name in names_in(language).items()
if english.get(code) != name
}
ASSETS.mkdir(parents=True, exist_ok=True)
(ASSETS / 'countries.json').write_text(
json.dumps(names, ensure_ascii=False, sort_keys=True, separators=(',', ':')) + '\n',
encoding='utf-8',
)
print(RELEASE, {language: len(names[language]) for language in LANGUAGES})
main()