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
This commit is contained in:
comasqw
2024-06-25 19:02:02 +04:00
committed by GitHub
parent e12f499594
commit fa86f705aa
14 changed files with 270 additions and 0 deletions

View File

@@ -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

View File

@@ -0,0 +1,6 @@
{
"paths": {
"prototypes": "../../../Resources/Prototypes/_CP14/Entities",
"localization": "../../../Resources/Locale/ru-RU/_CP14/_PROTO/entities"
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
@echo off
pip install -r requirements.txt
pause

View File

@@ -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()

View File

@@ -0,0 +1 @@
PyYAML==6.0.1

View File

@@ -0,0 +1,3 @@
@echo off
python main.py
pause

View File

@@ -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