6
2025-08-05 10:00:54 +03:00

221 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import typing
import logging
from pydash import py_
from file import FluentFile
from fluentast import FluentAstAbstract
from fluentformatter import FluentFormatter
from project import Project
from fluent.syntax import ast, FluentParser, FluentSerializer
# Осуществляет актуализацию ключей. Находит файлы английского перевода, проверяет: есть ли русскоязычная пара
# Если нет - создаёт файл с копией переводов из англоязычного
# Далее, пофайлово проверяются ключи. Если в английском файле больше ключей - создает недостающие в русском, с английской копией перевода
# Отмечает русские файлы, в которых есть те ключи, что нет в аналогичных английских
# Отмечает русские файлы, у которых нет англоязычной пары
######################################### Class defifitions ############################################################
class RelativeFile:
def __init__(self, file: FluentFile, locale: typing.AnyStr, relative_path_from_locale: typing.AnyStr):
self.file = file
self.locale = locale
self.relative_path_from_locale = relative_path_from_locale
class FilesFinder:
def __init__(self, project: Project):
self.project: Project = project
self.created_files: typing.List[FluentFile] = []
def get_relative_path_dict(self, file: FluentFile, locale):
if locale == 'ru-RU':
return RelativeFile(file=file, locale=locale,
relative_path_from_locale=file.get_relative_path(self.project.ru_locale_dir_path))
elif locale == 'en-US':
return RelativeFile(file=file, locale=locale,
relative_path_from_locale=file.get_relative_path(self.project.en_locale_dir_path))
else:
raise Exception(f'Локаль {locale} не поддерживается')
def get_file_pair(self, en_file: FluentFile) -> typing.Tuple[FluentFile, FluentFile]:
ru_file_path = en_file.full_path.replace('en-US', 'ru-RU')
ru_file = FluentFile(ru_file_path)
return en_file, ru_file
def execute(self):
self.created_files = []
groups = self.get_files_pars()
keys_without_pair = list(filter(lambda g: len(groups[g]) < 2, groups))
for key_without_pair in keys_without_pair:
relative_file: RelativeFile = groups.get(key_without_pair)[0]
if relative_file.locale == 'en-US':
ru_file = self.create_ru_analog(relative_file)
self.created_files.append(ru_file)
elif relative_file.locale == 'ru-RU':
is_engine_files = "robust-toolbox" in (relative_file.file.full_path)
is_corvax_files = "corvax" in (relative_file.file.full_path)
if not is_engine_files and not is_corvax_files:
self.warn_en_analog_not_exist(relative_file)
else:
raise Exception(f'Файл {relative_file.file.full_path} имеет неизвестную локаль "{relative_file.locale}"')
return self.created_files
def get_files_pars(self):
en_fluent_files = self.project.get_fluent_files_by_dir(project.en_locale_dir_path)
ru_fluent_files = self.project.get_fluent_files_by_dir(project.ru_locale_dir_path)
en_fluent_relative_files = list(map(lambda f: self.get_relative_path_dict(f, 'en-US'), en_fluent_files))
ru_fluent_relative_files = list(map(lambda f: self.get_relative_path_dict(f, 'ru-RU'), ru_fluent_files))
relative_files = py_.flatten_depth(py_.concat(en_fluent_relative_files, ru_fluent_relative_files), depth=1)
return py_.group_by(relative_files, 'relative_path_from_locale')
def create_ru_analog(self, en_relative_file: RelativeFile) -> FluentFile:
en_file: FluentFile = en_relative_file.file
en_file_data = en_file.read_data()
ru_file_path = en_file.full_path.replace('en-US', 'ru-RU')
ru_file = FluentFile(ru_file_path)
ru_file.save_data(en_file_data)
logging.info(f'Создан файл {ru_file_path} с переводами из английского файла')
return ru_file
def warn_en_analog_not_exist(self, ru_relative_file: RelativeFile):
file: FluentFile = ru_relative_file.file
en_file_path = file.full_path.replace('ru-RU', 'en-US')
logging.warning(f'Файл {file.full_path} не имеет английского аналога по пути {en_file_path}')
class KeyFinder:
def __init__(self, files_dict):
self.files_dict = files_dict
self.changed_files: typing.List[FluentFile] = []
def execute(self) -> typing.List[FluentFile]:
self.changed_files = []
for pair in self.files_dict:
ru_relative_file = py_.find(self.files_dict[pair], {'locale': 'ru-RU'})
en_relative_file = py_.find(self.files_dict[pair], {'locale': 'en-US'})
if not en_relative_file or not ru_relative_file:
continue
ru_file: FluentFile = ru_relative_file.file
en_file: FluentFile = en_relative_file.file
self.compare_files(en_file, ru_file)
return self.changed_files
def compare_files(self, en_file, ru_file):
ru_file_parsed: ast.Resource = ru_file.parse_data(ru_file.read_data())
en_file_parsed: ast.Resource = en_file.parse_data(en_file.read_data())
self.write_to_ru_files(ru_file, ru_file_parsed, en_file_parsed)
self.log_not_exist_en_files(en_file, ru_file_parsed, en_file_parsed)
def write_to_ru_files(self, ru_file, ru_file_parsed, en_file_parsed):
for idx, en_message in enumerate(en_file_parsed.body):
if isinstance(en_message, ast.ResourceComment) or isinstance(en_message, ast.GroupComment) or isinstance(en_message, ast.Comment):
continue
ru_message_analog_idx = py_.find_index(ru_file_parsed.body, lambda ru_message: self.find_duplicate_message_id_name(ru_message, en_message))
have_changes = False
# Attributes
if getattr(en_message, 'attributes', None) and ru_message_analog_idx != -1:
if not ru_file_parsed.body[ru_message_analog_idx].attributes:
ru_file_parsed.body[ru_message_analog_idx].attributes = en_message.attributes
have_changes = True
else:
for en_attr in en_message.attributes:
ru_attr_analog = py_.find(ru_file_parsed.body[ru_message_analog_idx].attributes, lambda ru_attr: ru_attr.id.name == en_attr.id.name)
if not ru_attr_analog:
ru_file_parsed.body[ru_message_analog_idx].attributes.append(en_attr)
have_changes = True
# New elements
if ru_message_analog_idx == -1:
ru_file_body = ru_file_parsed.body
if (len(ru_file_body) >= idx + 1):
ru_file_parsed = self.append_message(ru_file_parsed, en_message, idx)
else:
ru_file_parsed = self.push_message(ru_file_parsed, en_message)
have_changes = True
if have_changes:
serialized = serializer.serialize(ru_file_parsed)
self.save_and_log_file(ru_file, serialized, en_message)
def log_not_exist_en_files(self, en_file, ru_file_parsed, en_file_parsed):
for idx, ru_message in enumerate(ru_file_parsed.body):
if isinstance(ru_message, ast.ResourceComment) or isinstance(ru_message, ast.GroupComment) or isinstance(ru_message, ast.Comment):
continue
en_message_analog = py_.find(en_file_parsed.body, lambda en_message: self.find_duplicate_message_id_name(ru_message, en_message))
if not en_message_analog:
logging.warning(f'Ключ "{FluentAstAbstract.get_id_name(ru_message)}" не имеет английского аналога по пути {en_file.full_path}"')
def append_message(self, ru_file_parsed, en_message, en_message_idx):
ru_message_part_1 = ru_file_parsed.body[0:en_message_idx]
ru_message_part_middle = [en_message]
ru_message_part_2 = ru_file_parsed.body[en_message_idx:]
new_body = py_.flatten_depth([ru_message_part_1, ru_message_part_middle, ru_message_part_2], depth=1)
ru_file_parsed.body = new_body
return ru_file_parsed
def push_message(self, ru_file_parsed, en_message):
ru_file_parsed.body.append(en_message)
return ru_file_parsed
def save_and_log_file(self, file, file_data, message):
file.save_data(file_data)
logging.info(f'В файл {file.full_path} добавлен ключ "{FluentAstAbstract.get_id_name(message)}"')
self.changed_files.append(file)
def find_duplicate_message_id_name(self, ru_message, en_message):
ru_element_id_name = FluentAstAbstract.get_id_name(ru_message)
en_element_id_name = FluentAstAbstract.get_id_name(en_message)
if not ru_element_id_name or not en_element_id_name:
return False
if ru_element_id_name == en_element_id_name:
return ru_message
else:
return None
######################################## Var definitions ###############################################################
logging.basicConfig(level = logging.INFO)
project = Project()
parser = FluentParser()
serializer = FluentSerializer(with_junk=True)
files_finder = FilesFinder(project)
key_finder = KeyFinder(files_finder.get_files_pars())
########################################################################################################################
print('Проверка актуальности файлов ...')
created_files = files_finder.execute()
if len(created_files):
print('Форматирование созданных файлов ...')
FluentFormatter.format(created_files)
print('Проверка актуальности ключей ...')
changed_files = key_finder.execute()
if len(changed_files):
print('Форматирование изменённых файлов ...')
FluentFormatter.format(changed_files)