Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a17e0f1

Browse files
committed
A bunch of changes, primarily to command line argument parsing
(inspired by Detlef Lannert). Specifically, -k/--keyword no longer takes an optional argument to clear the default keywords. Instead, use -K/--no-default-keywords to clear them. -n/--add-location also no longer takes an optional argument to set the comment style. Instead, use -S/--style to set the comment style to GNU or Solaris. -o/--output can take `-' as the filename, meaning write to standard output. The inputfile name can also be `-' meaning read from standard in. A few other changes include Kludge to mark the file docstring as translatable. Since the marking is to place _() around the docstring, and because we actually have to define the _() function before we use it, this means that we have to manually assign to __doc__ the output of _(). This doesn't seem too bad because you'll only use this idiom when translating a script's docstring (you really don't need to translate most module docstrings). Convert everything to string methods and do not import the string module. Bump the version number to 1.1
1 parent 34d11f0 commit a17e0f1

1 file changed

Lines changed: 100 additions & 64 deletions

File tree

Tools/i18n/pygettext.py

Lines changed: 100 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44
# minimally patched to make it even more xgettext compatible
55
# by Peter Funk <[email protected]>
66

7-
"""pygettext -- Python equivalent of xgettext(1)
7+
# for selftesting
8+
try:
9+
import fintl
10+
_ = fintl.gettext
11+
except ImportError:
12+
def _(s): return s
13+
14+
15+
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
816
917
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
1018
internationalization of C programs. Most of these tools are independent of
@@ -39,9 +47,11 @@
3947
4048
NOTE: pygettext attempts to be option and feature compatible with GNU xgettext
4149
where ever possible. However some options are still missing or are not fully
42-
implemented.
50+
implemented. Also, xgettext's use of command line switches with option
51+
arguments is broken, and in these cases, pygettext just defines additional
52+
switches.
4353
44-
Usage: pygettext [options] filename ...
54+
Usage: pygettext [options] inputfile ...
4555
4656
Options:
4757
@@ -61,33 +71,42 @@
6171
--help
6272
print this help message and exit
6373
64-
-k [word]
65-
--keyword[=word]
66-
Additional keywords to look for. Without `word' means not to use the
67-
default keywords. The default keywords, which are always looked for
68-
if not explicitly disabled: _
74+
-k word
75+
--keyword=word
76+
Keywords to look for in addition to the default set, which are:
77+
%(DEFAULTKEYWORDS)s
78+
79+
You can have multiple -k flags on the command line.
6980
70-
The default keyword list is different than GNU xgettext. You can have
71-
multiple -k flags on the command line.
81+
-K
82+
--no-default-keywords
83+
Disable the default set of keywords (see above). Any keywords
84+
explicitly added with the -k/--keyword option are still recognized.
7285
7386
--no-location
74-
Do not write filename/lineno location comments
87+
Do not write filename/lineno location comments.
7588
76-
-n [style]
77-
--add-location[=style]
89+
-n
90+
--add-location
7891
Write filename/lineno location comments indicating where each
7992
extracted string is found in the source. These lines appear before
80-
each msgid. Two styles are supported:
93+
each msgid. The style of comments is controlled by the -S/--style
94+
option. This is the default.
95+
96+
-S stylename
97+
--style stylename
98+
Specify which style to use for location comments. Two styles are
99+
supported:
81100
82101
Solaris # File: filename, line: line-number
83-
Gnu #: filename:line
102+
GNU #: filename:line
84103
85-
If style is omitted, Gnu is used. The style name is case
86-
insensitive. By default, locations are included.
104+
The style name is case insensitive. GNU style is the default.
87105
88106
-o filename
89107
--output=filename
90-
Rename the default output file from messages.pot to filename.
108+
Rename the default output file from messages.pot to filename. If
109+
filename is `-' then the output is sent to standard out.
91110
92111
-p dir
93112
--output-dir=dir
@@ -111,27 +130,25 @@
111130
extracted from the input files. Each string to be excluded must
112131
appear on a line by itself in the file.
113132
114-
"""
133+
If `inputfile' is -, standard input is read.
134+
135+
""")
115136

116137
import os
117138
import sys
118-
import string
119139
import time
120140
import getopt
121141
import tokenize
122142

123-
__version__ = '1.0'
143+
__version__ = '1.1'
124144

145+
default_keywords = ['_']
146+
DEFAULTKEYWORDS = ', '.join(default_keywords)
125147

126-
127-
# for selftesting
128-
try:
129-
import fintl
130-
_ = fintl.gettext
131-
except ImportError:
132-
def _(s): return s
148+
EMPTYSTRING = ''
133149

134150

151+
135152
# The normal pot-file header. msgmerge and EMACS' po-mode work better if
136153
# it's there.
137154
pot_header = _('''\
@@ -189,7 +206,7 @@ def escape(s):
189206
s = list(s)
190207
for i in range(len(s)):
191208
s[i] = escapes[ord(s[i])]
192-
return string.join(s, '')
209+
return EMPTYSTRING.join(s)
193210

194211

195212
def safe_eval(s):
@@ -200,7 +217,7 @@ def safe_eval(s):
200217
def normalize(s):
201218
# This converts the various Python string types into a format that is
202219
# appropriate for .po files, namely much closer to C style.
203-
lines = string.split(s, '\n')
220+
lines = s.split('\n')
204221
if len(lines) == 1:
205222
s = '"' + escape(s) + '"'
206223
else:
@@ -209,7 +226,8 @@ def normalize(s):
209226
lines[-1] = lines[-1] + '\n'
210227
for i in range(len(lines)):
211228
lines[i] = escape(lines[i])
212-
s = '""\n"' + string.join(lines, '\\n"\n"') + '"'
229+
lineterm = '\\n"\n"'
230+
s = '""\n"' + lineterm.join(lines) + '"'
213231
return s
214232

215233

@@ -245,7 +263,7 @@ def __openseen(self, ttype, tstring, lineno):
245263
# of messages seen. Reset state for the next batch. If there
246264
# were no strings inside _(), then just ignore this entry.
247265
if self.__data:
248-
msg = string.join(self.__data, '')
266+
msg = EMPTYSTRING.join(self.__data)
249267
if not msg in self.__options.toexclude:
250268
entry = (self.__curfile, self.__lineno)
251269
linenos = self.__messages.get(msg)
@@ -271,12 +289,14 @@ def write(self, fp):
271289
# as that generated by xgettext...
272290
print pot_header % {'time': timestamp, 'version': __version__}
273291
for k, v in self.__messages.items():
292+
if not options.writelocations:
293+
pass
274294
# location comments are different b/w Solaris and GNU:
275-
if options.location == options.SOLARIS:
295+
elif options.locationstyle == options.SOLARIS:
276296
for filename, lineno in v:
277297
d = {'filename': filename, 'lineno': lineno}
278298
print _('# File: %(filename)s, line: %(lineno)d') % d
279-
elif options.location == options.GNU:
299+
elif options.locationstyle == options.GNU:
280300
# fit as many locations on one line, as long as the
281301
# resulting line length doesn't exceeds 'options.width'
282302
locline = '#:'
@@ -298,14 +318,15 @@ def write(self, fp):
298318

299319

300320
def main():
301-
default_keywords = ['_']
321+
global default_keywords
302322
try:
303323
opts, args = getopt.getopt(
304324
sys.argv[1:],
305-
'ad:Ehk:n:o:p:Vvw:x:',
306-
['extract-all', 'default-domain', 'escape', 'help', 'keyword',
325+
'ad:Ehk:Kno:p:S:Vvw:x:',
326+
['extract-all', 'default-domain', 'escape', 'help',
327+
'keyword=', 'no-default-keywords',
307328
'add-location', 'no-location', 'output=', 'output-dir=',
308-
'verbose', 'version', 'width=', 'exclude-file=',
329+
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
309330
])
310331
except getopt.error, msg:
311332
usage(1, msg)
@@ -321,7 +342,8 @@ class Options:
321342
keywords = []
322343
outpath = ''
323344
outfile = 'messages.pot'
324-
location = GNU
345+
writelocations = 1
346+
locationstyle = GNU
325347
verbose = 0
326348
width = 78
327349
excludefilename = ''
@@ -342,19 +364,17 @@ class Options:
342364
elif opt in ('-E', '--escape'):
343365
options.escape = 1
344366
elif opt in ('-k', '--keyword'):
345-
if arg is None:
346-
default_keywords = []
347367
options.keywords.append(arg)
368+
elif opt in ('-K', '--no-default-keywords'):
369+
default_keywords = []
348370
elif opt in ('-n', '--add-location'):
349-
if arg is None:
350-
arg = 'gnu'
351-
try:
352-
options.location = locations[string.lower(arg)]
353-
except KeyError:
354-
d = {'arg':arg}
355-
usage(1, _('Invalid value for --add-location: %(arg)s') % d)
371+
options.writelocations = 1
356372
elif opt in ('--no-location',):
357-
options.location = 0
373+
options.writelocations = 0
374+
elif opt in ('-S', '--style'):
375+
options.locationstyle = locations.get(arg.lower())
376+
if options.locationstyle is None:
377+
usage(1, _('Invalid value for --style: %s') % arg)
358378
elif opt in ('-o', '--output'):
359379
options.outfile = arg
360380
elif opt in ('-p', '--output-dir'):
@@ -368,9 +388,7 @@ class Options:
368388
try:
369389
options.width = int(arg)
370390
except ValueError:
371-
d = {'arg':arg}
372-
usage(1, _('Invalid value for --width: %(arg)s, must be int')
373-
% d)
391+
usage(1, _('--width argument must be an integer: %s') % arg)
374392
elif opt in ('-x', '--exclude-file'):
375393
options.excludefilename = arg
376394

@@ -396,19 +414,37 @@ class Options:
396414
# slurp through all the files
397415
eater = TokenEater(options)
398416
for filename in args:
399-
if options.verbose:
400-
print _('Working on %(filename)s') % {'filename':filename}
401-
fp = open(filename)
402-
eater.set_filename(filename)
403-
tokenize.tokenize(fp.readline, eater)
404-
fp.close()
405-
406-
if options.outpath:
407-
options.outfile = os.path.join(options.outpath, options.outfile)
408-
fp = open(options.outfile, 'w')
409-
eater.write(fp)
410-
fp.close()
417+
if filename == '-':
418+
if options.verbose:
419+
print _('Reading standard input')
420+
fp = sys.stdin
421+
closep = 0
422+
else:
423+
if options.verbose:
424+
print _('Working on %s') % filename
425+
fp = open(filename)
426+
closep = 1
427+
try:
428+
eater.set_filename(filename)
429+
tokenize.tokenize(fp.readline, eater)
430+
finally:
431+
if closep:
432+
fp.close()
411433

434+
# write the output
435+
if options.outfile == '-':
436+
fp = sys.stdout
437+
closep = 0
438+
else:
439+
if options.outpath:
440+
options.outfile = os.path.join(options.outpath, options.outfile)
441+
fp = open(options.outfile, 'w')
442+
closep = 1
443+
try:
444+
eater.write(fp)
445+
finally:
446+
if closep:
447+
fp.close()
412448

413449

414450
if __name__ == '__main__':

0 commit comments

Comments
 (0)