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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
#!/usr/bin/env python
"""
This script makes easy all the boring steps to use gettext with a python
application.
For localization you need to:
1 Mark the strings in the source code as translatable
2 Use xgettext to get a pot file from it
3 Use a copy of this pot file for every language you want to have
translations
4 Translate these po files
5 Use msgmerge every time you change the source code and the strings you
need to translate change
6 Generate the mo binary files for every po file you have
To use this script you need to:
- have a directory where you put the po files: the PO_DIR
- have a directory where you put the mo files: the LANG_DIR
- choose a name for the pot file: the POT_FILE
- choose a name for the mo files: the MO_FILE
Note that you have only one POT_FILE but you have one po file in the PO_DIR for
every language you have translations. Then you have a MO_FILE for every po file
and they are stored in LANG_DIR/lang/LC_MESSAGES/ where lang is the language
this MO_FILE belongs to.
"""
from glob import glob
import os
from os.path import join, splitext, basename, exists, isdir
from optparse import OptionParser
import sys
from shutil import copyfile
class LangAdmin:
def __init__(self, po_dir='po', pot_file='gazpacho.pot',
mo_file='gazpacho.mo', lang_dir='locale'):
# where to put the po files (one for each language)
self.po_dir = po_dir
# name of the pot (po template) file (it is stored in the cwd)
self.pot_file = pot_file
# name of the mo file (one for each directory)
self.mo_file = mo_file
# name of the directory where the mo files are stored
self.lang_dir = lang_dir
def get_languages(self):
"""Gives a list of all the languages that have translation"""
languages = []
for lang in glob(join(self.po_dir, '*.po')):
languages.append(splitext(basename(lang))[0])
return languages
def _list_py_files(self, directory, recurse=True):
files = glob(join(directory, '*.py'))
if recurse:
dirs = [join(directory, filename) for filename \
in os.listdir(directory)
if isdir(join(directory, filename))]
for d in dirs:
files += self._list_py_files(d, recurse)
return files
def generate_pot_file(self, recurse=True, directories=[]):
"""Get all the python files in the directories parameter and create
a pot file using xgettext. If the recurse parameter is True it search
for more .py files in the subdirectories of the directories list
"""
files = []
for dirname in directories:
files += self._list_py_files(dirname, recurse)
cmd = 'xgettext -k_ -kN_ -o %s %s' % (self.pot_file, ' '.join(files))
print cmd
os.system(cmd)
def add_language(self, lang):
"""Create another language by copying the self.pot_file into the
self.po_dir using the lang parameter for its name. You need to fill at
least the charset property of the prolog of this new file if you don't
want the other commands to fail
"""
if not exists(self.pot_file):
print 'ERROR: You need to generate the pot file before adding '\
'any language.\n' \
'Use the command pot for that'
sys.exit(1)
copyfile(self.pot_file, join(self.po_dir, lang+'.po'))
print 'Please fill the prolog information of the file', \
join(self.po_dir, lang+'.po')
def merge_translations(self):
"""Merge the new self.pot_file with the existing po files in the
self.po_dir directory using the command msgmerge
"""
for lang_file in glob(join(self.po_dir, '*.po')):
cmd = 'msgmerge -U %s %s' % (lang_file, self.pot_file)
print cmd
os.system(cmd)
def generate_mo_files(self):
"""For every po file in the self.po_dir directory generates a
self.mo_file using msgfmt. It guess the language name from the po file
and creates the directories needed under self.lang_dir to put the final
self.mo_file in the right place
"""
if not exists(self.lang_dir):
os.mkdir(self.lang_dir)
for lang in self.get_languages():
src = join(self.po_dir, lang+'.po')
dst = join(self.lang_dir, lang, 'LC_MESSAGES', self.mo_file)
if not exists(join(self.lang_dir, lang, 'LC_MESSAGES')):
if not exists(join(self.lang_dir, lang)):
os.mkdir(join(self.lang_dir, lang))
os.mkdir(join(self.lang_dir, lang, 'LC_MESSAGES'))
cmd = 'msgfmt -o %s %s' % (dst, src)
print cmd
os.system(cmd)
if __name__ == '__main__':
usage = """usage: %prog [options] command
where command can be one of:
list List all the languages supported
add LANG Add the language LANG
pot DIRS Get the translatable strings for every file in DIRS that
is a .py file and creates the .pot file from them
merge Merge all the languages files with the POT file
mo Create a .mo file for every .po file and put it in the right
place"""
parser = OptionParser(usage)
options, args = parser.parse_args()
if len(args) == 0:
parser.print_help()
print '\nERROR: You should provide one command'
sys.exit(1)
langadmin = LangAdmin()
command = args.pop(0)
if command == 'list':
langs = langadmin.get_languages()
print ' '.join(langs)
elif command == 'pot':
if len(args) == 0:
parser.print_help()
print '\nERROR: The pot command needs at least one directory to '\
'look for .py files with translatable strings'
sys.exit(1)
langadmin.generate_pot_file(True, args)
elif command == 'add':
if len(args) != 1:
parser.print_help()
print '\nERROR: You need to specify one and only one language '\
'to add'
sys.exit(1)
langadmin.add_language(args[0])
elif command == 'merge':
langadmin.merge_translations()
elif command == 'mo':
langadmin.generate_mo_files()
else:
parser.print_help()
print '\nERROR: Unknown command'
sys.exit(1)
|