summaryrefslogtreecommitdiff
path: root/solenv/bin/desktop-translate.py
blob: 639fa89af48fc77599aecf3c6cc2533da6cf096b (plain)
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
158
159
160
161
162
163
164
165
166
167
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This file incorporates work covered by the following license notice:
#
#   Licensed to the Apache Software Foundation (ASF) under one or more
#   contributor license agreements. See the NOTICE file distributed
#   with this work for additional information regarding copyright
#   ownership. The ASF licenses this file to you under the Apache
#   License, Version 2.0 (the "License"); you may not use this file
#   except in compliance with the License. You may obtain a copy of
#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
#

#
# Translates multiple .desktop files at once with strings from .ulf
# files; if you add new translatable .ulf files please add them to
# l10ntools/source/localize.cxx
#

import os, sys, argparse, io

def encodeDesktopString(s):
    # <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
    # value-types> says "The escape sequences \s, \n, \t, \r, and \\ are supported for values of
    # type string and localestring, meaning ASCII space, newline, tab, carriage return, and
    # backslash, respectively."  <https://specifications.freedesktop.org/desktop-entry-spec/
    # desktop-entry-spec-1.1.html#basic-format> says "A file is interpreted as a series of lines
    # that are separated by linefeed characters", so it is apparently necessary to escape at least
    # linefeed and backslash characters.  It is unclear why that spec talks about "linefeed" in
    # one place and about "newline" ("\n") and "carriage return" ("\r") in another, and how they are
    # supposed to relate, so just escape any U+000A LINE FEED as "\n" and any U+000D CARRIAGE RETURN
    # as "\r"; it is unclear exactly which occurrences of U+0020 SPACE and U+0009 CHARACTER
    # TABULATION would need to be escaped, so they are mostly left unescaped, for readability:
    s = s.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r');
    if s.startswith(' '):
        # <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
        # entries> says "Space before and after the equals sign should be ignored", so escape a
        # leading U+0020 SPACE as "\s" (while it is not clear whether "space" there means just
        # U+0020 SPACE or any kind of white space, in which case at least a leading U+0009 CHARACTER
        # TABULATION should similarly be escaped as "\t"; also, it is unclear whether such
        # characters should also be escaped at the end):
        s = '\\s' + s[1:]
    return s

parser = argparse.ArgumentParser()
parser.add_argument('-p', dest='productname', default='LibreOffice')
parser.add_argument('-d', dest='workdir', default='.')
parser.add_argument('--key', dest='key')
parser.add_argument('--prefix', dest='prefix', default='')
parser.add_argument('--ext', dest='ext')
parser.add_argument('--template-dir', dest='template_dir', default=None)
parser.add_argument('ifile')

o = parser.parse_args()

if o.template_dir is None:
    template_dir = '{}/{}'.format(o.workdir, o.prefix)
else:
    template_dir = o.template_dir

# hack for unity section
if o.key == "UnityQuickList":
    outkey = "Name"
else:
    outkey = o.key


templates = {}

# open input file
source = io.open(o.ifile, encoding='utf-8')

template = None

# read ulf file
for line in source:
    if line.strip() == '':
        continue
    if line[0] == "[":
        template = line.split(']', 1)[0][1:]
        entry = {}
        # For every section in the specified ulf file there should exist
        # a template file in $workdir ..
        entry['outfile'] = "{}{}.{}".format(template_dir, template, o.ext)
        entry['translations'] = {}
        templates[template] = entry
    else:
        # split locale = "value" into 2 strings
        if ' = ' not in line:
            continue
        locale, value = line.split(' = ')

        if locale != line:
            # replace en-US with en
            locale = locale.replace('en-US', 'en')

            # use just anything inside the ""
            assert(value[0] == '"')
            # Some entries span multiple lines.
            # An entry will always end on a double quote.
            while not value.endswith('"\n'):
                value += source.readline()
            value = value[1:-2]

            # replace resource placeholder
            value = value.replace('%PRODUCTNAME', o.productname)

            locale = locale.replace('-', '_')

            templates[template]['translations'][locale] = value

source.close()

processed = 0
# process templates
for template in templates:
    outfilename = templates[template]['outfile']

    # open the template file - ignore sections for which no
    # templates exist
    try:
        template_file = io.open(outfilename, encoding='utf-8')
    except Exception:
        # string files processed one by one
        if o.ext == 'str':
            continue
        sys.exit("Warning: No template found for item '{}' : '{}' : '{}': $!\n".format(template, outfile, line))
    processed += 1

    # open output file
    tmpfilename = '{}.tmp'.format(outfilename)
    outfile = io.open(tmpfilename, 'w', encoding='utf-8')

    # emit the template to the output file
    for line in template_file:
        keyline = line
        if keyline.startswith(o.key):
            keyline = outkey + keyline[len(o.key):]
        outfile.write(keyline)
        if o.key in line:
            translations = templates[template]['translations']
            for locale in sorted (translations.keys()):
                value = translations.get(locale, None)
                # print "locale is $locale\n";
                # print "value is $value\n";
                if value:
                    if o.ext == "desktop" or o.ext == "str":
                        if o.ext == "desktop":
                            value = encodeDesktopString(value)
                        outfile.write(u"""{}[{}]={}\n""".format(outkey, locale, value))
                    else:
                        outfile.write(u"""\t[{}]{}={}\n""".format(locale, outkey, value))

    template_file.close()

    outfile.close()
    if os.path.exists(outfilename):
        os.unlink(outfilename)
    os.rename(tmpfilename, outfilename)

if o.ext == 'str' and processed == 0:
    sys.exit("Warning: No matching templates processed")