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' 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 "" 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/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" 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" diff --git a/plugins/Later/locale/fr.po b/plugins/Later/locale/fr.po index 0ce99e82c..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 : " +msgstr "Envoyé le %s : <%s> %s" diff --git a/plugins/Plugin/locale/fr.po b/plugins/Plugin/locale/fr.po index 0c5d61a53..d62ab426e 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 "" diff --git a/scripts/supybot b/scripts/supybot index ec9b7ecfe..dac2fad3c 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/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, diff --git a/src/i18n.py b/src/i18n.py index e2800334e..0cbd573bb 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: @@ -108,17 +129,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() @@ -179,14 +195,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): @@ -195,12 +213,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) @@ -304,8 +318,14 @@ 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}) - obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__) - # We use _.__call__() instead of _() because of a pygettext warning. - return obj + 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 diff --git a/src/test.py b/src/test.py index 2ff5fa465..99d3514d8 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 @@ -372,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) diff --git a/src/utils/str.py b/src/utils/str.py index 23dbeff99..033547c2c 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):