Skip to content

Commit b4ba843

Browse files
authored
Do not allow substituting alternates or drafts in derived locales (#1113)
* download_import_cldr.py: pass remaining arguments through to import_cldr * Do not allow substituting alternates or drafts in derived locales For more coverage, we've allowed using alternate or draft values when no officially accepted values have been present. However, non-global (i.e. e.g. `de_CH` locales) may have an alternate spelling for what would be an alternate in the parent locale (and that alternate hasn't been imported into the parent), and the import would have then accepted the alternate from the child locale as a non-alternate. Refs #1112
1 parent d3346ee commit b4ba843

File tree

3 files changed

+41
-13
lines changed

3 files changed

+41
-13
lines changed

scripts/download_import_cldr.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ def main():
7979
subprocess.check_call([
8080
sys.executable,
8181
os.path.join(scripts_path, 'import_cldr.py'),
82-
common_path])
82+
common_path,
83+
*sys.argv[1:],
84+
])
8385

8486

8587
if __name__ == '__main__':

scripts/import_cldr.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,8 @@ def _process_local_datas(sup, srcdir, destdir, force=False, dump_json=False):
417417
if locale_id in day_period_rules:
418418
data["day_period_rules"] = day_period_rules[locale_id]
419419

420-
parse_locale_display_names(data, tree)
420+
is_global = ("_" not in locale_id)
421+
parse_locale_display_names(data, tree, is_global=is_global)
421422
parse_list_patterns(data, tree)
422423
parse_dates(data, tree, sup, regions, territory)
423424

@@ -489,43 +490,54 @@ def _should_skip_elem(elem, type=None, dest=None):
489490
:param dest: Destination dict. May be elided to skip the dict check.
490491
:return: skip boolean
491492
"""
492-
if 'draft' in elem.attrib or 'alt' in elem.attrib:
493+
if _is_draft_or_alt(elem):
493494
if dest is None or type in dest:
494495
return True
495496

496497

497-
def _import_type_text(dest, elem, type=None):
498+
def _is_draft_or_alt(elem) -> bool:
499+
return 'draft' in elem.attrib or 'alt' in elem.attrib
500+
501+
502+
def _import_type_text(dest, elem, type=None, *, allow_variant_and_draft_fallback=True) -> None:
498503
"""
499504
Conditionally import the element's inner text(s) into the `dest` dict.
500505
501-
The condition being, namely, that the element isn't a draft/alternate version
502-
of a pre-existing element.
506+
If `allow_variant_and_draft_fallback` is True, then the element may be imported
507+
if there otherwise isn't a pre-existing element of the same type.
503508
504509
:param dest: Destination dict
505510
:param elem: XML element.
506511
:param type: Override type. (By default, the `type` attr of the element.)
507-
:return:
512+
:param allow_variant_and_draft_fallback: See above.
513+
:return: Nothing.
508514
"""
509515
if type is None:
510516
type = elem.attrib['type']
511-
if _should_skip_elem(elem, type, dest):
517+
518+
# Already have this, nothing to do.
519+
if type in dest:
520+
return
521+
522+
if not allow_variant_and_draft_fallback and _is_draft_or_alt(elem):
523+
# Not allowed to use a draft/alternate here.
512524
return
513525
dest[type] = _text(elem)
514526

515527

516-
def parse_locale_display_names(data, tree):
528+
def parse_locale_display_names(data, tree, *, is_global: bool):
517529
territories = data.setdefault('territories', {})
518530
for elem in tree.findall('.//territories/territory'):
519-
_import_type_text(territories, elem)
531+
_import_type_text(territories, elem, allow_variant_and_draft_fallback=is_global)
520532
languages = data.setdefault('languages', {})
521533
for elem in tree.findall('.//languages/language'):
522-
_import_type_text(languages, elem)
534+
_import_type_text(languages, elem, allow_variant_and_draft_fallback=is_global)
523535
variants = data.setdefault('variants', {})
524536
for elem in tree.findall('.//variants/variant'):
525-
_import_type_text(variants, elem)
537+
_import_type_text(variants, elem, allow_variant_and_draft_fallback=is_global)
526538
scripts = data.setdefault('scripts', {})
527539
for elem in tree.findall('.//scripts/script'):
528-
_import_type_text(scripts, elem)
540+
_import_type_text(scripts, elem, allow_variant_and_draft_fallback=is_global)
529541

530542

531543
def parse_list_patterns(data, tree):

tests/test_core.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,17 @@ def test_issue_814():
348348
loc = Locale.parse('ca_ES_valencia')
349349
assert loc.variant == "VALENCIA"
350350
assert loc.get_display_name() == 'català (Espanya, valencià)'
351+
352+
353+
def test_issue_1112():
354+
"""
355+
Test that an alternate spelling of `Türkei` doesn't inadvertently
356+
get imported from `de_AT` to replace the parent's non-alternate spelling.
357+
"""
358+
assert (
359+
Locale.parse('de').territories['TR'] ==
360+
Locale.parse('de_AT').territories['TR'] ==
361+
Locale.parse('de_CH').territories['TR'] ==
362+
Locale.parse('de_DE').territories['TR'] ==
363+
'Türkei'
364+
)

0 commit comments

Comments
 (0)