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 .
20 # Translates multiple .desktop files at once with strings from .ulf
21 # files; if you add new translatable .ulf files please add them to
22 # l10ntools/source/localize.cxx
25 import os
, sys
, argparse
, io
27 def encodeDesktopString(s
):
28 # <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
29 # value-types> says "The escape sequences \s, \n, \t, \r, and \\ are supported for values of
30 # type string and localestring, meaning ASCII space, newline, tab, carriage return, and
31 # backslash, respectively." <https://specifications.freedesktop.org/desktop-entry-spec/
32 # desktop-entry-spec-1.1.html#basic-format> says "A file is interpreted as a series of lines
33 # that are separated by linefeed characters", so it is apparently necessary to escape at least
34 # linefeed and backslash characters. It is unclear why that spec talks about "linefeed" in
35 # one place and about "newline" ("\n") and "carriage return" ("\r") in another, and how they are
36 # supposed to relate, so just escape any U+000A LINE FEED as "\n" and any U+000D CARRIAGE RETURN
37 # as "\r"; it is unclear exactly which occurrences of U+0020 SPACE and U+0009 CHARACTER
38 # TABULATION would need to be escaped, so they are mostly left unescaped, for readability:
39 s
= s
.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r');
41 # <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
42 # entries> says "Space before and after the equals sign should be ignored", so escape a
43 # leading U+0020 SPACE as "\s" (while it is not clear whether "space" there means just
44 # U+0020 SPACE or any kind of white space, in which case at least a leading U+0009 CHARACTER
45 # TABULATION should similarly be escaped as "\t"; also, it is unclear whether such
46 # characters should also be escaped at the end):
50 parser
= argparse
.ArgumentParser()
51 parser
.add_argument('-p', dest
='productname', default
='LibreOffice')
52 parser
.add_argument('-d', dest
='workdir', default
='.')
53 parser
.add_argument('--key', dest
='key')
54 parser
.add_argument('--prefix', dest
='prefix', default
='')
55 parser
.add_argument('--ext', dest
='ext')
56 parser
.add_argument('--template-dir', dest
='template_dir', default
=None)
57 parser
.add_argument('ifile')
59 o
= parser
.parse_args()
61 if o
.template_dir
is None:
62 template_dir
= '{}/{}'.format(o
.workdir
, o
.prefix
)
64 template_dir
= o
.template_dir
66 # hack for unity section
67 if o
.key
== "UnityQuickList":
76 source
= io
.open(o
.ifile
, encoding
='utf-8')
82 if line
.strip() == '':
85 template
= line
.split(']', 1)[0][1:]
87 # For every section in the specified ulf file there should exist
88 # a template file in $workdir ..
89 entry
['outfile'] = "{}{}.{}".format(template_dir
, template
, o
.ext
)
90 entry
['translations'] = {}
91 templates
[template
] = entry
93 # split locale = "value" into 2 strings
96 locale
, value
= line
.split(' = ')
99 # replace en-US with en
100 locale
= locale
.replace('en-US', 'en')
102 # use just anything inside the ""
103 assert(value
[0] == '"')
104 # Some entries span multiple lines.
105 # An entry will always end on a double quote.
106 while not value
.endswith('"\n'):
107 value
+= source
.readline()
110 # replace resource placeholder
111 value
= value
.replace('%PRODUCTNAME', o
.productname
)
113 locale
= locale
.replace('-', '_')
115 templates
[template
]['translations'][locale
] = value
121 for template
in templates
:
122 outfilename
= templates
[template
]['outfile']
124 # open the template file - ignore sections for which no
127 template_file
= io
.open(outfilename
, encoding
='utf-8')
129 # string files processed one by one
132 sys
.exit("Warning: No template found for item '{}' : '{}' : '{}': $!\n".format(template
, outfile
, line
))
136 tmpfilename
= '{}.tmp'.format(outfilename
)
137 outfile
= io
.open(tmpfilename
, 'w', encoding
='utf-8')
139 # emit the template to the output file
140 for line
in template_file
:
142 if keyline
.startswith(o
.key
):
143 keyline
= outkey
+ keyline
[len(o
.key
):]
144 outfile
.write(keyline
)
146 translations
= templates
[template
]['translations']
147 for locale
in sorted (translations
.keys()):
148 value
= translations
.get(locale
, None)
149 # print "locale is $locale\n";
150 # print "value is $value\n";
152 if o
.ext
== "desktop" or o
.ext
== "str":
153 if o
.ext
== "desktop":
154 value
= encodeDesktopString(value
)
155 outfile
.write(u
"""{}[{}]={}\n""".format(outkey
, locale
, value
))
157 outfile
.write(u
"""\t[{}]{}={}\n""".format(locale
, outkey
, value
))
159 template_file
.close()
162 if os
.path
.exists(outfilename
):
163 os
.unlink(outfilename
)
164 os
.rename(tmpfilename
, outfilename
)
166 if o
.ext
== 'str' and processed
== 0:
167 sys
.exit("Warning: No matching templates processed")