Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localisation #282

Draft
wants to merge 11 commits into
base: Experimental-Mod-Pack
Choose a base branch
from
41 changes: 41 additions & 0 deletions .github/workflows/localise.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Localisation

on: pull_request

jobs:
update-localisation:
# Don't run if this is a draft.
if: github.event.pull_request.draft == true
name: Update Localisation
runs-on: ubuntu-latest

steps:
- name: Checkout Git repository
uses: actions/checkout@v2
# Comply with git-auto-commit
with:
ref: ${{ github.head_ref }}

- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9

- name: install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade orjson

- name: run update_en_strings.py
# TODO: Find a git command that will run on other branches.
run: |
python ../../locale/update_en_strings.py ../data
git --no-pager diff --name-status $GITHUB_BASE_REF...$GITHUB_SHA | python ../../locale/handle_file_operations.py

- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Automatically update english strings.
# This shouldn't matter, but just in case.
file_pattern: *.json
# Give blame where it is due.
commit_author: Author <actions@github.com>
43 changes: 43 additions & 0 deletions locale/handle_file_operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python
import sys
import os
from pathlib import Path
import shutil

# Ensure that the path is correct.
PATH_TO_LOCALE = Path(__file__).parent.absolute()
LOCALES = tuple(
PATH_TO_LOCALE.joinpath(d) for d in os.scandir(PATH_TO_LOCALE) if d.is_dir()
)

for line in sys.stdin:
line = line.split("\t")
if len(line) == 3:
code, old_file, new_file = line.split("\t")
code = code[0]
else:
code, filepath = line

# We only handle deleted or renamed files.
if code not in ("D", "R"):
continue

# filepath starts relative to Community-Mod-Compilation/. Remove data/
filepath = Path(*Path(filepath).parts[1:])
old_file = Path(*Path(old_file).parts[1:])
new_file = Path(*Path(new_file).parts[1:])

if code == "D":
for locale in LOCALES:
path = Path(locale, filepath)
# It is quite probable that the translation does not exist.
if path.is_file():
path.unlink()

elif code == "R":
for locale in LOCALES:
locale_new = Path(locale, new_file)
locale_old = Path(locale, old_file)
if locale_old.is_file():
shutil.copy(locale_old, locale_new)
locale_old.unlink()
72 changes: 72 additions & 0 deletions locale/update_en_strings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python

import orjson
from orjson import OPT_APPEND_NEWLINE, OPT_INDENT_2
import os
from pathlib import Path
from stat import S_IXOTH

# TODO: Make a script that doesn't rely on recreating every file.
PRETTY_PRINT = OPT_APPEND_NEWLINE | OPT_INDENT_2


def generate_localisation_file(path: Path):
# Assume Community-Mod-Compilation/data/.
# Assume this script is in locale, and then make absolute.
locale_file = Path("en", *path.parts[2:]).resolve()

if not locale_file.is_file():
if not locale_file.parent.is_dir():
locale_file.parent.mkdir(mode=S_IXOTH, parents=True, exist_ok=True)
# Get every directory starting from Community-Mod-Compilation/locale/en/
# TODO: Replace this with a call to range().
for i, p in enumerate(locale_file.parts[3:-1], 4):
parent_dir = os.path.join(locale_file.parts[:i])
# Check if permission allows everybody to execute.
if os.stat(parent_dir)[0] != S_IXOTH:
os.chmod(parent_dir, S_IXOTH)
# Annoying, but this is the only file creation option on Windows and MacOS
with open(locale_file, "w"):
pass

# Return path to the new file.
return locale_file


def get_translation_strings(path: Path):
tr_file = []
try:
json = orjson.loads(path.read_bytes())
except orjson.JSONDecodeError:
raise orjson.JSONDecodeError(f"File: {path}")

if type(json) is not list:
return

for jo in json:
if type(jo) is not dict:
continue
# TODO: Check if there are things without descriptions to be translated.
if jo.get("description") and jo.get("name"):
tr_file.append({"name": jo["name"], "description": jo["description"]})

return tr_file


def main(directory):
for root, dirnames, filenames in os.walk(directory):
for filename in [f for f in filenames if f.endswith(".json")]:
path = Path(root, filename)
tr_file = get_translation_strings(path)
# No point in generating a new file if it's going to be empty.
if not tr_file:
continue
local = generate_localisation_file(path)
with open(local, "wb") as f:
f.write(orjson.dumps(tr_file, option=PRETTY_PRINT))


if __name__ == "__main__":
import sys

main(sys.argv[1])