Merge lp:~jr/bzr/i18n-errors into lp:bzr

Proposed by Jonathan Riddell
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 6133
Proposed branch: lp:~jr/bzr/i18n-errors
Merge into: lp:bzr
Diff against target: 161 lines (+45/-14)
4 files modified
bzrlib/errors.py (+9/-2)
bzrlib/pack.py (+1/-1)
bzrlib/tests/test_i18n.py (+32/-11)
doc/en/release-notes/bzr-2.5.txt (+3/-0)
To merge this branch: bzr merge lp:~jr/bzr/i18n-errors
Reviewer Review Type Date Requested Status
Martin Packman (community) Needs Fixing
Jelmer Vernooij (community) Approve
Review via email: mp+73547@code.launchpad.net

Commit message

Turn on translations for errors.

Description of the change

Turn on translations for errors

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

It seems like this could install the i18n support more than once, wouldn't it need to be protected against that, like in the command help ?

It would be nice to have a smoke test for this (and perhaps also the command help i18n support), especially given none of the core developers uses i18n.

review: Needs Fixing
Revision history for this message
Jonathan Riddell (jr) wrote :

>It seems like this could install the i18n support more than once, wouldn't it need to be protected against that, like in the command help ?

This is no longer the case now that this branch is in trunk https://code.launchpad.net/~jr/bzr/i18n-install-once

>It would be nice to have a smoke test for this (and perhaps also the command help i18n support), especially given none of the core developers uses i18n.

Added

Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Revision history for this message
Martin Packman (gz) wrote :

Summarizing from IRC conversion, the error module has a lot of pre-existing problems that have been mostly safe to ignore because:

* All _fmt strings are ascii str, which can be upcast to either non-ascii bytes or unicode (but still break when trying to do both, see bug 273978 for instance).
* Many users have utf-8 consoles so printing utf-8 encoded error messages rather than encoding unicode appropriately appears fine.

In making the _fmt string a localised utf-8 message, these existing confusions with string types are exposed.

+ unicode_fmt = osutils.safe_unicode(fmt)
+ if type(fmt) == unicode:
+ trace.mutter("Unicode strings in error.fmt are deprecated")

I'd replace this with just unicode(fmt) and add a comment that all _fmt strings should be ascii.

+ return gettext(unicode_fmt).encode('utf-8')

Remove the encode here. That will fix exceptions that include paths, or any other unicode strings in the message. On the other hand, it breaks exceptions that think it's safe to interpolate arbitrary bytes into exception messages, but they're already bogus and need fixing anyway.

+ self.overrideAttr(i18n, '_translations', ZzzTranslations())
+ try:
+ workingtree.WorkingTree.open('./foo')
+ except errors.NotBranchError,e:
+ err = str(e)
+ self.assertContainsRe(err, "zz{{Not a branch: .*}}")

If we can make ZzzTranslations return more than just ascii it would be more realistic, and this test would then fail with a UnicodeError.

review: Needs Fixing
Revision history for this message
Martin Packman (gz) wrote :

Actually, NotBranchError has some special-casing to prevent breakage, but many other PathError subclasses do not.

Revision history for this message
Jonathan Riddell (jr) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/errors.py'
--- bzrlib/errors.py 2011-09-05 10:28:30 +0000
+++ bzrlib/errors.py 2011-09-07 11:50:38 +0000
@@ -20,7 +20,10 @@
20from bzrlib import (20from bzrlib import (
21 osutils,21 osutils,
22 symbol_versioning,22 symbol_versioning,
23 i18n,
24 trace,
23 )25 )
26from bzrlib.i18n import gettext
24from bzrlib.patches import (27from bzrlib.patches import (
25 MalformedHunkHeader,28 MalformedHunkHeader,
26 MalformedLine,29 MalformedLine,
@@ -140,7 +143,11 @@
140 """Return format string for this exception or None"""143 """Return format string for this exception or None"""
141 fmt = getattr(self, '_fmt', None)144 fmt = getattr(self, '_fmt', None)
142 if fmt is not None:145 if fmt is not None:
143 return fmt146 i18n.install()
147 unicode_fmt = unicode(fmt) #_fmt strings should be ascii
148 if type(fmt) == unicode:
149 trace.mutter("Unicode strings in error.fmt are deprecated")
150 return gettext(unicode_fmt)
144 fmt = getattr(self, '__doc__', None)151 fmt = getattr(self, '__doc__', None)
145 if fmt is not None:152 if fmt is not None:
146 symbol_versioning.warn("%s uses its docstring as a format, "153 symbol_versioning.warn("%s uses its docstring as a format, "
@@ -2792,7 +2799,7 @@
2792 _fmt = "Container has multiple records with the same name: %(name)s"2799 _fmt = "Container has multiple records with the same name: %(name)s"
27932800
2794 def __init__(self, name):2801 def __init__(self, name):
2795 self.name = name2802 self.name = name.decode("utf-8")
27962803
27972804
2798class NoDestinationAddress(InternalBzrError):2805class NoDestinationAddress(InternalBzrError):
27992806
=== modified file 'bzrlib/pack.py'
--- bzrlib/pack.py 2011-04-08 14:45:25 +0000
+++ bzrlib/pack.py 2011-09-07 11:50:38 +0000
@@ -333,7 +333,7 @@
333 # risk that the same unicode string has been encoded two333 # risk that the same unicode string has been encoded two
334 # different ways.334 # different ways.
335 if name_tuple in all_names:335 if name_tuple in all_names:
336 raise errors.DuplicateRecordNameError(name_tuple)336 raise errors.DuplicateRecordNameError(name_tuple[0])
337 all_names.add(name_tuple)337 all_names.add(name_tuple)
338 excess_bytes = self.reader_func(1)338 excess_bytes = self.reader_func(1)
339 if excess_bytes != '':339 if excess_bytes != '':
340340
=== modified file 'bzrlib/tests/test_i18n.py'
--- bzrlib/tests/test_i18n.py 2011-08-25 10:33:14 +0000
+++ bzrlib/tests/test_i18n.py 2011-09-07 11:50:38 +0000
@@ -16,7 +16,11 @@
1616
17"""Tests for bzrlib.i18n"""17"""Tests for bzrlib.i18n"""
1818
19from bzrlib import i18n, tests19from bzrlib import (i18n,
20 tests,
21 errors,
22 workingtree,
23 )
2024
2125
22class ZzzTranslations(object):26class ZzzTranslations(object):
@@ -28,7 +32,7 @@
28 _null_translation = i18n._gettext.NullTranslations()32 _null_translation = i18n._gettext.NullTranslations()
2933
30 def zzz(self, s):34 def zzz(self, s):
31 return u'zz{{%s}}' % s35 return u'zz\xe5{{%s}}' % s
3236
33 def ugettext(self, s):37 def ugettext(self, s):
34 return self.zzz(self._null_translation.ugettext(s))38 return self.zzz(self._null_translation.ugettext(s))
@@ -47,18 +51,18 @@
47 trans = ZzzTranslations()51 trans = ZzzTranslations()
4852
49 t = trans.zzz('msg')53 t = trans.zzz('msg')
50 self._check_exact(u'zz{{msg}}', t)54 self._check_exact(u'zz\xe5{{msg}}', t)
5155
52 t = trans.ugettext('msg')56 t = trans.ugettext('msg')
53 self._check_exact(u'zz{{msg}}', t)57 self._check_exact(u'zz\xe5{{msg}}', t)
5458
55 t = trans.ungettext('msg1', 'msg2', 0)59 t = trans.ungettext('msg1', 'msg2', 0)
56 self._check_exact(u'zz{{msg2}}', t)60 self._check_exact(u'zz\xe5{{msg2}}', t)
57 t = trans.ungettext('msg1', 'msg2', 2)61 t = trans.ungettext('msg1', 'msg2', 2)
58 self._check_exact(u'zz{{msg2}}', t)62 self._check_exact(u'zz\xe5{{msg2}}', t)
5963
60 t = trans.ungettext('msg1', 'msg2', 1)64 t = trans.ungettext('msg1', 'msg2', 1)
61 self._check_exact(u'zz{{msg1}}', t)65 self._check_exact(u'zz\xe5{{msg1}}', t)
6266
6367
64class TestGetText(tests.TestCase):68class TestGetText(tests.TestCase):
@@ -68,11 +72,11 @@
68 self.overrideAttr(i18n, '_translations', ZzzTranslations())72 self.overrideAttr(i18n, '_translations', ZzzTranslations())
6973
70 def test_oneline(self):74 def test_oneline(self):
71 self.assertEqual(u"zz{{spam ham eggs}}",75 self.assertEqual(u"zz\xe5{{spam ham eggs}}",
72 i18n.gettext("spam ham eggs"))76 i18n.gettext("spam ham eggs"))
7377
74 def test_multiline(self):78 def test_multiline(self):
75 self.assertEqual(u"zz{{spam\nham\n\neggs\n}}",79 self.assertEqual(u"zz\xe5{{spam\nham\n\neggs\n}}",
76 i18n.gettext("spam\nham\n\neggs\n"))80 i18n.gettext("spam\nham\n\neggs\n"))
7781
7882
@@ -83,11 +87,11 @@
83 self.overrideAttr(i18n, '_translations', ZzzTranslations())87 self.overrideAttr(i18n, '_translations', ZzzTranslations())
8488
85 def test_oneline(self):89 def test_oneline(self):
86 self.assertEqual(u"zz{{spam ham eggs}}",90 self.assertEqual(u"zz\xe5{{spam ham eggs}}",
87 i18n.gettext_per_paragraph("spam ham eggs"))91 i18n.gettext_per_paragraph("spam ham eggs"))
8892
89 def test_multiline(self):93 def test_multiline(self):
90 self.assertEqual(u"zz{{spam\nham}}\n\nzz{{eggs\n}}",94 self.assertEqual(u"zz\xe5{{spam\nham}}\n\nzz\xe5{{eggs\n}}",
91 i18n.gettext_per_paragraph("spam\nham\n\neggs\n"))95 i18n.gettext_per_paragraph("spam\nham\n\neggs\n"))
9296
9397
@@ -104,3 +108,20 @@
104 self.overrideEnv('LC_MESSAGES', None)108 self.overrideEnv('LC_MESSAGES', None)
105 self.overrideEnv('LANG', None)109 self.overrideEnv('LANG', None)
106 i18n.install()110 i18n.install()
111
112class TestTranslate(tests.TestCaseWithTransport):
113
114 def setUp(self):
115 super(TestTranslate, self).setUp()
116 self.overrideAttr(i18n, '_translations', ZzzTranslations())
117
118 def test_error_message_translation(self):
119 """do errors get translated?"""
120 err = None
121 tree = self.make_branch_and_tree('.')
122 self.overrideAttr(i18n, '_translations', ZzzTranslations())
123 try:
124 workingtree.WorkingTree.open('./foo')
125 except errors.NotBranchError,e:
126 err = str(e)
127 self.assertContainsRe(err, u"zz\xe5{{Not a branch: .*}}".encode("utf-8"))
107128
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- doc/en/release-notes/bzr-2.5.txt 2011-09-06 13:35:07 +0000
+++ doc/en/release-notes/bzr-2.5.txt 2011-09-07 11:50:38 +0000
@@ -92,6 +92,9 @@
92* bzr now ships with translations for command help. (Jonathan92* bzr now ships with translations for command help. (Jonathan
93 Riddell, INADA Naoki, #83941)93 Riddell, INADA Naoki, #83941)
9494
95* bzr now ships with translations for command errors. (Jonathan
96 Riddell, INADA Naoki)
97
95Improvements98Improvements
96************99************
97100