4 # gen_xmlpool.py /path/to/t_option.h localedir lang lang lang ...
6 # For each given language, this script expects to find a .mo file at
7 # `{localedir}/{language}/LC_MESSAGES/options.mo`.
10 from __future__
import print_function
, unicode_literals
18 if sys
.version_info
< (3, 0):
19 gettext_method
= 'ugettext'
21 gettext_method
= 'gettext'
23 # Escape special characters in C strings
25 escapeSeqs
= {'\a' : '\\a', '\b' : '\\b', '\f' : '\\f', '\n' : '\\n',
26 '\r' : '\\r', '\t' : '\\t', '\v' : '\\v', '\\' : '\\\\'}
27 # " -> '' is a hack. Quotes (") aren't possible in XML attributes.
28 # Better use Unicode characters for typographic quotes in option
29 # descriptions and translations.
34 # Special case: escape double quote with “ or ”, depending
35 # on whether it's an open or close quote. This is needed because plain
36 # double quotes are not possible in XML attributes.
50 # Expand escape sequences in C strings (needed for gettext lookup)
52 escapeSeqs
= {'a' : '\a', 'b' : '\b', 'f' : '\f', 'n' : '\n',
53 'r' : '\r', 't' : '\t', 'v' : '\v',
54 '"' : '"', '\\' : '\\'}
68 if (c
>= '0' and c
<= '9') or \
69 (c
>= 'a' and c
<= 'f') or \
70 (c
>= 'A' and c
<= 'F'):
71 num
= num
* 16 + int(c
, 16)
80 if c
>= '0' and c
<= '7':
81 num
= num
* 8 + int(c
, 8)
93 elif c
>= '0' and c
<= '7':
100 elif c
== 'x' or c
== 'X':
109 # Expand matches. The first match is always a DESC or DESC_BEGIN match.
110 # Subsequent matches are ENUM matches.
112 # DESC, DESC_BEGIN format: \1 \2=<lang> \3 \4=gettext(" \5=<text> \6=") \7
113 # ENUM format: \1 \2=gettext(" \3=<text> \4=") \5
114 def expandMatches(matches
, translations
, outfile
, end
=None):
115 assert len(matches
) > 0
116 nTranslations
= len(translations
)
118 # Expand the description+enums for all translations
119 for lang
,trans
in translations
:
121 # Make sure that all but the last line of a simple description
122 # are extended with a backslash.
124 if len(matches
) == 1 and i
< len(translations
) and \
125 not matches
[0].expand(r
'\7').endswith('\\'):
127 text
= escapeCString(getattr(trans
, gettext_method
)(expandCString(
128 matches
[0].expand (r
'\5'))))
129 text
= (matches
[0].expand(r
'\1' + lang
+ r
'\3"' + text
+ r
'"\7') + suffix
)
131 outfile
.write(text
+ '\n')
133 # Expand any subsequent enum lines
134 for match
in matches
[1:]:
135 text
= escapeCString(getattr(trans
, gettext_method
)(expandCString(
136 match
.expand(r
'\3'))))
137 text
= match
.expand(r
'\1"' + text
+ r
'"\5')
139 outfile
.write(text
+ '\n')
141 # Expand description end
145 # Regular expressions:
146 reLibintl_h
= re
.compile(r
'#\s*include\s*<libintl.h>')
147 reDESC
= re
.compile(r
'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
148 reDESC_BEGIN
= re
.compile(r
'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
149 reENUM
= re
.compile(r
'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
150 reDESC_END
= re
.compile(r
'\s*DRI_CONF_DESC_END')
154 parser
= argparse
.ArgumentParser()
155 parser
.add_argument('--template', required
=True)
156 parser
.add_argument('--output', required
=True)
157 parser
.add_argument('--localedir', required
=True)
158 parser
.add_argument('--languages', nargs
='*', default
=[])
159 args
= parser
.parse_args()
161 # Compile a list of translation classes to all supported languages.
162 # The first translation is always a NullTranslations.
163 translations
= [("en", gettext
.NullTranslations())]
164 for lang
in args
.languages
:
166 filename
= os
.path
.join(args
.localedir
, '{}.gmo'.format(lang
))
167 with io
.open(filename
, 'rb') as f
:
168 trans
= gettext
.GNUTranslations(f
)
169 except (IOError, OSError):
170 print("Warning: language '%s' not found." % lang
, file=sys
.stderr
)
172 translations
.append((lang
, trans
))
174 with io
.open(args
.output
, mode
='wt', encoding
='utf-8') as output
:
175 output
.write("/* This is file is generated automatically. Don't edit! */\n")
177 # Process the options template and generate options.h with all
179 with io
.open(args
.template
, mode
="rt", encoding
='utf-8') as template
:
181 for line
in template
:
183 matchENUM
= reENUM
.match(line
)
184 matchDESC_END
= reDESC_END
.match(line
)
186 descMatches
.append(matchENUM
)
188 expandMatches(descMatches
, translations
, output
, line
)
191 print("Warning: unexpected line inside description dropped:\n",
192 line
, file=sys
.stderr
)
194 if reLibintl_h
.search(line
):
195 # Ignore (comment out) #include <libintl.h>
196 output
.write("/* %s * commented out by gen_xmlpool.py */\n" % line
)
198 matchDESC
= reDESC
.match(line
)
199 matchDESC_BEGIN
= reDESC_BEGIN
.match(line
)
201 assert not descMatches
202 expandMatches([matchDESC
], translations
, output
)
203 elif matchDESC_BEGIN
:
204 assert not descMatches
205 descMatches
= [matchDESC_BEGIN
]
211 print("Warning: unterminated description at end of file.", file=sys
.stderr
)
212 expandMatches(descMatches
, translations
, output
)
215 if __name__
== '__main__':