2 # This file is part of the LibreOffice project.
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v. 2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 # This file incorporates work covered by the following license notice:
10 # Licensed to the Apache Software Foundation (ASF) under one or more
11 # contributor license agreements. See the NOTICE file distributed
12 # with this work for additional information regarding copyright
13 # ownership. The ASF licenses this file to you under the Apache
14 # License, Version 2.0 (the "License"); you may not use this file
15 # except in compliance with the License. You may obtain a copy of
16 # the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 """Translates multiple .desktop files at once with strings from .ulf
20 files; if you add new translatable .ulf files please add them to
21 l10ntools/source/localize.cxx in case the module is not already listed."""
29 def encode_desktop_string(s_value
):
30 """Function encoding strings to be used as values in .desktop files."""
31 # <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
32 # value-types> says "The escape sequences \s, \n, \t, \r, and \\ are supported for values of
33 # type string and localestring, meaning ASCII space, newline, tab, carriage return, and
34 # backslash, respectively." <https://specifications.freedesktop.org/desktop-entry-spec/
35 # desktop-entry-spec-1.1.html#basic-format> says "A file is interpreted as a series of lines
36 # that are separated by linefeed characters", so it is apparently necessary to escape at least
37 # linefeed and backslash characters. It is unclear why that spec talks about "linefeed" in
38 # one place and about "newline" ("\n") and "carriage return" ("\r") in another, and how they are
39 # supposed to relate, so just escape any U+000A LINE FEED as "\n" and any U+000D CARRIAGE RETURN
40 # as "\r"; it is unclear exactly which occurrences of U+0020 SPACE and U+0009 CHARACTER
41 # TABULATION would need to be escaped, so they are mostly left unescaped, for readability:
42 s_value
= s_value
.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r")
43 if s_value
.startswith(" "):
44 # <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
45 # entries> says "Space before and after the equals sign should be ignored", so escape a
46 # leading U+0020 SPACE as "\s" (while it is not clear whether "space" there means just
47 # U+0020 SPACE or any kind of white space, in which case at least a leading U+0009 CHARACTER
48 # TABULATION should similarly be escaped as "\t"; also, it is unclear whether such
49 # characters should also be escaped at the end):
50 s_value
= "\\s" + s_value
[1:]
54 parser
= argparse
.ArgumentParser()
55 parser
.add_argument("-p", dest
="productname", default
="LibreOffice")
56 parser
.add_argument("-d", dest
="workdir", default
=".")
57 parser
.add_argument("--key", dest
="key")
58 parser
.add_argument("--prefix", dest
="prefix", default
="")
59 parser
.add_argument("--ext", dest
="ext")
60 parser
.add_argument("--template-dir", dest
="template_dir", default
=None)
61 parser
.add_argument("ifile")
63 o
= parser
.parse_args()
65 if o
.template_dir
is None:
66 template_dir
= f
"{o.workdir}/{o.prefix}"
68 template_dir
= o
.template_dir
70 # hack for unity section
71 if o
.key
== "UnityQuickList":
80 source
= io
.open(o
.ifile
, encoding
="utf-8")
86 if line
.strip() == "":
89 template
= line
.split("]", 1)[0][1:]
91 # For every section in the specified ulf file there should exist
92 # a template file in $workdir ..
93 entry
["outfile"] = f
"{template_dir}{template}.{o.ext}"
94 entry
["translations"] = {}
95 templates
[template
] = entry
97 # split locale = "value" into 2 strings
100 locale
, value
= line
.split(" = ")
103 # replace en-US with en
104 locale
= locale
.replace("en-US", "en")
106 # use just anything inside the ""
107 assert value
[0] == '"'
108 # Some entries span multiple lines.
109 # An entry will always end on a double quote.
110 while not value
.endswith('"\n'):
111 value
+= source
.readline()
114 # replace resource placeholder
115 value
= value
.replace("%PRODUCTNAME", o
.productname
)
117 locale
= locale
.replace("-", "_")
119 templates
[template
]["translations"][locale
] = value
125 for template
, entries
in templates
.items():
126 outfilename
= entries
["outfile"]
128 # open the template file - ignore sections for which no
131 template_file
= io
.open(outfilename
, encoding
="utf-8")
133 # string files processed one by one
137 f
"Warning: No template found for item '{template}' : '{outfilename}'\n"
142 tmpfilename
= f
"{outfilename}.tmp"
143 outfile
= io
.open(tmpfilename
, "w", encoding
="utf-8")
145 # emit the template to the output file
146 for line
in template_file
:
148 if keyline
.startswith(o
.key
):
149 keyline
= OUTKEY
+ keyline
[len(o
.key
) :]
150 outfile
.write(keyline
)
152 translations
= entries
["translations"]
153 for locale
in sorted(translations
.keys()):
154 value
= translations
.get(locale
, None)
155 # print "locale is $locale\n";
156 # print "value is $value\n";
158 if o
.ext
in ("desktop", "str"):
159 if o
.ext
== "desktop":
160 value
= encode_desktop_string(value
)
161 outfile
.write(f
"{OUTKEY}[{locale}]={value}\n")
163 outfile
.write(f
"\t[{locale}]{OUTKEY}={value}\n")
165 template_file
.close()
168 if os
.path
.exists(outfilename
):
169 os
.unlink(outfilename
)
170 os
.rename(tmpfilename
, outfilename
)
172 if o
.ext
== "str" and processed
== 0:
173 sys
.exit("Warning: No matching templates processed")