|
Package Dropbox ::
Package web2py ::
Package gluon ::
Module languages
|
|
1
2
3
4 """
5 This file is part of the web2py Web Framework
6 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8
9 Plural subsystem is created by Vladyslav Kozlovskyy (Ukraine)
10 <dbdevelop@gmail.com>
11 """
12
13 import os
14 import re
15 import sys
16 import pkgutil
17 import logging
18 import marshal
19 from cgi import escape
20 from threading import RLock
21
22 try:
23 import copyreg as copy_reg
24 except ImportError:
25 import copy_reg
26
27 from portalocker import read_locked, LockedFile
28 from utf8 import Utf8
29
30 from fileutils import listdir
31 import settings
32 from cfs import getcfs
33 from html import XML, xmlescape
34 from contrib.markmin.markmin2html import render, markmin_escape
35 from string import maketrans
36
37 __all__ = ['translator', 'findT', 'update_all_languages']
38
39 ostat = os.stat
40 oslistdir = os.listdir
41 pjoin = os.path.join
42 pexists = os.path.exists
43 pdirname = os.path.dirname
44 isdir = os.path.isdir
45 is_gae = False
46
47 DEFAULT_LANGUAGE = 'en'
48 DEFAULT_LANGUAGE_NAME = 'English'
49
50
51
52 DEFAULT_NPLURALS = 1
53
54 DEFAULT_GET_PLURAL_ID = lambda n: 0
55
56 DEFAULT_CONSTRUCT_PLURAL_FORM = lambda word, plural_id: word
57
58 NUMBERS = (int, long, float)
59
60
61 PY_STRING_LITERAL_RE = r'(?<=[^\w]T\()(?P<name>'\
62 + r"[uU]?[rR]?(?:'''(?:[^']|'{1,2}(?!'))*''')|"\
63 + r"(?:'(?:[^'\\]|\\.)*')|" + r'(?:"""(?:[^"]|"{1,2}(?!"))*""")|'\
64 + r'(?:"(?:[^"\\]|\\.)*"))'
65
66 regex_translate = re.compile(PY_STRING_LITERAL_RE, re.DOTALL)
67 regex_param = re.compile(r'{(?P<s>.+?)}')
68
69
70 regex_language = \
71 re.compile('([a-z]{2}(?:\-[a-z]{2})?(?:\-[a-z]{2})?)(?:[,;]|$)')
72 regex_langfile = re.compile('^[a-z]{2}(-[a-z]{2})?\.py$')
73 regex_backslash = re.compile(r"\\([\\{}%])")
74 regex_plural = re.compile('%({.+?})')
75 regex_plural_dict = re.compile('^{(?P<w>[^()[\]][^()[\]]*?)\((?P<n>[^()\[\]]+)\)}$')
76 regex_plural_tuple = re.compile(
77 '^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$')
78 regex_plural_file = re.compile('^plural-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$')
79
80
82 if text.strip():
83 try:
84 import ast
85 return ast.literal_eval(text)
86 except ImportError:
87 return eval(text, {}, {})
88 return None
89
90
91
92
94 def markmin_aux(m):
95 return '{%s}' % markmin_escape(m.group('s'))
96 return render(regex_param.sub(markmin_aux, s),
97 sep='br', autolinks=None, id_prefix='')
98
99
100
101
104
105
108
109
112 ttab_in = maketrans("\\%{}", '\x1c\x1d\x1e\x1f')
113 ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}")
114
115
116
117
118
119
120
121
122
123
124
125 global_language_cache = {}
126
127
143
144
154
155
157 lang_text = read_locked(filename).replace('\r\n', '\n')
158 clear_cache(filename)
159 try:
160 return safe_eval(lang_text) or {}
161 except Exception:
162 e = sys.exc_info()[1]
163 status = 'Syntax error in %s (%s)' % (filename, e)
164 logging.error(status)
165 return {'__corrupted__': status}
166
167
169 """ return dictionary with translation messages
170 """
171 return getcfs('lang:' + filename, filename,
172 lambda: read_dict_aux(filename))
173
174
176 """
177 create list of all possible plural rules files
178 result is cached in PLURAL_RULES dictionary to increase speed
179 """
180 plurals = {}
181 try:
182 import contrib.plural_rules as package
183 for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
184 if len(modname) == 2:
185 module = __import__(package.__name__ + '.' + modname,
186 fromlist=[modname])
187 lang = modname
188 pname = modname + '.py'
189 nplurals = getattr(module, 'nplurals', DEFAULT_NPLURALS)
190 get_plural_id = getattr(
191 module, 'get_plural_id',
192 DEFAULT_GET_PLURAL_ID)
193 construct_plural_form = getattr(
194 module, 'construct_plural_form',
195 DEFAULT_CONSTRUCT_PLURAL_FORM)
196 plurals[lang] = (lang, nplurals, get_plural_id,
197 construct_plural_form)
198 except ImportError:
199 e = sys.exc_info()[1]
200 logging.warn('Unable to import plural rules: %s' % e)
201 return plurals
202
203 PLURAL_RULES = read_possible_plural_rules()
204
205
207 def get_lang_struct(lang, langcode, langname, langfile_mtime):
208 if lang == 'default':
209 real_lang = langcode.lower()
210 else:
211 real_lang = lang
212 (prules_langcode,
213 nplurals,
214 get_plural_id,
215 construct_plural_form
216 ) = PLURAL_RULES.get(real_lang[:2], ('default',
217 DEFAULT_NPLURALS,
218 DEFAULT_GET_PLURAL_ID,
219 DEFAULT_CONSTRUCT_PLURAL_FORM))
220 if prules_langcode != 'default':
221 (pluraldict_fname,
222 pluraldict_mtime) = plurals.get(real_lang,
223 plurals.get(real_lang[:2],
224 ('plural-%s.py' % real_lang, 0)))
225 else:
226 pluraldict_fname = None
227 pluraldict_mtime = 0
228 return (langcode,
229 langname,
230
231 langfile_mtime,
232 pluraldict_fname,
233 pluraldict_mtime,
234 prules_langcode,
235 nplurals,
236 get_plural_id,
237 construct_plural_form)
238
239 plurals = {}
240 flist = oslistdir(langdir)
241
242 for pname in flist:
243 if regex_plural_file.match(pname):
244 plurals[pname[7:-3]] = (pname,
245 ostat(pjoin(langdir, pname)).st_mtime)
246 langs = {}
247
248 for fname in flist:
249 if regex_langfile.match(fname) or fname == 'default.py':
250 fname_with_path = pjoin(langdir, fname)
251 d = read_dict(fname_with_path)
252 lang = fname[:-3]
253 langcode = d.get('!langcode!', lang if lang != 'default'
254 else DEFAULT_LANGUAGE)
255 langname = d.get('!langname!', langcode)
256 langfile_mtime = ostat(fname_with_path).st_mtime
257 langs[lang] = get_lang_struct(lang, langcode,
258 langname, langfile_mtime)
259 if 'default' not in langs:
260
261
262 langs['default'] = get_lang_struct('default', DEFAULT_LANGUAGE,
263 DEFAULT_LANGUAGE_NAME, 0)
264 deflang = langs['default']
265 deflangcode = deflang[0]
266 if deflangcode not in langs:
267
268 langs[deflangcode] = deflang[:2] + (0,) + deflang[3:]
269
270 return langs
271
272
276
277
279 lang_text = read_locked(filename).replace('\r\n', '\n')
280 try:
281 return eval(lang_text) or {}
282 except Exception:
283 e = sys.exc_info()[1]
284 status = 'Syntax error in %s (%s)' % (filename, e)
285 logging.error(status)
286 return {'__corrupted__': status}
287
288
292
293
295 if '__corrupted__' in contents:
296 return
297 try:
298 fp = LockedFile(filename, 'w')
299 fp.write('#!/usr/bin/env python\n{\n# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...],\n')
300
301 for key in sorted(contents, lambda x, y: cmp(unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower())):
302 forms = '[' + ','.join([repr(Utf8(form))
303 for form in contents[key]]) + ']'
304 fp.write('%s: %s,\n' % (repr(Utf8(key)), forms))
305 fp.write('}\n')
306 except (IOError, OSError):
307 if not is_gae:
308 logging.warning('Unable to write to file %s' % filename)
309 return
310 finally:
311 fp.close()
312
313
315 if '__corrupted__' in contents:
316 return
317 try:
318 fp = LockedFile(filename, 'w')
319 except (IOError, OSError):
320 if not settings.global_settings.web2py_runtime_gae:
321 logging.warning('Unable to write to file %s' % filename)
322 return
323 fp.write('# coding: utf8\n{\n')
324 for key in sorted(contents, lambda x, y: cmp(unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower())):
325 fp.write('%s: %s,\n' % (repr(Utf8(key)), repr(Utf8(contents[key]))))
326 fp.write('}\n')
327 fp.close()
328
329
331 """
332 never to be called explicitly, returned by
333 translator.__call__() or translator.M()
334 """
335 m = s = T = f = t = None
336 M = is_copy = False
337
338 - def __init__(
339 self,
340 message,
341 symbols={},
342 T=None,
343 filter=None,
344 ftag=None,
345 M=False
346 ):
363
365 return "<lazyT %s>" % (repr(Utf8(self.m)), )
366
370
372 return str(self) == str(other)
373
375 return str(self) != str(other)
376
378 return '%s%s' % (self, other)
379
381 return '%s%s' % (other, self)
382
384 return str(self) * other
385
387 return cmp(str(self), str(other))
388
390 return hash(str(self))
391
393 return getattr(str(self), name)
394
397
399 return str(self)[i:j]
400
402 for c in str(self):
403 yield c
404
406 return len(str(self))
407
409 return str(self) if self.M else escape(str(self))
410
412 return str(self).encode(*a, **b)
413
415 return str(self).decode(*a, **b)
416
419
424
425
427 """
428 this class is instantiated by gluon.compileapp.build_environment
429 as the T object
430 ::
431 T.force(None) # turns off translation
432 T.force('fr, it') # forces web2py to translate using fr.py or it.py
433
434 T(\"Hello World\") # translates \"Hello World\" using the selected file
435
436 notice 1: there is no need to force since, by default, T uses
437 http_accept_language to determine a translation file.
438 notice 2:
439 en and en-en are considered different languages!
440 notice 3:
441 if language xx-yy is not found force() probes other similar
442 languages using such algorithm:
443 xx-yy.py -> xx.py -> xx-yy*.py -> xx*.py
444 """
445
446 - def __init__(self, langpath, http_accept_language):
447 self.langpath = langpath
448 self.http_accept_language = http_accept_language
449 self.is_writable = not is_gae
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468 self.set_current_languages()
469 self.lazy = True
470 self.otherTs = {}
471 self.filter = markmin
472 self.ftag = 'markmin'
473
475 """
476 return info for selected language or dictionary with all
477 possible languages info from APP/languages/*.py
478 args:
479 *lang* (str): language
480 returns:
481 if *lang* is defined:
482 return tuple(langcode, langname, langfile_mtime,
483 pluraldict_fname, pluraldict_mtime,
484 prules_langcode, nplurals,
485 get_plural_id, construct_plural_form)
486 or None
487
488 if *lang* is NOT defined:
489 returns dictionary with all possible languages:
490 { langcode(from filename):
491 ( langcode, # language code from !langcode!
492 langname,
493 # language name in national spelling from !langname!
494 langfile_mtime, # m_time of language file
495 pluraldict_fname,# name of plural dictionary file or None (when default.py is not exist)
496 pluraldict_mtime,# m_time of plural dictionary file or 0 if file is not exist
497 prules_langcode, # code of plural rules language or 'default'
498 nplurals, # nplurals for current language
499 get_plural_id, # get_plural_id() for current language
500 construct_plural_form) # construct_plural_form() for current language
501 }
502 """
503 info = read_possible_languages(self.langpath)
504 if lang:
505 info = info.get(lang)
506 return info
507
509 """ get list of all possible languages for current applications """
510 return list(set(self.current_languages +
511 [lang for lang in read_possible_languages(self.langpath).iterkeys()
512 if lang != 'default']))
513
515 """
516 set current AKA "default" languages
517 setting one of this languages makes force() function
518 turn translation off to use default language
519 """
520 if len(languages) == 1 and isinstance(
521 languages[0], (tuple, list)):
522 languages = languages[0]
523 if not languages or languages[0] is None:
524
525 pl_info = self.get_possible_languages_info('default')
526 if pl_info[2] == 0:
527
528 self.default_language_file = self.langpath
529 self.default_t = {}
530 self.current_languages = [DEFAULT_LANGUAGE]
531 else:
532 self.default_language_file = pjoin(self.langpath,
533 'default.py')
534 self.default_t = read_dict(self.default_language_file)
535 self.current_languages = [pl_info[0]]
536 else:
537 self.current_languages = list(languages)
538 self.force(self.http_accept_language)
539
541 """ get plural form of word for number *n*
542 NOTE: *word" MUST be defined in current language
543 (T.accepted_language)
544
545 invoked from T()/T.M() in %%{} tag
546 args:
547 word (str): word in singular
548 n (numeric): number plural form created for
549
550 returns:
551 (str): word in appropriate singular/plural form
552 """
553 if int(n) == 1:
554 return word
555 elif word:
556 id = self.get_plural_id(abs(int(n)))
557
558
559
560
561 if id != 0:
562 forms = self.plural_dict.get(word, [])
563 if len(forms) >= id:
564
565 return forms[id - 1]
566 else:
567
568 forms += [''] * (self.nplurals - len(forms) - 1)
569 form = self.construct_plural_form(word, id)
570 forms[id - 1] = form
571 self.plural_dict[word] = forms
572 if self.is_writable and self.plural_file:
573 write_plural_dict(self.plural_file,
574 self.plural_dict)
575 return form
576 return word
577
578 - def force(self, *languages):
579 """
580
581 select language(s) for translation
582
583 if a list of languages is passed as a parameter,
584 first language from this list that matches the ones
585 from the possible_languages dictionary will be
586 selected
587
588 default language will be selected if none
589 of them matches possible_languages.
590 """
591 pl_info = read_possible_languages(self.langpath)
592
593 def set_plural(language):
594 """
595 initialize plural forms subsystem
596 """
597 lang_info = pl_info.get(language)
598 if lang_info:
599 (pname,
600 pmtime,
601 self.plural_language,
602 self.nplurals,
603 self.get_plural_id,
604 self.construct_plural_form
605 ) = lang_info[3:]
606 pdict = {}
607 if pname:
608 pname = pjoin(self.langpath, pname)
609 if pmtime != 0:
610 pdict = read_plural_dict(pname)
611 self.plural_file = pname
612 self.plural_dict = pdict
613 else:
614 self.plural_language = 'default'
615 self.nplurals = DEFAULT_NPLURALS
616 self.get_plural_id = DEFAULT_GET_PLURAL_ID
617 self.construct_plural_form = DEFAULT_CONSTRUCT_PLURAL_FORM
618 self.plural_file = None
619 self.plural_dict = {}
620 language = ''
621 if len(languages) == 1 and isinstance(languages[0], str):
622 languages = regex_language.findall(languages[0].lower())
623 elif not languages or languages[0] is None:
624 languages = []
625 self.requested_languages = languages = tuple(languages)
626 if languages:
627 all_languages = set(lang for lang in pl_info.iterkeys()
628 if lang != 'default') \
629 | set(self.current_languages)
630 for lang in languages:
631
632
633
634 lang5 = lang[:5]
635 if lang5 in all_languages:
636 language = lang5
637 else:
638 lang2 = lang[:2]
639 if len(lang5) > 2 and lang2 in all_languages:
640 language = lang2
641 else:
642 for l in all_languages:
643 if l[:2] == lang2:
644 language = l
645 if language:
646 if language in self.current_languages:
647 break
648 self.language_file = pjoin(self.langpath, language + '.py')
649 self.t = read_dict(self.language_file)
650 self.cache = global_language_cache.setdefault(
651 self.language_file,
652 ({}, RLock()))
653 set_plural(language)
654 self.accepted_language = language
655 return languages
656 self.accepted_language = language or self.current_languages[0]
657 self.language_file = self.default_language_file
658 self.cache = global_language_cache.setdefault(self.language_file,
659 ({}, RLock()))
660 self.t = self.default_t
661 set_plural(self.accepted_language)
662 return languages
663
664 - def __call__(self, message, symbols={}, language=None, lazy=None):
665 """
666 get cached translated plain text message with inserted parameters(symbols)
667 if lazy==True lazyT object is returned
668 """
669 if lazy is None:
670 lazy = self.lazy
671 if not language:
672 if lazy:
673 return lazyT(message, symbols, self)
674 else:
675 return self.translate(message, symbols)
676 else:
677 try:
678 otherT = self.otherTs[language]
679 except KeyError:
680 otherT = self.otherTs[language] = translator(
681 self.langpath, self.http_accept_language)
682 otherT.force(language)
683 return otherT(message, symbols, lazy=lazy)
684
685 - def apply_filter(self, message, symbols={}, filter=None, ftag=None):
686 def get_tr(message, prefix, filter):
687 s = self.get_t(message, prefix)
688 return filter(s) if filter else self.filter(s)
689 if filter:
690 prefix = '@' + (ftag or 'userdef') + '\x01'
691 else:
692 prefix = '@' + self.ftag + '\x01'
693 message = get_from_cache(
694 self.cache, prefix + message,
695 lambda: get_tr(message, prefix, filter))
696 if symbols or symbols == 0 or symbols == "":
697 if isinstance(symbols, dict):
698 symbols.update(
699 (key, xmlescape(value).translate(ttab_in))
700 for key, value in symbols.iteritems()
701 if not isinstance(value, NUMBERS))
702 else:
703 if not isinstance(symbols, tuple):
704 symbols = (symbols,)
705 symbols = tuple(
706 value if isinstance(value, NUMBERS)
707 else xmlescape(value).translate(ttab_in)
708 for value in symbols)
709 message = self.params_substitution(message, symbols)
710 return XML(message.translate(ttab_out))
711
712 - def M(self, message, symbols={}, language=None,
713 lazy=None, filter=None, ftag=None):
714 """
715 get cached translated markmin-message with inserted parametes
716 if lazy==True lazyT object is returned
717 """
718 if lazy is None:
719 lazy = self.lazy
720 if not language:
721 if lazy:
722 return lazyT(message, symbols, self, filter, ftag, True)
723 else:
724 return self.apply_filter(message, symbols, filter, ftag)
725 else:
726 try:
727 otherT = self.otherTs[language]
728 except KeyError:
729 otherT = self.otherTs[language] = translator(self.request)
730 otherT.force(language)
731 return otherT.M(message, symbols, lazy=lazy)
732
733 - def get_t(self, message, prefix=''):
734 """
735 user ## to add a comment into a translation string
736 the comment can be useful do discriminate different possible
737 translations for the same string (for example different locations)
738
739 T(' hello world ') -> ' hello world '
740 T(' hello world ## token') -> ' hello world '
741 T('hello ## world## token') -> 'hello ## world'
742
743 the ## notation is ignored in multiline strings and strings that
744 start with ##. this is to allow markmin syntax to be translated
745 """
746 if isinstance(message, unicode):
747 message = message.encode('utf8')
748 if isinstance(prefix, unicode):
749 prefix = prefix.encode('utf8')
750 key = prefix + message
751 mt = self.t.get(key, None)
752 if mt is not None:
753 return mt
754
755 if message.find('##') > 0 and not '\n' in message:
756
757 message = message.rsplit('##', 1)[0]
758
759 self.t[key] = mt = self.default_t.get(key, message)
760
761 if self.is_writable and self.language_file != self.default_language_file:
762 write_dict(self.language_file, self.t)
763 return regex_backslash.sub(
764 lambda m: m.group(1).translate(ttab_in), mt)
765
767 """
768 substitute parameters from symbols into message using %.
769 also parse %%{} placeholders for plural-forms processing.
770 returns: string with parameters
771 NOTE: *symbols* MUST BE OR tuple OR dict of parameters!
772 """
773 def sub_plural(m):
774 """string in %{} is transformed by this rules:
775 If string starts with \\, ! or ? such transformations
776 take place:
777
778 "!string of words" -> "String of word" (Capitalize)
779 "!!string of words" -> "String Of Word" (Title)
780 "!!!string of words" -> "STRING OF WORD" (Upper)
781 "\\!string of words" -> "!string of word"
782 (remove \\ and disable transformations)
783 "?word?number" -> "word" (return word, if number == 1)
784 "?number" or "??number" -> "" (remove number,
785 if number == 1)
786 "?word?number" -> "number" (if number != 1)
787 """
788 def sub_tuple(m):
789 """ word[number], !word[number], !!word[number], !!!word[number]
790 word, !word, !!word, !!!word, ?word?number, ??number, ?number
791 ?word?word[number], ?word?[number], ??word[number]
792 """
793 w, i = m.group('w', 'i')
794 c = w[0]
795 if c not in '!?':
796 return self.plural(w, symbols[int(i or 0)])
797 elif c == '?':
798 (p1, sep, p2) = w[1:].partition("?")
799 part1 = p1 if sep else ""
800 (part2, sep, part3) = (p2 if sep else p1).partition("?")
801 if not sep:
802 part3 = part2
803 if i is None:
804
805 if not part2:
806 return m.group(0)
807 num = int(part2)
808 else:
809
810 num = int(symbols[int(i or 0)])
811 return part1 if num == 1 else part3 if num == 0 else part2
812 elif w.startswith('!!!'):
813 word = w[3:]
814 fun = upper_fun
815 elif w.startswith('!!'):
816 word = w[2:]
817 fun = title_fun
818 else:
819 word = w[1:]
820 fun = cap_fun
821 if i is not None:
822 return fun(self.plural(word, symbols[int(i)]))
823 return fun(word)
824
825 def sub_dict(m):
826 """ word(var), !word(var), !!word(var), !!!word(var)
827 word(num), !word(num), !!word(num), !!!word(num)
828 ?word2(var), ?word1?word2(var), ?word1?word2?word0(var)
829 ?word2(num), ?word1?word2(num), ?word1?word2?word0(num)
830 """
831 w, n = m.group('w', 'n')
832 c = w[0]
833 n = int(n) if n.isdigit() else symbols[n]
834 if c not in '!?':
835 return self.plural(w, n)
836 elif c == '?':
837
838 (p1, sep, p2) = w[1:].partition("?")
839 part1 = p1 if sep else ""
840 (part2, sep, part3) = (p2 if sep else p1).partition("?")
841 if not sep:
842 part3 = part2
843 num = int(n)
844 return part1 if num == 1 else part3 if num == 0 else part2
845 elif w.startswith('!!!'):
846 word = w[3:]
847 fun = upper_fun
848 elif w.startswith('!!'):
849 word = w[2:]
850 fun = title_fun
851 else:
852 word = w[1:]
853 fun = cap_fun
854 return fun(self.plural(word, n))
855
856 s = m.group(1)
857 part = regex_plural_tuple.sub(sub_tuple, s)
858 if part == s:
859 part = regex_plural_dict.sub(sub_dict, s)
860 if part == s:
861 return m.group(0)
862 return part
863 message = message % symbols
864 message = regex_plural.sub(sub_plural, message)
865 return message
866
868 """
869 get cached translated message with inserted parameters(symbols)
870 """
871 message = get_from_cache(self.cache, message,
872 lambda: self.get_t(message))
873 if symbols or symbols == 0 or symbols == "":
874 if isinstance(symbols, dict):
875 symbols.update(
876 (key, str(value).translate(ttab_in))
877 for key, value in symbols.iteritems()
878 if not isinstance(value, NUMBERS))
879 else:
880 if not isinstance(symbols, tuple):
881 symbols = (symbols,)
882 symbols = tuple(
883 value if isinstance(value, NUMBERS)
884 else str(value).translate(ttab_in)
885 for value in symbols)
886 message = self.params_substitution(message, symbols)
887 return message.translate(ttab_out)
888
889
891 """
892 must be run by the admin app
893 """
894 lang_file = pjoin(path, 'languages', language + '.py')
895 sentences = read_dict(lang_file)
896 mp = pjoin(path, 'models')
897 cp = pjoin(path, 'controllers')
898 vp = pjoin(path, 'views')
899 mop = pjoin(path, 'modules')
900 for filename in \
901 listdir(mp, '^.+\.py$', 0) + listdir(cp, '^.+\.py$', 0)\
902 + listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0):
903 data = read_locked(filename)
904 items = regex_translate.findall(data)
905 for item in items:
906 try:
907 message = safe_eval(item)
908 except:
909 continue
910 if not message.startswith('#') and not '\n' in message:
911 tokens = message.rsplit('##', 1)
912 else:
913
914 tokens = [message]
915 if len(tokens) == 2:
916 message = tokens[0].strip() + '##' + tokens[1].strip()
917 if message and not message in sentences:
918 sentences[message] = message
919 if not '!langcode!' in sentences:
920 sentences['!langcode!'] = (
921 DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language)
922 if not '!langname!' in sentences:
923 sentences['!langname!'] = (
924 DEFAULT_LANGUAGE_NAME if language in ('default', DEFAULT_LANGUAGE)
925 else sentences['!langcode!'])
926 write_dict(lang_file, sentences)
927
928
929
930
932 return marshal.loads(data)
933
934
937 copy_reg.pickle(lazyT, lazyT_pickle, lazyT_unpickle)
938
939
941 path = pjoin(application_path, 'languages/')
942 for language in oslistdir(path):
943 if regex_langfile.match(language):
944 findT(application_path, language[:-3])
945
946
947 if __name__ == '__main__':
948 import doctest
949 doctest.testmod()
950