Package turbogears :: Package toolbox :: Package admi18n

Source Code for Package turbogears.toolbox.admi18n

  1  """Graphical user interface for i18n administration""" 
  2   
  3  import os 
  4  import sys 
  5  import time 
  6  import shutil 
  7  import codecs 
  8   
  9  import turbogears 
 10  from turbogears import controllers, expose, i18n 
 11  from turbogears.i18n.pygettext import pygettext 
 12  from turbogears.i18n.pygettext import msgfmt 
 13  from turbogears.i18n.pygettext import catalog 
 14   
 15  import cherrypy 
 16  from cherrypy.lib import static 
 17   
 18  # this is a list of supported file extensions. 
 19  supported_exts = ['.py', '.kid', '.tmpl', '.html', '.mak'] 
20 21 22 -class Internationalization(controllers.RootController):
23 """I18N administration tool. 24 25 Collect your strings, add and manage locales, 26 edit and compile your catalogs. 27 28 """ 29 30 __label__ = 'admi18n' 31 __version__ = '0.1' 32 __author__ = 'Ronald Jaramillo' 33 __email__ = 'ronald@checkandshare.com' 34 __copyright__ = 'Copyright 2005 Ronald Jaramillo' 35 __license__ = 'MIT' 36 37 baseTemplate = 'turbogears.toolbox.admi18n' 38 languages = None 39 icon = "/tg_static/images/admi18n.png" 40 need_project = True 41
42 - def __init__(self, currentProject=None):
43 self.currentProject = currentProject 44 if not self.currentProject: 45 self.currentProject = os.getcwd()
46
47 - def get_languages(self):
48 if not self.languages: 49 self.languages = i18n.get_languages() 50 51 return self.languages
52
53 - def remove_locale(self, code):
54 locales = self.locales_directory() 55 if type(code) != type([]): 56 code = [code] 57 58 for c in code: 59 path = os.path.join(locales, c) 60 try: 61 shutil.rmtree(path) 62 except OSError,e: 63 print e 64 return
65
66 - def compile_catalogs(self, codes):
67 locales = self.locales_directory() 68 for code in codes.split(','): 69 path = os.path.join(locales, code, 'LC_MESSAGES', 'messages.po') 70 if not os.path.exists(path): 71 continue 72 73 dest = path.replace('.po', '.mo') 74 #run msgfmt on file... 75 msgfmt.make(path, dest)
76
77 - def merge_catalogs(self, codes):
78 locales = self.locales_directory() 79 src = os.path.join(locales, 'messages.pot') 80 paths = [] 81 for code in codes.split(','): 82 path = os.path.join(locales, code, 'LC_MESSAGES', 'messages.po') 83 if not os.path.exists(path): 84 continue 85 86 paths.append(path) 87 catalog.merge(src, paths)
88
89 - def add_locale(self, code):
90 locales = self.locales_directory() 91 path = os.path.join(locales, code) 92 try: 93 os.mkdir(path) 94 except OSError, e: 95 print e 96 return 97 98 path = os.path.join(path, 'LC_MESSAGES') 99 try: 100 os.mkdir(path) 101 except OSError, e: 102 print e 103 return 104 105 src = os.path.join(locales, 'messages.pot') 106 dest = os.path.join(path, 'messages.po') 107 shutil.copy(src, dest)
108 109 @expose('json')
110 - def po_upload(self, myFile, code):
111 path = os.path.join(self.locales_directory(), 112 code, 'LC_MESSAGES', 'messages.po') 113 f = codecs.open(path, 'wb', 'utf-8') 114 f.write(unicode(myFile.file.read(), 'utf-8', errors='replace')) 115 f.close() 116 raise cherrypy.HTTPRedirect(turbogears.url('language', code=code))
117
118 - def google_translate(self, code, from_lang, to_lang, args):
119 path = os.path.join(self.locales_directory(), 120 code, 'LC_MESSAGES', 'messages.po') 121 for arg in args: 122 if not 'text_' in arg: 123 continue 124 msg_id = args[arg].strip() 125 if '\r' in msg_id: 126 msg_id = '\n'.join(msg_id.splitlines()) 127 translated = i18n.utils.google_translate( 128 from_lang, to_lang, msg_id) 129 catalog.update(path, msg_id, translated)
130 131 @expose('json')
132 - def update_catalog(self, code, msg_id, msg_text):
133 path = os.path.join(self.locales_directory(), 134 code, 'LC_MESSAGES', 'messages.po') 135 catalog.update(path, msg_id, msg_text) 136 return 'ok'
137 138 @expose('%s.po_view' % baseTemplate)
139 - def po_view(self, code, sort_by=None, dir=None, 140 from_lang=None, to_lang=None, **kargs):
141 visible_checkbox = False 142 if from_lang and to_lang: 143 visible_checkbox = True 144 self.google_translate(code, from_lang, to_lang, kargs) 145 path = os.path.join(self.locales_directory(), 146 code, 'LC_MESSAGES', 'messages.po') 147 return dict(code=code, catalog=catalog.items(path, sort_by, dir), 148 visible_checkbox=visible_checkbox)
149 150 @expose('%s.language' % baseTemplate)
151 - def language(self, code):
152 path = os.path.join(self.locales_directory(), 153 code, 'LC_MESSAGES', 'messages.po') 154 po_message_file = dict(path=path, 155 modified=time.ctime(os.path.getmtime(path)), 156 size=os.path.getsize(path)) 157 return dict(code=code, 158 language=self.language_for_code(code), 159 po_message_file=po_message_file)
160 161 @expose('json')
162 - def language_list(self):
163 return dict(languages=self.get_languages())
164 165 @expose('%s.languageManagement' % baseTemplate)
166 - def language_management(self, add=None, rem=None, compile=None, merge=None):
167 if add: 168 self.add_locale(add) 169 if rem: 170 self.remove_locale(rem) 171 if compile: 172 self.compile_catalogs(compile) 173 if merge: 174 self.merge_catalogs(merge) 175 return dict(languages=list(), 176 locales=self.project_locales())
177
178 - def language_for_code(self, code):
179 for c, language in self.get_languages(): 180 if c == code: 181 return language
182
183 - def locales_directory(self):
184 locales_dir = os.path.join(self.currentProject, 'locales') 185 if not os.path.isdir(locales_dir): 186 try: 187 os.mkdir(locales_dir) 188 except OSError, e: 189 print e 190 return 191 return locales_dir
192
193 - def project_locales(self):
194 locales = [] 195 locales_dir = self.locales_directory() 196 if not locales_dir: 197 return locales 198 199 for item in os.listdir(locales_dir): 200 path = os.path.join(locales_dir, item) 201 if not os.path.isdir(path): 202 continue 203 204 language = self.language_for_code(item) 205 if not language: 206 continue 207 208 modified = '-' 209 compiled = '-' 210 po = os.path.join(path, 'LC_MESSAGES', 'messages.po') 211 mo = os.path.join(path, 'LC_MESSAGES', 'messages.mo') 212 if os.path.exists(po): 213 modified = time.ctime(os.path.getmtime(po)) 214 215 if os.path.exists(mo): 216 compiled = time.ctime(os.path.getmtime(mo)) 217 218 locales.append(dict( 219 code=item, 220 language=language, 221 coverage=0, 222 status=0, 223 modified=modified, 224 compiled=compiled 225 )) 226 return locales
227
228 - def project_files(self):
229 p = turbogears.util.get_package_name() 230 base_level = len([x for x in p.split(os.sep) if x]) 231 fl, dct, visibility = [], {}, {} 232 233 def collect_files(file_list, dirpath, namelist): 234 level = len([x for x in dirpath.split(os.sep) if x]) - base_level 235 slot0 = dict( # directory info 236 dir=os.path.dirname(dirpath), 237 file_name=os.path.basename(dirpath), 238 path=dirpath, isdir=True, level=level) 239 slot1 = list() # children directories info 240 slot2 = list() # children files info 241 slots = (slot0, slot1, slot2) 242 dct[dirpath] = slots 243 if level: 244 dct[os.path.dirname(dirpath)][1].append(slots) 245 else: 246 file_list.append(slots) 247 248 namelist.sort() 249 for name in namelist[:]: 250 if (name.startswith('.') 251 or name in ['static', 'sqlobject-history']): 252 namelist.remove(name) 253 continue 254 255 p = os.path.join(dirpath, name) 256 if (os.path.isfile(p) 257 and os.path.splitext(name)[-1] in supported_exts): 258 slot2.append(dict(dir=dirpath, file_name=name, 259 path=p, isdir=os.path.isdir(p), level=level+1)) 260 261 # decide if current directory (and ancestors) should be visible 262 visibility[dirpath] = bool(slot2) 263 if slot2: 264 while not visibility.get(os.path.dirname(dirpath), True): 265 dirpath = os.path.dirname(dirpath) 266 visibility[dirpath] = True
267 268 os.path.walk(p, collect_files, fl) 269 return [x for x in turbogears.util.flatten_sequence(fl) 270 if not x['isdir'] or visibility[x['path']]]
271
272 - def collect_string_for_files(self, files):
273 if not files: 274 return 275 276 params = ['', '-v'] 277 for file in files: 278 params.append(file) 279 280 pygettext.sys.argv = params 281 pygettext.main() 282 283 pot = os.path.join(self.currentProject, 'messages.pot') 284 if not os.path.exists(pot): 285 return 286 287 locales = self.locales_directory() 288 filename = os.path.join(locales, 'messages.pot') 289 try: 290 shutil.copyfile(pot, filename) 291 except IOError, e: 292 print e
293
294 - def pot_message_file(self):
295 locales = self.locales_directory() 296 pot = os.path.join(locales, 'messages.pot') 297 if not os.path.exists(pot): 298 return 299 300 return dict(name='messages.pot', path=pot, 301 modified=time.ctime(os.path.getmtime(pot)), 302 size=os.path.getsize(pot))
303 304 @expose()
305 - def lang_file(self, code):
306 # serve static file, the code can be pot or a lang code 307 locales = self.locales_directory() 308 if code == 'pot': 309 path = os.path.join(locales, 'messages.pot') 310 else: 311 path = os.path.join(locales, code) 312 path = os.path.join(path, 'LC_MESSAGES') 313 path = os.path.join(path, 'messages.po') 314 if 'If-Modified-Since' in cherrypy.request.headers: 315 del cherrypy.request.headers['If-Modified-Since'] # see ticket #879 316 return static.serve_file(path, 'application/x-download', 'attachment')
317 318 @expose('%s.stringCollection' % baseTemplate)
319 - def string_collection(self, files=[]):
320 if files: 321 if type(files) != type([]): 322 files = [files] 323 self.collect_string_for_files(files) 324 return dict(project_files=self.project_files(), 325 pot_message_file=self.pot_message_file())
326 327 @expose('%s.internationalization' % baseTemplate)
328 - def index(self):
329 return dict()
330