• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dfint / df-gettext-toolkit / 5871136315

pending completion
5871136315

push

github

insolor
Upgrade style of the type annotations using ruff

157 of 404 branches covered (38.86%)

Branch coverage included in aggregate %.

53 of 53 new or added lines in 18 files covered. (100.0%)

369 of 876 relevant lines covered (42.12%)

1.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/df_gettext_toolkit/create_mod/from_template.py
1
from collections.abc import Iterator, Mapping
×
2
from dataclasses import dataclass
×
3
from pathlib import Path
×
4

5
import jinja2
×
6
import typer
×
7
from babel.messages.pofile import read_po
×
8
from loguru import logger
×
9

10
from df_gettext_toolkit.create_mod.generate_preview import main as generate_preview
×
11
from df_gettext_toolkit.create_pot.from_steam_text import get_raw_object_type
×
12
from df_gettext_toolkit.translate.translate_plain_text import translate_plain_text_file
×
13
from df_gettext_toolkit.translate.translate_raws import translate_single_raw_file
×
14
from df_gettext_toolkit.utils.backup import backup
×
15

16

17
@dataclass
×
18
class Dictionaries:
×
19
    language_name: str
×
20
    dictionary_object: Mapping[tuple[str, str | None], str]
×
21
    dictionary_textset: Mapping[str, str]
×
22

23

24
def create_single_localized_mod(
×
25
    template_path: Path,
26
    dictionaries: Dictionaries,
27
    source_encoding: str,
28
    destination_encoding: str,
29
) -> Iterator[str]:
30
    yield from localize_directory(template_path / "objects", dictionaries, source_encoding, destination_encoding)
×
31
    translated_files = len(list((template_path / "objects").glob("*.txt")))
×
32
    logger.info(f"Translated: {translated_files} files")
×
33
    language_name = dictionaries.language_name
×
34
    create_info(template_path / "info.txt", source_encoding, destination_encoding, language_name)
×
35

36
    svg_template_path = Path(__file__).parent / "templates" / "preview_template.svg"
×
37
    generate_preview(
×
38
        svg_template_path,
39
        language_name.upper(),
40
        "translation",
41
        template_path / "preview.svg",
42
    )
43

44

45
def localize_directory(
×
46
    template_path: Path,
47
    dictionaries: Dictionaries,
48
    source_encoding: str,
49
    destination_encoding: str,
50
) -> Iterator[str]:
51
    for file_path in template_path.glob("*.txt"):
×
52
        if file_path.is_file():
×
53
            object_type = get_raw_object_type(file_path, source_encoding)
×
54
            with backup(file_path) as bak_name:
×
55
                if object_type == "TEXT_SET":
×
56
                    yield from translate_plain_text_file(
×
57
                        bak_name, file_path, dictionaries.dictionary_textset, destination_encoding, False
58
                    )
59
                else:
60
                    yield from translate_single_raw_file(
×
61
                        bak_name, file_path, dictionaries.dictionary_object, destination_encoding
62
                    )
63

64

65
def fill_info_template(template_path: Path, **kwargs: str | list[str] | dict[str, str]) -> str:
×
66
    with template_path.open() as template_file:
×
67
        template_text = template_file.read()
×
68
        template = jinja2.Template(template_text)
×
69

70
        rendered = template.render(**kwargs)
×
71
        result = "\n".join(filter(bool, rendered.splitlines()))
×
72
        return result
×
73

74

75
def create_info(info_file: Path, source_encoding: str, destination_encoding: str, language: str) -> None:
×
76
    with info_file.open("w", encoding=destination_encoding) as dest:
×
77
        info_template_path = Path(__file__).parent / "templates" / "info_template.txt"
×
78
        rendered = fill_info_template(
×
79
            info_template_path,
80
            name=f"{language.upper()} Translation",
81
            description=f"Translation to {language.upper()} language for vanilla mods",
82
            author="DFINT",
83
            id=f"{language.lower()}_vanilla_translation",
84
            steam_title=f"{language.upper()} Translation",
85
            steam_description=f"Translation to {language.upper()} language for vanilla mods",
86
            steam_tags=["ui", "qol", "translation"],
87
            steam_key_value_tags=dict(language=language),
88
        )
89
        print(rendered, file=dest)
×
90

91

92
def get_dictionaries(translation_path: Path, language: str) -> Dictionaries:
×
93
    po_files = {"objects": Path(), "text_set": Path()}
×
94
    for po_file in po_files:
×
95
        mtime = 0
×
96
        for file in translation_path.glob(f"*{po_file}*{language}.po"):
×
97
            if file.is_file() and file.stat().st_mtime > mtime:
×
98
                po_files[po_file] = file
×
99
        if not po_files[po_file].is_file():
×
100
            raise Exception(f"Unable to find {po_file} po file for language {language}")
×
101

102
    with open(po_files["objects"], "r", encoding="utf-8") as pofile:
×
103
        dictionary_object: Mapping[tuple[str, str | None], str] = {
×
104
            (item.id, item.context): item.string for item in read_po(pofile)
105
        }
106
    with open(po_files["text_set"], "r", encoding="utf-8") as po_file:
×
107
        dictionary_textset: Mapping[str, str] = {item.id: item.string for item in read_po(po_file) if item.id}
×
108
    return Dictionaries(language.lower(), dictionary_object, dictionary_textset)
×
109

110

111
@logger.catch
×
112
def main(
×
113
    template_path: Path,
114
    translation_path: Path,
115
    language: str,
116
    destination_encoding: str,
117
    source_encoding: str = "cp437",
118
) -> None:
119
    assert template_path.exists(), "Source path doesn't exist"
×
120
    assert translation_path.exists(), "Translation path doesn't exist"
×
121

122
    dictionaries = get_dictionaries(translation_path, language)
×
123

124
    for file in create_single_localized_mod(
×
125
        template_path,
126
        dictionaries,
127
        source_encoding,
128
        destination_encoding,
129
    ):
130
        logger.debug(f"{file} translated")
×
131

132
    for bak_file in template_path.glob("**/*.bak"):
×
133
        try:
×
134
            bak_file.unlink()
×
135
        except Exception:
×
136
            logger.error(f"Error occurred while removing {bak_file.resolve()}")
×
137

138
    template_path.rename(template_path.parent / f"{template_path.name}_translation")
×
139
    logger.warning(
×
140
        "All done! Consider to change info.txt file and made unique preview.png "
141
        "before uploading to steam or sharing the mod."
142
    )
143

144

145
if __name__ == "__main__":
146
    typer.run(main)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc