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:
45
Tools/_CP14/LocalizationHelper/README.md
Normal file
45
Tools/_CP14/LocalizationHelper/README.md
Normal 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
|
||||
|
||||
6
Tools/_CP14/LocalizationHelper/config.json
Normal file
6
Tools/_CP14/LocalizationHelper/config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"paths": {
|
||||
"prototypes": "../../../Resources/Prototypes/_CP14/Entities",
|
||||
"localization": "../../../Resources/Locale/ru-RU/_CP14/_PROTO/entities"
|
||||
}
|
||||
}
|
||||
0
Tools/_CP14/LocalizationHelper/fluent/__init__.py
Normal file
0
Tools/_CP14/LocalizationHelper/fluent/__init__.py
Normal file
38
Tools/_CP14/LocalizationHelper/fluent/ftl_reader.py
Normal file
38
Tools/_CP14/LocalizationHelper/fluent/ftl_reader.py
Normal 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
|
||||
17
Tools/_CP14/LocalizationHelper/fluent/ftl_writer.py
Normal file
17
Tools/_CP14/LocalizationHelper/fluent/ftl_writer.py
Normal 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
|
||||
23
Tools/_CP14/LocalizationHelper/ftl_parser/ftl_parser.py
Normal file
23
Tools/_CP14/LocalizationHelper/ftl_parser/ftl_parser.py
Normal 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
|
||||
3
Tools/_CP14/LocalizationHelper/install_packages.bat
Normal file
3
Tools/_CP14/LocalizationHelper/install_packages.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
pip install -r requirements.txt
|
||||
pause
|
||||
0
Tools/_CP14/LocalizationHelper/logs/errors_log.txt
Normal file
0
Tools/_CP14/LocalizationHelper/logs/errors_log.txt
Normal file
82
Tools/_CP14/LocalizationHelper/main.py
Normal file
82
Tools/_CP14/LocalizationHelper/main.py
Normal 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()
|
||||
1
Tools/_CP14/LocalizationHelper/requirements.txt
Normal file
1
Tools/_CP14/LocalizationHelper/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
PyYAML==6.0.1
|
||||
3
Tools/_CP14/LocalizationHelper/run.bat
Normal file
3
Tools/_CP14/LocalizationHelper/run.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
python main.py
|
||||
pause
|
||||
52
Tools/_CP14/LocalizationHelper/yml_parser/yml_parser.py
Normal file
52
Tools/_CP14/LocalizationHelper/yml_parser/yml_parser.py
Normal 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
|
||||
Reference in New Issue
Block a user