mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
feat(i18n): add placeholder validation to translation checker
Detects mismatched placeholders like {count} vs {pocet} between
source (en.json) and translations. Catches cases where raw placeholders
like {# models} are translated without preserving the placeholder format.
Found 14 issues in cs.json as test case.
This commit is contained in:
@@ -242,6 +242,42 @@ def find_untranslated(source: Dict, trans: Dict) -> Set[str]:
|
||||
return untranslated
|
||||
|
||||
|
||||
def find_placeholder_issues(source: Dict, trans: Dict) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
Find placeholder mismatches between source and translation.
|
||||
Returns list of (key, source_placeholder, trans_placeholder)
|
||||
"""
|
||||
source_keys = get_all_keys(source)
|
||||
issues = []
|
||||
|
||||
for key in source_keys:
|
||||
source_val = get_value_by_path(source, key)
|
||||
trans_val = get_value_by_path(trans, key)
|
||||
|
||||
if source_val is None or trans_val is None:
|
||||
continue
|
||||
|
||||
if not isinstance(source_val, str) or not isinstance(trans_val, str):
|
||||
continue
|
||||
|
||||
# Extract placeholders: {name}, {count}, {0}, etc.
|
||||
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))
|
||||
|
||||
# Check for missing placeholders
|
||||
missing = source_placeholders - trans_placeholders
|
||||
if missing:
|
||||
issues.append((key, str(source_placeholders), str(trans_placeholders)))
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def compare_category(source: Dict, trans: Dict, category: str) -> Tuple[bool, List[str]]:
|
||||
"""Compare a specific category, return (complete, missing_keys)"""
|
||||
if category not in source:
|
||||
@@ -315,6 +351,20 @@ def generate_report():
|
||||
else:
|
||||
print_success("All keys appear to be translated!")
|
||||
|
||||
# Placeholder issues
|
||||
print_header("Placeholder Mismatches")
|
||||
placeholder_issues = find_placeholder_issues(source, trans)
|
||||
if placeholder_issues:
|
||||
print(f"{YELLOW}Found {len(placeholder_issues)} placeholder mismatches:{NC}")
|
||||
for key, src_ph, trans_ph in placeholder_issues[:20]:
|
||||
print(f" - {key}")
|
||||
print(f" Source: {src_ph}")
|
||||
print(f" Trans: {trans_ph}")
|
||||
if len(placeholder_issues) > 20:
|
||||
print(f" ... and {len(placeholder_issues) - 20} more")
|
||||
else:
|
||||
print_success("All placeholders match!")
|
||||
|
||||
# Per-category status
|
||||
print_header("Per-Category Status")
|
||||
for category in sorted(source.keys()):
|
||||
|
||||
Reference in New Issue
Block a user