From 79930a74357a814ada8ebfb59f288789e1fdc97b Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 1 Nov 2010 19:48:45 +0100 Subject: [PATCH 01/14] Bug fix in src/i18n.py --- src/i18n.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/i18n.py b/src/i18n.py index 4877ec32a..7edfeca90 100644 --- a/src/i18n.py +++ b/src/i18n.py @@ -311,6 +311,10 @@ def internationalizeDocstring(obj): Only useful for commands (commands' docstring is displayed on IRC)""" if sys.modules[obj.__module__].__dict__.has_key('_'): internationalizedCommands.update({hash(obj): obj}) - obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__) - # We use _.__call__() instead of _() because of a pygettext warning. + try: + obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__) + # We use _.__call__() instead of _() because of a pygettext warning. + except AttributeError: + # attribute '__doc__' of 'type' objects is not writable + pass return obj From 382bad4a1da127f98795523f8faa6764cea7fbea Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 1 Nov 2010 19:52:28 +0100 Subject: [PATCH 02/14] AutoMode: fix misspell in french locale --- plugins/AutoMode/locale/fr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/AutoMode/locale/fr.po b/plugins/AutoMode/locale/fr.po index a866bb41a..53c063034 100644 --- a/plugins/AutoMode/locale/fr.po +++ b/plugins/AutoMode/locale/fr.po @@ -23,7 +23,7 @@ msgstr "Détermine si ce plugin est activé." msgid "" "Determines whether this plugin will automode\n" " owners." -msgstr "Détermine si ce pluginmettra des modes automatiques sur les owners." +msgstr "Détermine si ce plugin mettra des modes automatiques sur les owners." #: config.py:52 msgid "" From c0ff3c3f92b589365043023216c19dfcd6b536f6 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 1 Nov 2010 19:57:18 +0100 Subject: [PATCH 03/14] Bug fix in i18n.py (decorated commands without docstring raise an error) --- src/i18n.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/i18n.py b/src/i18n.py index 7edfeca90..a5eca10da 100644 --- a/src/i18n.py +++ b/src/i18n.py @@ -309,6 +309,8 @@ def internationalizeDocstring(obj): """Decorates functions and internationalize their docstring. Only useful for commands (commands' docstring is displayed on IRC)""" + if obj.__doc__ == None: + return obj if sys.modules[obj.__module__].__dict__.has_key('_'): internationalizedCommands.update({hash(obj): obj}) try: From 31d9d47751b708f04610040175390b95823eb851 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 1 Nov 2010 20:15:02 +0100 Subject: [PATCH 04/14] Remove debug message --- src/test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test.py b/src/test.py index 2ff5fa465..e1b629e25 100644 --- a/src/test.py +++ b/src/test.py @@ -360,7 +360,6 @@ class PluginTestCase(SupyTestCase): return for cb in self.irc.callbacks: name = cb.name() - print " --- " + name if ((name in self._noTestDoc) and \ not name.lower() in self.__class__.__name__.lower()): continue From 02cb15d522a6e7987bd41120c1154da80edb6409 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 1 Nov 2010 20:18:44 +0100 Subject: [PATCH 05/14] Remove the 'testInternationalization' --- src/test.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test.py b/src/test.py index e1b629e25..99d3514d8 100644 --- a/src/test.py +++ b/src/test.py @@ -371,12 +371,6 @@ class PluginTestCase(SupyTestCase): attr == callbacks.canonicalName(attr): self.failUnless(getattr(cb, attr, None).__doc__, '%s.%s has no help.' % (name, attr)) - def testInternationalization(self): - name = self.__class__.__module__[0:-len('.test')] - if self.__class__.__module__.startswith('supybot'): - return - self.failIf(hasattr(sys.modules[name], '_') == False, - '%s has no internationalizer.' % name) From 9bd66a7e7c4011b307fa52cec0d97f9ab7c360d4 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 3 Nov 2010 19:09:42 +0100 Subject: [PATCH 06/14] Plugin: fix two localization error --- plugins/Plugin/locale/fr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Plugin/locale/fr.po b/plugins/Plugin/locale/fr.po index 0c5d61a53..c5dd0eb4c 100644 --- a/plugins/Plugin/locale/fr.po +++ b/plugins/Plugin/locale/fr.po @@ -69,11 +69,11 @@ msgstr "plugin" #: plugin.py:92 msgid "The %q command is available in the %L %s." -msgstr "La commande %q est disponibles dans le(s) plugin %v." +msgstr "La commande %q est disponibles dans le(s) plugin(s) %L %v." #: plugin.py:95 msgid "There is no command %q." -msgstr "Il n'y a pas de commande q." +msgstr "Il n'y a pas de commande %q." #: plugin.py:100 msgid "" From 485c6161ee29a13f47f72f5491834ba3cb105092 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 3 Nov 2010 19:12:00 +0100 Subject: [PATCH 07/14] Plugin: fix a little localization error --- plugins/Plugin/locale/fr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Plugin/locale/fr.po b/plugins/Plugin/locale/fr.po index c5dd0eb4c..d62ab426e 100644 --- a/plugins/Plugin/locale/fr.po +++ b/plugins/Plugin/locale/fr.po @@ -69,7 +69,7 @@ msgstr "plugin" #: plugin.py:92 msgid "The %q command is available in the %L %s." -msgstr "La commande %q est disponibles dans le(s) plugin(s) %L %v." +msgstr "La commande %q est disponibles dans le(s) plugin(s) %L%v." #: plugin.py:95 msgid "There is no command %q." From b1f0e058a805a695e20293f076c6ff6e2ed2b266 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sat, 6 Nov 2010 08:12:26 +0100 Subject: [PATCH 08/14] Fix two function misspell in locale/fr.py --- locale/fr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locale/fr.py b/locale/fr.py index 23bb731d2..2a6884ea1 100644 --- a/locale/fr.py +++ b/locale/fr.py @@ -40,7 +40,7 @@ def pluralize(s): lowered in ['bijou', 'caillou', 'chou', 'genou', 'hibou', 'joujou', 'pou']: return s + 'x' - elif lowered.endwith('al') and \ + elif lowered.endswith('al') and \ lowered not in ['bal', 'carnaval', 'chacal', 'festival', 'récital', 'régal', 'cal', 'étal', 'aval', 'caracal', 'val', 'choral', 'corral', 'galgal', 'gayal']: @@ -53,7 +53,7 @@ def pluralize(s): return s + 'x' elif lowered == 'pare-feu': return s - elif lowered.endwith('eu') and \ + elif lowered.endswith('eu') and \ lowered not in ['bleu', 'pneu', 'émeu', 'enfeu']: # Note: when 'lieu' is a fish, it has a 's' ; else, it has a 'x' return s + 'x' From 323ffe1a1f2f723fdef99e172e9d11409342d65d Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Thu, 11 Nov 2010 12:01:56 +0100 Subject: [PATCH 09/14] i18n: Fix internationalization problems --- scripts/supybot | 3 +++ src/i18n.py | 60 +++++++++++++++++++++++++++++------------------- src/utils/str.py | 12 +++------- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/scripts/supybot b/scripts/supybot index 7f1953776..5658c25ec 100644 --- a/scripts/supybot +++ b/scripts/supybot @@ -61,6 +61,7 @@ import textwrap started = time.time() import supybot +import supybot.i18n as i18n import supybot.utils as utils import supybot.registry as registry import supybot.questions as questions @@ -178,6 +179,7 @@ if __name__ == '__main__': docs/GETTING_STARTED and follow the instructions.""")) else: registryFilename = args.pop() + i18n.getLocaleFromRegistryFilename(registryFilename) try: # The registry *MUST* be opened before importing log or conf. registry.open(registryFilename) @@ -210,6 +212,7 @@ if __name__ == '__main__': sys.exit(-1) import supybot.conf as conf import supybot.world as world + i18n.import_conf() world.starting = True def closeRegistry(): diff --git a/src/i18n.py b/src/i18n.py index a5eca10da..773448d02 100644 --- a/src/i18n.py +++ b/src/i18n.py @@ -37,6 +37,7 @@ import re import sys import time import threading +conf = None # Don't import conf here ; because conf needs this module WAITING_FOR_MSGID = 1 @@ -47,16 +48,26 @@ IN_MSGSTR = 4 MSGID = 'msgid "' MSGSTR = 'msgstr "' +currentLocale = 'en' + +def getLocaleFromRegistryFilename(filename): + """Called by the 'supybot' script. Gets the locale name before conf is + loaded.""" + global currentLocale + for line in open(filename, 'r'): + if line.startswith('supybot.language: '): + currentLocale = line[len('supybot.language: '):] + def import_conf(): - import supybot.conf as conf - globals().update({'conf': conf}) + """Imports the conf into this module""" + global conf + conf = __import__('supybot.conf').conf conf.registerGlobalValue(conf.supybot, 'language', - conf.registry.String('en', """Determines the bot's default language. - Valid values are things like en, fr, de, etc.""")) - for key in i18nClasses: - i18nClasses[key].loadLocale() + conf.registry.String(currentLocale, """Determines the bot's default + language. Valid values are things like en, fr, de, etc.""")) def getPluginDir(plugin_name): + """Gets the directory of the given plugin""" filename = None try: filename = sys.modules[plugin_name].__file__ @@ -74,6 +85,8 @@ def getPluginDir(plugin_name): return def getLocalePath(name, localeName, extension): + """Gets the path of the locale file of the given plugin ('supybot' stands + for the core).""" if name != 'supybot': directory = getPluginDir(name) + 'locale' else: @@ -85,7 +98,15 @@ i18nClasses = {} internationalizedCommands = {} internationalizedFunctions = [] # No need to know there name -def reloadLocals(): +def reloadLocalesIfRequired(): + global currentLocale + if conf is None: + return + if currentLocale != conf.supybot.language(): + currentLocale = conf.supybot.language() + reloadLocales() + +def reloadLocales(): for pluginName in i18nClasses: i18nClasses[pluginName].loadLocale() for commandHash in internationalizedCommands: @@ -111,17 +132,12 @@ class _PluginInternationalization: self.name = name self.currentLocaleName = None i18nClasses.update({name: self}) - if name != 'supybot' and not 'conf' in globals(): - # if conf is loadable but not loaded - import_conf() self.loadLocale() def loadLocale(self, localeName=None): """(Re)loads the locale used by this class.""" - if localeName is None and 'conf' in globals(): - localeName = conf.supybot.language() - elif localeName is None: - localeName = 'en' + if localeName is None: + localeName = currentLocale self.currentLocaleName = localeName self._loadL10nCode() @@ -184,14 +200,16 @@ class _PluginInternationalization: self._addToDatabase(untranslated, translated) def _addToDatabase(self, untranslated, translated): - untranslated = self._unescape(untranslated) + untranslated = self._unescape(untranslated, True) translated = self._unescape(translated) self.translations.update({untranslated: translated}) - def _unescape(self, string): + def _unescape(self, string, removeNewline=False): import supybot.utils as utils string = str.replace(string, '\\n', '\n') # gettext escapes the \n - string = utils.str.normalizeWhitespace(string, removeNewline=False) + string = str.replace(string, '\\"', '"') + string = str.replace(string, "\'", "'") + string = utils.str.normalizeWhitespace(string, removeNewline) return string def __call__(self, untranslated): @@ -200,12 +218,8 @@ class _PluginInternationalization: his is the function which is called when a plugin runs _()""" if untranslated.__class__ == internationalizedString: return untranslated._original - untranslated = self._unescape(untranslated) - if not 'conf' in globals(): - return untranslated - if self.currentLocaleName != conf.supybot.language(): - # If the locale has been changed - reloadLocals() + untranslated = self._unescape(untranslated, True) + reloadLocalesIfRequired() try: string = self._translate(untranslated) return self._addTracker(string, untranslated) diff --git a/src/utils/str.py b/src/utils/str.py index c624fe7bb..d410aa542 100644 --- a/src/utils/str.py +++ b/src/utils/str.py @@ -61,16 +61,10 @@ def rsplit(s, sep=None, maxsplit=-1): def normalizeWhitespace(s, removeNewline=True): """Normalizes the whitespace in a string; \s+ becomes one space.""" - beginning = s.startswith(' ') - ending = s.endswith(' ') if removeNewline: - s = ' '.join(s.split()) - else: - s = ' '.join(s.split(' ')) - if beginning: - s = ' ' + s - if ending: - s = s + ' ' + s = str.replace(s, '\n', '') + while ' ' in s: + s = str.replace(s, ' ', ' ') return s def distance(s, t): From 11f7033ee0ddc06ecd0acc84827e16ea83bd3287 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Thu, 11 Nov 2010 12:36:47 +0100 Subject: [PATCH 10/14] Factoids: Internationalize a config variable --- plugins/Factoids/config.py | 2 +- plugins/Factoids/messages.pot | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/Factoids/config.py b/plugins/Factoids/config.py index 6fdce802f..4f167865f 100644 --- a/plugins/Factoids/config.py +++ b/plugins/Factoids/config.py @@ -61,7 +61,7 @@ conf.registerChannelValue(Factoids, 'replyWhenInvalidCommand', commands by searching for a factoid; basically making the whatis unnecessary when you want all factoids for a given key."""))) conf.registerChannelValue(Factoids, 'format', - FactoidFormat('$key could be $value.', _("""Determines the format of + FactoidFormat(_('$key could be $value.'), _("""Determines the format of the response given when a factoid's value is requested. All the standard substitutes apply, in addition to "$key" for the factoid's key and "$value" for the factoid's value."""))) diff --git a/plugins/Factoids/messages.pot b/plugins/Factoids/messages.pot index 2c40af2e8..5bcd6f497 100644 --- a/plugins/Factoids/messages.pot +++ b/plugins/Factoids/messages.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2010-10-17 10:59+CEST\n" +"POT-Creation-Date: 2010-11-11 12:37+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -44,6 +44,10 @@ msgid "" " unnecessary when you want all factoids for a given key." msgstr "" +#: config.py:64 +msgid "$key could be $value." +msgstr "" + #: config.py:64 msgid "" "Determines the format of\n" From 4d957e858e21bdc4121467dca33bf28980966659 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Thu, 11 Nov 2010 12:39:13 +0100 Subject: [PATCH 11/14] Factoids: localize a string --- plugins/Factoids/locale/fr.po | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/Factoids/locale/fr.po b/plugins/Factoids/locale/fr.po index 79f1b413f..a9d4b6531 100644 --- a/plugins/Factoids/locale/fr.po +++ b/plugins/Factoids/locale/fr.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: Supybot-fr\n" -"POT-Creation-Date: 2010-10-17 10:59+CEST\n" +"POT-Creation-Date: 2010-11-11 12:37+CET\n" "PO-Revision-Date: \n" "Last-Translator: Valentin Lorentz \n" "Language-Team: Supybot-fr \n" @@ -41,6 +41,10 @@ msgid "" " unnecessary when you want all factoids for a given key." msgstr "Détermine si le bot répondra aux commandes invalides lors de la recherche d'une factoid ; permet simplement de rendre la commande 'whatis' inutile lorsque vous voulez toutes les factoids d'un clef donnée." +#: config.py:64 +msgid "$key could be $value." +msgstr "$key semble être $value." + #: config.py:64 msgid "" "Determines the format of\n" From 0998c2a43f320e9001ef40a2b56ebae175002e0a Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sun, 14 Nov 2010 14:36:02 +0100 Subject: [PATCH 12/14] Fix bug in src/commands.py (forgotten comma) --- src/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands.py b/src/commands.py index 8f3961bbf..bc54ce884 100644 --- a/src/commands.py +++ b/src/commands.py @@ -199,7 +199,7 @@ def getFloat(irc, msg, args, state, type=_('floating point number')): def getPositiveInt(irc, msg, args, state, *L): getInt(irc, msg, args, state, - p=lambda i: i>0, type=_('positive integer') *L) + p=lambda i: i>0, type=_('positive integer'), *L) def getNonNegativeInt(irc, msg, args, state, *L): getInt(irc, msg, args, state, From 415f79d9a53924a3322c1e36621fd42e31194bec Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 17 Nov 2010 16:44:34 +0100 Subject: [PATCH 13/14] Later: fix localization problem --- plugins/Later/locale/fr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Later/locale/fr.po b/plugins/Later/locale/fr.po index 0ce99e82c..f798ef713 100644 --- a/plugins/Later/locale/fr.po +++ b/plugins/Later/locale/fr.po @@ -104,5 +104,5 @@ msgstr "Il n'y a pas de note pour %r" #: plugin.py:182 msgid "Sent %s: <%s> %s" -msgstr "Envoyé le %s : " +msgstr "Envoyé le %s : <%> %s" From 05560299d9fd247148ccf207c8d1c56ff8ddd30e Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 17 Nov 2010 21:40:11 +0100 Subject: [PATCH 14/14] Later: fix localisation problem --- plugins/Later/locale/fr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Later/locale/fr.po b/plugins/Later/locale/fr.po index f798ef713..b03053f05 100644 --- a/plugins/Later/locale/fr.po +++ b/plugins/Later/locale/fr.po @@ -104,5 +104,5 @@ msgstr "Il n'y a pas de note pour %r" #: plugin.py:182 msgid "Sent %s: <%s> %s" -msgstr "Envoyé le %s : <%> %s" +msgstr "Envoyé le %s : <%s> %s"