File: build_i18n.py

package info (click to toggle)
python-distutils-extra 3.2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 220 kB
  • sloc: python: 1,817; makefile: 10
file content (157 lines) | stat: -rw-r--r-- 6,059 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""distutils_extra.command.build_i18n

Implements the Distutils 'build_i18n' command."""

# TODO: Address following pylint complaints
# pylint: disable=attribute-defined-outside-init,broad-except,eval-used,missing-function-docstring

import glob
import os
import pathlib

from setuptools import Command


# pylint: disable-next=invalid-name,too-many-instance-attributes
class build_i18n(Command):
    """integrate the gettext framework"""

    description = __doc__

    user_options = [
        ("desktop-files=", None, ".desktop.in files that should be merged"),
        ("xml-files=", None, ".xml.in files that should be merged"),
        ("schemas-files=", None, ".schemas.in files that should be merged"),
        ("ba-files=", None, "bonobo-activation files that should be merged"),
        ("rfc822deb-files=", None, "RFC822 files that should be merged"),
        ("key-files=", None, ".key.in files that should be merged"),
        ("domain=", "d", "gettext domain"),
        ("merge-po", "m", "merge po files against template"),
        ("po-dir=", "p", "directory that holds the i18n files"),
        ("bug-contact=", None, "contact address for msgid bugs"),
    ]

    boolean_options = ["merge-po"]

    def initialize_options(self):
        self.desktop_files = []
        self.xml_files = []
        self.key_files = []
        self.schemas_files = []
        self.ba_files = []
        self.rfc822deb_files = []
        self.domain = None
        self.merge_po = False
        self.bug_contact = None
        self.po_dir = None

    def finalize_options(self):
        if self.domain is None:
            self.domain = self.distribution.metadata.name
        if self.po_dir is None:
            self.po_dir = "po"

    def run(self):
        """
        Update the language files, generate mo files and add them
        to the to be installed files
        """
        # TODO: split into smaller methods
        # pylint: disable=too-many-branches,too-many-locals,too-many-statements
        if not os.path.isdir(self.po_dir):
            return

        data_files = self.distribution.data_files
        if data_files is None:
            # in case not data_files are defined in setup.py
            self.distribution.data_files = data_files = []

        if self.bug_contact is not None:
            os.environ["XGETTEXT_ARGS"] = f"--msgid-bugs-address={self.bug_contact} "

        # Print a warning if there is a Makefile that would overwrite our
        # values
        if os.path.exists(f"{self.po_dir}/Makefile"):
            self.announce(
                """
WARNING: Intltool will use the values specified from the
         existing po/Makefile in favor of the values
         from setup.cfg.
         Remove the Makefile to avoid problems."""
            )

        # If there is a po/LINGUAS file, or the LINGUAS environment variable
        # is set, only compile the languages listed there.
        selected_languages = None
        linguas_file = pathlib.Path(self.po_dir) / "LINGUAS"
        if linguas_file.is_file():
            selected_languages = linguas_file.read_text().split()
        if "LINGUAS" in os.environ:
            selected_languages = os.environ["LINGUAS"].split()

        # Update po(t) files and print a report
        # We have to change the working dir to the po dir for intltool
        cmd = ["intltool-update", (self.merge_po and "-r" or "-p"), "-g", self.domain]
        cwd = os.getcwd()
        os.chdir(self.po_dir)
        self.spawn(cmd)
        os.chdir(cwd)
        max_po_mtime = 0
        for po_file in glob.glob(f"{self.po_dir}/*.po"):
            lang = os.path.basename(po_file[:-3])
            if selected_languages and lang not in selected_languages:
                continue
            mo_dir = os.path.join("build", "mo", lang, "LC_MESSAGES")
            mo_file = os.path.join(mo_dir, f"{self.domain}.mo")
            if not os.path.exists(mo_dir):
                os.makedirs(mo_dir)
            cmd = ["msgfmt", po_file, "-o", mo_file]
            po_mtime = os.path.getmtime(po_file)
            mo_mtime = os.path.exists(mo_file) and os.path.getmtime(mo_file) or 0
            if po_mtime > max_po_mtime:
                max_po_mtime = po_mtime
            if po_mtime > mo_mtime:
                self.spawn(cmd)

            targetpath = os.path.join("share/locale", lang, "LC_MESSAGES")
            data_files.append((targetpath, (mo_file,)))

        # merge .in with translation
        for option, switch in (
            (self.xml_files, "-x"),
            (self.desktop_files, "-d"),
            (self.schemas_files, "-s"),
            (self.rfc822deb_files, "-r"),
            (self.ba_files, "-b"),
            (self.key_files, "-k"),
        ):
            try:
                file_set = eval(option)
            except Exception:
                continue
            for target, files in file_set:
                build_target = os.path.join("build", target)
                if not os.path.exists(build_target):
                    os.makedirs(build_target)
                files_merged = []
                for file in files:
                    if file.endswith(".in"):
                        file_merged = os.path.basename(file[:-3])
                    else:
                        file_merged = os.path.basename(file)
                    file_merged = os.path.join(build_target, file_merged)
                    cmd = ["intltool-merge", switch, self.po_dir, file, file_merged]
                    mtime_merged = (
                        os.path.exists(file_merged)
                        and os.path.getmtime(file_merged)
                        or 0
                    )
                    mtime_file = os.path.getmtime(file)
                    if mtime_merged < max_po_mtime or mtime_merged < mtime_file:
                        # Only build if output is older than input (.po,.in)
                        self.spawn(cmd)
                    files_merged.append(file_merged)
                data_files.append((target, files_merged))


# class build