From fa86f705aa2043d3f17c015fe381124e2f89904c Mon Sep 17 00:00:00 2001 From: comasqw <138010940+comasqw@users.noreply.github.com> Date: Tue, 25 Jun 2024 19:02:02 +0400 Subject: [PATCH] Localization Helper (#275) * Localization Helper * Update main.py * Update main.py * adding comments to code and translating exceptions into English * cringe fix * Update yml_parser.py * tweak * Update main.py --- Tools/_CP14/LocalizationHelper/README.md | 45 ++++++++++ Tools/_CP14/LocalizationHelper/config.json | 6 ++ .../LocalizationHelper/fluent/__init__.py | 0 .../LocalizationHelper/fluent/ftl_reader.py | 38 +++++++++ .../LocalizationHelper/fluent/ftl_writer.py | 17 ++++ .../LocalizationHelper/ftl_parser/__init__.py | 0 .../ftl_parser/ftl_parser.py | 23 ++++++ .../LocalizationHelper/install_packages.bat | 3 + .../LocalizationHelper/logs/errors_log.txt | 0 Tools/_CP14/LocalizationHelper/main.py | 82 +++++++++++++++++++ .../_CP14/LocalizationHelper/requirements.txt | 1 + Tools/_CP14/LocalizationHelper/run.bat | 3 + .../LocalizationHelper/yml_parser/__init__.py | 0 .../yml_parser/yml_parser.py | 52 ++++++++++++ 14 files changed, 270 insertions(+) create mode 100644 Tools/_CP14/LocalizationHelper/README.md create mode 100644 Tools/_CP14/LocalizationHelper/config.json create mode 100644 Tools/_CP14/LocalizationHelper/fluent/__init__.py create mode 100644 Tools/_CP14/LocalizationHelper/fluent/ftl_reader.py create mode 100644 Tools/_CP14/LocalizationHelper/fluent/ftl_writer.py create mode 100644 Tools/_CP14/LocalizationHelper/ftl_parser/__init__.py create mode 100644 Tools/_CP14/LocalizationHelper/ftl_parser/ftl_parser.py create mode 100644 Tools/_CP14/LocalizationHelper/install_packages.bat create mode 100644 Tools/_CP14/LocalizationHelper/logs/errors_log.txt create mode 100644 Tools/_CP14/LocalizationHelper/main.py create mode 100644 Tools/_CP14/LocalizationHelper/requirements.txt create mode 100644 Tools/_CP14/LocalizationHelper/run.bat create mode 100644 Tools/_CP14/LocalizationHelper/yml_parser/__init__.py create mode 100644 Tools/_CP14/LocalizationHelper/yml_parser/yml_parser.py diff --git a/Tools/_CP14/LocalizationHelper/README.md b/Tools/_CP14/LocalizationHelper/README.md new file mode 100644 index 0000000000..c55bdd79a1 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/README.md @@ -0,0 +1,45 @@ + +# Localization Helper + +A script to help support game translation + +## The right version of python: 3.10+ + + +## Deployment + +in console + +```bash +pip install -r requirements.txt +``` +or just run + +```bash +install_packages.bat +``` + +## Run +in console + +```bash +python main.py +``` +or just run + +```bash +run.bat +``` + +## Demo + + +https://youtu.be/5HfDjLzhjA4 +## License + +Author: asqw: Discord - .asqw, GitHub - comasqw + +Date: 24.06.2024 + +License: All right reserved for CrystallPunk14 project only + diff --git a/Tools/_CP14/LocalizationHelper/config.json b/Tools/_CP14/LocalizationHelper/config.json new file mode 100644 index 0000000000..ae130c1fbf --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/config.json @@ -0,0 +1,6 @@ +{ + "paths": { + "prototypes": "../../../Resources/Prototypes/_CP14/Entities", + "localization": "../../../Resources/Locale/ru-RU/_CP14/_PROTO/entities" + } +} \ No newline at end of file diff --git a/Tools/_CP14/LocalizationHelper/fluent/__init__.py b/Tools/_CP14/LocalizationHelper/fluent/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tools/_CP14/LocalizationHelper/fluent/ftl_reader.py b/Tools/_CP14/LocalizationHelper/fluent/ftl_reader.py new file mode 100644 index 0000000000..691ee66200 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/fluent/ftl_reader.py @@ -0,0 +1,38 @@ +def read_ftl(path: str) -> dict: + """ + The function looks at each line of the ftl + file and determines by the indentation in the line whether + it is a new prototype or an attribute of an old one. + """ + prototypes = { + + } + + last_prototype = "" + + try: + with open(path, encoding="utf-8") as file: + for line in file.readlines(): + if line.startswith("#") or line.startswith("\n"): + continue + + if not line.startswith(" "): + proto_id, proto_name = line.split(" = ") + proto_id = proto_id.replace("ent-", "") + last_prototype = proto_id + prototypes[proto_id] = {"name": proto_name.strip(), + "desc": None, + "suffix": None + } + else: + if "desc" in line: + attr = "desc" + elif "suffix" in line: + attr = "suffix" + + prototypes[last_prototype][attr] = line.split(" = ")[-1].strip() + except Exception as e: + with open("logs/errors_log.txt", "a") as file: + file.write(f"FTL-ERROR:\nAn error occurred while reading a file {path}, error - {e}\n") + + return prototypes \ No newline at end of file diff --git a/Tools/_CP14/LocalizationHelper/fluent/ftl_writer.py b/Tools/_CP14/LocalizationHelper/fluent/ftl_writer.py new file mode 100644 index 0000000000..920db10693 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/fluent/ftl_writer.py @@ -0,0 +1,17 @@ +import json + + +def create_ftl(key: str, prototype: dict) -> str: + ftl = "" + + ftl += f"ent-{key} = {prototype["name"]}\n" + + if prototype["desc"] is not None: + ftl += f" .desc = {prototype["desc"]}\n" + + if prototype["suffix"] is not None: + ftl += f" .suffix = {prototype["suffix"]}\n" + + ftl += "\n" + + return ftl diff --git a/Tools/_CP14/LocalizationHelper/ftl_parser/__init__.py b/Tools/_CP14/LocalizationHelper/ftl_parser/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tools/_CP14/LocalizationHelper/ftl_parser/ftl_parser.py b/Tools/_CP14/LocalizationHelper/ftl_parser/ftl_parser.py new file mode 100644 index 0000000000..33ccd9b186 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/ftl_parser/ftl_parser.py @@ -0,0 +1,23 @@ +from fluent import ftl_reader +import os + + +def ftl_parser(path: str) -> dict: + """ + The function gets the path, then with the help of the os library + goes through each file,checks that the file extension is "ftl", + then reads it through the "ftl_reader" module of the "fluent" package. + """ + prototypes = {} + + for dirpath, _, filenames in os.walk(path): + for filename in filenames: + path = f"{dirpath}\\{filename}" + + if not filename.endswith(".ftl"): + continue + + file = ftl_reader.read_ftl(path) + prototypes.update(file) + + return prototypes diff --git a/Tools/_CP14/LocalizationHelper/install_packages.bat b/Tools/_CP14/LocalizationHelper/install_packages.bat new file mode 100644 index 0000000000..20fa101d9d --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/install_packages.bat @@ -0,0 +1,3 @@ +@echo off +pip install -r requirements.txt +pause diff --git a/Tools/_CP14/LocalizationHelper/logs/errors_log.txt b/Tools/_CP14/LocalizationHelper/logs/errors_log.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tools/_CP14/LocalizationHelper/main.py b/Tools/_CP14/LocalizationHelper/main.py new file mode 100644 index 0000000000..1ad5cec839 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/main.py @@ -0,0 +1,82 @@ +import json +from yml_parser import yml_parser +from ftl_parser import ftl_parser +from fluent import ftl_writer + + +def read_config(): + with open("config.json", "r", encoding="utf-8") as file: + return json.load(file) + + +def get_paths(config: dict): + prototypes_path = config["paths"]["prototypes"] + localization_path = config["paths"]["localization"] + return prototypes_path, localization_path + + +def main(): + """ + The function reads the config, gets paths to prototypes and localization files, + and through parsers gets two dictionaries with information about prototypes, + and creates one common vocabulary. + """ + + with open("logs/errors_log.txt", "w") as file: + file.write("") + + config = read_config() + prototypes_path, localization_path = get_paths(config) + prototypes_dict, localization_dict = yml_parser.yml_parser(prototypes_path), ftl_parser.ftl_parser(localization_path) + + all_prototypes = {**prototypes_dict, **localization_dict} + + entities_ftl = "" + + """ + The function traverses each prototype from the dictionary, checks if it has a parent, + and performs certain checks on the attributes of the parent if the prototype does not have its own attributes. + """ + + for prototype in all_prototypes: + prototype_attrs = all_prototypes[prototype] + + try: + if prototype in prototypes_dict: + prototype_attrs["parent"] = prototypes_dict[prototype]["parent"] + + parent = prototype_attrs["parent"] + if not prototype_attrs.get("name"): + prototype_attrs["name"] = f"{{ ent-{prototype_attrs["parent"]} }}" + + if not prototype_attrs["desc"]: + if parent and not isinstance(parent, list) and prototypes_dict.get(parent): + prototype_attrs["desc"] = f"{{ ent-{parent}.desc }}" + + proto_ftl = ftl_writer.create_ftl(prototype, all_prototypes[prototype]) + entities_ftl += proto_ftl + + except Exception as e: + with open("logs/errors_log.txt", "a") as file: + file.write(f"RETRIEVING-ERROR:\nAn error occurred while retrieving data to be written to the file - {e}\n") + + + file_name = "entities.ftl" + with open(file_name, "w", encoding="utf-8") as file: + file.write(entities_ftl) + + print(f"{file_name} has been created\n") + + with open("logs/errors_log.txt", "r") as file: + errors = file.read() + + successful_count = len(all_prototypes) - errors.count("ERROR") + print(f"""Of the {len(all_prototypes)} prototypes, {successful_count} were successfully processed. +Errors can be found in 'logs/errors_log.txt'. +Number of errors during YML processing - {errors.count("YML-ERROR")} +Number of errors during FTL processing - {errors.count("FTL-ERROR")} +Number of errors during data extraction and creation of new FTL - {errors.count("RETRIEVING-ERROR")}""") + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/Tools/_CP14/LocalizationHelper/requirements.txt b/Tools/_CP14/LocalizationHelper/requirements.txt new file mode 100644 index 0000000000..036b1ca276 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/requirements.txt @@ -0,0 +1 @@ +PyYAML==6.0.1 \ No newline at end of file diff --git a/Tools/_CP14/LocalizationHelper/run.bat b/Tools/_CP14/LocalizationHelper/run.bat new file mode 100644 index 0000000000..c083a40942 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/run.bat @@ -0,0 +1,3 @@ +@echo off +python main.py +pause diff --git a/Tools/_CP14/LocalizationHelper/yml_parser/__init__.py b/Tools/_CP14/LocalizationHelper/yml_parser/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tools/_CP14/LocalizationHelper/yml_parser/yml_parser.py b/Tools/_CP14/LocalizationHelper/yml_parser/yml_parser.py new file mode 100644 index 0000000000..0b0f2289c7 --- /dev/null +++ b/Tools/_CP14/LocalizationHelper/yml_parser/yml_parser.py @@ -0,0 +1,52 @@ +import yaml +import os + + +def check_proto_attrs(prototype: dict) -> bool: + return any(prototype.get(attr) is not None for attr in ["name", "description", "suffix"]) + + +def get_proto_attrs(prototypes: dict, prototype: dict) -> None: + prototypes[prototype.get("id")] = { + "parent": prototype.get("parent"), + "name": prototype.get("name"), + "desc": prototype.get("description"), + "suffix": prototype.get("suffix") + } + + +def yml_parser(path: str) -> dict: + """ + The function gets the path, then with the help of the os library + goes through each file,checks that the file extension is "ftl", + then processes the file using the "PyYaml" library + """ + prototypes = {} + + for dirpath, _, filenames in os.walk(path): + for filename in filenames: + path = f"{dirpath}\\{filename}" + + if not filename.endswith(".yml"): + continue + + try: + with open(path, encoding="utf-8") as file: + proto = "" + for line in file.readlines(): + # The PyYaml library cannot handle the following SpaceStation 14 prototype syntax - !type: ... + if "!type" in line: + continue + proto += line + + data = yaml.safe_load(proto) + except Exception as e: + with open("logs/errors_log.txt", "a") as file: + file.write(f"YML-ERROR:\nAn error occurred during prototype processing {path}, error - {e}\n") + else: + if data is not None: + for prototype in data: + if check_proto_attrs(prototype): + get_proto_attrs(prototypes, prototype) + + return prototypes