Rev 5994: (vila) Start implementing command help text localization (Inada Naoki) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Jun 28 11:39:51 UTC 2011


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5994 [merge]
revision-id: pqm at pqm.ubuntu.com-20110628113948-nrljydmsqi6kf01c
parent: pqm at pqm.ubuntu.com-20110623091743-rt1rp0jt21gxexlo
parent: v.ladeuil+lp at free.fr-20110628102829-te96uxnc0jpprsq9
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2011-06-28 11:39:48 +0000
message:
  (vila) Start implementing command help text localization (Inada Naoki)
modified:
  bzrlib/annotate.py             annotate.py-20050922133147-7c60541d2614f022
  bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
  bzrlib/export_pot.py           bzrgettext-20110429104643-3wjy38532whc21yj-2
  bzrlib/help.py                 help.py-20050505025907-4dd7a6d63912f894
  bzrlib/help_topics/__init__.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
  bzrlib/i18n.py                 i18n.py-20110429130428-eblvodng604h3dzi-1
  bzrlib/tests/test_export_pot.py test_export_pot.py-20110509102137-efovgz233s9uk2b2-1
  bzrlib/tests/test_help.py      test_help.py-20070419045354-6q6rq15j9e2n5fna-1
  bzrlib/tests/test_i18n.py      test_i18n.py-20110517012016-wjj0ai7qrasnj49p-1
  doc/en/release-notes/bzr-2.4.txt bzr2.4.txt-20110114053217-k7ym9jfz243fddjm-1
=== modified file 'bzrlib/annotate.py'
--- a/bzrlib/annotate.py	2011-06-13 09:54:39 +0000
+++ b/bzrlib/annotate.py	2011-06-27 15:52:06 +0000
@@ -38,7 +38,6 @@
 from bzrlib import (
     errors,
     osutils,
-    i18n,
     )
 from bzrlib.config import extract_email_address
 from bzrlib.repository import _strip_NULL_ghosts
@@ -108,7 +107,7 @@
         try:
             current_rev.committer = branch.get_config().username()
         except errors.NoWhoami:
-            current_rev.committer = i18n.gettext("local user")
+            current_rev.committer = 'local user'
         current_rev.message = "?"
         current_rev.timestamp = round(time.time(), 3)
         current_rev.timezone = osutils.local_time_offset()

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2011-05-19 09:32:38 +0000
+++ b/bzrlib/commands.py	2011-06-27 15:36:58 +0000
@@ -36,6 +36,7 @@
     cmdline,
     debug,
     errors,
+    i18n,
     option,
     osutils,
     trace,
@@ -44,6 +45,7 @@
 """)
 
 from bzrlib.hooks import Hooks
+from bzrlib.i18n import gettext
 # Compatibility - Option used to be in commands.
 from bzrlib.option import Option
 from bzrlib.plugin import disable_plugins, load_plugins
@@ -408,6 +410,7 @@
     takes_options = []
     encoding_type = 'strict'
     invoked_as = None
+    l10n = True
 
     hidden = False
 
@@ -485,9 +488,18 @@
             usage help (e.g. Purpose, Usage, Options) with a
             message explaining how to obtain full help.
         """
+        if self.l10n and not i18n.installed():
+            i18n.install()  # Install i18n only for get_help_text for now.
         doc = self.help()
-        if not doc:
-            doc = "No help for this command."
+        if doc:
+            # Note: If self.gettext() translates ':Usage:\n', the section will
+            # be shown after "Description" section and we don't want to
+            # translate the usage string.
+            # Though, bzr export-pot don't exports :Usage: section and it must
+            # not be translated.
+            doc = self.gettext(doc)
+        else:
+            doc = gettext("No help for this command.")
 
         # Extract the summary (purpose) and sections out from the text
         purpose,sections,order = self._get_help_parts(doc)
@@ -500,11 +512,11 @@
 
         # The header is the purpose and usage
         result = ""
-        result += ':Purpose: %s\n' % purpose
+        result += gettext(':Purpose: %s\n') % (purpose,)
         if usage.find('\n') >= 0:
-            result += ':Usage:\n%s\n' % usage
+            result += gettext(':Usage:\n%s\n') % (usage,)
         else:
-            result += ':Usage:   %s\n' % usage
+            result += gettext(':Usage:   %s\n') % (usage,)
         result += '\n'
 
         # Add the options
@@ -512,7 +524,8 @@
         # XXX: optparse implicitly rewraps the help, and not always perfectly,
         # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
         # 20090319
-        options = option.get_optparser(self.options()).format_option_help()
+        parser = option.get_optparser(self.options())
+        options = parser.format_option_help()
         # FIXME: According to the spec, ReST option lists actually don't
         # support options like --1.14 so that causes syntax errors (in Sphinx
         # at least).  As that pattern always appears in the commands that
@@ -522,10 +535,7 @@
         if not plain and options.find('  --1.14  ') != -1:
             options = options.replace(' format:\n', ' format::\n\n', 1)
         if options.startswith('Options:'):
-            result += ':' + options
-        elif options.startswith('options:'):
-            # Python 2.4 version of optparse
-            result += ':Options:' + options[len('options:'):]
+            result += gettext(':Options:%s') % (options[len('options:'):],)
         else:
             result += options
         result += '\n'
@@ -536,26 +546,26 @@
             if sections.has_key(None):
                 text = sections.pop(None)
                 text = '\n  '.join(text.splitlines())
-                result += ':%s:\n  %s\n\n' % ('Description',text)
+                result += gettext(':Description:\n  %s\n\n') % (text,)
 
             # Add the custom sections (e.g. Examples). Note that there's no need
             # to indent these as they must be indented already in the source.
             if sections:
                 for label in order:
-                    if sections.has_key(label):
-                        result += ':%s:\n%s\n' % (label,sections[label])
+                    if label in sections:
+                        result += ':%s:\n%s\n' % (label, sections[label])
                 result += '\n'
         else:
-            result += ("See bzr help %s for more details and examples.\n\n"
+            result += (gettext("See bzr help %s for more details and examples.\n\n")
                 % self.name())
 
         # Add the aliases, source (plug-in) and see also links, if any
         if self.aliases:
-            result += ':Aliases:  '
+            result += gettext(':Aliases:  ')
             result += ', '.join(self.aliases) + '\n'
         plugin_name = self.plugin_name()
         if plugin_name is not None:
-            result += ':From:     plugin "%s"\n' % plugin_name
+            result += gettext(':From:     plugin "%s"\n') % plugin_name
         see_also = self.get_see_also(additional_see_also)
         if see_also:
             if not plain and see_also_as_links:
@@ -567,11 +577,10 @@
                         see_also_links.append(item)
                     else:
                         # Use a Sphinx link for this entry
-                        link_text = ":doc:`%s <%s-help>`" % (item, item)
+                        link_text = gettext(":doc:`%s <%s-help>`") % (item, item)
                         see_also_links.append(link_text)
                 see_also = see_also_links
-            result += ':See also: '
-            result += ', '.join(see_also) + '\n'
+            result += gettext(':See also: %s') % ', '.join(see_also) + '\n'
 
         # If this will be rendered as plain text, convert it
         if plain:
@@ -658,13 +667,14 @@
     def run_argv_aliases(self, argv, alias_argv=None):
         """Parse the command line and run with extra aliases in alias_argv."""
         args, opts = parse_args(self, argv, alias_argv)
+        self._setup_outf()
 
         # Process the standard options
         if 'help' in opts:  # e.g. bzr add --help
-            sys.stdout.write(self.get_help_text())
+            self.outf.write(self.get_help_text())
             return 0
         if 'usage' in opts:  # e.g. bzr add --usage
-            sys.stdout.write(self.get_help_text(verbose=False))
+            self.outf.write(self.get_help_text(verbose=False))
             return 0
         trace.set_verbosity_level(option._verbosity_level)
         if 'verbose' in self.supported_std_options:
@@ -685,8 +695,6 @@
         all_cmd_args = cmdargs.copy()
         all_cmd_args.update(cmdopts)
 
-        self._setup_outf()
-
         try:
             return self.run(**all_cmd_args)
         finally:
@@ -751,6 +759,14 @@
             return None
         return getdoc(self)
 
+    def gettext(self, message):
+        """Returns the gettext function used to translate this command's help.
+
+        Commands provided by plugins should override this to use their
+        own i18n system.
+        """
+        return i18n.gettext_per_paragraph(message)
+
     def name(self):
         """Return the canonical name for this command.
 
@@ -1041,8 +1057,8 @@
     argv = _specified_or_unicode_argv(argv)
     trace.mutter("bzr arguments: %r", argv)
 
-    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin =  \
-                opt_no_aliases = False
+    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
+            opt_no_l10n = opt_no_aliases = False
     opt_lsprof_file = opt_coverage_dir = None
 
     # --no-plugins is handled specially at a very early stage. We need
@@ -1065,6 +1081,8 @@
             opt_no_plugins = True
         elif a == '--no-aliases':
             opt_no_aliases = True
+        elif a == '--no-l10n':
+            opt_no_l10n = True
         elif a == '--builtin':
             opt_builtin = True
         elif a == '--concurrency':
@@ -1106,6 +1124,8 @@
 
     cmd = argv.pop(0)
     cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
+    if opt_no_l10n:
+        cmd.l10n = False
     run = cmd_obj.run_argv_aliases
     run_argv = [argv, alias_argv]
 

=== modified file 'bzrlib/export_pot.py'
--- a/bzrlib/export_pot.py	2011-05-12 12:19:35 +0000
+++ b/bzrlib/export_pot.py	2011-05-28 12:17:22 +0000
@@ -76,10 +76,12 @@
            'msgid %s\n' % _normalize(s) +
            'msgstr ""\n')
 
-def _poentry_per_paragraph(outf, path, lineno, msgid):
+def _poentry_per_paragraph(outf, path, lineno, msgid, filter=lambda x: False):
     # TODO: How to split long help?
     paragraphs = msgid.split('\n\n')
     for p in paragraphs:
+        if filter(p):
+            continue
         _poentry(outf, path, lineno, p)
         lineno += p.count('\n') + 2
 
@@ -145,7 +147,7 @@
                      'help of %r option of %r command' % (name, cmd.name()))
 
 
-def _write_command_help(outf, cmd_name, cmd):
+def _write_command_help(outf, cmd):
     path = inspect.getfile(cmd.__class__)
     if path.endswith('.pyc'):
         path = path[:-1]
@@ -155,9 +157,16 @@
     lineno = offsets[cmd.__doc__]
     doc = inspect.getdoc(cmd)
 
-    _poentry_per_paragraph(outf, path, lineno, doc)
+    def filter(p):
+        # ':Usage:' has special meaning in help topics.
+        # This is usage example of command and should not be translated.
+        if p.splitlines()[0] == ':Usage:':
+            return True
+
+    _poentry_per_paragraph(outf, path, lineno, doc, filter)
     _command_options(outf, path, cmd)
 
+
 def _command_helps(outf):
     """Extract docstrings from path.
 
@@ -172,7 +181,7 @@
         if command.hidden:
             continue
         note("Exporting messages from builtin command: %s", cmd_name)
-        _write_command_help(outf, cmd_name, command)
+        _write_command_help(outf, command)
 
     plugin_path = plugin.get_core_plugin_path()
     core_plugins = glob(plugin_path + '/*/__init__.py')
@@ -189,7 +198,7 @@
             continue
         note("Exporting messages from plugin command: %s in %s",
              cmd_name, command.plugin_name())
-        _write_command_help(outf, cmd_name, command)
+        _write_command_help(outf, command)
 
 
 def _error_messages(outf):

=== modified file 'bzrlib/help.py'
--- a/bzrlib/help.py	2011-05-11 16:52:02 +0000
+++ b/bzrlib/help.py	2011-05-18 18:32:22 +0000
@@ -22,7 +22,6 @@
 # TODO: `help commands --all` should show hidden commands
 
 import sys
-import textwrap
 
 from bzrlib import (
     commands as _mod_commands,
@@ -30,6 +29,7 @@
     help_topics,
     osutils,
     plugin,
+    utextwrap,
     )
 
 
@@ -96,7 +96,7 @@
         else:
             firstline = ''
         helpstring = '%-*s %s%s' % (max_name, cmd_name, firstline, plugin_name)
-        lines = textwrap.wrap(
+        lines = utextwrap.wrap(
             helpstring, subsequent_indent=indent,
             width=width,
             break_long_words=False)

=== modified file 'bzrlib/help_topics/__init__.py'
--- a/bzrlib/help_topics/__init__.py	2010-11-06 10:55:58 +0000
+++ b/bzrlib/help_topics/__init__.py	2011-05-28 13:46:51 +0000
@@ -316,6 +316,7 @@
 --builtin      Use the built-in version of a command, not the plugin version.
                This does not suppress other plugin effects.
 --no-plugins   Do not process any plugins.
+--no-l10n      Do not translate messages.
 --concurrency  Number of processes that can be run concurrently (selftest).
 
 --profile      Profile execution using the hotshot profiler.

=== modified file 'bzrlib/i18n.py'
--- a/bzrlib/i18n.py	2011-05-27 21:38:33 +0000
+++ b/bzrlib/i18n.py	2011-06-27 15:08:26 +0000
@@ -26,7 +26,7 @@
 import os
 import sys
 
-_translation = _gettext.NullTranslations()
+_translations = None
 
 
 def gettext(message):
@@ -34,7 +34,7 @@
     
     :returns: translated message as unicode.
     """
-    return _translation.ugettext(message)
+    return _translations.ugettext(message)
 
 
 def ngettext(s, p, n):
@@ -42,7 +42,7 @@
 
     :returns: translated message as unicode.
     """
-    return _translation.ungettext(s, p, n)
+    return _translations.ungettext(s, p, n)
 
 
 def N_(msg):
@@ -56,17 +56,21 @@
     :returns: concatenated translated message as unicode.
     """
     paragraphs = message.split(u'\n\n')
-    ugettext = _translation.ugettext
+    ugettext = _translations.ugettext
     # Be careful not to translate the empty string -- it holds the
     # meta data of the .po file.
     return u'\n\n'.join(ugettext(p) if p else u'' for p in paragraphs)
 
 
+def installed():
+    return _translations is not None
+
+
 def install(lang=None):
-    global _translation
+    global _translations
     if lang is None:
         lang = _get_current_locale()
-    _translation = _gettext.translation(
+    _translations = _gettext.translation(
             'bzr',
             localedir=_get_locale_dir(),
             languages=lang.split(':'),
@@ -74,8 +78,8 @@
 
 
 def uninstall():
-    global _translation
-    _translation = _null_translation
+    global _translations
+    _translations = None
 
 
 def _get_locale_dir():

=== modified file 'bzrlib/tests/test_export_pot.py'
--- a/bzrlib/tests/test_export_pot.py	2011-05-11 17:44:45 +0000
+++ b/bzrlib/tests/test_export_pot.py	2011-06-28 10:28:29 +0000
@@ -18,10 +18,14 @@
 import textwrap
 
 from bzrlib import (
+    commands,
     export_pot,
     tests,
     )
 
+import re
+
+
 class TestEscape(tests.TestCase):
 
     def test_simple_escape(self):
@@ -145,3 +149,45 @@
                 "EGG\\n"
                 msgstr ""\n
                 ''')
+
+
+class TestExportCommandHelp(PoEntryTestCase):
+
+    def test_command_help(self):
+
+        class cmd_Demo(commands.Command):
+            __doc__ = """A sample command.
+
+            :Usage:
+                bzr demo
+
+            :Examples:
+                Example 1::
+
+                    cmd arg1
+
+            Blah Blah Blah
+            """
+
+        export_pot._write_command_help(self._outf, cmd_Demo())
+        result = self._outf.getvalue()
+        # We don't care about filename and lineno here.
+        result = re.sub(r'(?m)^#: [^\n]+\n', '', result)
+
+        self.assertEqualDiff(
+                'msgid "A sample command."\n'
+                'msgstr ""\n'
+                '\n'                # :Usage: should not be translated.
+                'msgid ""\n'
+                '":Examples:\\n"\n'
+                '"    Example 1::"\n'
+                'msgstr ""\n'
+                '\n'
+                'msgid "        cmd arg1"\n'
+                'msgstr ""\n'
+                '\n'
+                'msgid "Blah Blah Blah"\n'
+                'msgstr ""\n'
+                '\n',
+                result
+                )

=== modified file 'bzrlib/tests/test_help.py'
--- a/bzrlib/tests/test_help.py	2011-01-12 01:01:53 +0000
+++ b/bzrlib/tests/test_help.py	2011-06-27 15:36:58 +0000
@@ -16,45 +16,63 @@
 
 """Unit tests for the bzrlib.help module."""
 
+import textwrap
+
 from bzrlib import (
     builtins,
     commands,
     errors,
     help,
     help_topics,
+    i18n,
     plugin,
     tests,
     )
 
-
-class TestHelp(tests.TestCase):
-
-    def setUp(self):
-        tests.TestCase.setUp(self)
-        commands.install_bzr_command_hooks()
+from bzrlib.tests.test_i18n import ZzzTranslations
+import re
 
 
 class TestCommandHelp(tests.TestCase):
     """Tests for help on commands."""
 
+    def assertCmdHelp(self, expected, cmd):
+        self.assertEqualDiff(textwrap.dedent(expected), cmd.get_help_text())
+
     def test_command_help_includes_see_also(self):
         class cmd_WithSeeAlso(commands.Command):
             __doc__ = """A sample command."""
             _see_also = ['foo', 'bar']
-        cmd = cmd_WithSeeAlso()
-        helptext = cmd.get_help_text()
-        self.assertEndsWith(
-            helptext,
-            '  -v, --verbose  Display more information.\n'
-            '  -q, --quiet    Only display errors and warnings.\n'
-            '  -h, --help     Show help message.\n'
-            '\n'
-            'See also: bar, foo\n')
+        self.assertCmdHelp('''\
+            Purpose: A sample command.
+            Usage:   bzr WithSeeAlso
+            
+            Options:
+              --usage        Show usage message and options.
+              -v, --verbose  Display more information.
+              -q, --quiet    Only display errors and warnings.
+              -h, --help     Show help message.
+            
+            See also: bar, foo
+            ''',
+                           cmd_WithSeeAlso())
 
     def test_get_help_text(self):
         """Commands have a get_help_text method which returns their help."""
         class cmd_Demo(commands.Command):
             __doc__ = """A sample command."""
+        self.assertCmdHelp('''\
+            Purpose: A sample command.
+            Usage:   bzr Demo
+            
+            Options:
+              --usage        Show usage message and options.
+              -v, --verbose  Display more information.
+              -q, --quiet    Only display errors and warnings.
+              -h, --help     Show help message.
+
+            ''',
+                           cmd_Demo())
         cmd = cmd_Demo()
         helptext = cmd.get_help_text()
         self.assertStartsWith(helptext,
@@ -295,6 +313,182 @@
             '  Blah blah blah.\n\n')
 
 
+class ZzzTranslationsForDoc(ZzzTranslations):
+
+    _section_pat = re.compile(':\w+:\\n\\s+')
+    _indent_pat = re.compile('\\s+')
+
+    def zzz(self, s):
+        m = self._section_pat.match(s)
+        if m is None:
+            m = self._indent_pat.match(s)
+        if m:
+            return u'%szz{{%s}}' % (m.group(0), s[m.end():])
+        return u'zz{{%s}}' % s
+
+
+class TestCommandHelpI18n(tests.TestCase):
+    """Tests for help on translated commands."""
+
+    def setUp(self):
+        super(TestCommandHelpI18n, self).setUp()
+        self.overrideAttr(i18n, '_translations', ZzzTranslationsForDoc())
+
+    def assertCmdHelp(self, expected, cmd):
+        self.assertEqualDiff(textwrap.dedent(expected), cmd.get_help_text())
+
+    def test_command_help_includes_see_also(self):
+        class cmd_WithSeeAlso(commands.Command):
+            __doc__ = """A sample command."""
+            _see_also = ['foo', 'bar']
+        self.assertCmdHelp('''\
+            zz{{:Purpose: zz{{A sample command.}}
+            }}zz{{:Usage:   bzr WithSeeAlso
+            }}
+            zz{{:Options:
+              --usage        Show usage message and options.
+              -v, --verbose  Display more information.
+              -q, --quiet    Only display errors and warnings.
+              -h, --help     Show help message.
+            }}
+            zz{{:See also: bar, foo}}
+            ''',
+                           cmd_WithSeeAlso())
+
+    def test_get_help_text(self):
+        """Commands have a get_help_text method which returns their help."""
+        class cmd_Demo(commands.Command):
+            __doc__ = """A sample command."""
+        self.assertCmdHelp('''\
+            zz{{:Purpose: zz{{A sample command.}}
+            }}zz{{:Usage:   bzr Demo
+            }}
+            zz{{:Options:
+              --usage        Show usage message and options.
+              -v, --verbose  Display more information.
+              -q, --quiet    Only display errors and warnings.
+              -h, --help     Show help message.
+            }}
+            ''',
+                           cmd_Demo())
+
+    def test_command_with_additional_see_also(self):
+        class cmd_WithSeeAlso(commands.Command):
+            __doc__ = """A sample command."""
+            _see_also = ['foo', 'bar']
+        cmd = cmd_WithSeeAlso()
+        helptext = cmd.get_help_text(['gam'])
+        self.assertEndsWith(
+            helptext,
+            '  -v, --verbose  Display more information.\n'
+            '  -q, --quiet    Only display errors and warnings.\n'
+            '  -h, --help     Show help message.\n'
+            '}}\n'
+            'zz{{:See also: bar, foo, gam}}\n')
+
+    def test_command_only_additional_see_also(self):
+        class cmd_WithSeeAlso(commands.Command):
+            __doc__ = """A sample command."""
+        cmd = cmd_WithSeeAlso()
+        helptext = cmd.get_help_text(['gam'])
+        self.assertEndsWith(
+            helptext,
+            'zz{{:Options:\n'
+            '  --usage        Show usage message and options.\n'
+            '  -v, --verbose  Display more information.\n'
+            '  -q, --quiet    Only display errors and warnings.\n'
+            '  -h, --help     Show help message.\n'
+            '}}\n'
+            'zz{{:See also: gam}}\n')
+
+
+    def test_help_custom_section_ordering(self):
+        """Custom descriptive sections should remain in the order given."""
+        # The help formatter expect the class name to start with 'cmd_'
+        class cmd_Demo(commands.Command):
+            __doc__ = """A sample command.
+ 
+            Blah blah blah.
+
+            :Formats:
+              Interesting stuff about formats.
+
+            :Examples:
+              Example 1::
+ 
+                cmd arg1
+
+            :Tips:
+              Clever things to keep in mind.
+            """
+        self.assertCmdHelp('''\
+            zz{{:Purpose: zz{{A sample command.}}
+            }}zz{{:Usage:   bzr Demo
+            }}
+            zz{{:Options:
+              --usage        Show usage message and options.
+              -v, --verbose  Display more information.
+              -q, --quiet    Only display errors and warnings.
+              -h, --help     Show help message.
+            }}
+            Description:
+              zz{{zz{{Blah blah blah.}}
+            
+            }}:Formats:
+              zz{{Interesting stuff about formats.}}
+            
+            Examples:
+              zz{{Example 1::}}
+            
+                zz{{cmd arg1}}
+            
+            Tips:
+              zz{{Clever things to keep in mind.}}
+
+            ''',
+                           cmd_Demo())
+
+    def test_help_text_custom_usage(self):
+        """Help text may contain a custom usage section."""
+        class cmd_Demo(commands.Command):
+            __doc__ = """A sample command.
+
+            :Usage:
+                cmd Demo [opts] args
+
+                cmd Demo -h
+
+            Blah blah blah.
+            """
+        self.assertCmdHelp('''\
+            zz{{:Purpose: zz{{A sample command.}}
+            }}zz{{:Usage:
+                zz{{cmd Demo [opts] args}}
+            
+                zz{{cmd Demo -h}}
+
+            }}
+            zz{{:Options:
+              --usage        Show usage message and options.
+              -v, --verbose  Display more information.
+              -q, --quiet    Only display errors and warnings.
+              -h, --help     Show help message.
+            }}
+            Description:
+              zz{{zz{{Blah blah blah.}}
+
+            }}
+            ''',
+                           cmd_Demo())
+
+
+class TestHelp(tests.TestCase):
+
+    def setUp(self):
+        tests.TestCase.setUp(self)
+        commands.install_bzr_command_hooks()
+
+
 class TestRegisteredTopic(TestHelp):
     """Tests for the RegisteredTopic class."""
 
@@ -306,10 +500,10 @@
         self.assertEqual('basic', topic.topic)
 
     def test_get_help_text(self):
-        """A RegisteredTopic returns the get_detail results for get_help_text."""
+        """RegisteredTopic returns the get_detail results for get_help_text."""
         topic = help_topics.RegisteredTopic('commands')
         self.assertEqual(help_topics.topic_registry.get_detail('commands'),
-            topic.get_help_text())
+                         topic.get_help_text())
 
     def test_get_help_text_with_additional_see_also(self):
         topic = help_topics.RegisteredTopic('commands')
@@ -327,7 +521,7 @@
             '\n')
 
     def test_get_help_topic(self):
-        """The help topic for a RegisteredTopic is its topic from construction."""
+        """The help topic for RegisteredTopic is its topic from construction."""
         topic = help_topics.RegisteredTopic('foobar')
         self.assertEqual('foobar', topic.get_help_topic())
         topic = help_topics.RegisteredTopic('baz')

=== modified file 'bzrlib/tests/test_i18n.py'
--- a/bzrlib/tests/test_i18n.py	2011-05-27 06:37:07 +0000
+++ b/bzrlib/tests/test_i18n.py	2011-06-27 15:52:06 +0000
@@ -67,7 +67,7 @@
 
     def setUp(self):
         super(TestGetText, self).setUp()
-        self.overrideAttr(i18n, '_translation', ZzzTranslations())
+        self.overrideAttr(i18n, '_translations', ZzzTranslations())
 
     def test_oneline(self):
         self.assertEqual(u"zz{{spam ham eggs}}",
@@ -82,7 +82,7 @@
 
     def setUp(self):
         super(TestGetTextPerParagraph, self).setUp()
-        self.overrideAttr(i18n, '_translation', ZzzTranslations())
+        self.overrideAttr(i18n, '_translations', ZzzTranslations())
 
     def test_oneline(self):
         self.assertEqual(u"zz{{spam ham eggs}}",

=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- a/doc/en/release-notes/bzr-2.4.txt	2011-06-21 17:27:28 +0000
+++ b/doc/en/release-notes/bzr-2.4.txt	2011-06-27 16:06:21 +0000
@@ -58,6 +58,10 @@
 .. Major internal changes, unlikely to be visible to users or plugin 
    developers, but interesting for bzr developers.
 
+* Start implementing localization, starting with command help text (but not
+  the command options themselves). This will allow bootstrapping the bzr
+  internationalization process. (Inada Naoki)
+
 Testing
 *******
 
@@ -105,9 +109,8 @@
   (Jonathan Riddell, #274578)
 
 
-* New hook set_commit_message in bzrlib.msgeditor to set
-  a commit message and revision properties.  (Jonathan Riddell,
-  #274578)
+* New hook set_commit_message in bzrlib.msgeditor to set a commit message
+  and revision properties.  (Jonathan Riddell, #274578)
 
 * Support ``-S`` as an alias for ``--short`` for the ``log`` and
   ``missing`` commands. (Martin von Gagern, #38655)
@@ -118,8 +121,8 @@
 .. Improvements to existing commands, especially improved performance 
    or memory usage, or better results.
 
-* ``bzr annotate`` can be run without setting whoami data first. (Jonathan
-  Riddell, #667408)
+* ``bzr annotate`` can be run without setting whoami data first.
+  (Jonathan Riddell, #667408)
 
 Bug Fixes
 *********
@@ -369,8 +372,8 @@
 * Merging into empty branches now gives an error as this is currently
   not supported. (Jonathan Riddell, #242175)
 
-* Do not show exception to user on pointless commit error (Jonathan
-  Riddell #317357)
+* Do not show exception to user on pointless commit error.
+  (Jonathan Riddell #317357)
 
 * ``WT.update_basis_by_delta`` no longer requires that the deltas match
   the current WT state. This allows ``update_basis_by_delta`` to be used




More information about the bazaar-commits mailing list