mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-23 02:49:27 +01:00
utils: Rewrite i18n initialization
The previous implementation was messy and needlessly complicated This simplifies the logic and removes hackiness by making utils/str.py handle internationalization logic itself, instead of bending over backwards to load logic from the parent package at import time.
This commit is contained in:
parent
4a620bf7f0
commit
93370b6f0e
@ -33,10 +33,7 @@ from . import dynamicScope
|
||||
|
||||
from . import i18n
|
||||
|
||||
builtins = (__builtins__ if isinstance(__builtins__, dict) else __builtins__.__dict__)
|
||||
builtins['supybotInternationalization'] = i18n.PluginInternationalization()
|
||||
from . import utils
|
||||
del builtins['supybotInternationalization']
|
||||
|
||||
(__builtins__ if isinstance(__builtins__, dict) else __builtins__.__dict__)['format'] = utils.str.format
|
||||
|
||||
|
52
src/i18n.py
52
src/i18n.py
@ -113,7 +113,6 @@ def getLocalePath(name, localeName, extension):
|
||||
|
||||
i18nClasses = weakref.WeakValueDictionary()
|
||||
internationalizedCommands = weakref.WeakValueDictionary()
|
||||
internationalizedFunctions = [] # No need to know their name
|
||||
|
||||
def reloadLocalesIfRequired():
|
||||
global currentLocale
|
||||
@ -124,12 +123,13 @@ def reloadLocalesIfRequired():
|
||||
reloadLocales()
|
||||
|
||||
def reloadLocales():
|
||||
import supybot.utils as utils
|
||||
|
||||
for pluginClass in i18nClasses.values():
|
||||
pluginClass.loadLocale()
|
||||
for command in list(internationalizedCommands.values()):
|
||||
internationalizeDocstring(command)
|
||||
for function in internationalizedFunctions:
|
||||
function.loadLocale()
|
||||
utils.str._relocalizeFunctions(PluginInternationalization())
|
||||
|
||||
def normalize(string, removeNewline=False):
|
||||
import supybot.utils as utils
|
||||
@ -201,7 +201,6 @@ def parse(translationFile):
|
||||
return translations
|
||||
|
||||
|
||||
i18nSupybot = None
|
||||
def PluginInternationalization(name='supybot'):
|
||||
# This is a proxy that prevents having several objects for the same plugin
|
||||
if name in i18nClasses:
|
||||
@ -326,40 +325,6 @@ class _PluginInternationalization:
|
||||
name in self._l10nFunctions:
|
||||
return self._l10nFunctions[name]
|
||||
|
||||
def internationalizeFunction(self, name):
|
||||
"""Decorates functions and internationalize their code.
|
||||
|
||||
Only useful for Supybot core functions"""
|
||||
if self.name != 'supybot':
|
||||
return
|
||||
class FunctionInternationalizer:
|
||||
def __init__(self, parent, name):
|
||||
self._parent = parent
|
||||
self._name = name
|
||||
def __call__(self, obj):
|
||||
obj = InternationalizedFunction(self._parent, self._name, obj)
|
||||
obj.loadLocale()
|
||||
return obj
|
||||
return FunctionInternationalizer(self, name)
|
||||
|
||||
class InternationalizedFunction:
|
||||
"""Proxy for functions that need to be fully localized.
|
||||
|
||||
The localization code is in locales/LOCALE.py"""
|
||||
def __init__(self, internationalizer, name, function):
|
||||
self._internationalizer = internationalizer
|
||||
self._name = name
|
||||
self._origin = function
|
||||
internationalizedFunctions.append(self)
|
||||
def loadLocale(self):
|
||||
self.__call__ = self._internationalizer.localizeFunction(self._name)
|
||||
if self.__call__ == None:
|
||||
self.restore()
|
||||
def restore(self):
|
||||
self.__call__ = self._origin
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self._origin(*args, **kwargs)
|
||||
|
||||
try:
|
||||
class InternationalizedString(str):
|
||||
@ -375,6 +340,7 @@ except TypeError:
|
||||
know if a string is already localized"""
|
||||
pass
|
||||
|
||||
|
||||
def internationalizeDocstring(obj):
|
||||
"""Decorates functions and internationalize their docstring.
|
||||
|
||||
@ -391,3 +357,13 @@ def internationalizeDocstring(obj):
|
||||
# attribute '__doc__' of 'type' objects is not writable
|
||||
pass
|
||||
return obj
|
||||
|
||||
|
||||
def _install():
|
||||
from . import utils
|
||||
_ = PluginInternationalization()
|
||||
utils.gen._ = _
|
||||
utils.str._ = _
|
||||
utils.str._relocalizeFunctions(_)
|
||||
|
||||
_install()
|
||||
|
@ -50,6 +50,7 @@ csv.split = split
|
||||
|
||||
builtins = (__builtins__ if isinstance(__builtins__, dict) else __builtins__.__dict__)
|
||||
|
||||
|
||||
# We use this often enough that we're going to stick it in builtins.
|
||||
def force(x):
|
||||
if callable(x):
|
||||
@ -58,8 +59,6 @@ def force(x):
|
||||
return x
|
||||
builtins['force'] = force
|
||||
|
||||
internationalization = builtins.get('supybotInternationalization', None)
|
||||
|
||||
# These imports need to happen below the block above, so things get put into
|
||||
# __builtins__ appropriately.
|
||||
from .gen import *
|
||||
|
@ -45,7 +45,9 @@ from . import crypt
|
||||
from .str import format
|
||||
from .file import mktemp
|
||||
from . import minisix
|
||||
from . import internationalization as _
|
||||
|
||||
# will be replaced by supybot.i18n.install()
|
||||
_ = lambda x: x
|
||||
|
||||
def warn_non_constant_time(f):
|
||||
@functools.wraps(f)
|
||||
|
@ -38,20 +38,46 @@ import sys
|
||||
import time
|
||||
import string
|
||||
import textwrap
|
||||
import functools
|
||||
|
||||
from . import minisix
|
||||
from .iter import any
|
||||
from .structures import TwoWayDictionary
|
||||
|
||||
from . import internationalization as _
|
||||
internationalizeFunction = _.internationalizeFunction
|
||||
|
||||
try:
|
||||
from charade.universaldetector import UniversalDetector
|
||||
charadeLoaded = True
|
||||
except ImportError:
|
||||
charadeLoaded = False
|
||||
|
||||
# will be replaced by supybot.i18n.install()
|
||||
_ = lambda x: x
|
||||
|
||||
# used by supybot.i18n.reloadLocales() to (re)load the localized function of
|
||||
# these functions
|
||||
_localizedFunctions = {}
|
||||
_defaultFunctions = {}
|
||||
|
||||
|
||||
def internationalizeFunction(f):
|
||||
f_name = f.__name__
|
||||
_localizedFunctions[f_name] = f
|
||||
_defaultFunctions[f_name] = f
|
||||
|
||||
@functools.wraps(f)
|
||||
def newf(*args, **kwargs):
|
||||
f = _localizedFunctions[f_name]
|
||||
assert f is not None, "_localizedFunctions[%s] is None" % f_name
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return newf
|
||||
|
||||
|
||||
def _relocalizeFunctions(localizer):
|
||||
for f_name in list(_localizedFunctions):
|
||||
f = localizer.localizeFunction(f_name) or _defaultFunctions[f_name]
|
||||
_localizedFunctions[f_name] = f
|
||||
|
||||
if minisix.PY3:
|
||||
def decode_raw_line(line):
|
||||
#first, try to decode using utf-8
|
||||
@ -390,7 +416,7 @@ def matchCase(s1, s2):
|
||||
L[i] = L[i].upper()
|
||||
return ''.join(L)
|
||||
|
||||
@internationalizeFunction('pluralize')
|
||||
@internationalizeFunction
|
||||
def pluralize(s):
|
||||
"""Returns the plural of s. Put any exceptions to the general English
|
||||
rule of appending 's' in the plurals dictionary.
|
||||
@ -413,7 +439,7 @@ def pluralize(s):
|
||||
else:
|
||||
return matchCase(s, s+'s')
|
||||
|
||||
@internationalizeFunction('depluralize')
|
||||
@internationalizeFunction
|
||||
def depluralize(s):
|
||||
"""Returns the singular of s."""
|
||||
consonants = 'bcdfghjklmnpqrstvwxz'
|
||||
@ -467,7 +493,7 @@ def nItems(n, item, between=None):
|
||||
else:
|
||||
return format('%s %s %s', n, between, item)
|
||||
|
||||
@internationalizeFunction('ordinal')
|
||||
@internationalizeFunction
|
||||
def ordinal(i):
|
||||
"""Returns i + the ordinal indicator for the number.
|
||||
|
||||
@ -486,7 +512,7 @@ def ordinal(i):
|
||||
ord = 'rd'
|
||||
return '%s%s' % (i, ord)
|
||||
|
||||
@internationalizeFunction('be')
|
||||
@internationalizeFunction
|
||||
def be(i):
|
||||
"""Returns the form of the verb 'to be' based on the number i."""
|
||||
if i == 1:
|
||||
@ -494,7 +520,7 @@ def be(i):
|
||||
else:
|
||||
return 'are'
|
||||
|
||||
@internationalizeFunction('has')
|
||||
@internationalizeFunction
|
||||
def has(i):
|
||||
"""Returns the form of the verb 'to have' based on the number i."""
|
||||
if i == 1:
|
||||
|
Loading…
Reference in New Issue
Block a user