mirror of
https://github.com/imputnet/helium.git
synced 2026-08-20 00:57:32 +02:00
c4732aacde
forages for strings that were already translated in the past within chromium and adds them to the translations, effectively reducing effort for review
112 lines
3.8 KiB
Python
112 lines
3.8 KiB
Python
# Copyright 2026 The Helium Authors
|
|
# You can use, redistribute, and/or modify this source code under
|
|
# the terms of the GPL-3.0 license that can be found in the LICENSE file.
|
|
"""Helper for finding existing translated strings in upstream Chromium."""
|
|
|
|
import sys
|
|
import json
|
|
from pathlib import Path
|
|
from collections import defaultdict
|
|
import xml.etree.ElementTree as xml
|
|
|
|
I18N_DIR = Path(__file__).resolve().parent.parent / 'i18n'
|
|
SOURCE_PATH = I18N_DIR / 'source.gen.json'
|
|
TRANSLATIONS_DIR = I18N_DIR / 'translations'
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / 'utils'))
|
|
from i18n_apply import get_id, build_xtb_index, resolve_xtb
|
|
import name_substitution_utils as namesub
|
|
|
|
|
|
def get_untranslated_strings_by_xtb(source, lang, xtb_index):
|
|
"""Generates a map of xtb_path -> [untranslated strings]."""
|
|
translation_path = TRANSLATIONS_DIR / f'{lang}.json'
|
|
trans_keys = set()
|
|
|
|
if translation_path.exists():
|
|
with open(translation_path, encoding='utf-8') as file:
|
|
translations = json.load(file)
|
|
for translation in translations:
|
|
trans_keys.add((translation['name'], translation['source']))
|
|
|
|
filtered = defaultdict(list)
|
|
for string in source:
|
|
xtb_file = resolve_xtb(string, lang, xtb_index)
|
|
assert xtb_file is not None
|
|
if (string['name'], string['message']) not in trans_keys:
|
|
filtered[xtb_file].append(string)
|
|
return filtered
|
|
|
|
|
|
def to_fpmap(strings):
|
|
"""Generates a fingerprint -> source string mapping."""
|
|
fp_map = {}
|
|
for string in strings:
|
|
fingerprint = get_id(string['name'], string['context'], string['message'],
|
|
string.get('meaning'))
|
|
fp_map[fingerprint] = string
|
|
return fp_map
|
|
|
|
|
|
def stringify_inner_xml(node):
|
|
"""Takes an XML node and stringifies its inner contents."""
|
|
parts = [node.text or '']
|
|
for child in node:
|
|
parts.append(xml.tostring(child, encoding='unicode'))
|
|
return ''.join(parts)
|
|
|
|
|
|
def find_matching(path, fpmap):
|
|
"""Finds pre-existing matching translations for Helium strings."""
|
|
content = path.read_text(encoding='utf-8')
|
|
root = xml.fromstring(content)
|
|
|
|
out = {}
|
|
for node in root.findall('.//translation'):
|
|
fingerprint = node.get('id')
|
|
if fingerprint in fpmap:
|
|
out[fingerprint] = stringify_inner_xml(node)
|
|
return out
|
|
|
|
|
|
def apply_matching(lang, matching, fpmap):
|
|
"""
|
|
Takes a map of found matches and applies them to the helium i18n file.
|
|
"""
|
|
translation_path = TRANSLATIONS_DIR / f'{lang}.json'
|
|
translations = []
|
|
if translation_path.exists():
|
|
with open(translation_path, encoding='utf-8') as file:
|
|
translations = json.load(file)
|
|
|
|
for fingerprint, translation in matching.items():
|
|
original = fpmap[fingerprint]
|
|
translations.append({
|
|
'name': namesub.replace_text(original['name'])[0],
|
|
'source': namesub.replace_text(original['message'])[0],
|
|
'message': namesub.replace_text(translation)[0],
|
|
})
|
|
|
|
with open(translation_path, 'w', encoding='utf-8') as file:
|
|
json.dump(translations, file, indent=2, ensure_ascii=False)
|
|
file.write('\n')
|
|
|
|
|
|
def run(args):
|
|
"""Forages for usable existing Chromium translations."""
|
|
with open(SOURCE_PATH, encoding='utf-8') as file:
|
|
source = json.load(file)
|
|
with open(I18N_DIR / 'languages.json', encoding='utf-8') as file:
|
|
languages = json.load(file)
|
|
|
|
namesub.add_grit_to_path(args.tree)
|
|
xtb_map = build_xtb_index(source, args.tree)
|
|
|
|
for lang in languages:
|
|
missing = get_untranslated_strings_by_xtb(source, lang, xtb_map)
|
|
for path, strings in missing.items():
|
|
fpmap = to_fpmap(strings)
|
|
matching = find_matching(path, fpmap)
|
|
if matching:
|
|
apply_matching(lang, matching, fpmap)
|