Internationalize Time, Todo, Topic, URL, Unix, Utilities, and Web

This commit is contained in:
Valentin Lorentz 2010-10-20 09:39:44 +02:00
parent 371a40e004
commit 6a9a8d81b8
21 changed files with 1279 additions and 117 deletions

View File

@ -29,6 +29,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Time')
def configure(advanced): def configure(advanced):
# This will be called by supybot to configure this module. advanced is # This will be called by supybot to configure this module. advanced is
@ -40,10 +42,10 @@ def configure(advanced):
Time = conf.registerPlugin('Time') Time = conf.registerPlugin('Time')
conf.registerChannelValue(Time, 'format', conf.registerChannelValue(Time, 'format',
registry.String(str(conf.supybot.reply.format.time()), """Determines the registry.String(str(conf.supybot.reply.format.time()), _("""Determines the
format string for timestamps. Refer to the Python documentation for the format string for timestamps. Refer to the Python documentation for the
time module to see what formats are accepted. If you set this variable to time module to see what formats are accepted. If you set this variable to
the empty string, the timestamp will not be shown.""")) the empty string, the timestamp will not be shown.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

97
plugins/Time/messages.pot Normal file
View File

@ -0,0 +1,97 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:38+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:45
msgid ""
"Determines the\n"
" format string for timestamps. Refer to the Python documentation for the\n"
" time module to see what formats are accepted. If you set this variable to\n"
" the empty string, the timestamp will not be shown."
msgstr ""
#: plugin.py:60
#, docstring
msgid ""
"[<years>y] [<weeks>w] [<days>d] [<hours>h] [<minutes>m] [<seconds>s]\n"
"\n"
" Returns the number of seconds in the number of <years>, <weeks>,\n"
" <days>, <hours>, <minutes>, and <seconds> given. An example usage is\n"
" \"seconds 2h 30m\", which would return 9000, which is '3600*2 + 30*60'.\n"
" Useful for scheduling events at a given number of seconds in the\n"
" future.\n"
" "
msgstr ""
#: plugin.py:95
#, docstring
msgid ""
"<time string>\n"
"\n"
" Returns the number of seconds since epoch <time string> is.\n"
" <time string> can be any number of natural formats; just try something\n"
" and see if it will work.\n"
" "
msgstr ""
#: plugin.py:106 plugin.py:122
msgid "That's right now!"
msgstr ""
#: plugin.py:111
#, docstring
msgid ""
"<time string>\n"
"\n"
" Returns the number of seconds until <time string>.\n"
" "
msgstr ""
#: plugin.py:127
#, docstring
msgid ""
"[<seconds since epoch>]\n"
"\n"
" Returns the ctime for <seconds since epoch>, or the current ctime if\n"
" no <seconds since epoch> is given.\n"
" "
msgstr ""
#: plugin.py:133
msgid "number of seconds since epoch"
msgstr ""
#: plugin.py:138
#, docstring
msgid ""
"[<format>] [<seconds since epoch>]\n"
"\n"
" Returns the current time in <format> format, or, if <format> is not\n"
" given, uses the configurable format for the current channel. If no\n"
" <seconds since epoch> time is given, the current time is used.\n"
" "
msgstr ""
#: plugin.py:155
#, docstring
msgid ""
"<seconds>\n"
"\n"
" Returns a pretty string that is the amount of time represented by\n"
" <seconds>.\n"
" "
msgstr ""

View File

@ -34,6 +34,8 @@ import supybot.conf as conf
import supybot.utils as utils import supybot.utils as utils
from supybot.commands import * from supybot.commands import *
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Time')
parser = utils.python.universalImport('dateutil.parser', 'local.dateutil.parser') parser = utils.python.universalImport('dateutil.parser', 'local.dateutil.parser')
@ -53,6 +55,7 @@ def parse(s):
return i return i
class Time(callbacks.Plugin): class Time(callbacks.Plugin):
@internationalizeDocstring
def seconds(self, irc, msg, args): def seconds(self, irc, msg, args):
"""[<years>y] [<weeks>w] [<days>d] [<hours>h] [<minutes>m] [<seconds>s] """[<years>y] [<weeks>w] [<days>d] [<hours>h] [<minutes>m] [<seconds>s]
@ -87,6 +90,7 @@ class Time(callbacks.Plugin):
seconds += i seconds += i
irc.reply(str(seconds)) irc.reply(str(seconds))
@internationalizeDocstring
def at(self, irc, msg, args, s): def at(self, irc, msg, args, s):
"""<time string> """<time string>
@ -99,9 +103,10 @@ class Time(callbacks.Plugin):
if new != now: if new != now:
irc.reply(str(new)) irc.reply(str(new))
else: else:
irc.error('That\'s right now!') irc.error(_('That\'s right now!'))
at = wrap(at, ['text']) at = wrap(at, ['text'])
@internationalizeDocstring
def until(self, irc, msg, args, s): def until(self, irc, msg, args, s):
"""<time string> """<time string>
@ -114,9 +119,10 @@ class Time(callbacks.Plugin):
new += 86400 new += 86400
irc.reply(str(new-now)) irc.reply(str(new-now))
else: else:
irc.error('That\'s right now!') irc.error(_('That\'s right now!'))
until = wrap(until, ['text']) until = wrap(until, ['text'])
@internationalizeDocstring
def ctime(self, irc, msg, args, seconds): def ctime(self, irc, msg, args, seconds):
"""[<seconds since epoch>] """[<seconds since epoch>]
@ -124,9 +130,10 @@ class Time(callbacks.Plugin):
no <seconds since epoch> is given. no <seconds since epoch> is given.
""" """
irc.reply(time.ctime(seconds)) irc.reply(time.ctime(seconds))
ctime = wrap(ctime, [additional(('int', 'number of seconds since epoch'), ctime = wrap(ctime,[additional(('int', _('number of seconds since epoch')),
TIME.time)]) TIME.time)])
@internationalizeDocstring
def time(self, irc, msg, args, channel, format, seconds): def time(self, irc, msg, args, channel, format, seconds):
"""[<format>] [<seconds since epoch>] """[<format>] [<seconds since epoch>]
@ -143,6 +150,7 @@ class Time(callbacks.Plugin):
time = wrap(time, [optional('channel'), optional('nonInt'), time = wrap(time, [optional('channel'), optional('nonInt'),
additional('float', TIME.time)]) additional('float', TIME.time)])
@internationalizeDocstring
def elapsed(self, irc, msg, args, seconds): def elapsed(self, irc, msg, args, seconds):
"""<seconds> """<seconds>

View File

@ -29,6 +29,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Todo')
def configure(advanced): def configure(advanced):
# This will be called by supybot to configure this module. advanced is # This will be called by supybot to configure this module. advanced is
@ -42,7 +44,7 @@ def configure(advanced):
Todo = conf.registerPlugin('Todo') Todo = conf.registerPlugin('Todo')
# This is where your configuration variables (if any) should go. For example: # This is where your configuration variables (if any) should go. For example:
# conf.registerGlobalValue(Todo, 'someConfigVariableName', # conf.registerGlobalValue(Todo, 'someConfigVariableName',
# registry.Boolean(False, """Help for someConfigVariableName.""")) # registry.Boolean(False, _("""Help for someConfigVariableName.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

129
plugins/Todo/messages.pot Normal file
View File

@ -0,0 +1,129 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:38+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: plugin.py:135
#, docstring
msgid ""
"[<username> [<task id>]|<task id>]\n"
"\n"
" Retrieves a task for the given task id. If no task id is given, it\n"
" will return a list of task ids that that user has added to their todo\n"
" list.\n"
" "
msgstr ""
#: plugin.py:150
msgid "#%i: %s"
msgstr ""
#: plugin.py:155
msgid "%s for %s: %L"
msgstr ""
#: plugin.py:159
msgid "That user has no tasks in their todo list."
msgstr ""
#: plugin.py:161
msgid "You have no tasks in your todo list."
msgstr ""
#: plugin.py:168
msgid "Active"
msgstr ""
#: plugin.py:170
msgid "Inactive"
msgstr ""
#: plugin.py:172
msgid ", priority: %i"
msgstr ""
#: plugin.py:175
msgid "%s todo for %s: %s (Added at %s)"
msgstr ""
#: plugin.py:179 plugin.py:260 plugin.py:274
msgid "task id"
msgstr ""
#: plugin.py:184
#, docstring
msgid ""
"[--priority=<num>] <text>\n"
"\n"
" Adds <text> as a task in your own personal todo list. The optional\n"
" priority argument allows you to set a task as a high or low priority.\n"
" Any integer is valid.\n"
" "
msgstr ""
#: plugin.py:195
msgid "(Todo #%i added)"
msgstr ""
#: plugin.py:201
#, docstring
msgid ""
"<task id> [<task id> ...]\n"
"\n"
" Removes <task id> from your personal todo list.\n"
" "
msgstr ""
#: plugin.py:212
msgid "Task %i could not be removed either because that id doesn't exist or it has been removed already."
msgstr ""
#: plugin.py:216
msgid "No tasks were removed because the following tasks could not be removed: %L."
msgstr ""
#: plugin.py:226
#, docstring
msgid ""
"[--{regexp} <value>] [<glob> <glob> ...]\n"
"\n"
" Searches your todos for tasks matching <glob>. If --regexp is given,\n"
" its associated value is taken as a regexp and matched against the\n"
" tasks.\n"
" "
msgstr ""
#: plugin.py:246
msgid "No tasks matched that query."
msgstr ""
#: plugin.py:252
#, docstring
msgid ""
"<id> <priority>\n"
"\n"
" Sets the priority of the todo with the given id to the specified value.\n"
" "
msgstr ""
#: plugin.py:266
#, docstring
msgid ""
"<task id> <regexp>\n"
"\n"
" Modify the task with the given id using the supplied regexp.\n"
" "
msgstr ""

View File

@ -41,6 +41,8 @@ from supybot.commands import *
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Todo')
class TodoRecord(dbi.Record): class TodoRecord(dbi.Record):
__fields__ = [ __fields__ = [
@ -128,6 +130,7 @@ class Todo(callbacks.Plugin):
def _shrink(self, s): def _shrink(self, s):
return utils.str.ellipsisify(s, 50) return utils.str.ellipsisify(s, 50)
@internationalizeDocstring
def todo(self, irc, msg, args, user, taskid): def todo(self, irc, msg, args, user, taskid):
"""[<username> [<task id>]|<task id>] """[<username> [<task id>]|<task id>]
@ -144,38 +147,39 @@ class Todo(callbacks.Plugin):
try: try:
tasks = self.db.getTodos(user.id) tasks = self.db.getTodos(user.id)
utils.sortBy(operator.attrgetter('priority'), tasks) utils.sortBy(operator.attrgetter('priority'), tasks)
tasks = [format('#%i: %s', t.id, self._shrink(t.task)) tasks = [format(_('#%i: %s'), t.id, self._shrink(t.task))
for t in tasks] for t in tasks]
Todo = 'Todo' Todo = 'Todo'
if len(tasks) != 1: if len(tasks) != 1:
Todo = 'Todos' Todo = 'Todos'
irc.reply(format('%s for %s: %L', irc.reply(format(_('%s for %s: %L'),
Todo, user.name, tasks)) Todo, user.name, tasks))
except dbi.NoRecordError: except dbi.NoRecordError:
if u != user: if u != user:
irc.reply('That user has no tasks in their todo list.') irc.reply(_('That user has no tasks in their todo list.'))
else: else:
irc.reply('You have no tasks in your todo list.') irc.reply(_('You have no tasks in your todo list.'))
return return
# Reply with the user's task # Reply with the user's task
else: else:
try: try:
t = self.db.get(user.id, taskid) t = self.db.get(user.id, taskid)
if t.active: if t.active:
active = 'Active' active = _('Active')
else: else:
active = 'Inactive' active = _('Inactive')
if t.priority: if t.priority:
t.task += format(', priority: %i', t.priority) t.task += format(_(', priority: %i'), t.priority)
at = time.strftime(conf.supybot.reply.format.time(), at = time.strftime(conf.supybot.reply.format.time(),
time.localtime(t.at)) time.localtime(t.at))
s = format('%s todo for %s: %s (Added at %s)', s = format(_('%s todo for %s: %s (Added at %s)'),
active, user.name, t.task, at) active, user.name, t.task, at)
irc.reply(s) irc.reply(s)
except dbi.NoRecordError: except dbi.NoRecordError:
irc.errorInvalid('task id', taskid) irc.errorInvalid(_('task id'), taskid)
todo = wrap(todo, [first('otherUser', 'user'), additional(('id', 'task'))]) todo = wrap(todo, [first('otherUser', 'user'), additional(('id', 'task'))])
@internationalizeDocstring
def add(self, irc, msg, args, user, optlist, text, now): def add(self, irc, msg, args, user, optlist, text, now):
"""[--priority=<num>] <text> """[--priority=<num>] <text>
@ -188,10 +192,11 @@ class Todo(callbacks.Plugin):
if option == 'priority': if option == 'priority':
priority = arg priority = arg
todoId = self.db.add(priority, now, user.id, text) todoId = self.db.add(priority, now, user.id, text)
irc.replySuccess(format('(Todo #%i added)', todoId)) irc.replySuccess(format(_('(Todo #%i added)'), todoId))
add = wrap(add, ['user', getopts({'priority': ('int', 'priority')}), add = wrap(add, ['user', getopts({'priority': ('int', 'priority')}),
'text', 'now']) 'text', 'now'])
@internationalizeDocstring
def remove(self, irc, msg, args, user, tasks): def remove(self, irc, msg, args, user, tasks):
"""<task id> [<task id> ...] """<task id> [<task id> ...]
@ -204,18 +209,19 @@ class Todo(callbacks.Plugin):
except dbi.NoRecordError: except dbi.NoRecordError:
invalid.append(taskid) invalid.append(taskid)
if invalid and len(invalid) == 1: if invalid and len(invalid) == 1:
irc.error(format('Task %i could not be removed either because ' irc.error(format(_('Task %i could not be removed either because '
'that id doesn\'t exist or it has been removed ' 'that id doesn\'t exist or it has been removed '
'already.', invalid[0])) 'already.'), invalid[0]))
elif invalid: elif invalid:
irc.error(format('No tasks were removed because the following ' irc.error(format(_('No tasks were removed because the following '
'tasks could not be removed: %L.', invalid)) 'tasks could not be removed: %L.'), invalid))
else: else:
for taskid in tasks: for taskid in tasks:
self.db.remove(user.id, taskid) self.db.remove(user.id, taskid)
irc.replySuccess() irc.replySuccess()
remove = wrap(remove, ['user', many(('id', 'task'))]) remove = wrap(remove, ['user', many(('id', 'task'))])
@internationalizeDocstring
def search(self, irc, msg, args, user, optlist, globs): def search(self, irc, msg, args, user, optlist, globs):
"""[--{regexp} <value>] [<glob> <glob> ...] """[--{regexp} <value>] [<glob> <glob> ...]
@ -237,10 +243,11 @@ class Todo(callbacks.Plugin):
L = [format('#%i: %s', t.id, self._shrink(t.task)) for t in tasks] L = [format('#%i: %s', t.id, self._shrink(t.task)) for t in tasks]
irc.reply(format('%L', L)) irc.reply(format('%L', L))
except dbi.NoRecordError: except dbi.NoRecordError:
irc.reply('No tasks matched that query.') irc.reply(_('No tasks matched that query.'))
search = wrap(search, search = wrap(search,
['user', getopts({'regexp': 'regexpMatcher'}), any('glob')]) ['user', getopts({'regexp': 'regexpMatcher'}), any('glob')])
@internationalizeDocstring
def setpriority(self, irc, msg, args, user, id, priority): def setpriority(self, irc, msg, args, user, id, priority):
"""<id> <priority> """<id> <priority>
@ -250,10 +257,11 @@ class Todo(callbacks.Plugin):
self.db.setpriority(user.id, id, priority) self.db.setpriority(user.id, id, priority)
irc.replySuccess() irc.replySuccess()
except dbi.NoRecordError: except dbi.NoRecordError:
irc.errorInvalid('task id', id) irc.errorInvalid(_('task id'), id)
setpriority = wrap(setpriority, setpriority = wrap(setpriority,
['user', ('id', 'task'), ('int', 'priority')]) ['user', ('id', 'task'), ('int', 'priority')])
@internationalizeDocstring
def change(self, irc, msg, args, user, id, replacer): def change(self, irc, msg, args, user, id, replacer):
"""<task id> <regexp> """<task id> <regexp>
@ -263,7 +271,7 @@ class Todo(callbacks.Plugin):
self.db.change(user.id, id, replacer) self.db.change(user.id, id, replacer)
irc.replySuccess() irc.replySuccess()
except dbi.NoRecordError: except dbi.NoRecordError:
irc.errorInvalid('task id', id) irc.errorInvalid(_('task id'), id)
change = wrap(change, ['user', ('id', 'task'), 'regexpReplacer']) change = wrap(change, ['user', ('id', 'task'), 'regexpReplacer'])

View File

@ -29,6 +29,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Topic')
def configure(advanced): def configure(advanced):
# This will be called by supybot to configure this module. advanced is # This will be called by supybot to configure this module. advanced is
@ -45,32 +47,32 @@ class TopicFormat(registry.TemplatedString):
Topic = conf.registerPlugin('Topic') Topic = conf.registerPlugin('Topic')
conf.registerChannelValue(Topic, 'separator', conf.registerChannelValue(Topic, 'separator',
registry.StringSurroundedBySpaces(' || ', """Determines what separator is registry.StringSurroundedBySpaces(' || ', _("""Determines what separator is
used between individually added topics in the channel topic.""")) used between individually added topics in the channel topic.""")))
conf.registerChannelValue(Topic, 'format', conf.registerChannelValue(Topic, 'format',
TopicFormat('$topic ($nick)', """Determines what format is used to add TopicFormat('$topic ($nick)', _("""Determines what format is used to add
topics in the topic. All the standard substitutes apply, in addition to topics in the topic. All the standard substitutes apply, in addition to
"$topic" for the topic itself.""")) "$topic" for the topic itself.""")))
conf.registerChannelValue(Topic, 'recognizeTopiclen', conf.registerChannelValue(Topic, 'recognizeTopiclen',
registry.Boolean(True, """Determines whether the bot will recognize the registry.Boolean(True, _("""Determines whether the bot will recognize the
TOPICLEN value sent to it by the server and thus refuse to send TOPICs TOPICLEN value sent to it by the server and thus refuse to send TOPICs
longer than the TOPICLEN. These topics are likely to be truncated by the longer than the TOPICLEN. These topics are likely to be truncated by the
server anyway, so this defaults to True.""")) server anyway, so this defaults to True.""")))
conf.registerChannelValue(Topic, 'default', conf.registerChannelValue(Topic, 'default',
registry.String('', """Determines what the default topic for the channel registry.String('', _("""Determines what the default topic for the channel
is. This is used by the default command to set this topic.""")) is. This is used by the default command to set this topic.""")))
conf.registerGroup(Topic, 'undo') conf.registerGroup(Topic, 'undo')
conf.registerChannelValue(Topic.undo, 'max', conf.registerChannelValue(Topic.undo, 'max',
registry.NonNegativeInteger(10, """Determines the number of previous registry.NonNegativeInteger(10, _("""Determines the number of previous
topics to keep around in case the undo command is called.""")) topics to keep around in case the undo command is called.""")))
conf.registerChannelValue(Topic, 'requireManageCapability', conf.registerChannelValue(Topic, 'requireManageCapability',
registry.String('channel,op; channel,halfop', registry.String('channel,op; channel,halfop',
"""Determines the _("""Determines the
capabilities required (if any) to make any topic changes, capabilities required (if any) to make any topic changes,
(everything except for read-only operations). Use 'channel,capab' for (everything except for read-only operations). Use 'channel,capab' for
channel-level capabilities. channel-level capabilities.
Note that absence of an explicit anticapability means user has Note that absence of an explicit anticapability means user has
capability.""")) capability.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

356
plugins/Topic/messages.pot Normal file
View File

@ -0,0 +1,356 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:38+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:45
#, docstring
msgid "Value must include $topic, otherwise the actual topic would be left out."
msgstr ""
#: config.py:50
msgid ""
"Determines what separator is\n"
" used between individually added topics in the channel topic."
msgstr ""
#: config.py:53
msgid ""
"Determines what format is used to add\n"
" topics in the topic. All the standard substitutes apply, in addition to\n"
" \"$topic\" for the topic itself."
msgstr ""
#: config.py:57
msgid ""
"Determines whether the bot will recognize the\n"
" TOPICLEN value sent to it by the server and thus refuse to send TOPICs\n"
" longer than the TOPICLEN. These topics are likely to be truncated by the\n"
" server anyway, so this defaults to True."
msgstr ""
#: config.py:62
msgid ""
"Determines what the default topic for the channel\n"
" is. This is used by the default command to set this topic."
msgstr ""
#: config.py:66
msgid ""
"Determines the number of previous\n"
" topics to keep around in case the undo command is called."
msgstr ""
#: config.py:70
msgid ""
"Determines the \n"
" capabilities required (if any) to make any topic changes,\n"
" (everything except for read-only operations). Use 'channel,capab' for \n"
" channel-level capabilities.\n"
" Note that absence of an explicit anticapability means user has \n"
" capability."
msgstr ""
#: plugin.py:55
msgid "I'm not currently in %s."
msgstr ""
#: plugin.py:59
msgid "I can't change the topic, I'm not opped and %s is +t."
msgstr ""
#: plugin.py:66
msgid "The topic must not include %q."
msgstr ""
#: plugin.py:77
msgid "topic number"
msgstr ""
#: plugin.py:90
msgid "There are no topics in %s."
msgstr ""
#: plugin.py:198
msgid "That topic is too long for this server (maximum length: %i; this topic: %i)."
msgstr ""
#: plugin.py:212
#, docstring
msgid ""
"Check if the user has any of the required capabilities to manage\n"
" the channel topic.\n"
"\n"
" The list of required capabilities is in requireManageCapability\n"
" channel config.\n"
"\n"
" Also allow if the user is a chanop. Since he can change the topic\n"
" manually anyway.\n"
" "
msgstr ""
#: plugin.py:264
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Returns the topic for <channel>. <channel> is only necessary if the\n"
" message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:275
#, docstring
msgid ""
"[<channel>] <topic>\n"
"\n"
" Adds <topic> to the topics for <channel>. <channel> is only necessary\n"
" if the message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:290
#, docstring
msgid ""
"[<channel>] <topic>\n"
"\n"
" Adds <topic> to the topics for <channel>. If the topic is too long\n"
" for the server, topics will be popped until there is enough room.\n"
" <channel> is only necessary if the message isn't sent in the channel\n"
" itself.\n"
" "
msgstr ""
#: plugin.py:307
#, docstring
msgid ""
"[<channel>] <number> <topic>\n"
"\n"
" Replaces topic <number> with <topic>.\n"
" "
msgstr ""
#: plugin.py:321
#, docstring
msgid ""
"[<channel>] <topic>\n"
"\n"
" Adds <topic> to the topics for <channel> at the beginning of the topics\n"
" currently on <channel>. <channel> is only necessary if the message\n"
" isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:337
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Shuffles the topics in <channel>. <channel> is only necessary if the\n"
" message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:347
msgid "I can't shuffle 1 or fewer topics."
msgstr ""
#: plugin.py:359
#, docstring
msgid ""
"[<channel>] <number> [<number> ...]\n"
"\n"
" Reorders the topics from <channel> in the order of the specified\n"
" <number> arguments. <number> is a one-based index into the topics.\n"
" <channel> is only necessary if the message isn't sent in the channel\n"
" itself.\n"
" "
msgstr ""
#: plugin.py:372
msgid "I cannot reorder 1 or fewer topics."
msgstr ""
#: plugin.py:374
msgid "All topic numbers must be specified."
msgstr ""
#: plugin.py:376
msgid "Duplicate topic numbers cannot be specified."
msgstr ""
#: plugin.py:384
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Returns a list of the topics in <channel>, prefixed by their indexes.\n"
" Mostly useful for topic reordering. <channel> is only necessary if the\n"
" message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:393
msgid "%i: %s"
msgstr ""
#: plugin.py:400
#, docstring
msgid ""
"[<channel>] <number>\n"
"\n"
" Returns topic number <number> from <channel>. <number> is a one-based\n"
" index into the topics. <channel> is only necessary if the message\n"
" isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:415
#, docstring
msgid ""
"[<channel>] <number> <regexp>\n"
"\n"
" Changes the topic number <number> on <channel> according to the regular\n"
" expression <regexp>. <number> is the one-based index into the topics;\n"
" <regexp> is a regular expression of the form\n"
" s/regexp/replacement/flags. <channel> is only necessary if the message\n"
" isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:433
#, docstring
msgid ""
"[<channel>] [<number>] <topic>\n"
"\n"
" Sets the topic <number> to be <text>. If no <number> is given, this\n"
" sets the entire topic. <channel> is only necessary if the message\n"
" isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:454
#, docstring
msgid ""
"[<channel>] <number>\n"
"\n"
" Removes topic <number> from the topic for <channel> Topics are\n"
" numbered starting from 1; you can also use negative indexes to refer\n"
" to topics starting the from the end of the topic. <channel> is only\n"
" necessary if the message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:471 plugin.py:485
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Locks the topic (sets the mode +t) in <channel>. <channel> is only\n"
" necessary if the message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:481
msgid "lock the topic"
msgstr ""
#: plugin.py:495
msgid "unlock the topic"
msgstr ""
#: plugin.py:499
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Restores the topic to the last topic set by the bot. <channel> is only\n"
" necessary if the message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:510
msgid "I haven't yet set the topic in %s."
msgstr ""
#: plugin.py:518
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Restores the topic to the one previous to the last topic command that\n"
" set it. <channel> is only necessary if the message isn't sent in the\n"
" channel itself.\n"
" "
msgstr ""
#: plugin.py:532
msgid "There are no more undos for %s."
msgstr ""
#: plugin.py:537
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Undoes the last undo. <channel> is only necessary if the message isn't\n"
" sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:549
msgid "There are no redos for %s."
msgstr ""
#: plugin.py:554
#, docstring
msgid ""
"[<channel>] <first topic number> <second topic number>\n"
"\n"
" Swaps the order of the first topic number and the second topic number.\n"
" <channel> is only necessary if the message isn't sent in the channel\n"
" itself.\n"
" "
msgstr ""
#: plugin.py:565
msgid "I refuse to swap the same topic with itself."
msgstr ""
#: plugin.py:575
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Sets the topic in <channel> to the default topic for <channel>. The\n"
" default topic for a channel may be configured via the configuration\n"
" variable supybot.plugins.Topic.default.\n"
" "
msgstr ""
#: plugin.py:588
msgid "There is no default topic configured for %s."
msgstr ""
#: plugin.py:594
#, docstring
msgid ""
"[<channel>] <separator>\n"
"\n"
" Sets the topic separator for <channel> to <separator> Converts the\n"
" current topic appropriately.\n"
" "
msgstr ""

View File

@ -43,6 +43,8 @@ import supybot.ircmsgs as ircmsgs
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Topic')
def canChangeTopic(irc, msg, args, state): def canChangeTopic(irc, msg, args, state):
@ -50,18 +52,19 @@ def canChangeTopic(irc, msg, args, state):
callConverter('channel', irc, msg, args, state) callConverter('channel', irc, msg, args, state)
callConverter('inChannel', irc, msg, args, state) callConverter('inChannel', irc, msg, args, state)
if state.channel not in irc.state.channels: if state.channel not in irc.state.channels:
state.error(format('I\'m not currently in %s.', state.channel), state.error(format(_('I\'m not currently in %s.'), state.channel),
Raise=True) Raise=True)
c = irc.state.channels[state.channel] c = irc.state.channels[state.channel]
if irc.nick not in c.ops and 't' in c.modes: if irc.nick not in c.ops and 't' in c.modes:
state.error(format('I can\'t change the topic, I\'m not opped ' state.error(format(_('I can\'t change the topic, I\'m not opped '
'and %s is +t.', state.channel), Raise=True) 'and %s is +t.'), state.channel), Raise=True)
def getTopic(irc, msg, args, state, format=True): def getTopic(irc, msg, args, state, format=True):
separator = state.cb.registryValue('separator', state.channel) separator = state.cb.registryValue('separator', state.channel)
if separator in args[0]: if separator in args[0]:
state.errorInvalid('topic', args[0], state.errorInvalid('topic', args[0],
format('The topic must not include %q.', separator)) format(_('The topic must not include %q.'),
separator))
topic = args.pop(0) topic = args.pop(0)
if format: if format:
env = {'topic': topic} env = {'topic': topic}
@ -71,7 +74,7 @@ def getTopic(irc, msg, args, state, format=True):
def getTopicNumber(irc, msg, args, state): def getTopicNumber(irc, msg, args, state):
def error(s): def error(s):
state.errorInvalid('topic number', s) state.errorInvalid(_('topic number'), s)
try: try:
n = int(args[0]) n = int(args[0])
if not n: if not n:
@ -84,7 +87,7 @@ def getTopicNumber(irc, msg, args, state):
separator = state.cb.registryValue('separator', state.channel) separator = state.cb.registryValue('separator', state.channel)
topics = splitTopic(topic, separator) topics = splitTopic(topic, separator)
if not topics: if not topics:
state.error(format('There are no topics in %s.', state.channel), state.error(format(_('There are no topics in %s.'), state.channel),
Raise=True) Raise=True)
try: try:
topics[n] topics[n]
@ -192,9 +195,9 @@ class Topic(callbacks.Plugin):
newTopic = self._joinTopic(channel, topics) newTopic = self._joinTopic(channel, topics)
elif len(newTopic) > maxLen: elif len(newTopic) > maxLen:
if self.registryValue('recognizeTopiclen', channel): if self.registryValue('recognizeTopiclen', channel):
irc.error(format('That topic is too long for this server ' irc.error(format(_('That topic is too long for this '
'(maximum length: %i; this topic: %i).', 'server (maximum length: %i; this topic: '
maxLen, len(newTopic)), '%i).'), maxLen, len(newTopic)),
Raise=True) Raise=True)
except KeyError: except KeyError:
pass pass
@ -204,6 +207,7 @@ class Topic(callbacks.Plugin):
irc.queueMsg(ircmsgs.topic(channel, newTopic)) irc.queueMsg(ircmsgs.topic(channel, newTopic))
irc.noReply() irc.noReply()
@internationalizeDocstring
def _checkManageCapabilities(self, irc, msg, channel): def _checkManageCapabilities(self, irc, msg, channel):
"""Check if the user has any of the required capabilities to manage """Check if the user has any of the required capabilities to manage
the channel topic. the channel topic.
@ -255,6 +259,7 @@ class Topic(callbacks.Plugin):
# us to undo the first topic change that takes place in a channel. # us to undo the first topic change that takes place in a channel.
self._addUndo(msg.args[1], [msg.args[2]]) self._addUndo(msg.args[1], [msg.args[2]])
@internationalizeDocstring
def topic(self, irc, msg, args, channel): def topic(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -265,6 +270,7 @@ class Topic(callbacks.Plugin):
irc.reply(topic) irc.reply(topic)
topic = wrap(topic, ['inChannel']) topic = wrap(topic, ['inChannel'])
@internationalizeDocstring
def add(self, irc, msg, args, channel, topic): def add(self, irc, msg, args, channel, topic):
"""[<channel>] <topic> """[<channel>] <topic>
@ -279,6 +285,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
add = wrap(add, ['canChangeTopic', rest('topic')]) add = wrap(add, ['canChangeTopic', rest('topic')])
@internationalizeDocstring
def fit(self, irc, msg, args, channel, topic): def fit(self, irc, msg, args, channel, topic):
"""[<channel>] <topic> """[<channel>] <topic>
@ -295,6 +302,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics, fit=True) self._sendTopics(irc, channel, topics, fit=True)
fit = wrap(fit, ['canChangeTopic', rest('topic')]) fit = wrap(fit, ['canChangeTopic', rest('topic')])
@internationalizeDocstring
def replace(self, irc, msg, args, channel, i, topic): def replace(self, irc, msg, args, channel, i, topic):
"""[<channel>] <number> <topic> """[<channel>] <number> <topic>
@ -308,6 +316,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
replace = wrap(replace, ['canChangeTopic', 'topicNumber', rest('topic')]) replace = wrap(replace, ['canChangeTopic', 'topicNumber', rest('topic')])
@internationalizeDocstring
def insert(self, irc, msg, args, channel, topic): def insert(self, irc, msg, args, channel, topic):
"""[<channel>] <topic> """[<channel>] <topic>
@ -323,6 +332,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
insert = wrap(insert, ['canChangeTopic', rest('topic')]) insert = wrap(insert, ['canChangeTopic', rest('topic')])
@internationalizeDocstring
def shuffle(self, irc, msg, args, channel): def shuffle(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -334,7 +344,7 @@ class Topic(callbacks.Plugin):
irc.errorNoCapability(capabilities, Raise=True) irc.errorNoCapability(capabilities, Raise=True)
topics = self._splitTopic(irc.state.getTopic(channel), channel) topics = self._splitTopic(irc.state.getTopic(channel), channel)
if len(topics) == 0 or len(topics) == 1: if len(topics) == 0 or len(topics) == 1:
irc.error('I can\'t shuffle 1 or fewer topics.', Raise=True) irc.error(_('I can\'t shuffle 1 or fewer topics.'), Raise=True)
elif len(topics) == 2: elif len(topics) == 2:
topics.reverse() topics.reverse()
else: else:
@ -344,6 +354,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
shuffle = wrap(shuffle, ['canChangeTopic']) shuffle = wrap(shuffle, ['canChangeTopic'])
@internationalizeDocstring
def reorder(self, irc, msg, args, channel, numbers): def reorder(self, irc, msg, args, channel, numbers):
"""[<channel>] <number> [<number> ...] """[<channel>] <number> [<number> ...]
@ -358,16 +369,17 @@ class Topic(callbacks.Plugin):
topics = self._splitTopic(irc.state.getTopic(channel), channel) topics = self._splitTopic(irc.state.getTopic(channel), channel)
num = len(topics) num = len(topics)
if num == 0 or num == 1: if num == 0 or num == 1:
irc.error('I cannot reorder 1 or fewer topics.', Raise=True) irc.error(_('I cannot reorder 1 or fewer topics.'), Raise=True)
if len(numbers) != num: if len(numbers) != num:
irc.error('All topic numbers must be specified.', Raise=True) irc.error(_('All topic numbers must be specified.'), Raise=True)
if sorted(numbers) != range(num): if sorted(numbers) != range(num):
irc.error('Duplicate topic numbers cannot be specified.') irc.error(_('Duplicate topic numbers cannot be specified.'))
return return
newtopics = [topics[i] for i in numbers] newtopics = [topics[i] for i in numbers]
self._sendTopics(irc, channel, newtopics) self._sendTopics(irc, channel, newtopics)
reorder = wrap(reorder, ['canChangeTopic', many('topicNumber')]) reorder = wrap(reorder, ['canChangeTopic', many('topicNumber')])
@internationalizeDocstring
def list(self, irc, msg, args, channel): def list(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -378,11 +390,12 @@ class Topic(callbacks.Plugin):
topics = self._splitTopic(irc.state.getTopic(channel), channel) topics = self._splitTopic(irc.state.getTopic(channel), channel)
L = [] L = []
for (i, t) in enumerate(topics): for (i, t) in enumerate(topics):
L.append(format('%i: %s', i+1, utils.str.ellipsisify(t, 30))) L.append(format(_('%i: %s'), i+1, utils.str.ellipsisify(t, 30)))
s = utils.str.commaAndify(L) s = utils.str.commaAndify(L)
irc.reply(s) irc.reply(s)
list = wrap(list, ['inChannel']) list = wrap(list, ['inChannel'])
@internationalizeDocstring
def get(self, irc, msg, args, channel, number): def get(self, irc, msg, args, channel, number):
"""[<channel>] <number> """[<channel>] <number>
@ -397,6 +410,7 @@ class Topic(callbacks.Plugin):
irc.reply(topics[number]) irc.reply(topics[number])
get = wrap(get, ['inChannel', 'topicNumber']) get = wrap(get, ['inChannel', 'topicNumber'])
@internationalizeDocstring
def change(self, irc, msg, args, channel, number, replacer): def change(self, irc, msg, args, channel, number, replacer):
"""[<channel>] <number> <regexp> """[<channel>] <number> <regexp>
@ -414,6 +428,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
change = wrap(change, ['canChangeTopic', 'topicNumber', 'regexpReplacer']) change = wrap(change, ['canChangeTopic', 'topicNumber', 'regexpReplacer'])
@internationalizeDocstring
def set(self, irc, msg, args, channel, number, topic): def set(self, irc, msg, args, channel, number, topic):
"""[<channel>] [<number>] <topic> """[<channel>] [<number>] <topic>
@ -434,6 +449,7 @@ class Topic(callbacks.Plugin):
optional('topicNumber'), optional('topicNumber'),
rest(('topic', False))]) rest(('topic', False))])
@internationalizeDocstring
def remove(self, irc, msg, args, channel, number): def remove(self, irc, msg, args, channel, number):
"""[<channel>] <number> """[<channel>] <number>
@ -450,6 +466,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
remove = wrap(remove, ['canChangeTopic', 'topicNumber']) remove = wrap(remove, ['canChangeTopic', 'topicNumber'])
@internationalizeDocstring
def lock(self, irc, msg, args, channel): def lock(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -461,8 +478,9 @@ class Topic(callbacks.Plugin):
irc.errorNoCapability(capabilities, Raise=True) irc.errorNoCapability(capabilities, Raise=True)
irc.queueMsg(ircmsgs.mode(channel, '+t')) irc.queueMsg(ircmsgs.mode(channel, '+t'))
irc.noReply() irc.noReply()
lock = wrap(lock, ['channel', ('haveOp', 'lock the topic')]) lock = wrap(lock, ['channel', ('haveOp', _('lock the topic'))])
@internationalizeDocstring
def unlock(self, irc, msg, args, channel): def unlock(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -474,8 +492,9 @@ class Topic(callbacks.Plugin):
irc.errorNoCapability(capabilities, Raise=True) irc.errorNoCapability(capabilities, Raise=True)
irc.queueMsg(ircmsgs.mode(channel, '-t')) irc.queueMsg(ircmsgs.mode(channel, '-t'))
irc.noReply() irc.noReply()
unlock = wrap(unlock, ['channel', ('haveOp', 'unlock the topic')]) unlock = wrap(unlock, ['channel', ('haveOp', _('unlock the topic'))])
@internationalizeDocstring
def restore(self, irc, msg, args, channel): def restore(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -488,11 +507,13 @@ class Topic(callbacks.Plugin):
try: try:
topics = self.lastTopics[channel] topics = self.lastTopics[channel]
except KeyError: except KeyError:
irc.error(format('I haven\'t yet set the topic in %s.', channel)) irc.error(format(_('I haven\'t yet set the topic in %s.'),
channel))
return return
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
restore = wrap(restore, ['canChangeTopic']) restore = wrap(restore, ['canChangeTopic'])
@internationalizeDocstring
def undo(self, irc, msg, args, channel): def undo(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -508,9 +529,10 @@ class Topic(callbacks.Plugin):
if topics is not None: if topics is not None:
self._sendTopics(irc, channel, topics, isDo=True) self._sendTopics(irc, channel, topics, isDo=True)
else: else:
irc.error(format('There are no more undos for %s.', channel)) irc.error(format(_('There are no more undos for %s.'), channel))
undo = wrap(undo, ['canChangetopic']) undo = wrap(undo, ['canChangetopic'])
@internationalizeDocstring
def redo(self, irc, msg, args, channel): def redo(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -524,9 +546,10 @@ class Topic(callbacks.Plugin):
if topics is not None: if topics is not None:
self._sendTopics(irc, channel, topics, isDo=True) self._sendTopics(irc, channel, topics, isDo=True)
else: else:
irc.error(format('There are no redos for %s.', channel)) irc.error(format(_('There are no redos for %s.'), channel))
redo = wrap(redo, ['canChangeTopic']) redo = wrap(redo, ['canChangeTopic'])
@internationalizeDocstring
def swap(self, irc, msg, args, channel, first, second): def swap(self, irc, msg, args, channel, first, second):
"""[<channel>] <first topic number> <second topic number> """[<channel>] <first topic number> <second topic number>
@ -539,7 +562,7 @@ class Topic(callbacks.Plugin):
irc.errorNoCapability(capabilities, Raise=True) irc.errorNoCapability(capabilities, Raise=True)
topics = self._splitTopic(irc.state.getTopic(channel), channel) topics = self._splitTopic(irc.state.getTopic(channel), channel)
if first == second: if first == second:
irc.error('I refuse to swap the same topic with itself.') irc.error(_('I refuse to swap the same topic with itself.'))
return return
t = topics[first] t = topics[first]
topics[first] = topics[second] topics[first] = topics[second]
@ -547,6 +570,7 @@ class Topic(callbacks.Plugin):
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
swap = wrap(swap, ['canChangeTopic', 'topicNumber', 'topicNumber']) swap = wrap(swap, ['canChangeTopic', 'topicNumber', 'topicNumber'])
@internationalizeDocstring
def default(self, irc, msg, args, channel): def default(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -561,10 +585,11 @@ class Topic(callbacks.Plugin):
if topic: if topic:
self._sendTopics(irc, channel, [topic]) self._sendTopics(irc, channel, [topic])
else: else:
irc.error(format('There is no default topic configured for %s.', irc.error(format(_('There is no default topic configured for %s.'),
channel)) channel))
default = wrap(default, ['canChangeTopic']) default = wrap(default, ['canChangeTopic'])
@internationalizeDocstring
def separator(self, irc, msg, args, channel, separator): def separator(self, irc, msg, args, channel, separator):
"""[<channel>] <separator> """[<channel>] <separator>

View File

@ -29,6 +29,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('URL')
def configure(advanced): def configure(advanced):
# This will be called by supybot to configure this module. advanced is # This will be called by supybot to configure this module. advanced is
@ -40,10 +42,10 @@ def configure(advanced):
URL = conf.registerPlugin('URL') URL = conf.registerPlugin('URL')
conf.registerChannelValue(URL, 'nonSnarfingRegexp', conf.registerChannelValue(URL, 'nonSnarfingRegexp',
registry.Regexp(None, """Determines what URLs are not to be snarfed and registry.Regexp(None, _("""Determines what URLs are not to be snarfed and
stored in the database for the channel; URLs matching the given regexp will stored in the database for the channel; URLs matching the given regexp will
not be snarfed. Give the empty string if you have no URLs that you'd like not be snarfed. Give the empty string if you have no URLs that you'd like
to exclude from being snarfed.""")) to exclude from being snarfed.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

58
plugins/URL/messages.pot Normal file
View File

@ -0,0 +1,58 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:38+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:45
msgid ""
"Determines what URLs are not to be snarfed and\n"
" stored in the database for the channel; URLs matching the given regexp will\n"
" not be snarfed. Give the empty string if you have no URLs that you'd like\n"
" to exclude from being snarfed."
msgstr ""
#: plugin.py:89
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Returns the number of URLs in the URL database. <channel> is only\n"
" required if the message isn't sent in the channel itself.\n"
" "
msgstr ""
#: plugin.py:96
msgid "I have %n in my database."
msgstr ""
#: plugin.py:101
#, docstring
msgid ""
"[<channel>] [--{from,with,without,near,proto} <value>] [--nolimit]\n"
"\n"
" Gives the last URL matching the given criteria. --from is from whom\n"
" the URL came; --proto is the protocol the URL used; --with is something\n"
" inside the URL; --without is something that should not be in the URL;\n"
" --near is something in the same message as the URL; If --nolimit is\n"
" given, returns all the URLs that are found. to just the URL.\n"
" <channel> is only necessary if the message isn't sent in the channel\n"
" itself.\n"
" "
msgstr ""
#: plugin.py:143
msgid "No URLs matched that criteria."
msgstr ""

View File

@ -36,6 +36,8 @@ import supybot.plugins as plugins
import supybot.ircmsgs as ircmsgs import supybot.ircmsgs as ircmsgs
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('URL')
class UrlRecord(dbi.Record): class UrlRecord(dbi.Record):
__fields__ = [ __fields__ = [
@ -82,6 +84,7 @@ class URL(callbacks.Plugin):
self.log.debug('Adding %u to db.', url) self.log.debug('Adding %u to db.', url)
self.db.add(channel, url, msg) self.db.add(channel, url, msg)
@internationalizeDocstring
def stats(self, irc, msg, args, channel): def stats(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -90,9 +93,10 @@ class URL(callbacks.Plugin):
""" """
self.db.vacuum(channel) self.db.vacuum(channel)
count = self.db.size(channel) count = self.db.size(channel)
irc.reply(format('I have %n in my database.', (count, 'URL'))) irc.reply(format(_('I have %n in my database.'), (count, 'URL')))
stats = wrap(stats, ['channeldb']) stats = wrap(stats, ['channeldb'])
@internationalizeDocstring
def last(self, irc, msg, args, channel, optlist): def last(self, irc, msg, args, channel, optlist):
"""[<channel>] [--{from,with,without,near,proto} <value>] [--nolimit] """[<channel>] [--{from,with,without,near,proto} <value>] [--nolimit]
@ -136,7 +140,7 @@ class URL(callbacks.Plugin):
return True return True
urls = [record.url for record in self.db.urls(channel, predicate)] urls = [record.url for record in self.db.urls(channel, predicate)]
if not urls: if not urls:
irc.reply('No URLs matched that criteria.') irc.reply(_('No URLs matched that criteria.'))
else: else:
if nolimit: if nolimit:
urls = [format('%u', url) for url in urls] urls = [format('%u', url) for url in urls]

View File

@ -30,6 +30,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.utils as utils import supybot.utils as utils
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Unix')
import plugin import plugin
@ -42,11 +44,11 @@ def configure(advanced):
# registry as appropriate. # registry as appropriate.
from supybot.questions import output, expect, anything, something, yn from supybot.questions import output, expect, anything, something, yn
conf.registerPlugin('Unix', True) conf.registerPlugin('Unix', True)
output("""The "progstats" command can reveal potentially sensitive output(_("""The "progstats" command can reveal potentially sensitive
information about your machine. Here's an example of its output: information about your machine. Here's an example of its output:
%s\n""" % progstats()) %s\n""") % progstats())
if yn('Would you like to disable this command for non-owner users?', if yn(_('Would you like to disable this command for non-owner users?'),
default=True): default=True):
conf.supybot.commands.disabled().add('Unix.progstats') conf.supybot.commands.disabled().add('Unix.progstats')
@ -54,36 +56,36 @@ def configure(advanced):
Unix = conf.registerPlugin('Unix') Unix = conf.registerPlugin('Unix')
conf.registerGroup(Unix, 'fortune') conf.registerGroup(Unix, 'fortune')
conf.registerGlobalValue(Unix.fortune, 'command', conf.registerGlobalValue(Unix.fortune, 'command',
registry.String(utils.findBinaryInPath('fortune') or '', """Determines what registry.String(utils.findBinaryInPath('fortune') or '', _("""Determines
command will be called for the fortune command.""")) what command will be called for the fortune command.""")))
conf.registerGlobalValue(Unix.fortune, 'short', conf.registerGlobalValue(Unix.fortune, 'short',
registry.Boolean(True, """Determines whether only short fortunes will be registry.Boolean(True, _("""Determines whether only short fortunes will be
used if possible. This sends the -s option to the fortune program.""")) used if possible. This sends the -s option to the fortune program.""")))
conf.registerGlobalValue(Unix.fortune, 'equal', conf.registerGlobalValue(Unix.fortune, 'equal',
registry.Boolean(True, """Determines whether fortune will give equal registry.Boolean(True, _("""Determines whether fortune will give equal
weight to the different fortune databases. If false, then larger weight to the different fortune databases. If false, then larger
databases will be given more weight. This sends the -e option to the databases will be given more weight. This sends the -e option to the
fortune program.""")) fortune program.""")))
conf.registerGlobalValue(Unix.fortune, 'offensive', conf.registerGlobalValue(Unix.fortune, 'offensive',
registry.Boolean(False, """Determines whether fortune will retrieve registry.Boolean(False, _("""Determines whether fortune will retrieve
offensive fortunes along with the normal fortunes. This sends the -a offensive fortunes along with the normal fortunes. This sends the -a
option to the fortune program.""")) option to the fortune program.""")))
conf.registerGlobalValue(Unix.fortune, 'files', conf.registerGlobalValue(Unix.fortune, 'files',
registry.SpaceSeparatedListOfStrings([], """Determines what specific file registry.SpaceSeparatedListOfStrings([], _("""Determines what specific file
(if any) will be used with the fortune command; if none is given, the (if any) will be used with the fortune command; if none is given, the
system-wide default will be used. Do note that this fortune file must be system-wide default will be used. Do note that this fortune file must be
placed with the rest of your system's fortune files.""")) placed with the rest of your system's fortune files.""")))
conf.registerGroup(Unix, 'spell') conf.registerGroup(Unix, 'spell')
conf.registerGlobalValue(Unix.spell, 'command', conf.registerGlobalValue(Unix.spell, 'command',
registry.String(utils.findBinaryInPath('aspell') or registry.String(utils.findBinaryInPath('aspell') or
utils.findBinaryInPath('ispell') or '', """Determines what utils.findBinaryInPath('ispell') or '', _("""Determines
command will be called for the spell command.""")) what command will be called for the spell command.""")))
conf.registerGroup(Unix, 'wtf') conf.registerGroup(Unix, 'wtf')
conf.registerGlobalValue(Unix.wtf, 'command', conf.registerGlobalValue(Unix.wtf, 'command',
registry.String(utils.findBinaryInPath('wtf') or '', """Determines what registry.String(utils.findBinaryInPath('wtf') or '', _("""Determines what
command will be called for the wtf command.""")) command will be called for the wtf command.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

198
plugins/Unix/messages.pot Normal file
View File

@ -0,0 +1,198 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:38+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:47
msgid ""
"The \"progstats\" command can reveal potentially sensitive\n"
" information about your machine. Here's an example of its output:\n"
"\n"
" %s\n"
msgstr ""
#: config.py:51
msgid "Would you like to disable this command for non-owner users?"
msgstr ""
#: config.py:59
msgid ""
"Determines\n"
" what command will be called for the fortune command."
msgstr ""
#: config.py:62
msgid ""
"Determines whether only short fortunes will be\n"
" used if possible. This sends the -s option to the fortune program."
msgstr ""
#: config.py:65
msgid ""
"Determines whether fortune will give equal\n"
" weight to the different fortune databases. If false, then larger\n"
" databases will be given more weight. This sends the -e option to the\n"
" fortune program."
msgstr ""
#: config.py:70
msgid ""
"Determines whether fortune will retrieve\n"
" offensive fortunes along with the normal fortunes. This sends the -a\n"
" option to the fortune program."
msgstr ""
#: config.py:74
msgid ""
"Determines what specific file\n"
" (if any) will be used with the fortune command; if none is given, the\n"
" system-wide default will be used. Do note that this fortune file must be\n"
" placed with the rest of your system's fortune files."
msgstr ""
#: config.py:82
msgid ""
"Determines\n"
" what command will be called for the spell command."
msgstr ""
#: config.py:87
msgid ""
"Determines what\n"
" command will be called for the wtf command."
msgstr ""
#: plugin.py:73
#, docstring
msgid ""
"<error number or code>\n"
"\n"
" Returns the number of an errno code, or the errno code of a number.\n"
" "
msgstr ""
#: plugin.py:85
msgid "I can't find the errno number for that code."
msgstr ""
#: plugin.py:88
msgid "(unknown)"
msgstr ""
#: plugin.py:89
msgid "%s (#%i): %s"
msgstr ""
#: plugin.py:94
#, docstring
msgid ""
"takes no arguments\n"
"\n"
" Returns various unix-y information on the running supybot process.\n"
" "
msgstr ""
#: plugin.py:102
#, docstring
msgid ""
"takes no arguments\n"
"\n"
" Returns the current pid of the process for this Supybot.\n"
" "
msgstr ""
#: plugin.py:112
#, docstring
msgid ""
"<password> [<salt>]\n"
"\n"
" Returns the resulting of doing a crypt() on <password> If <salt> is\n"
" not given, uses a random salt. If running on a glibc2 system,\n"
" prepending '$1$' to your salt will cause crypt to return an MD5sum\n"
" based crypt rather than the standard DES based crypt.\n"
" "
msgstr ""
#: plugin.py:131
#, docstring
msgid ""
"<word>\n"
"\n"
" Returns the result of passing <word> to aspell/ispell. The results\n"
" shown are sorted from best to worst in terms of being a likely match\n"
" for the spelling of <word>.\n"
" "
msgstr ""
#: plugin.py:140
msgid "The spell checking command is not configured. If one is installed, reconfigure supybot.plugins.Unix.spell.command appropriately."
msgstr ""
#: plugin.py:145
msgid "<word> must begin with an alphabet character."
msgstr ""
#: plugin.py:167
msgid "No results found."
msgstr ""
#: plugin.py:178
msgid "%q may be spelled correctly."
msgstr ""
#: plugin.py:180
msgid "I could not find an alternate spelling for %q"
msgstr ""
#: plugin.py:184
msgid "Possible spellings for %q: %L."
msgstr ""
#: plugin.py:193
#, docstring
msgid ""
"takes no arguments\n"
"\n"
" Returns a fortune from the *nix fortune program.\n"
" "
msgstr ""
#: plugin.py:213
msgid "It seems the configured fortune command was not available."
msgstr ""
#: plugin.py:222
msgid "The fortune command is not configured. If fortune is installed on this system, reconfigure the supybot.plugins.Unix.fortune.command configuration variable appropriately."
msgstr ""
#: plugin.py:229
#, docstring
msgid ""
"[is] <something>\n"
"\n"
" Returns wtf <something> is. 'wtf' is a *nix command that first\n"
" appeared in NetBSD 1.5. In most *nices, it's available in some sort\n"
" of 'bsdgames' package.\n"
" "
msgstr ""
#: plugin.py:244
msgid "It seems the configured wtf command was not available."
msgstr ""
#: plugin.py:253
msgid "The wtf command is not configured. If it is installed on this system, reconfigure the supybot.plugins.Unix.wtf.command configuration variable appropriately."
msgstr ""

View File

@ -44,6 +44,8 @@ from supybot.commands import *
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Unix')
def progstats(): def progstats():
pw = pwd.getpwuid(os.getuid()) pw = pwd.getpwuid(os.getuid())
@ -66,6 +68,7 @@ def pipeReadline(fd, timeout=2):
raise TimeoutError raise TimeoutError
class Unix(callbacks.Plugin): class Unix(callbacks.Plugin):
@internationalizeDocstring
def errno(self, irc, msg, args, s): def errno(self, irc, msg, args, s):
"""<error number or code> """<error number or code>
@ -79,13 +82,14 @@ class Unix(callbacks.Plugin):
try: try:
i = getattr(errno, name) i = getattr(errno, name)
except AttributeError: except AttributeError:
irc.reply('I can\'t find the errno number for that code.') irc.reply(_('I can\'t find the errno number for that code.'))
return return
except KeyError: except KeyError:
name = '(unknown)' name = _('(unknown)')
irc.reply(format('%s (#%i): %s', name, i, os.strerror(i))) irc.reply(format(_('%s (#%i): %s'), name, i, os.strerror(i)))
errno = wrap(errno, ['something']) errno = wrap(errno, ['something'])
@internationalizeDocstring
def progstats(self, irc, msg, args): def progstats(self, irc, msg, args):
"""takes no arguments """takes no arguments
@ -93,6 +97,7 @@ class Unix(callbacks.Plugin):
""" """
irc.reply(progstats()) irc.reply(progstats())
@internationalizeDocstring
def pid(self, irc, msg, args): def pid(self, irc, msg, args):
"""takes no arguments """takes no arguments
@ -102,6 +107,7 @@ class Unix(callbacks.Plugin):
pid = wrap(pid, [('checkCapability', 'owner')]) pid = wrap(pid, [('checkCapability', 'owner')])
_cryptre = re.compile(r'[./0-9A-Za-z]') _cryptre = re.compile(r'[./0-9A-Za-z]')
@internationalizeDocstring
def crypt(self, irc, msg, args, password, salt): def crypt(self, irc, msg, args, password, salt):
"""<password> [<salt>] """<password> [<salt>]
@ -120,6 +126,7 @@ class Unix(callbacks.Plugin):
irc.reply(crypt.crypt(password, salt)) irc.reply(crypt.crypt(password, salt))
crypt = wrap(crypt, ['something', additional('something')]) crypt = wrap(crypt, ['something', additional('something')])
@internationalizeDocstring
def spell(self, irc, msg, args, word): def spell(self, irc, msg, args, word):
"""<word> """<word>
@ -130,12 +137,12 @@ class Unix(callbacks.Plugin):
# We are only checking the first word # We are only checking the first word
spellCmd = self.registryValue('spell.command') spellCmd = self.registryValue('spell.command')
if not spellCmd: if not spellCmd:
irc.error('The spell checking command is not configured. If one ' irc.error(_('The spell checking command is not configured. If one '
'is installed, reconfigure ' 'is installed, reconfigure '
'supybot.plugins.Unix.spell.command appropriately.', 'supybot.plugins.Unix.spell.command appropriately.'),
Raise=True) Raise=True)
if word and not word[0].isalpha(): if word and not word[0].isalpha():
irc.error('<word> must begin with an alphabet character.') irc.error(_('<word> must begin with an alphabet character.'))
return return
try: try:
inst = subprocess.Popen([spellCmd, '-a'], close_fds=True, inst = subprocess.Popen([spellCmd, '-a'], close_fds=True,
@ -157,7 +164,7 @@ class Unix(callbacks.Plugin):
lines = filter(None, out.splitlines()) lines = filter(None, out.splitlines())
lines.pop(0) # Banner lines.pop(0) # Banner
if not lines: if not lines:
irc.error('No results found.', Raise=True) irc.error(_('No results found.'), Raise=True)
line = lines.pop(0) line = lines.pop(0)
line2 = '' line2 = ''
if lines: if lines:
@ -168,18 +175,20 @@ class Unix(callbacks.Plugin):
if line[0] in '*+' and line2: if line[0] in '*+' and line2:
line = line2 line = line2
if line[0] in '*+': if line[0] in '*+':
resp = format('%q may be spelled correctly.', word) resp = format(_('%q may be spelled correctly.'), word)
elif line[0] == '#': elif line[0] == '#':
resp = format('I could not find an alternate spelling for %q',word) resp = format(_('I could not find an alternate spelling for %q'),
word)
elif line[0] == '&': elif line[0] == '&':
matches = line.split(':')[1].strip() matches = line.split(':')[1].strip()
resp = format('Possible spellings for %q: %L.', resp = format(_('Possible spellings for %q: %L.'),
word, matches.split(', ')) word, matches.split(', '))
else: else:
resp = 'Something unexpected was seen in the [ai]spell output.' resp = 'Something unexpected was seen in the [ai]spell output.'
irc.reply(resp) irc.reply(resp)
spell = wrap(spell, ['somethingWithoutSpaces']) spell = wrap(spell, ['somethingWithoutSpaces'])
@internationalizeDocstring
def fortune(self, irc, msg, args): def fortune(self, irc, msg, args):
"""takes no arguments """takes no arguments
@ -201,8 +210,8 @@ class Unix(callbacks.Plugin):
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=file(os.devnull)) stdin=file(os.devnull))
except OSError, e: except OSError, e:
irc.error('It seems the configured fortune command was ' irc.error(_('It seems the configured fortune command was '
'not available.', Raise=True) 'not available.'), Raise=True)
(out, err) = inst.communicate() (out, err) = inst.communicate()
inst.wait() inst.wait()
lines = out.splitlines() lines = out.splitlines()
@ -210,11 +219,12 @@ class Unix(callbacks.Plugin):
lines = filter(None, lines) lines = filter(None, lines)
irc.replies(lines, joiner=' ') irc.replies(lines, joiner=' ')
else: else:
irc.error('The fortune command is not configured. If fortune is ' irc.error(_('The fortune command is not configured. If fortune is '
'installed on this system, reconfigure the ' 'installed on this system, reconfigure the '
'supybot.plugins.Unix.fortune.command configuration ' 'supybot.plugins.Unix.fortune.command configuration '
'variable appropriately.') 'variable appropriately.'))
@internationalizeDocstring
def wtf(self, irc, msg, args, _, something): def wtf(self, irc, msg, args, _, something):
"""[is] <something> """[is] <something>
@ -231,8 +241,8 @@ class Unix(callbacks.Plugin):
stderr=file(os.devnull), stderr=file(os.devnull),
stdin=file(os.devnull)) stdin=file(os.devnull))
except OSError: except OSError:
irc.error('It seems the configured wtf command was not ' irc.error(_('It seems the configured wtf command was not '
'available.', Raise=True) 'available.'), Raise=True)
(out, _) = inst.communicate() (out, _) = inst.communicate()
inst.wait() inst.wait()
if out: if out:
@ -240,10 +250,10 @@ class Unix(callbacks.Plugin):
response = utils.str.normalizeWhitespace(response) response = utils.str.normalizeWhitespace(response)
irc.reply(response) irc.reply(response)
else: else:
irc.error('The wtf command is not configured. If it is installed ' irc.error(_('The wtf command is not configured. If it is installed '
'on this system, reconfigure the ' 'on this system, reconfigure the '
'supybot.plugins.Unix.wtf.command configuration ' 'supybot.plugins.Unix.wtf.command configuration '
'variable appropriately.') 'variable appropriately.'))
wtf = wrap(wtf, [optional(('literal', ['is'])), 'something']) wtf = wrap(wtf, [optional(('literal', ['is'])), 'something'])
Class = Unix Class = Unix

View File

@ -29,6 +29,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Utilities')
def configure(advanced): def configure(advanced):
# This will be called by supybot to configure this module. advanced is # This will be called by supybot to configure this module. advanced is
@ -42,7 +44,7 @@ def configure(advanced):
Utilities = conf.registerPlugin('Utilities') Utilities = conf.registerPlugin('Utilities')
# This is where your configuration variables (if any) should go. For example: # This is where your configuration variables (if any) should go. For example:
# conf.registerGlobalValue(Utilities, 'someConfigVariableName', # conf.registerGlobalValue(Utilities, 'someConfigVariableName',
# registry.Boolean(False, """Help for someConfigVariableName.""")) # registry.Boolean(False, _("""Help for someConfigVariableName.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:39+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: plugin.py:45
#, docstring
msgid ""
"requires no arguments\n"
"\n"
" Does nothing. Useful sometimes for sequencing commands when you don't\n"
" care about their non-error return values.\n"
" "
msgstr ""
#: plugin.py:59
#, docstring
msgid ""
"[<text>]\n"
"\n"
" Does nothing except to reply with a success message. This is useful\n"
" when you want to run multiple commands as nested commands, and don't\n"
" care about their output as long as they're successful. An error, of\n"
" course, will break out of this command. <text>, if given, will be\n"
" appended to the end of the success message.\n"
" "
msgstr ""
#: plugin.py:72
#, docstring
msgid ""
"<text> [<text> ...]\n"
"\n"
" Returns the last argument given. Useful when you'd like multiple\n"
" nested commands to run, but only the output of the last one to be\n"
" returned.\n"
" "
msgstr ""
#: plugin.py:86
#, docstring
msgid ""
"<text>\n"
"\n"
" Returns the arguments given it. Uses our standard substitute on the\n"
" string(s) given to it; $nick (or $who), $randomNick, $randomInt,\n"
" $botnick, $channel, $user, $host, $today, $now, and $randomDate are all\n"
" handled appropriately.\n"
" "
msgstr ""
#: plugin.py:99
#, docstring
msgid ""
"<arg> [<arg> ...]\n"
"\n"
" Shuffles the arguments given it.\n"
" "
msgstr ""
#: plugin.py:109
#, docstring
msgid ""
"<command> <text>\n"
"\n"
" Tokenizes <text> and calls <command> with the resulting arguments.\n"
" "
msgstr ""

View File

@ -34,10 +34,13 @@ import random
from supybot.commands import * from supybot.commands import *
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Utilities')
class Utilities(callbacks.Plugin): class Utilities(callbacks.Plugin):
# Yes, I really do mean "requires no arguments" below. "takes no # Yes, I really do mean "requires no arguments" below. "takes no
# arguments" would probably lead people to think it was a useless command. # arguments" would probably lead people to think it was a useless command.
@internationalizeDocstring
def ignore(self, irc, msg, args): def ignore(self, irc, msg, args):
"""requires no arguments """requires no arguments
@ -51,6 +54,7 @@ class Utilities(callbacks.Plugin):
irc.reply('') irc.reply('')
# Do be careful not to wrap this unless you do any('something'). # Do be careful not to wrap this unless you do any('something').
@internationalizeDocstring
def success(self, irc, msg, args, text): def success(self, irc, msg, args, text):
"""[<text>] """[<text>]
@ -63,6 +67,7 @@ class Utilities(callbacks.Plugin):
irc.replySuccess(text) irc.replySuccess(text)
success = wrap(success, [additional('text')]) success = wrap(success, [additional('text')])
@internationalizeDocstring
def last(self, irc, msg, args): def last(self, irc, msg, args):
"""<text> [<text> ...] """<text> [<text> ...]
@ -76,6 +81,7 @@ class Utilities(callbacks.Plugin):
else: else:
raise callbacks.ArgumentError raise callbacks.ArgumentError
@internationalizeDocstring
def echo(self, irc, msg, args, text): def echo(self, irc, msg, args, text):
"""<text> """<text>
@ -88,6 +94,7 @@ class Utilities(callbacks.Plugin):
irc.reply(text, prefixNick=False) irc.reply(text, prefixNick=False)
echo = wrap(echo, ['text']) echo = wrap(echo, ['text'])
@internationalizeDocstring
def shuffle(self, irc, msg, args, things): def shuffle(self, irc, msg, args, things):
"""<arg> [<arg> ...] """<arg> [<arg> ...]
@ -97,6 +104,7 @@ class Utilities(callbacks.Plugin):
irc.reply(' '.join(things)) irc.reply(' '.join(things))
shuffle = wrap(shuffle, [many('anything')]) shuffle = wrap(shuffle, [many('anything')])
@internationalizeDocstring
def apply(self, irc, msg, args, command, rest): def apply(self, irc, msg, args, command, rest):
"""<command> <text> """<command> <text>

View File

@ -29,6 +29,8 @@
import supybot.conf as conf import supybot.conf as conf
import supybot.registry as registry import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Web')
def configure(advanced): def configure(advanced):
# This will be called by supybot to configure this module. advanced is # This will be called by supybot to configure this module. advanced is
@ -45,17 +47,17 @@ def configure(advanced):
Web = conf.registerPlugin('Web') Web = conf.registerPlugin('Web')
conf.registerChannelValue(Web, 'titleSnarfer', conf.registerChannelValue(Web, 'titleSnarfer',
registry.Boolean(False, """Determines whether the bot will output the HTML registry.Boolean(False, _("""Determines whether the bot will output the
title of URLs it sees in the channel.""")) HTML title of URLs it sees in the channel.""")))
conf.registerChannelValue(Web, 'nonSnarfingRegexp', conf.registerChannelValue(Web, 'nonSnarfingRegexp',
registry.Regexp(None, """Determines what URLs are to be snarfed and stored registry.Regexp(None, _("""Determines what URLs are to be snarfed and
in the database in the channel; URLs matching the regexp given will not be stored in the database in the channel; URLs matching the regexp given will
snarfed. Give the empty string if you have no URLs that you'd like to not be snarfed. Give the empty string if you have no URLs that you'd like
exclude from being snarfed.""")) to exclude from being snarfed.""")))
conf.registerGroup(Web, 'fetch') conf.registerGroup(Web, 'fetch')
conf.registerGlobalValue(Web.fetch, 'maximum', conf.registerGlobalValue(Web.fetch, 'maximum',
registry.NonNegativeInteger(0, """Determines the maximum number of registry.NonNegativeInteger(0, _("""Determines the maximum number of
bytes the bot will download via the 'fetch' command in this plugin.""")) bytes the bot will download via the 'fetch' command in this plugin.""")))
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

156
plugins/Web/messages.pot Normal file
View File

@ -0,0 +1,156 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2010-10-20 09:39+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:50
msgid ""
"Determines whether the bot will output the\n"
" HTML title of URLs it sees in the channel."
msgstr ""
#: config.py:53
msgid ""
"Determines what URLs are to be snarfed and\n"
" stored in the database in the channel; URLs matching the regexp given will\n"
" not be snarfed. Give the empty string if you have no URLs that you'd like\n"
" to exclude from being snarfed."
msgstr ""
#: config.py:60
msgid ""
"Determines the maximum number of\n"
" bytes the bot will download via the 'fetch' command in this plugin."
msgstr ""
#: plugin.py:71
#, docstring
msgid "Add the help for \"@help Web\" here."
msgstr ""
#: plugin.py:114
#, docstring
msgid ""
"<url>\n"
"\n"
" Returns the HTTP headers of <url>. Only HTTP urls are valid, of\n"
" course.\n"
" "
msgstr ""
#: plugin.py:121
msgid "%s: %s"
msgstr ""
#: plugin.py:131
#, docstring
msgid ""
"<url>\n"
"\n"
" Returns the DOCTYPE string of <url>. Only HTTP urls are valid, of\n"
" course.\n"
" "
msgstr ""
#: plugin.py:143
msgid "That URL has no specified doctype."
msgstr ""
#: plugin.py:148
#, docstring
msgid ""
"<url>\n"
"\n"
" Returns the Content-Length header of <url>. Only HTTP urls are valid,\n"
" of course.\n"
" "
msgstr ""
#: plugin.py:157 plugin.py:162
msgid "%u is %i bytes long."
msgstr ""
#: plugin.py:164
msgid "The server didn't tell me how long %u is but it's longer than %i bytes."
msgstr ""
#: plugin.py:173
#, docstring
msgid ""
"<url>\n"
"\n"
" Returns the HTML <title>...</title> of a URL.\n"
" "
msgstr ""
#: plugin.py:188
msgid "That URL appears to have no HTML title."
msgstr ""
#: plugin.py:190
msgid "That URL appears to have no HTML title within the first %i bytes."
msgstr ""
#: plugin.py:198
#, docstring
msgid ""
"<hostname|ip>\n"
"\n"
" Returns Netcraft.com's determination of what operating system and\n"
" webserver is running on the host given.\n"
" "
msgstr ""
#: plugin.py:212
msgid "No results found for %s."
msgstr ""
#: plugin.py:214
msgid "The format of page the was odd."
msgstr ""
#: plugin.py:219
#, docstring
msgid ""
"<text>\n"
"\n"
" Returns the URL quoted form of the text.\n"
" "
msgstr ""
#: plugin.py:228
#, docstring
msgid ""
"<text>\n"
"\n"
" Returns the text un-URL quoted.\n"
" "
msgstr ""
#: plugin.py:238
#, docstring
msgid ""
"<url>\n"
"\n"
" Returns the contents of <url>, or as much as is configured in\n"
" supybot.plugins.Web.fetch.maximum. If that configuration variable is\n"
" set to 0, this command will be effectively disabled.\n"
" "
msgstr ""
#: plugin.py:246
msgid "This command is disabled (supybot.plugins.Web.fetch.maximum is set to 0)."
msgstr ""

View File

@ -38,6 +38,8 @@ from supybot.commands import *
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Web')
class Title(HTMLParser.HTMLParser): class Title(HTMLParser.HTMLParser):
entitydefs = htmlentitydefs.entitydefs.copy() entitydefs = htmlentitydefs.entitydefs.copy()
@ -107,6 +109,7 @@ class Web(callbacks.PluginRegexp):
titleSnarfer = urlSnarfer(titleSnarfer) titleSnarfer = urlSnarfer(titleSnarfer)
titleSnarfer.__doc__ = utils.web._httpUrlRe titleSnarfer.__doc__ = utils.web._httpUrlRe
@internationalizeDocstring
def headers(self, irc, msg, args, url): def headers(self, irc, msg, args, url):
"""<url> """<url>
@ -115,7 +118,7 @@ class Web(callbacks.PluginRegexp):
""" """
fd = utils.web.getUrlFd(url) fd = utils.web.getUrlFd(url)
try: try:
s = ', '.join([format('%s: %s', k, v) s = ', '.join([format(_('%s: %s'), k, v)
for (k, v) in fd.headers.items()]) for (k, v) in fd.headers.items()])
irc.reply(s) irc.reply(s)
finally: finally:
@ -123,6 +126,7 @@ class Web(callbacks.PluginRegexp):
headers = wrap(headers, ['httpUrl']) headers = wrap(headers, ['httpUrl'])
_doctypeRe = re.compile(r'(<!DOCTYPE[^>]+>)', re.M) _doctypeRe = re.compile(r'(<!DOCTYPE[^>]+>)', re.M)
@internationalizeDocstring
def doctype(self, irc, msg, args, url): def doctype(self, irc, msg, args, url):
"""<url> """<url>
@ -136,9 +140,10 @@ class Web(callbacks.PluginRegexp):
s = utils.str.normalizeWhitespace(m.group(0)) s = utils.str.normalizeWhitespace(m.group(0))
irc.reply(s) irc.reply(s)
else: else:
irc.reply('That URL has no specified doctype.') irc.reply(_('That URL has no specified doctype.'))
doctype = wrap(doctype, ['httpUrl']) doctype = wrap(doctype, ['httpUrl'])
@internationalizeDocstring
def size(self, irc, msg, args, url): def size(self, irc, msg, args, url):
"""<url> """<url>
@ -149,20 +154,21 @@ class Web(callbacks.PluginRegexp):
try: try:
try: try:
size = fd.headers['Content-Length'] size = fd.headers['Content-Length']
irc.reply(format('%u is %i bytes long.', url, size)) irc.reply(format(_('%u is %i bytes long.'), url, size))
except KeyError: except KeyError:
size = conf.supybot.protocols.http.peekSize() size = conf.supybot.protocols.http.peekSize()
s = fd.read(size) s = fd.read(size)
if len(s) != size: if len(s) != size:
irc.reply(format('%u is %i bytes long.', url, len(s))) irc.reply(format(_('%u is %i bytes long.'), url, len(s)))
else: else:
irc.reply(format('The server didn\'t tell me how long %u ' irc.reply(format(_('The server didn\'t tell me how long %u '
'is but it\'s longer than %i bytes.', 'is but it\'s longer than %i bytes.'),
url, size)) url, size))
finally: finally:
fd.close() fd.close()
size = wrap(size, ['httpUrl']) size = wrap(size, ['httpUrl'])
@internationalizeDocstring
def title(self, irc, msg, args, url): def title(self, irc, msg, args, url):
"""<url> """<url>
@ -179,14 +185,15 @@ class Web(callbacks.PluginRegexp):
if parser.title: if parser.title:
irc.reply(utils.web.htmlToText(parser.title.strip())) irc.reply(utils.web.htmlToText(parser.title.strip()))
elif len(text) < size: elif len(text) < size:
irc.reply('That URL appears to have no HTML title.') irc.reply(_('That URL appears to have no HTML title.'))
else: else:
irc.reply(format('That URL appears to have no HTML title ' irc.reply(format(_('That URL appears to have no HTML title '
'within the first %i bytes.', size)) 'within the first %i bytes.'), size))
title = wrap(title, ['httpUrl']) title = wrap(title, ['httpUrl'])
_netcraftre = re.compile(r'td align="left">\s+<a[^>]+>(.*?)<a href', _netcraftre = re.compile(r'td align="left">\s+<a[^>]+>(.*?)<a href',
re.S | re.I) re.S | re.I)
@internationalizeDocstring
def netcraft(self, irc, msg, args, hostname): def netcraft(self, irc, msg, args, hostname):
"""<hostname|ip> """<hostname|ip>
@ -202,11 +209,12 @@ class Web(callbacks.PluginRegexp):
s = s.rstrip('-').strip() s = s.rstrip('-').strip()
irc.reply(s) # Snip off "the site" irc.reply(s) # Snip off "the site"
elif 'We could not get any results' in html: elif 'We could not get any results' in html:
irc.reply('No results found for %s.' % hostname) irc.reply(_('No results found for %s.') % hostname)
else: else:
irc.error('The format of page the was odd.') irc.error(_('The format of page the was odd.'))
netcraft = wrap(netcraft, ['text']) netcraft = wrap(netcraft, ['text'])
@internationalizeDocstring
def urlquote(self, irc, msg, args, text): def urlquote(self, irc, msg, args, text):
"""<text> """<text>
@ -215,6 +223,7 @@ class Web(callbacks.PluginRegexp):
irc.reply(utils.web.urlquote(text)) irc.reply(utils.web.urlquote(text))
urlquote = wrap(urlquote, ['text']) urlquote = wrap(urlquote, ['text'])
@internationalizeDocstring
def urlunquote(self, irc, msg, args, text): def urlunquote(self, irc, msg, args, text):
"""<text> """<text>
@ -224,6 +233,7 @@ class Web(callbacks.PluginRegexp):
irc.reply(s) irc.reply(s)
urlunquote = wrap(urlunquote, ['text']) urlunquote = wrap(urlunquote, ['text'])
@internationalizeDocstring
def fetch(self, irc, msg, args, url): def fetch(self, irc, msg, args, url):
"""<url> """<url>
@ -233,8 +243,8 @@ class Web(callbacks.PluginRegexp):
""" """
max = self.registryValue('fetch.maximum') max = self.registryValue('fetch.maximum')
if not max: if not max:
irc.error('This command is disabled ' irc.error(_('This command is disabled '
'(supybot.plugins.Web.fetch.maximum is set to 0).', '(supybot.plugins.Web.fetch.maximum is set to 0).'),
Raise=True) Raise=True)
fd = utils.web.getUrlFd(url) fd = utils.web.getUrlFd(url)
irc.reply(fd.read(max)) irc.reply(fd.read(max))