Remove redundant spaces in src/i18n.py

This commit is contained in:
Valentin Lorentz 2010-11-19 17:00:55 +01:00
parent a618f111aa
commit 3fafd31f51

View File

@ -55,43 +55,43 @@ def getLocaleFromRegistryFilename(filename):
loaded.""" loaded."""
global currentLocale global currentLocale
for line in open(filename, 'r'): for line in open(filename, 'r'):
if line.startswith('supybot.language: '): if line.startswith('supybot.language: '):
currentLocale = line[len('supybot.language: '):] currentLocale = line[len('supybot.language: '):]
def import_conf(): def import_conf():
"""Imports the conf into this module""" """Imports the conf into this module"""
global conf global conf
conf = __import__('supybot.conf').conf conf = __import__('supybot.conf').conf
conf.registerGlobalValue(conf.supybot, 'language', conf.registerGlobalValue(conf.supybot, 'language',
conf.registry.String(currentLocale, """Determines the bot's default conf.registry.String(currentLocale, """Determines the bot's default
language. Valid values are things like en, fr, de, etc.""")) language. Valid values are things like en, fr, de, etc."""))
def getPluginDir(plugin_name): def getPluginDir(plugin_name):
"""Gets the directory of the given plugin""" """Gets the directory of the given plugin"""
filename = None filename = None
try: try:
filename = sys.modules[plugin_name].__file__ filename = sys.modules[plugin_name].__file__
except KeyError: # It sometimes happens with Owner except KeyError: # It sometimes happens with Owner
pass pass
if filename == None: if filename == None:
filename = sys.modules['supybot.plugins.' + plugin_name].__file__ filename = sys.modules['supybot.plugins.' + plugin_name].__file__
if filename.endswith(".pyc"): if filename.endswith(".pyc"):
filename = filename[0:-1] filename = filename[0:-1]
allowed_files = ['__init__.py', 'config.py', 'plugin.py', 'test.py'] allowed_files = ['__init__.py', 'config.py', 'plugin.py', 'test.py']
for allowed_file in allowed_files: for allowed_file in allowed_files:
if filename.endswith(allowed_file): if filename.endswith(allowed_file):
return filename[0:-len(allowed_file)] return filename[0:-len(allowed_file)]
return return
def getLocalePath(name, localeName, extension): def getLocalePath(name, localeName, extension):
"""Gets the path of the locale file of the given plugin ('supybot' stands """Gets the path of the locale file of the given plugin ('supybot' stands
for the core).""" for the core)."""
if name != 'supybot': if name != 'supybot':
directory = getPluginDir(name) + 'locale' directory = getPluginDir(name) + 'locale'
else: else:
import ansi # Any Supybot plugin could fit import ansi # Any Supybot plugin could fit
directory = ansi.__file__[0:-len('ansi.pyc')] + 'locale' directory = ansi.__file__[0:-len('ansi.pyc')] + 'locale'
return '%s/%s.%s' % (directory, localeName, extension) return '%s/%s.%s' % (directory, localeName, extension)
i18nClasses = {} i18nClasses = {}
@ -101,213 +101,213 @@ internationalizedFunctions = [] # No need to know there name
def reloadLocalesIfRequired(): def reloadLocalesIfRequired():
global currentLocale global currentLocale
if conf is None: if conf is None:
return return
if currentLocale != conf.supybot.language(): if currentLocale != conf.supybot.language():
currentLocale = conf.supybot.language() currentLocale = conf.supybot.language()
reloadLocales() reloadLocales()
def reloadLocales(): def reloadLocales():
for pluginName in i18nClasses: for pluginName in i18nClasses:
i18nClasses[pluginName].loadLocale() i18nClasses[pluginName].loadLocale()
for commandHash in internationalizedCommands: for commandHash in internationalizedCommands:
internationalizeDocstring(internationalizedCommands[commandHash]) internationalizeDocstring(internationalizedCommands[commandHash])
for function in internationalizedFunctions: for function in internationalizedFunctions:
function.loadLocale() function.loadLocale()
i18nSupybot = None i18nSupybot = None
def PluginInternationalization(name='supybot'): def PluginInternationalization(name='supybot'):
# This is a proxy that prevents having several objects for the same plugin # This is a proxy that prevents having several objects for the same plugin
if i18nClasses.has_key(name): if i18nClasses.has_key(name):
return i18nClasses[name] return i18nClasses[name]
else: else:
return _PluginInternationalization(name) return _PluginInternationalization(name)
class _PluginInternationalization: class _PluginInternationalization:
"""Internationalization managment for a plugin.""" """Internationalization managment for a plugin."""
def __init__(self, name='supybot'): def __init__(self, name='supybot'):
self.name = name self.name = name
self.currentLocaleName = None self.currentLocaleName = None
i18nClasses.update({name: self}) i18nClasses.update({name: self})
self.loadLocale() self.loadLocale()
def loadLocale(self, localeName=None): def loadLocale(self, localeName=None):
"""(Re)loads the locale used by this class.""" """(Re)loads the locale used by this class."""
if localeName is None: if localeName is None:
localeName = currentLocale localeName = currentLocale
self.currentLocaleName = localeName self.currentLocaleName = localeName
self._loadL10nCode()
try: self._loadL10nCode()
translationFile = open(getLocalePath(self.name, localeName, 'po'),
'ru') # ru is the mode, not the beginning try:
# of 'russian' ;) translationFile = open(getLocalePath(self.name, localeName, 'po'),
self._parse(translationFile) 'ru') # ru is the mode, not the beginning
except IOError: # The translation is unavailable # of 'russian' ;)
self.translations = {} self._parse(translationFile)
except IOError: # The translation is unavailable
self.translations = {}
def _parse(self, translationFile): def _parse(self, translationFile):
"""A .po files parser. """A .po files parser.
Give it a file object."""
step = WAITING_FOR_MSGID
self.translations = {}
for line in translationFile:
line = line[0:-1] # Remove the ending \n
if line.startswith(MSGID):
# Don't check if step is WAITING_FOR_MSGID
untranslated = ''
translated = ''
data = line[len(MSGID):-1]
if len(data) == 0: # Multiline mode
step = IN_MSGID
else:
untranslated += data
step = WAITING_FOR_MSGSTR
elif step is IN_MSGID and line.startswith('"') and \
line.endswith('"'):
untranslated += line[1:-1]
elif step is IN_MSGID and untranslated == '': # Empty MSGID
step = WAITING_FOR_MSGID
elif step is IN_MSGID: # the MSGID is finished
step = WAITING_FOR_MSGSTR
if step is WAITING_FOR_MSGSTR and line.startswith(MSGSTR):
data = line[len(MSGSTR):-1]
if len(data) == 0: # Multiline mode
step = IN_MSGSTR
else:
self._addToDatabase(untranslated, data)
step = WAITING_FOR_MSGID
elif step is IN_MSGSTR and line.startswith('"') and \
line.endswith('"'):
translated += line[1:-1]
elif step is IN_MSGSTR: # the MSGSTR is finished
step = WAITING_FOR_MSGID
if translated == '':
translated = untranslated
self._addToDatabase(untranslated, translated)
Give it a file object."""
step = WAITING_FOR_MSGID
self.translations = {}
for line in translationFile:
line = line[0:-1] # Remove the ending \n
if line.startswith(MSGID):
# Don't check if step is WAITING_FOR_MSGID
untranslated = ''
translated = ''
data = line[len(MSGID):-1]
if len(data) == 0: # Multiline mode
step = IN_MSGID
else:
untranslated += data
step = WAITING_FOR_MSGSTR
elif step is IN_MSGID and line.startswith('"') and \
line.endswith('"'):
untranslated += line[1:-1]
elif step is IN_MSGID and untranslated == '': # Empty MSGID
step = WAITING_FOR_MSGID
elif step is IN_MSGID: # the MSGID is finished
step = WAITING_FOR_MSGSTR
if step is WAITING_FOR_MSGSTR and line.startswith(MSGSTR):
data = line[len(MSGSTR):-1]
if len(data) == 0: # Multiline mode
step = IN_MSGSTR
else:
self._addToDatabase(untranslated, data)
step = WAITING_FOR_MSGID
elif step is IN_MSGSTR and line.startswith('"') and \
line.endswith('"'):
translated += line[1:-1]
elif step is IN_MSGSTR: # the MSGSTR is finished
step = WAITING_FOR_MSGID
if translated == '':
translated = untranslated
self._addToDatabase(untranslated, translated)
def _addToDatabase(self, untranslated, translated): def _addToDatabase(self, untranslated, translated):
untranslated = self._unescape(untranslated, True) untranslated = self._unescape(untranslated, True)
translated = self._unescape(translated) translated = self._unescape(translated)
self.translations.update({untranslated: translated}) self.translations.update({untranslated: translated})
def _unescape(self, string, removeNewline=False): def _unescape(self, string, removeNewline=False):
import supybot.utils as utils import supybot.utils as utils
string = str.replace(string, '\\n', '\n') # gettext escapes the \n string = str.replace(string, '\\n', '\n') # gettext escapes the \n
string = str.replace(string, '\\"', '"') string = str.replace(string, '\\"', '"')
string = str.replace(string, "\'", "'") string = str.replace(string, "\'", "'")
string = utils.str.normalizeWhitespace(string, removeNewline) string = utils.str.normalizeWhitespace(string, removeNewline)
return string return string
def __call__(self, untranslated): def __call__(self, untranslated):
"""Main function. """Main function.
his is the function which is called when a plugin runs _()"""
if untranslated.__class__ == internationalizedString:
return untranslated._original
untranslated = self._unescape(untranslated, True)
reloadLocalesIfRequired()
try:
string = self._translate(untranslated)
return self._addTracker(string, untranslated)
except KeyError:
pass
return untranslated
his is the function which is called when a plugin runs _()"""
if untranslated.__class__ == internationalizedString:
return untranslated._original
untranslated = self._unescape(untranslated, True)
reloadLocalesIfRequired()
try:
string = self._translate(untranslated)
return self._addTracker(string, untranslated)
except KeyError:
pass
return untranslated
def _translate(self, string): def _translate(self, string):
"""Translate the string. """Translate the string.
C the string internationalizer if any; else, use the local database"""
if string.__class__ == internationalizedString:
return string._internationalizer(string.untranslated)
else:
return self.translations[string]
C the string internationalizer if any; else, use the local database"""
if string.__class__ == internationalizedString:
return string._internationalizer(string.untranslated)
else:
return self.translations[string]
def _addTracker(self, string, untranslated): def _addTracker(self, string, untranslated):
"""Add a kind of 'tracker' on the string, in order to keep the """Add a kind of 'tracker' on the string, in order to keep the
untranslated string (used when changing the locale)""" untranslated string (used when changing the locale)"""
if string.__class__ == internationalizedString: if string.__class__ == internationalizedString:
return string return string
else: else:
string = internationalizedString(string) string = internationalizedString(string)
string._original = untranslated string._original = untranslated
string._internationalizer = self string._internationalizer = self
return string return string
def _loadL10nCode(self): def _loadL10nCode(self):
"""Open the file containing the code specific to this locale, and """Open the file containing the code specific to this locale, and
load its functions.""" load its functions."""
if self.name != 'supybot': if self.name != 'supybot':
return return
try: try:
execfile(self._getL10nCodePath()) execfile(self._getL10nCodePath())
except IOError: # File doesn't exist except IOError: # File doesn't exist
pass pass
functions = locals() functions = locals()
functions.pop('self') functions.pop('self')
self._l10nFunctions = functions self._l10nFunctions = functions
# Remove old functions and come back to the native language # Remove old functions and come back to the native language
def _getL10nCodePath(self): def _getL10nCodePath(self):
"""Returns the path to the code localization file. """Returns the path to the code localization file.
It contains functions that needs to by fully (code + strings)
localized"""
if self.name != 'supybot':
return
return getLocalePath('supybot', self.currentLocaleName, 'py')
It contains functions that needs to by fully (code + strings)
localized"""
if self.name != 'supybot':
return
return getLocalePath('supybot', self.currentLocaleName, 'py')
def localizeFunction(self, name): def localizeFunction(self, name):
"""Returns the localized version of the function. """Returns the localized version of the function.
Should be used only by the internationalizedFunction class"""
if self.name != 'supybot':
return
if hasattr(self, '_l10nFunctions') and \
self._l10nFunctions.has_key(name):
return self._l10nFunctions[name]
Should be used only by the internationalizedFunction class"""
if self.name != 'supybot':
return
if hasattr(self, '_l10nFunctions') and \
self._l10nFunctions.has_key(name):
return self._l10nFunctions[name]
def internationalizeFunction(self, name): def internationalizeFunction(self, name):
"""Decorates functions and internationalize their code. """Decorates functions and internationalize their code.
Only useful for Supybot core functions""" Only useful for Supybot core functions"""
if self.name != 'supybot': if self.name != 'supybot':
return return
class FunctionInternationalizer: class FunctionInternationalizer:
def __init__(self, parent, name): def __init__(self, parent, name):
self._parent = parent self._parent = parent
self._name = name self._name = name
def __call__(self, obj): def __call__(self, obj):
obj = internationalizedFunction(self._parent, self._name, obj) obj = internationalizedFunction(self._parent, self._name, obj)
obj.loadLocale() obj.loadLocale()
return obj return obj
return FunctionInternationalizer(self, name) return FunctionInternationalizer(self, name)
class internationalizedFunction: class internationalizedFunction:
"""Proxy for functions that need to be fully localized. """Proxy for functions that need to be fully localized.
The localization code is in locale/LOCALE.py""" The localization code is in locale/LOCALE.py"""
def __init__(self, internationalizer, name, function): def __init__(self, internationalizer, name, function):
self._internationalizer = internationalizer self._internationalizer = internationalizer
self._name = name self._name = name
self.__call__ = function self.__call__ = function
self._origin = function self._origin = function
internationalizedFunctions.append(self) internationalizedFunctions.append(self)
def loadLocale(self): def loadLocale(self):
self.__call__ = self._internationalizer.localizeFunction(self._name) self.__call__ = self._internationalizer.localizeFunction(self._name)
if self.__call__ == None: if self.__call__ == None:
self.restore() self.restore()
def restore(self): def restore(self):
self.__call__ = self._origin self.__call__ = self._origin
class internationalizedString(str): class internationalizedString(str):
"""Simple subclass to str, that allow to add attributes. Also used to """Simple subclass to str, that allow to add attributes. Also used to
@ -319,13 +319,13 @@ def internationalizeDocstring(obj):
Only useful for commands (commands' docstring is displayed on IRC)""" Only useful for commands (commands' docstring is displayed on IRC)"""
if obj.__doc__ == None: if obj.__doc__ == None:
return obj return obj
if sys.modules[obj.__module__].__dict__.has_key('_'): if sys.modules[obj.__module__].__dict__.has_key('_'):
internationalizedCommands.update({hash(obj): obj}) internationalizedCommands.update({hash(obj): obj})
try: try:
obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__) obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__)
# We use _.__call__() instead of _() because of a pygettext warning. # We use _.__call__() instead of _() because of a pygettext warning.
except AttributeError: except AttributeError:
# attribute '__doc__' of 'type' objects is not writable # attribute '__doc__' of 'type' objects is not writable
pass pass
return obj return obj