From d244affa6c1034cc52c2907cc733a3ed3446a9a3 Mon Sep 17 00:00:00 2001 From: zenobit Date: Mon, 30 Mar 2026 05:04:59 +0200 Subject: [PATCH] fix(i18n): ignore ICU inner placeholders {# X} in validator Updated regex to only match top-level placeholders like {count}, {day} and ignore {# X} format inside ICU plural/select constructs. --- scripts/validate_translation.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/scripts/validate_translation.py b/scripts/validate_translation.py index 7cca5f9a45..5d1a4a386d 100755 --- a/scripts/validate_translation.py +++ b/scripts/validate_translation.py @@ -245,6 +245,7 @@ def find_untranslated(source: Dict, trans: Dict) -> Set[str]: def find_placeholder_issues(source: Dict, trans: Dict) -> List[Tuple[str, str, str]]: """ Find placeholder mismatches between source and translation. + Only checks top-level placeholders like {count}, {day}, NOT ICU inner content. Returns list of (key, source_placeholder, trans_placeholder) """ source_keys = get_all_keys(source) @@ -260,15 +261,11 @@ def find_placeholder_issues(source: Dict, trans: Dict) -> List[Tuple[str, str, s if not isinstance(source_val, str) or not isinstance(trans_val, str): continue - # Extract placeholders: {name}, {count}, {0}, etc. + # Only extract top-level placeholders: {name}, {count}, {day}, NOT {# X} inside ICU import re - source_placeholders = set(re.findall(r'\{[^}]+\}', source_val)) - trans_placeholders = set(re.findall(r'\{[^}]+\}', trans_val)) - - # Also check ICU plural formats - icu_pattern = r'\{[^,]+,\s*(plural|select|selectordinal)' - source_icu = set(re.findall(icu_pattern, source_val)) - trans_icu = set(re.findall(icu_pattern, trans_val)) + # Match {name} but NOT {# inside ICU plural + source_placeholders = set(re.findall(r'\{[a-zA-Z][^}]*\}', source_val)) + trans_placeholders = set(re.findall(r'\{[a-zA-Z][^}]*\}', trans_val)) # Check for missing placeholders missing = source_placeholders - trans_placeholders