Merge branch 'l10n-fr' into testing

This commit is contained in:
Valentin Lorentz 2010-11-17 21:40:36 +01:00
commit d5ae366ceb
12 changed files with 70 additions and 52 deletions

View File

@ -40,7 +40,7 @@ def pluralize(s):
lowered in ['bijou', 'caillou', 'chou', 'genou', 'hibou', 'joujou', lowered in ['bijou', 'caillou', 'chou', 'genou', 'hibou', 'joujou',
'pou']: 'pou']:
return s + 'x' return s + 'x'
elif lowered.endwith('al') and \ elif lowered.endswith('al') and \
lowered not in ['bal', 'carnaval', 'chacal', 'festival', 'récital', lowered not in ['bal', 'carnaval', 'chacal', 'festival', 'récital',
'régal', 'cal', 'étal', 'aval', 'caracal', 'val', 'choral', 'régal', 'cal', 'étal', 'aval', 'caracal', 'val', 'choral',
'corral', 'galgal', 'gayal']: 'corral', 'galgal', 'gayal']:
@ -53,7 +53,7 @@ def pluralize(s):
return s + 'x' return s + 'x'
elif lowered == 'pare-feu': elif lowered == 'pare-feu':
return s return s
elif lowered.endwith('eu') and \ elif lowered.endswith('eu') and \
lowered not in ['bleu', 'pneu', 'émeu', 'enfeu']: lowered not in ['bleu', 'pneu', 'émeu', 'enfeu']:
# Note: when 'lieu' is a fish, it has a 's' ; else, it has a 'x' # Note: when 'lieu' is a fish, it has a 's' ; else, it has a 'x'
return s + 'x' return s + 'x'

View File

@ -23,7 +23,7 @@ msgstr "Détermine si ce plugin est activé."
msgid "" msgid ""
"Determines whether this plugin will automode\n" "Determines whether this plugin will automode\n"
" owners." " 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 #: config.py:52
msgid "" msgid ""

View File

@ -61,7 +61,7 @@ conf.registerChannelValue(Factoids, 'replyWhenInvalidCommand',
commands by searching for a factoid; basically making the whatis commands by searching for a factoid; basically making the whatis
unnecessary when you want all factoids for a given key."""))) unnecessary when you want all factoids for a given key.""")))
conf.registerChannelValue(Factoids, 'format', 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 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" substitutes apply, in addition to "$key" for the factoid's key and "$value"
for the factoid's value."""))) for the factoid's value.""")))

View File

@ -1,7 +1,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Supybot-fr\n" "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" "PO-Revision-Date: \n"
"Last-Translator: Valentin Lorentz <progval@gmail.com>\n" "Last-Translator: Valentin Lorentz <progval@gmail.com>\n"
"Language-Team: Supybot-fr <progval@gmail.com>\n" "Language-Team: Supybot-fr <progval@gmail.com>\n"
@ -41,6 +41,10 @@ msgid ""
" unnecessary when you want all factoids for a given key." " 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." 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 #: config.py:64
msgid "" msgid ""
"Determines the format of\n" "Determines the format of\n"

View File

@ -5,7 +5,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -44,6 +44,10 @@ msgid ""
" unnecessary when you want all factoids for a given key." " unnecessary when you want all factoids for a given key."
msgstr "" msgstr ""
#: config.py:64
msgid "$key could be $value."
msgstr ""
#: config.py:64 #: config.py:64
msgid "" msgid ""
"Determines the format of\n" "Determines the format of\n"

View File

@ -104,5 +104,5 @@ msgstr "Il n'y a pas de note pour %r"
#: plugin.py:182 #: plugin.py:182
msgid "Sent %s: <%s> %s" msgid "Sent %s: <%s> %s"
msgstr "Envoyé le %s : " msgstr "Envoyé le %s : <%s> %s"

View File

@ -69,11 +69,11 @@ msgstr "plugin"
#: plugin.py:92 #: plugin.py:92
msgid "The %q command is available in the %L %s." 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 #: plugin.py:95
msgid "There is no command %q." 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 #: plugin.py:100
msgid "" msgid ""

View File

@ -61,6 +61,7 @@ import textwrap
started = time.time() started = time.time()
import supybot import supybot
import supybot.i18n as i18n
import supybot.utils as utils import supybot.utils as utils
import supybot.registry as registry import supybot.registry as registry
import supybot.questions as questions import supybot.questions as questions
@ -178,6 +179,7 @@ if __name__ == '__main__':
docs/GETTING_STARTED and follow the instructions.""")) docs/GETTING_STARTED and follow the instructions."""))
else: else:
registryFilename = args.pop() registryFilename = args.pop()
i18n.getLocaleFromRegistryFilename(registryFilename)
try: try:
# The registry *MUST* be opened before importing log or conf. # The registry *MUST* be opened before importing log or conf.
registry.open(registryFilename) registry.open(registryFilename)
@ -210,6 +212,7 @@ if __name__ == '__main__':
sys.exit(-1) sys.exit(-1)
import supybot.conf as conf import supybot.conf as conf
import supybot.world as world import supybot.world as world
i18n.import_conf()
world.starting = True world.starting = True
def closeRegistry(): def closeRegistry():

View File

@ -199,7 +199,7 @@ def getFloat(irc, msg, args, state, type=_('floating point number')):
def getPositiveInt(irc, msg, args, state, *L): def getPositiveInt(irc, msg, args, state, *L):
getInt(irc, msg, args, state, 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): def getNonNegativeInt(irc, msg, args, state, *L):
getInt(irc, msg, args, state, getInt(irc, msg, args, state,

View File

@ -37,6 +37,7 @@ import re
import sys import sys
import time import time
import threading import threading
conf = None
# Don't import conf here ; because conf needs this module # Don't import conf here ; because conf needs this module
WAITING_FOR_MSGID = 1 WAITING_FOR_MSGID = 1
@ -47,16 +48,26 @@ IN_MSGSTR = 4
MSGID = 'msgid "' MSGID = 'msgid "'
MSGSTR = 'msgstr "' 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(): def import_conf():
import supybot.conf as conf """Imports the conf into this module"""
globals().update({'conf': conf}) global conf
conf = __import__('supybot.conf').conf
conf.registerGlobalValue(conf.supybot, 'language', conf.registerGlobalValue(conf.supybot, 'language',
conf.registry.String('en', """Determines the bot's default language. conf.registry.String(currentLocale, """Determines the bot's default
Valid values are things like en, fr, de, etc.""")) language. Valid values are things like en, fr, de, etc."""))
for key in i18nClasses:
i18nClasses[key].loadLocale()
def getPluginDir(plugin_name): def getPluginDir(plugin_name):
"""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__
@ -74,6 +85,8 @@ def getPluginDir(plugin_name):
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
for the core)."""
if name != 'supybot': if name != 'supybot':
directory = getPluginDir(name) + 'locale' directory = getPluginDir(name) + 'locale'
else: else:
@ -85,7 +98,15 @@ i18nClasses = {}
internationalizedCommands = {} internationalizedCommands = {}
internationalizedFunctions = [] # No need to know there name 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: for pluginName in i18nClasses:
i18nClasses[pluginName].loadLocale() i18nClasses[pluginName].loadLocale()
for commandHash in internationalizedCommands: for commandHash in internationalizedCommands:
@ -108,17 +129,12 @@ class _PluginInternationalization:
self.name = name self.name = name
self.currentLocaleName = None self.currentLocaleName = None
i18nClasses.update({name: self}) i18nClasses.update({name: self})
if name != 'supybot' and not 'conf' in globals():
# if conf is loadable but not loaded
import_conf()
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 and 'conf' in globals(): if localeName is None:
localeName = conf.supybot.language() localeName = currentLocale
elif localeName is None:
localeName = 'en'
self.currentLocaleName = localeName self.currentLocaleName = localeName
self._loadL10nCode() self._loadL10nCode()
@ -179,14 +195,16 @@ class _PluginInternationalization:
self._addToDatabase(untranslated, translated) self._addToDatabase(untranslated, translated)
def _addToDatabase(self, untranslated, translated): def _addToDatabase(self, untranslated, translated):
untranslated = self._unescape(untranslated) 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): 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 = utils.str.normalizeWhitespace(string, removeNewline=False) string = str.replace(string, '\\"', '"')
string = str.replace(string, "\'", "'")
string = utils.str.normalizeWhitespace(string, removeNewline)
return string return string
def __call__(self, untranslated): def __call__(self, untranslated):
@ -195,12 +213,8 @@ class _PluginInternationalization:
his is the function which is called when a plugin runs _()""" his is the function which is called when a plugin runs _()"""
if untranslated.__class__ == internationalizedString: if untranslated.__class__ == internationalizedString:
return untranslated._original return untranslated._original
untranslated = self._unescape(untranslated) untranslated = self._unescape(untranslated, True)
if not 'conf' in globals(): reloadLocalesIfRequired()
return untranslated
if self.currentLocaleName != conf.supybot.language():
# If the locale has been changed
reloadLocals()
try: try:
string = self._translate(untranslated) string = self._translate(untranslated)
return self._addTracker(string, untranslated) return self._addTracker(string, untranslated)
@ -304,8 +318,14 @@ def internationalizeDocstring(obj):
"""Decorates functions and internationalize their docstring. """Decorates functions and internationalize their docstring.
Only useful for commands (commands' docstring is displayed on IRC)""" Only useful for commands (commands' docstring is displayed on IRC)"""
if obj.__doc__ == None:
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})
obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__) try:
# We use _.__call__() instead of _() because of a pygettext warning. obj.__doc__=sys.modules[obj.__module__]._.__call__(obj.__doc__)
return obj # We use _.__call__() instead of _() because of a pygettext warning.
except AttributeError:
# attribute '__doc__' of 'type' objects is not writable
pass
return obj

View File

@ -360,7 +360,6 @@ class PluginTestCase(SupyTestCase):
return return
for cb in self.irc.callbacks: for cb in self.irc.callbacks:
name = cb.name() name = cb.name()
print " --- " + name
if ((name in self._noTestDoc) and \ if ((name in self._noTestDoc) and \
not name.lower() in self.__class__.__name__.lower()): not name.lower() in self.__class__.__name__.lower()):
continue continue
@ -372,12 +371,6 @@ class PluginTestCase(SupyTestCase):
attr == callbacks.canonicalName(attr): attr == callbacks.canonicalName(attr):
self.failUnless(getattr(cb, attr, None).__doc__, self.failUnless(getattr(cb, attr, None).__doc__,
'%s.%s has no help.' % (name, attr)) '%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)

View File

@ -61,16 +61,10 @@ def rsplit(s, sep=None, maxsplit=-1):
def normalizeWhitespace(s, removeNewline=True): def normalizeWhitespace(s, removeNewline=True):
"""Normalizes the whitespace in a string; \s+ becomes one space.""" """Normalizes the whitespace in a string; \s+ becomes one space."""
beginning = s.startswith(' ')
ending = s.endswith(' ')
if removeNewline: if removeNewline:
s = ' '.join(s.split()) s = str.replace(s, '\n', '')
else: while ' ' in s:
s = ' '.join(s.split(' ')) s = str.replace(s, ' ', ' ')
if beginning:
s = ' ' + s
if ending:
s = s + ' '
return s return s
def distance(s, t): def distance(s, t):