faster and leaner languages, should be 100% backward compatible, plurals work again

This commit is contained in:
mdipierro
2012-08-27 10:57:26 -05:00
parent a3dfc9f621
commit 3ff4176e1f
3 changed files with 135 additions and 152 deletions
+1 -1
View File
@@ -1 +1 @@
Version 2.00.0 (2012-08-27 10:13:44) dev Version 2.00.0 (2012-08-27 10:57:21) dev
+5 -5
View File
@@ -23,9 +23,9 @@ except ImportError:
GIT_MISSING = 'requires python-git module, but not installed or incompatible version' GIT_MISSING = 'requires python-git module, but not installed or incompatible version'
from gluon.languages import (regex_language, read_possible_languages, from gluon.languages import (regex_language, read_possible_languages,
read_possible_plurals, lang_sampling, lang_sampling,
read_dict, write_dict, read_plural_dict, read_dict, write_dict, read_plural_dict,
write_plural_dict) write_plural_dict, PLURAL_RULES)
if DEMO_MODE and request.function in ['change_password','pack','pack_plugin','upgrade_web2py','uninstall','cleanup','compile_app','remove_compiled_app','delete','delete_plugin','create_file','upload_file','update_languages','reload_routes','git_push','git_pull']: if DEMO_MODE and request.function in ['change_password','pack','pack_plugin','upgrade_web2py','uninstall','cleanup','compile_app','remove_compiled_app','delete','delete_plugin','create_file','upload_file','update_languages','reload_routes','git_push','git_pull']:
@@ -949,8 +949,8 @@ def design():
# get only existed files # get only existed files
languages = sorted(all_languages) languages = sorted(all_languages)
plural_rules={} plural_rules = {}
all_plurals=read_possible_plurals() all_plurals = PLURAL_RULES
for langfile,lang in all_languages.iteritems(): for langfile,lang in all_languages.iteritems():
lang=lang.strip() lang=lang.strip()
match_language = regex_language.match(lang) match_language = regex_language.match(lang)
@@ -961,7 +961,7 @@ def design():
plang = lang_sampling(match_language, all_plurals.keys()) plang = lang_sampling(match_language, all_plurals.keys())
if plang: if plang:
plural=all_plurals[plang] plural=all_plurals[plang]
plural_rules[langfile]=(plural[0],plang,plural[1],plural[3]) plural_rules[langfile]=(plural[0],plang,plural[4],plural[3])
else: else:
plural_rules[langfile]=(0,lang,'plural_rules-%s.py'%lang,'') plural_rules[langfile]=(0,lang,'plural_rules-%s.py'%lang,'')
+129 -146
View File
@@ -34,7 +34,7 @@ osep = os.sep
isdir = os.path.isdir isdir = os.path.isdir
is_gae = settings.global_settings.web2py_runtime_gae is_gae = settings.global_settings.web2py_runtime_gae
DEFAULT_ACCEPT_LANGUAGE = 'en' DEFAULT_LANGUAGE = 'en'
# DEFAULT PLURAL-FORMS RULES: # DEFAULT PLURAL-FORMS RULES:
# language doesn't use plural forms # language doesn't use plural forms
@@ -76,23 +76,24 @@ regex_param=re.compile(r'{(?P<s>.+?)}')
regex_language = \ regex_language = \
re.compile('^([a-zA-Z]{2})(\-[a-zA-Z]{2})?(\-[a-zA-Z]+)?$') re.compile('^([a-zA-Z]{2})(\-[a-zA-Z]{2})?(\-[a-zA-Z]+)?$')
regex_langfile = re.compile('^[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$') regex_langfile = re.compile('^[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$')
regex_langinfo = re.compile("^[^'\"]*['\"]([^'\"]*)['\"]\s*:\s*['\"]([^'\"]*)['\"].*$")
regex_backslash = re.compile(r"\\([\\{}%])") regex_backslash = re.compile(r"\\([\\{}%])")
regex_plural = re.compile('%({.+?})') regex_plural = re.compile('%({.+?})')
regex_plural_dict = re.compile('^{(?P<w>[^()[\]][^()[\]]*?)\((?P<n>[^()\[\]]+)\)}$') # %%{word(varname or number)} regex_plural_dict = re.compile('^{(?P<w>[^()[\]][^()[\]]*?)\((?P<n>[^()\[\]]+)\)}$') # %%{word(varname or number)}
regex_plural_tuple = re.compile('^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$') # %%{word[index]} or %%{word} regex_plural_tuple = re.compile('^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$') # %%{word[index]} or %%{word}
regex_plural_q = re.compile('^asdf$') # %%{?word?cnt}, %%{??cnt} or %%{?cnt}
regex_plural_rules = re.compile('^plural_rules-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$') regex_plural_rules = re.compile('^plural_rules-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$')
upper_fun = lambda s: unicode(s,'utf-8').upper().encode('utf-8') # UTF8 helper functions
title_fun = lambda s: unicode(s,'utf-8').title().encode('utf-8') def upper_fun(s):
cap_fun = lambda s: unicode(s,'utf-8').capitalize().encode('utf-8') return unicode(s,'utf-8').upper().encode('utf-8')
def title_fun(s):
return unicode(s,'utf-8').title().encode('utf-8')
def cap_fun(s):
return lambda s: unicode(s,'utf-8').capitalize().encode('utf-8')
ttab_in = maketrans("\\%{}", '\x1c\x1d\x1e\x1f') ttab_in = maketrans("\\%{}", '\x1c\x1d\x1e\x1f')
ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}") ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}")
# cache of translated messages: # cache of translated messages:
# of structure: # global_language_cache:
# { 'languages/xx.py': # { 'languages/xx.py':
# ( {"def-message": "xx-message", # ( {"def-message": "xx-message",
# ... # ...
@@ -100,35 +101,38 @@ ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}")
# 'languages/yy.py': ( {dict}, lock_object ) # 'languages/yy.py': ( {dict}, lock_object )
# ... # ...
# } # }
tcache={}
global_language_cache={}
def get_from_cache(cache, val, fun): def get_from_cache(cache, val, fun):
lock=cache[1] lang_dict, lock = cache
lock.acquire() lock.acquire()
try: try:
result=cache[0].get(val); result = lang_dict.get(val);
finally: finally:
lock.release() lock.release()
if result: if result:
return result return result
lock.acquire() lock.acquire()
try: try:
result=cache[0].setdefault(val, fun()) result = lang_dict.setdefault(val, fun())
finally: finally:
lock.release() lock.release()
return result return result
def clear_cache(cache): def clear_cache(filename):
lock=cache[1] cache = global_language_cache.setdefault(
filename, ({}, allocate_lock()))
lang_dict, lock = cache
lock.acquire() lock.acquire()
try: try:
cache[0].clear(); lang_dict.clear();
finally: finally:
lock.release() lock.release()
def lang_sampling(lang_tuple, langlist): def lang_sampling(lang_tuple, langlist):
""" search *lang_tuple* in *langlist* """
search *lang_tuple* in *langlist*
Args: Args:
lang_tuple (tuple of strings): ('aa'[[,'-bb'],'-cc']) lang_tuple (tuple of strings): ('aa'[[,'-bb'],'-cc'])
@@ -159,11 +163,8 @@ def lang_sampling(lang_tuple, langlist):
def read_dict_aux(filename): def read_dict_aux(filename):
fp = portalocker.LockedFile(filename, 'r') lang_text = portalocker.read_locked(filename).replace('\r\n', '\n')
lang_text = fp.read().replace('\r\n', '\n') clear_cache(filename)
fp.close()
# clear cache of processed messages:
clear_cache(tcache.setdefault(filename, ({}, allocate_lock())))
try: try:
return safe_eval(lang_text) or {} return safe_eval(lang_text) or {}
except Exception, e: except Exception, e:
@@ -180,9 +181,10 @@ def read_dict(filename):
def get_lang_info(lang, langdir): def get_lang_info(lang, langdir):
"""retrieve lang information from *langdir*/*lang*.py file. """
Read few strings from lang.py file until keys !langname!, retrieve lang information from *langdir*/*lang*.py file.
!langcode! or keys greater then '!*' were found Read few strings from lang.py file until keys !langname!,
!langcode! or keys greater then '!*' were found
args: args:
lang (str): lang-code or 'default' lang (str): lang-code or 'default'
@@ -193,27 +195,10 @@ def get_lang_info(lang, langdir):
e.g.: ('en', 'English', 1338549043.0) e.g.: ('en', 'English', 1338549043.0)
""" """
filename = ospath.join(langdir, lang+'.py') filename = ospath.join(langdir, lang+'.py')
langcode=langname='' d = read_dict(filename)
f = portalocker.LockedFile(filename, 'r') langcode = d.get('!langcode!',DEFAULT_LANGUAGE)
try: langname = d.get('!langname!',langcode)
while not (langcode and langname): return (langcode, langname or langcode, ostat(filename).st_mtime)
line = f.readline()
if not line:
break
match=regex_langinfo.match(line)
if match:
k = match.group(1)
if k == '!langname!':
langname = match.group(2)
elif k == '!langcode!':
langcode = match.group(2)
elif k[0:1] > '!':
break
finally:
f.close()
if not langcode:
langcode = lang if lang != 'default' else 'en'
return langcode, langname or langcode, ostat(filename).st_mtime
def read_possible_languages(appdir): def read_possible_languages(appdir):
langs = {} langs = {}
@@ -222,10 +207,10 @@ def read_possible_languages(appdir):
for filename in os.listdir(langdir): for filename in os.listdir(langdir):
if regex_langfile.match(filename) or filename=='default.py': if regex_langfile.match(filename) or filename=='default.py':
lang = filename[:-3] lang = filename[:-3]
langs[lang]=get_lang_info(lang, langdir) langs[lang] = get_lang_info(lang, langdir)
if not 'default' in langs: if not 'en' in langs:
# if default.py is not found, add default value: # if default.py is not found, add default value:
langs['default'] = ('en', 'English', 0) langs['en'] = ('en', 'English', 0)
return langs return langs
def read_global_plural_rules(filename): def read_global_plural_rules(filename):
@@ -240,14 +225,13 @@ def read_global_plural_rules(filename):
e.g.: (3, <function>, <function>, ok) e.g.: (3, <function>, <function>, ok)
""" """
env = {} env = {}
lock = portalocker.LockedFile(filename, 'r') data = portalocker.read_locked(filename)
try: try:
execfile(filename) in env exec(data) in env
status='ok' status='ok'
except Exception, e: except Exception, e:
status='Syntax error in %s (%s)' % (filename, e) status='Syntax error in %s (%s)' % (filename, e)
logging.error(status) logging.error(status)
lock.close()
nplurals = env.get('nplurals', DEFAULT_NPLURALS) nplurals = env.get('nplurals', DEFAULT_NPLURALS)
get_plural_id = env.get('get_plural_id', DEFAULT_GET_PLURAL_ID) get_plural_id = env.get('get_plural_id', DEFAULT_GET_PLURAL_ID)
construct_plural_form = env.get('construct_plural_form', construct_plural_form = env.get('construct_plural_form',
@@ -256,8 +240,9 @@ def read_global_plural_rules(filename):
def read_possible_plurals(): def read_possible_plurals():
""" create list of all possible plural rules files """
result is cached to increase speed create list of all possible plural rules files
result is cached to increase speed
""" """
pdir = abspath('gluon','contrib','rules') pdir = abspath('gluon','contrib','rules')
plurals = {} plurals = {}
@@ -268,21 +253,20 @@ def read_possible_plurals():
fname = ospath.join(pdir, pname) fname = ospath.join(pdir, pname)
n, f1, f2, status = read_global_plural_rules(fname) n, f1, f2, status = read_global_plural_rules(fname)
if status == 'ok': if status == 'ok':
plurals[lang] = (lang, n, f1, f2) plurals[lang] = (lang, n, f1, f2, pname)
plurals['default'] = ('default', plurals['default'] = ('default',
DEFAULT_NPLURALS, DEFAULT_NPLURALS,
DEFAULT_GET_PLURAL_ID, DEFAULT_GET_PLURAL_ID,
DEFAULT_CONSTRUCTOR_PLURAL_FORM) DEFAULT_CONSTRUCTOR_PLURAL_FORM,
None)
return plurals return plurals
PLURAL_RULES = read_possible_plurals() PLURAL_RULES = read_possible_plurals()
def read_plural_dict_aux(filename): def read_plural_dict_aux(filename):
fp = portalocker.LockedFile(filename, 'r') lang_text = portalocker.read_locked(filename).replace('\r\n', '\n')
lang_text = fp.read().replace('\r\n', '\n')
fp.close()
try: try:
return safe_eval(lang_text) or {} return eval(lang_text) or {}
except Exception, e: except Exception, e:
status='Syntax error in %s (%s)' % (filename, e) status='Syntax error in %s (%s)' % (filename, e)
logging.error(status) logging.error(status)
@@ -422,13 +406,10 @@ class lazyT(object):
return lazyT(self.m, symbols, self.T, self.f, self.t, self.M) return lazyT(self.m, symbols, self.T, self.f, self.t, self.M)
class translator(object): class translator(object):
""" """
this class is instantiated by gluon.compileapp.build_environment this class is instantiated by gluon.compileapp.build_environment
as the T object as the T object
:: ::
T.force(None) # turns off translation T.force(None) # turns off translation
T.force('fr, it') # forces web2py to translate using fr.py or it.py T.force('fr, it') # forces web2py to translate using fr.py or it.py
@@ -436,20 +417,21 @@ class translator(object):
notice 1: there is no need to force since, by default, T uses notice 1: there is no need to force since, by default, T uses
http_accept_language to determine a translation file. http_accept_language to determine a translation file.
notice 2:
notice 2: en and en-en are considered different languages! en and en-en are considered different languages!
notice 3:
notice 3: if language xx-yy is not found force() probes other similar if language xx-yy is not found force() probes other similar
languages using such algorithm: xx-yy.py -> xx.py -> xx-yy*.py -> xx*.py languages using such algorithm:
xx-yy.py -> xx.py -> xx-yy*.py -> xx*.py
""" """
def __init__(self, request): def __init__(self, request):
self.request = request self.request = request
self.folder = request.folder self.folder = request.folder
self.langpath = ospath.join(self.folder,'languages') self.langpath = ospath.join(self.folder,'languages')
self.filenames = set(os.listdir(self.langpath)) self.filenames = set(os.listdir(self.langpath))
self.cache = tcache.setdefault(None, ({},allocate_lock()))
self.http_accept_language = request.env.http_accept_language self.http_accept_language = request.env.http_accept_language
# self.cache # filled in self.force()
# self.accepted_language = None # filled in self.force() # self.accepted_language = None # filled in self.force()
# self.language_file = None # filled in self.force() # self.language_file = None # filled in self.force()
# self.plural_language = None # filled in self.force() # self.plural_language = None # filled in self.force()
@@ -468,12 +450,9 @@ class translator(object):
self.filter = markmin self.filter = markmin
self.ftag = 'markmin' self.ftag = 'markmin'
def get_possible_languages(self): def get_possible_languages(self):
possible_languages = [ return [lang[:-3] for lang in self.filenames \
lang[:-3] for lang in self.filenames \ if regex_langfile.match(lang)]
if regex_langfile.match(lang)]
return possible_languages
def set_current_languages(self, *languages): def set_current_languages(self, *languages):
""" """
@@ -488,27 +467,31 @@ class translator(object):
self.force(self.http_accept_language) self.force(self.http_accept_language)
def set_plural(self, language): def set_plural(self, language):
""" initialize plural forms subsystem """
invoked from self.force() initialize plural forms subsystem
invoked from self.force()
""" """
lang = language[:2] lang = language[:2]
(self.plural_language, (self.plural_language,
self.nplurals, self.nplurals,
self.get_plural_id, self.get_plural_id,
self.construct_plural_form, self.construct_plural_form,
self.plural_filename
) = PLURAL_RULES.get(language,PLURAL_RULES['default']) ) = PLURAL_RULES.get(language,PLURAL_RULES['default'])
filename = 'plural-%s.py' % self.plural_language for lang in (language, language[:5], language[:2]):
if filename in self.filenames: filename = 'plural-%s.py' % lang
self.plural_file = ospath.join(self.langpath,filename) if filename in self.filenames:
self.plural_dict = read_plural_dict(self.plural_file) self.plural_file = ospath.join(self.langpath,filename)
self.plural_dict = read_plural_dict(self.plural_file)
break
else: else:
self.plural_file = None self.plural_file = None
self.plural_dict = {} self.plural_dict = {}
def plural(self, word, n): def plural(self, word, n):
""" """
get plural form of word for number *n* get plural form of word for number *n*
NOTE: *word" MUST be defined in current language NOTE: *word* MUST be defined in current language
(T.accepted_language) (T.accepted_language)
invoked from T()/M() in %%{} tag invoked from T()/M() in %%{} tag
@@ -520,25 +503,27 @@ class translator(object):
(str): word in appropriate singular/plural form (str): word in appropriate singular/plural form
""" """
nplurals = self.nplurals nplurals = self.nplurals
if word: if int(n)==1:
id = self.get_plural_id(abs(int(n))) return word
if id > 0: elif word:
forms = self.plural_dict.get(word, []) id = min(int(n)-1,1) # self.get_plural_id(abs(int(n)))
if forms: # id = 0 first plural form
form = forms.get(id-1) # id = 1 second plural form
if form: # etc.
return form forms = self.plural_dict.get(word, [])
if len(forms)>=id:
# have this plural form
return forms[id-1]
else:
# guessing this plural form
forms += ['']*(nplurals-len(forms)-1)
form = self.construct_plural_form(word, id) form = self.construct_plural_form(word, id)
if len(forms) < nplurals-1:
forms.extend('' for i in xrange(nplurals-len(forms)-1))
forms[id-1] = form forms[id-1] = form
self.plural_dict[word] = forms self.plural_dict[word] = forms
if (self.plural_file and if self.plural_file and not is_gae:
not settings.global_settings.web2py_runtime_gae):
write_plural_dict(self.plural_file, write_plural_dict(self.plural_file,
self.plural_dict) self.plural_dict)
return form return form
return word
def get_possible_languages_info(self, lang=None): def get_possible_languages_info(self, lang=None):
""" """
@@ -556,9 +541,9 @@ class translator(object):
langname(from !langname! key), langname(from !langname! key),
langfile_mtime ) } langfile_mtime ) }
""" """
if lang: info = read_possible_languages(self.folder)
return read_possible_languages(self.folder).get(lang) if lang: info = ingo.get(lang)
return read_possible_languages(self.folder) return info
def force(self, *languages): def force(self, *languages):
""" """
@@ -572,7 +557,6 @@ class translator(object):
default language will be selected if none default language will be selected if none
of them matches possible_languages. of them matches possible_languages.
""" """
global tcache
language = '' language = ''
if isinstance(languages,str): if isinstance(languages,str):
languages = regex_language.findall(languages.lower()) languages = regex_language.findall(languages.lower())
@@ -593,21 +577,20 @@ class translator(object):
break break
else: else:
if 'default.py' in self.filenames: if 'default.py' in self.filenames:
language = DEFAULT_ACCEPT_LANGUAGE language = DEFAULT_LANGUAGE
langfile = 'default.py' langfile = 'default.py'
else: else:
language = DEFAULT_ACCEPT_LANGUAGE language = DEFAULT_LANGUAGE
langfile = None langfile = None
self.accepted_language = language self.accepted_language = language
if langfile: if langfile:
self.language_file = ospath.join(self.langpath,langfile) self.language_file = ospath.join(self.langpath,langfile)
self.t = read_dict(self.language_file) self.t = read_dict(self.language_file)
self.cache = tcache.setdefault(self.language_file,
({},allocate_lock()))
else: else:
self.language_file = None self.language_file = None
self.t = {} self.t = {}
self.cache = tcache[None] self.cache = global_language_cache.setdefault(
self.language_file,({},allocate_lock()))
self.set_plural(language) self.set_plural(language)
return languages return languages
@@ -639,26 +622,30 @@ class translator(object):
prefix = '@'+(ftag or 'userdef')+'\x01' prefix = '@'+(ftag or 'userdef')+'\x01'
else: else:
prefix = '@'+self.ftag+'\x01' prefix = '@'+self.ftag+'\x01'
message = get_from_cache(self.cache, prefix+message, message = get_from_cache(
lambda: get_tr(message, prefix, filter)) self.cache, prefix+message,
lambda: get_tr(message, prefix, filter))
if symbols or symbols == 0 or symbols == "": if symbols or symbols == 0 or symbols == "":
if isinstance(symbols, dict): if isinstance(symbols, dict):
symbols.update( (key, xmlescape(value).translate(ttab_in)) symbols.update(
for key, value in symbols.iteritems() (key, xmlescape(value).translate(ttab_in))
if not isinstance(value, NUMBERS) ) for key, value in symbols.iteritems()
if not isinstance(value, NUMBERS) )
else: else:
if not isinstance(symbols, tuple): if not isinstance(symbols, tuple):
symbols = (symbols,) symbols = (symbols,)
symbols = tuple(value if isinstance(value, NUMBERS) symbols = tuple(
else xmlescape(value).translate(ttab_in) value if isinstance(value, NUMBERS)
for value in symbols) else xmlescape(value).translate(ttab_in)
for value in symbols)
message = self.params_substitution(message, symbols) message = self.params_substitution(message, symbols)
return XML(message.translate(ttab_out)) return XML(message.translate(ttab_out))
def M(self, message, symbols={}, language=None, lazy=None, filter=None, ftag=None): def M(self, message, symbols={}, language=None,
""" get cached translated markmin-message with inserted parametes lazy=None, filter=None, ftag=None):
"""
if lazy==True lazyT object is returned get cached translated markmin-message with inserted parametes
if lazy==True lazyT object is returned
""" """
if lazy is None: if lazy is None:
lazy = self.lazy lazy = self.lazy
@@ -804,19 +791,21 @@ class translator(object):
""" """
get cached translated message with inserted parameters(symbols) get cached translated message with inserted parameters(symbols)
""" """
message = get_from_cache(self.cache, message, lambda: self.get_t(message)) message = get_from_cache(self.cache, message,
lambda: self.get_t(message))
if symbols or symbols == 0 or symbols == "": if symbols or symbols == 0 or symbols == "":
if isinstance(symbols, dict): if isinstance(symbols, dict):
symbols.update( (key, str(value).translate(ttab_in)) symbols.update(
for key, value in symbols.iteritems() (key, str(value).translate(ttab_in))
if not isinstance(value, NUMBERS) ) for key, value in symbols.iteritems()
if not isinstance(value, NUMBERS) )
else: else:
if not isinstance(symbols, tuple): if not isinstance(symbols, tuple):
symbols = (symbols,) symbols = (symbols,)
symbols = tuple(value if isinstance(value, NUMBERS) symbols = tuple(
else str(value).translate(ttab_in) value if isinstance(value, NUMBERS)
for value in symbols) else str(value).translate(ttab_in)
for value in symbols)
message = self.params_substitution(message, symbols) message = self.params_substitution(message, symbols)
return message.translate(ttab_out) return message.translate(ttab_out)
@@ -830,26 +819,25 @@ def findT(path, language='en'):
cp = ospath.join(path, 'controllers') cp = ospath.join(path, 'controllers')
vp = ospath.join(path, 'views') vp = ospath.join(path, 'views')
mop = ospath.join(path, 'modules') mop = ospath.join(path, 'modules')
for file in listdir(mp, '^.+\.py$', 0) + listdir(cp, '^.+\.py$', 0)\ for filename in \
+ listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0): listdir(mp, '^.+\.py$', 0)+listdir(cp, '^.+\.py$', 0)\
fp = portalocker.LockedFile(file, 'r') +listdir(vp, '^.+\.html$', 0)+listdir(mop, '^.+\.py$', 0):
data = fp.read() data = portalocker.read_locked(filename)
fp.close()
items = regex_translate.findall(data) items = regex_translate.findall(data)
for item in items: for item in items:
try: try:
message = eval(item) message = safe_eval(item)
if not message.startswith('#') and not '\n' in message:
tokens = message.rsplit('##', 1)
else:
# this allows markmin syntax in translations
tokens = [message]
if len(tokens) == 2:
message = tokens[0].strip() + '##' + tokens[1].strip()
if message and not message in sentences:
sentences[message] = message
except: except:
pass continue # silently ignore inproperly formatted strings
if not message.startswith('#') and not '\n' in message:
tokens = message.rsplit('##', 1)
else:
# this allows markmin syntax in translations
tokens = [message]
if len(tokens) == 2:
message = tokens[0].strip()+'##'+tokens[1].strip()
if message and not message in sentences:
sentences[message] = message
if not '!langcode!' in sentences: if not '!langcode!' in sentences:
sentences['!langcode!'] = ( sentences['!langcode!'] = (
'en' if language in ('default', 'en') else language) 'en' if language in ('default', 'en') else language)
@@ -875,8 +863,3 @@ def update_all_languages(application_path):
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
doctest.testmod() doctest.testmod()