2
# Kiwi: a Framework and Enhanced Widgets for Python
4
# Copyright (C) 2005 Async Open Source
6
# This library is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU Lesser General Public
8
# License as published by the Free Software Foundation; either
9
# version 2.1 of the License, or (at your option) any later version.
11
# This library is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
# Lesser General Public License for more details.
16
# You should have received a copy of the GNU Lesser General Public
17
# License along with this library; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
"""Internationalization utilities. Requires intltool and gettext"""
24
from distutils.dep_util import newer
25
from distutils.filelist import FileList, findall
26
from optparse import OptionParser
28
from shutil import copyfile
30
from kiwi.dist import listfiles
32
# This is a template, used to generate a list of translatable file
33
# which intltool can understand.
34
# It reuses the syntax from distutils MANIFEST files, a POTFILES.in
35
# will be generate from it, see update_po()
36
POTFILES = 'POTFILES.list'
38
def check_directory(root):
39
po_dir = os.path.join(root, 'po')
40
if not os.path.exists(po_dir):
41
raise SystemExit("A 'po` directory must exist")
42
if not os.path.isdir(po_dir):
43
raise SystemExit("po must be a directory")
45
locale_dir = os.path.join(root, 'locale')
46
if os.path.exists(locale_dir):
47
if not os.path.isdir(po_dir):
48
raise SystemExit("locale must be a directory")
50
def check_pot_file(root, package):
51
pot_file = os.path.join(root, 'po', '%s.pot' % package)
52
if not os.path.exists(pot_file):
53
raise SystemExit("Need a pot file, run --update first")
56
def get_translatable_files(root):
57
pofiles = os.path.join(root, 'po', POTFILES)
58
if not os.path.exists(pofiles):
59
print 'Warning: Could not find %s' % pofiles
65
for line in fp.readlines():
66
filelist.process_template_line(line)
69
def list_languages(root):
70
return [os.path.basename(po_file[:-3])
71
for po_file in listfiles(root, 'po', '*.po')]
73
def update_po(root, package):
74
files = get_translatable_files(root)
75
potfiles_in = os.path.join(root, 'po', 'POTFILES.in')
76
if os.path.exists(potfiles_in):
77
os.unlink(potfiles_in)
79
rml_files = _extract_rml_files(root)
81
fd = open(potfiles_in, 'w')
82
for filename in files + rml_files:
83
fd.write(filename + '\n')
88
os.chdir(os.path.join(root, 'po'))
90
if os.system('intltool-update 2> /dev/null > /dev/null') != 0:
91
raise SystemExit('ERROR: intltool-update could not be found')
94
res = os.system('intltool-update --pot --gettext-package=%s' % package)
96
raise SystemExit("ERROR: failed to generate pot file")
98
for lang in list_languages(root):
99
new = lang + '.new.po'
100
cmd = ('intltool-update --dist --gettext-package=%s '
101
'-o %s %s > /dev/null' % (package, new, lang))
103
if not os.path.exists(new):
104
raise SystemExit("ERROR: intltool failed, see above")
106
os.rename(new, lang + '.po')
113
os.unlink(potfiles_in)
115
def _clean_rml(data):
118
start_pos = data.find('<%')
122
fixed += data[:start_pos]
123
data = data[start_pos:]
124
end_pos = data.find('%>')
126
end_pos = data.find('/>')
128
data = data[end_pos+2:]
131
def _extract_rml_files(root):
133
for rml_file in findall(root):
134
if not rml_file.endswith('.rml'):
136
data = open(rml_file).read()
137
data = _clean_rml(data)
140
extracted = rml_file + '.extracted'
141
if os.path.exists(extracted):
143
open(extracted, 'w').write(data)
144
extracted = extracted[len(root)+1:]
145
cmd = 'intltool-extract --type=gettext/xml %s' % extracted
148
raise SystemExit("ERROR: failed to generate pot file")
150
files.append(extracted + '.h')
153
def compile_po_files(root, package):
154
if os.system('msgfmt 2> /dev/null') != 256:
155
print 'msgfmt could not be found, disabling translations'
158
mo_file = package + '.mo'
159
for po_file in listfiles(root, 'po', '*.po'):
160
lang = os.path.basename(po_file[:-3])
161
mo = os.path.join(root, 'locale', lang, 'LC_MESSAGES', mo_file)
163
if not os.path.exists(mo) or newer(po_file, mo):
164
directory = os.path.dirname(mo)
165
if not os.path.exists(directory):
166
os.makedirs(directory)
167
os.system('msgfmt %s -o %s' % (po_file, mo))
170
parser = OptionParser()
171
parser.add_option('-a', '--add',
172
action="store", type="string",
174
help="Add a new language")
175
parser.add_option('-l', '--list',
178
help="List all supported languages")
179
parser.add_option('-u', '--update',
182
help="Update pot file and all po files")
183
parser.add_option('-c', '--compile',
186
help="Compile all .po files into .mo")
187
parser.add_option('-p', '--package',
188
action="store", type="string",
192
options, args = parser.parse_args(args)
195
check_directory(root)
198
package = options.package
200
package = os.path.split(root)[1]
203
pot_file = check_pot_file(root, package)
204
copyfile(pot_file, os.path.join(root, 'po', options.lang + '.po'))
207
for lang in list_languages(root):
212
update_po(root, package)
215
check_pot_file(root, package)
216
compile_po_files(root, package)