Pylint no-else-return refactoring: tenth (and so far last) set of files
[check_mk.git] / cmk_base / localize.py
blobdc16c08d5cfd3953ec15d2fd95bbdac3f0450963
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 import os
28 import subprocess
29 import sys
31 import cmk.tty as tty
32 import cmk.paths
34 import cmk.log
35 logger = cmk.log.get_logger(__name__)
37 # TODO: Inherit from MKGeneralException?
38 class LocalizeException(Exception):
39 def __init__(self, reason):
40 self.reason = reason
41 super(LocalizeException, self).__init__(reason)
42 def __str__(self):
43 return self.reason
46 domain = 'multisite'
48 pot_file = None
49 po_file = None
50 mo_file = None
51 alias_file = None
52 locale_base = cmk.paths.local_locale_dir
54 if os.path.exists(cmk.paths.local_locale_dir + '/multisite.pot'):
55 pot_file = cmk.paths.local_locale_dir + '/multisite.pot'
56 else:
57 pot_file = locale_base + '/multisite.pot'
59 try:
60 os.makedirs(locale_base)
61 except:
62 pass
64 def localize_usage(err = ''):
65 sys.stdout.write("""Usage: check_mk [-v] --localize COMMAND [ARGS]
67 Available commands are:
68 update LANG [ALIAS] ... Creates or updates a .po file for the given
69 language. The alias is an optional attribute
70 which will be used as display string in the
71 Multisite GUI.
72 compile LANG ... Compiles the .po file into a .mo file which can
73 be used by gettext.
74 edit LANG ... Call update, open .po in editor and compile in one step
76 The regular process for translating is:
78 1.) Create/update the .po file for the given language
79 2.) Edit the .po file
80 3.) Compile the .po file to get a .mo file which can be used by gettext
82 Locale files are located in: %s
83 """ % locale_base)
85 def do_localize(args):
86 if len(args) == 0:
87 localize_usage()
88 sys.exit(1)
90 command = args[0]
91 if len(args) > 1:
92 lang = args[1]
93 else:
94 lang = None
96 alias = None
97 if len(args) > 2:
98 alias = args[2]
100 commands = {
101 "update" : localize_update,
102 "compile" : localize_compile,
103 "edit" : localize_edit,
105 f = commands.get(command)
106 if f:
107 check_binaries()
109 try:
110 f(lang)
111 write_alias(alias)
112 except LocalizeException, e:
113 logger.error("%s" % e)
114 sys.exit(1)
115 else:
116 allc = commands.keys()
117 allc.sort()
118 allc = [ tty.bold + c + tty.normal for c in allc ]
119 logger.error("Invalid localize command. Allowed are: %s and %s.",
120 ", ".join(allc[:-1]), allc[-1])
121 sys.exit(1)
123 def write_alias(alias):
124 if not alias:
125 return
127 if alias == '-':
128 os.remove(alias_file)
129 else:
130 file(alias_file, 'w').write(alias)
132 def check_binaries():
133 # Are the xgettext utils available?
134 for b in [ 'xgettext', 'msgmerge', 'msgfmt' ]:
135 if subprocess.call(['which', b], stdout=open(os.devnull , "wb")) != 0:
136 raise LocalizeException('%s binary not found in PATH\n' % b)
139 def get_languages():
140 return [ l for l in os.listdir(locale_base) if os.path.isdir(locale_base + '/' + l) ]
143 def init_files(lang):
144 global po_file, mo_file, alias_file
145 po_file = locale_base + '/%s/LC_MESSAGES/%s.po' % (lang, domain)
146 mo_file = locale_base + '/%s/LC_MESSAGES/%s.mo' % (lang, domain)
147 alias_file = locale_base + '/%s/alias' % (lang)
150 def localize_update_po():
151 # Merge the current .pot file with a given .po file
152 logger.verbose("Merging translations...")
153 if subprocess.call(['msgmerge', '-U', po_file, pot_file], stdout=open(os.devnull, "wb")) != 0:
154 logger.error('Failed!')
155 else:
156 logger.info('Success! Output: %s', po_file)
159 def localize_init_po(lang):
160 if subprocess.call(['msginit', '-i', pot_file, '--no-translator', '-l', lang,
161 '-o', po_file], stdout=open(os.devnull, "wb")) != 0:
162 logger.error('Failed!\n')
165 # Dig into the source code and generate a new .pot file
166 def localize_sniff():
167 logger.info('Sniffing source code...')
169 paths = [ cmk.paths.default_config_dir, cmk.paths.web_dir ]
170 if os.path.exists(cmk.paths.local_web_dir):
171 paths.append(cmk.paths.local_web_dir)
173 sniff_files = []
174 for path in paths:
175 for root, _dirs, files in os.walk(path):
176 for f in files:
177 if f.endswith(".py") or f.endswith(".mk"):
178 sniff_files.append(os.path.join(root, f))
180 if subprocess.call(['xgettext', '--no-wrap', '--sort-output', '--force-po',
181 '-L', 'Python', '--from-code=utf-8', '--omit-header',
182 '-o', pot_file ] + sniff_files,
183 stdout=open(os.devnull, "wb")) != 0:
184 logger.error('Failed!\n')
185 else:
186 header = r'''# +------------------------------------------------------------------+
187 # | ____ _ _ __ __ _ __ |
188 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
189 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
190 # | | |___| | | | __/ (__| < | | | | . \ |
191 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
192 # | |
193 # | Copyright Mathias Kettner 2010 mk@mathias-kettner.de |
194 # +------------------------------------------------------------------+
196 # This file is part of Check_MK.
197 # The official homepage is at http://mathias-kettner.de/check_mk.
199 # check_mk is free software; you can redistribute it and/or modify it
200 # under the terms of the GNU General Public License as published by
201 # the Free Software Foundation in version 2. check_mk is distributed
202 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
203 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
204 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
205 # tails. You should have received a copy of the GNU General Public
206 # License along with GNU Make; see the file COPYING. If not, write
207 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
208 # Boston, MA 02110-1301 USA.
209 msgid ""
210 msgstr ""
211 "Project-Id-Version: Check_MK Multisite translation 0.1\n"
212 "Report-Msgid-Bugs-To: checkmk-en@lists.mathias-kettner.de\n"
213 "POT-Creation-Date: 2011-05-13 09:42+0200\n"
214 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
215 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
216 "Language-Team: LANGUAGE <LL@li.org>\n"
217 "Language: LANGUAGE \n"
218 "MIME-Version: 1.0\n"
219 "Content-Type: text/plain; charset=utf-8\n"
220 "Content-Transfer-Encoding: 8bit\n"
224 f = open(pot_file).read()
225 open(pot_file, 'w').write(header + f)
226 logger.info('Success! Output: %s', pot_file)
229 def localize_edit(lang):
230 localize_update(lang)
232 editor = os.getenv("VISUAL", os.getenv("EDITOR", "/usr/bin/vi"))
233 if not os.path.exists(editor):
234 editor = 'vi'
236 if subprocess.call([editor, po_file]) == 0:
237 localize_compile(lang)
238 else:
239 logger.error("Aborted.")
242 # Start translating in a new language
243 def localize_update(lang):
244 if not lang:
245 raise LocalizeException('No language given')
247 init_files(lang)
249 try:
250 os.makedirs(os.path.dirname(po_file))
251 except:
252 pass
254 # Maybe initialize the file in the local hierarchy with the file in
255 # the default hierarchy
256 if not os.path.exists(po_file) \
257 and os.path.exists(cmk.paths.locale_dir + '/%s/LC_MESSAGES/%s.po' % (lang, domain)):
258 file(po_file, 'w').write(file(cmk.paths.locale_dir + '/%s/LC_MESSAGES/%s.po' % (lang, domain)).read())
259 logger.info('Initialize %s with the file in the default hierarchy', po_file)
261 localize_sniff()
263 if not os.path.exists(po_file):
264 logger.info('Initializing .po file for language %s...', lang)
265 localize_init_po(lang)
266 else:
267 logger.info('Updating .po file for language %s...', lang)
268 localize_update_po()
270 # Create a .mo file from the given .po file
271 def localize_compile(lang):
272 if not lang:
273 raise LocalizeException('No language given')
274 if lang not in get_languages():
275 raise LocalizeException('Invalid language given. Available: %s' % ' '.join(get_languages()))
277 init_files(lang)
279 # Maybe initialize the file in the local hierarchy with the file in
280 # the default hierarchy
281 if not os.path.exists(po_file) \
282 and os.path.exists(cmk.paths.locale_dir + '/%s/LC_MESSAGES/%s.po' % (lang, domain)):
283 file(po_file, 'w').write(file(cmk.paths.locale_dir + '/%s/LC_MESSAGES/%s.po' % (lang, domain)).read())
284 logger.info('Initialize %s with the file in the default hierarchy', po_file)
286 if not os.path.exists(po_file):
287 raise LocalizeException('The .po file %s does not exist.' % po_file)
289 if subprocess.call(['msgfmt', po_file, '-o', mo_file]) != 0:
290 logger.error('Failed!')
291 else:
292 logger.info('Success! Output: %s', mo_file)