1#
2# Copyright 2007 Zuza Software Foundation
3#
4# This file is part of translate.
5#
6# translate is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# translate is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, see <http://www.gnu.org/licenses/>.
18
19"""Convert .ini files to Gettext PO localization files.
20
21See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/ini2po.html
22for examples and usage instructions.
23"""
24
25import sys
26
27from translate.convert import convert
28from translate.storage import ini, po
29
30
31class ini2po:
32    """Convert one or two INI files to a single PO file."""
33
34    SourceStoreClass = ini.inifile
35    TargetStoreClass = po.pofile
36    TargetUnitClass = po.pounit
37
38    def __init__(
39        self,
40        input_file,
41        output_file,
42        template_file=None,
43        blank_msgstr=False,
44        duplicate_style="msgctxt",
45        dialect="default",
46    ):
47        """Initialize the converter."""
48        if ini.INIConfig is None:
49            print("Missing iniparse library!")
50            sys.exit()
51
52        self.blank_msgstr = blank_msgstr
53        self.duplicate_style = duplicate_style
54
55        self.extraction_msg = None
56        self.output_file = output_file
57        self.source_store = self.SourceStoreClass(input_file, dialect=dialect)
58        self.target_store = self.TargetStoreClass()
59        self.template_store = None
60
61        if template_file is not None:
62            self.template_store = self.SourceStoreClass(template_file, dialect=dialect)
63
64    def convert_unit(self, unit):
65        """Convert a source format unit to a target format unit."""
66        target_unit = self.TargetUnitClass(encoding="UTF-8")
67        target_unit.addlocation("".join(unit.getlocations()))
68        target_unit.source = unit.source
69        target_unit.target = ""
70        return target_unit
71
72    def convert_store(self):
73        """Convert a single source format file to a target format file."""
74        self.extraction_msg = "extracted from %s" % self.source_store.filename
75
76        for source_unit in self.source_store.units:
77            self.target_store.addunit(self.convert_unit(source_unit))
78
79    def merge_stores(self):
80        """Convert two source format files to a target format file."""
81        self.extraction_msg = "extracted from {}, {}".format(
82            self.template_store.filename,
83            self.source_store.filename,
84        )
85
86        self.source_store.makeindex()
87        for template_unit in self.template_store.units:
88            target_unit = self.convert_unit(template_unit)
89
90            template_unit_name = "".join(template_unit.getlocations())
91            add_translation = (
92                not self.blank_msgstr
93                and template_unit_name in self.source_store.locationindex
94            )
95            if add_translation:
96                source_unit = self.source_store.locationindex[template_unit_name]
97                target_unit.target = source_unit.source
98            self.target_store.addunit(target_unit)
99
100    def run(self):
101        """Run the converter."""
102        if self.template_store is None:
103            self.convert_store()
104        else:
105            self.merge_stores()
106
107        if self.extraction_msg:
108            self.target_store.header().addnote(self.extraction_msg, "developer")
109
110        self.target_store.removeduplicates(self.duplicate_style)
111
112        if self.target_store.isempty():
113            return 0
114
115        self.target_store.serialize(self.output_file)
116        return 1
117
118
119def run_converter(
120    input_file,
121    output_file,
122    template_file=None,
123    pot=False,
124    duplicatestyle="msgctxt",
125    dialect="default",
126):
127    """Wrapper around converter."""
128    return ini2po(
129        input_file,
130        output_file,
131        template_file,
132        blank_msgstr=pot,
133        duplicate_style=duplicatestyle,
134        dialect=dialect,
135    ).run()
136
137
138def convertisl(
139    input_file,
140    output_file,
141    template_file=None,
142    pot=False,
143    duplicatestyle="msgctxt",
144    dialect="inno",
145):
146    return run_converter(
147        input_file, output_file, template_file, pot, duplicatestyle, dialect
148    )
149
150
151formats = {
152    "ini": ("po", run_converter),
153    ("ini", "ini"): ("po", run_converter),
154    "isl": ("po", convertisl),
155    ("isl", "isl"): ("po", convertisl),
156    "iss": ("po", convertisl),
157    ("iss", "iss"): ("po", convertisl),
158}
159
160
161def main(argv=None):
162    parser = convert.ConvertOptionParser(
163        formats, usetemplates=True, usepots=True, description=__doc__
164    )
165    parser.add_duplicates_option()
166    parser.passthrough.append("pot")
167    parser.run(argv)
168
169
170if __name__ == "__main__":
171    main()
172