7185135 i18n messages should use parameterized values
authorTim Foster <tim.s.foster@oracle.com>
Fri, 02 Nov 2012 11:42:49 +1300
changeset 2826 cae308eb6426
parent 2825 0986d57e1337
child 2827 f0694460f5ca
7185135 i18n messages should use parameterized values 7188804 pkg5 should depend on gnu-gettext 7194773 pkg.mo should move to pkg:/package/pkg
.hgignore
src/client.py
src/modules/actions/depend.py
src/modules/altroot.py
src/modules/client/api_errors.py
src/modules/client/bootenv.py
src/modules/client/image.py
src/modules/client/pkg_solver.py
src/modules/client/progress.py
src/modules/flavor/base.py
src/modules/flavor/elf.py
src/modules/gui/beadmin.py
src/modules/gui/misc.py
src/modules/gui/progress.py
src/modules/gui/uarenamebe.py
src/modules/misc.py
src/modules/server/transaction.py
src/pkg/external_deps.txt
src/pkg/manifests/developer:opensolaris:pkg5.p5m
src/pkg/manifests/package:pkg.p5m
src/pkg/manifests/package:pkg:package-manager.p5m
src/pkgdep.py
src/publish.py
src/pull.py
src/setup.py
src/tests/cli/t_pkg_image_create.py
src/util/publish/pkgdiff.py
src/util/publish/pkglint.py
src/util/publish/pkgmogrify.py
--- a/.hgignore	Wed Oct 31 10:48:34 2012 -0700
+++ b/.hgignore	Fri Nov 02 11:42:49 2012 +1300
@@ -34,6 +34,7 @@
 ^src/gui/help/package-manager-__LOCALE__.omf$
 ^src/pkg/Makefile.link
 ^src/pkg/pkgtmp/
+^src/po/i18n_errs.txt$
 ^src/po/pkg.pot$
 ^src/tests/.coverage$
 ^src/tests/.coverage-.*$
--- a/src/client.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/client.py	Fri Nov 02 11:42:49 2012 +1300
@@ -1372,7 +1372,8 @@
                 api_inst.execute_plan()
                 rval = EXIT_OK
         except RuntimeError, e:
-                error(_("%s failed: %s") % (operation, e))
+                error(_("%(operation)s failed: %(err)s") %
+                    {"operation": operation, "err": e})
                 rval = EXIT_OOPS
         except (api_errors.InvalidPlanError,
             api_errors.ActionExecutionError,
@@ -1382,8 +1383,8 @@
                 error("\n" + str(e))
                 rval = EXIT_OOPS
         except (api_errors.LinkedImageException), e:
-                error(_("%s failed (linked image exception(s)):\n%s") %
-                      (operation, str(e)))
+                error(_("%(operation)s failed (linked image exception(s)):\n"
+                    "%(err)s") % {"operation": operation, "err": e})
                 rval = e.lix_exitrv
         except api_errors.ImageUpdateOnLiveImageException:
                 error(_("%s cannot be done on live image") % operation)
@@ -1421,7 +1422,8 @@
                 rval = EXIT_OOPS
         except Exception, e:
                 error(_("An unexpected error happened during "
-                    "%s: %s") % (operation, e))
+                    "%(operation)s: %(err)s") %
+                    {"operation": operation, "err": e})
                 raise
         finally:
                 exc_type = exc_value = exc_tb = None
@@ -1491,12 +1493,12 @@
                 error(_("No image rooted at '%s'") % e.user_dir, cmd=op)
                 return EXIT_OOPS
         if e_type == api_errors.InventoryException:
-                error("\n" + _("%s failed (inventory exception):\n%s") % (op,
-                    e))
+                error("\n" + _("%(operation)s failed (inventory exception):\n"
+                    "%(err)s") % {"operation": op, "err": e})
                 return EXIT_OOPS
         if isinstance(e, api_errors.LinkedImageException):
-                error(_("%s failed (linked image exception(s)):\n%s") %
-                      (op, str(e)))
+                error(_("%(operation)s failed (linked image exception(s)):\n"
+                    "%(err)s") % {"operation": op, "err": e})
                 return e.lix_exitrv
         if e_type == api_errors.IpkgOutOfDateException:
                 msg(_("""\
@@ -2104,12 +2106,14 @@
                 v = int(v)
         except (ValueError, TypeError):
                 # not a valid integer
-                err = _("invalid '%s' value: %s") % (k, v)
+                err = _("invalid '%(opt)s' value: %(val)s") % \
+                    {"opt": k, "val": v}
                 usage(err, cmd=op)
 
         # check the minimum bounds
         if minimum is not None and v < minimum:
-                err = _("'%s' must be >= %d") % (k, minimum)
+                err = _("'%(opt)s' must be >= %(minimum)d") % \
+                    {"opt": k, "minimum": minimum}
                 usage(err, cmd=op)
 
         # update the new options array to make the value an integer
@@ -2118,7 +2122,8 @@
 def opts_cb_fd(k, op, api_inst, opts, opts_new):
         opts_cb_int(k, op, api_inst, opts, opts_new, minimum=0)
 
-        err = _("invalid '%s' value: %s") % (k, opts_new[k])
+        err = _("invalid '%(opt)s' value: %(optval)s") % \
+            {"opt": k, "optval": opts_new[k]}
         try:
                 os.fstat(opts_new[k])
         except OSError:
@@ -2519,8 +2524,8 @@
 
                 # make sure the user didn't specify duplicate variants
                 if name in variants:
-                        usage(_("%s: duplicate variant specified: %s") %
-                            (op, name))
+                        usage(_("%(subcmd)s: duplicate variant specified: "
+                            "%(variant)s") % {"subcmd": op, "variant": name})
                 variants[name] = value
 
         return __api_op(op, api_inst, _accept=accept, _li_ignore=li_ignore,
@@ -2983,8 +2988,10 @@
         for a in api_inst.get_avoid_list():
                 tracking = " ".join(a[1])
                 if tracking:
-                        logger.info(_("    %s (group dependency of '%s')")
-                            % (a[0], tracking))
+                        logger.info(_(
+                            "    %(avoid_pkg)s (group dependency of "
+                            "'%(tracking_pkg)s')")
+                            % {"avoid_pkg": a[0], "tracking_pkg": tracking})
                 else:
                         logger.info("    %s" % a[0])
 
@@ -4043,8 +4050,8 @@
         total = cre.total
         succeeded = cre.succeeded
 
-        txt = _("pkg: %s/%s catalogs successfully updated:") % (succeeded,
-            total)
+        txt = _("pkg: %(succeeded)s/%(total)s catalogs successfully "
+            "updated:") % {"succeeded": succeeded, "total": total}
         if cre.failed:
                 # This ensures that the text gets printed before the errors.
                 logger.error(txt)
@@ -6609,7 +6616,8 @@
                 __ret = handle_errors(_wrapper, non_wrap_print=False)
                 s = ""
                 if __ret == 99:
-                        s += _("\n%s%s") % (__e, traceback_str)
+                        s += _("\n%(err)s%(stacktrace)s") % \
+                        {"err": __e, "stacktrace": traceback_str}
 
                 s += _("\n\nDespite the error while indexing, the operation "
                     "has completed successfuly.")
--- a/src/modules/actions/depend.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/actions/depend.py	Fri Nov 02 11:42:49 2012 +1300
@@ -178,9 +178,10 @@
                 if required and pkgdefs.PKG_STATE_OBSOLETE in \
                     image.get_pkg_state(installed_version):
                         errors.append(
-                            _("%s dependency on an obsolete package (%s);"
-                            "this package must be uninstalled manually") %
-                            (ctype, installed_version))
+                            _("%(dep_type)s dependency on an obsolete package "
+                            "(%(obs_pkg)s); this package must be uninstalled "
+                            "manually") %
+                            {"dep_type": ctype, "obs_pkg": installed_version})
                         return errors
                 return errors
 
--- a/src/modules/altroot.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/altroot.py	Fri Nov 02 11:42:49 2012 +1300
@@ -110,8 +110,8 @@
 
         # we're going to update root and path so prepare an error
         # message with the existing values now.
-        eremote = _("Path outside alternate root: root=%s, path=%s") % \
-            (root, path)
+        eremote = _("Path outside alternate root: root=%(root)s, "
+            "path=%(path)s") % {"root": root, "path": path}
 
         # make target into a relative path
         if os.path.isabs(path):
--- a/src/modules/client/api_errors.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/client/api_errors.py	Fri Nov 02 11:42:49 2012 +1300
@@ -550,10 +550,11 @@
                         res += [ s % p for p in self.illegal ]
 
                 if self.badarch:
-                        s = _("'%s' supports the following architectures: %s")
+                        s = _("'%(p)s' supports the following architectures: "
+                            "%(archs)s")
                         a = _("Image architecture is defined as: %s")
-                        res += [ s % (self.badarch[0],
-                            ", ".join(self.badarch[1]))]
+                        res += [ s % {"p": self.badarch[0],
+                            "archs": ", ".join(self.badarch[1])}]
                         res += [ a % (self.badarch[2])]
 
                 s = _("'%(p)s' depends on obsolete package '%(op)s'")
@@ -806,8 +807,8 @@
                                 for pkg in sorted(pkglist):
                                         s += _("        %s\n") % pkg
                         else:
-                                t = _("    %d packages deliver '%s', including:\n")
-                                s += t % (num, action)
+                                t = _("    %(n)d packages deliver '%(a)s', including:\n")
+                                s += t % {"n": num, "a": action}
                                 for pkg in sorted(pkglist)[:5]:
                                         s += _("        %s\n") % pkg
 
@@ -1453,7 +1454,8 @@
         def __str__(self):
                 if self.location:
                         return _("Error encountered while retrieving data from "
-                            "'%s':\n%s") % (self.location, self.data)
+                            "'%(location)s':\n%(data)s") % \
+                            {"location": self.location, "data": self.data}
                 return _("Error encountered while retrieving data from: %s") % \
                     self.data
 
--- a/src/modules/client/bootenv.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/client/bootenv.py	Fri Nov 02 11:42:49 2012 +1300
@@ -587,9 +587,9 @@
                                 self.img.history.log_operation_error(error=e)
                                 raise e
 
-                        logger.error(_("%s failed to be updated. No changes "
-                            "have been made to %s.") % (self.be_name,
-                            self.be_name))
+                        logger.error(_("%(bename)s failed to be updated. No "
+                            "changes have been made to %(bename)s.") %
+                            {"bename": self.be_name})
 
         def destroy_snapshot(self):
 
@@ -655,10 +655,11 @@
 
                         self.destroy_snapshot()
 
-                        logger.error(_("The Boot Environment %s failed to be "
-                            "updated. A snapshot was taken before the failed "
-                            "attempt and has been restored so no changes have "
-                            "been made to %s.") % (self.be_name, self.be_name))
+                        logger.error(_("The Boot Environment %(bename)s failed "
+                            "to be updated. A snapshot was taken before the "
+                            "failed attempt and has been restored so no "
+                            "changes have been made to %(bename)s.") %
+                            {"bename": self.be_name})
 
         def activate_install_uninstall(self):
                 """Activate an install/uninstall attempt. Which just means
--- a/src/modules/client/image.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/client/image.py	Fri Nov 02 11:42:49 2012 +1300
@@ -361,8 +361,9 @@
                 """A list of strings decribing errors encountered while parsing
                 trust anchors."""
 
-                return [_("%s is expected to be a certificate but could not be "
-                    "parsed.  The error encountered was:\n\t%s") % (p, e)
+                return [_("%(path)s is expected to be a certificate but could "
+                    "not be parsed.  The error encountered was:\n\t%(err)s") %
+                    {"path": p, "err": e}
                     for p, e in self.__bad_trust_anchors
                 ]
 
--- a/src/modules/client/pkg_solver.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/client/pkg_solver.py	Fri Nov 02 11:42:49 2012 +1300
@@ -1711,7 +1711,10 @@
                 tag = _("Reason:")
 
                 if fmri in already_seen:
-                        reason = _("%s  %s  [already rejected; see above]") % (indent, tag)
+                        # note to translators: 'indent' will be a series of
+                        # whitespaces.
+                        reason = _("%(indent)s  %(tag)s  [already rejected; "
+                            "see above]") % {"indent": indent, "tag": tag}
                         return fmri_id, [reason]
 
                 already_seen.add(fmri)
--- a/src/modules/client/progress.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/client/progress.py	Fri Nov 02 11:42:49 2012 +1300
@@ -450,9 +450,12 @@
 
                 # See if we indeed met our goal.
                 if goalcheck and not self.metgoal():
-                        exstr = _("Goal mismatch '%s': "
-                            "expected goal: %s, current value: %s") % \
-                            (self.name, str(self.goalitems), str(self.items))
+                        exstr = _("Goal mismatch '%(name)s': "
+                            "expected goal: %(expected)s, "
+                            "current value: %(current)s") % \
+                            {"name": self.name,
+                            "expected": self.goalitems,
+                            "current": self.items}
                         logger.error("\n" + exstr)
                         assert self.metgoal(), exstr
 
@@ -1751,8 +1754,15 @@
                 if self.major_phase == self.PHASE_UTILITY:
                         return ""
 
-                return _("%*s: ") % (self.phase_max_width,
-                    self.phase_names[self.major_phase])
+                # The following string was originally expressed as
+                # "%*s: " % \
+                #     (self.phase_max_width, self.phase_names[self.major_phase])
+                # however xgettext incorrectly flags this as an improper use of
+                # non-parameterized messages, which gets detected as an error
+                # during our build.  So instead, we express the string using
+                # an equivalent <str>.format(..) function
+                s = _("{phase:>%d}: ") % self.phase_max_width
+                return s.format(phase=self.phase_names[self.major_phase])
 
         #
         # Helper routines
@@ -1859,8 +1869,10 @@
                 # adjusts the output based on the major phase.
                 #
                 self._pe.cprint(self._phase_prefix() +
-                    _("Fetching manifests: %s  %d%% complete") %
-                    (self.mfst_fetch.pair(), self.mfst_fetch.pctdone()))
+                    _("Fetching manifests: %(num)s  %(pctcomplete)d%% "
+                    "complete") %
+                    {"num": self.mfst_fetch.pair(),
+                    "pctcomplete": self.mfst_fetch.pctdone()})
 
         def _mfst_commit(self, outspec):
                 # For now, manifest commit is hard to handle in this
@@ -1906,15 +1918,19 @@
                         mbs = format_pair("%.1f", self.dl_bytes.items,
                             self.dl_bytes.goalitems, scale=(1024 * 1024))
                         self._pe.cprint(
-                            _("Download: %s items  %sMB  %d%% complete %s") %
-                            (self.dl_files.pair(), mbs, self.dl_bytes.pctdone(),
-                            speedstr))
+                            _("Download: %(num)s items  %(mbs)sMB  "
+                            "%(pctcomplete)d%% complete %(speed)s") %
+                            {"num": self.dl_files.pair(), "mbs": mbs,
+                            "pctcomplete": self.dl_bytes.pctdone(),
+                            "speed": speedstr})
                 else:
                         # 'last'
                         goal = misc.bytes_to_str(self.dl_bytes.goalitems)
                         self.__generic_done(
-                            msg=_("Download: Completed %s in %.2f seconds %s") %
-                            (goal, self.dl_estimator.elapsed(), speedstr))
+                            msg=_("Download: Completed %(num)s in %(sec).2f "
+                            "seconds %(speed)s") %
+                            {"num": goal, "sec": self.dl_estimator.elapsed(),
+                            "speed": speedstr})
 
         def _republish_output(self, outspec):
                 if "startpkg" in outspec.changed:
@@ -1934,16 +1950,18 @@
                 if outspec.last:
                         goal = misc.bytes_to_str(self.archive_bytes.goalitems)
                         self.__generic_done(
-                            msg=_("Archiving: Completed %s in %.2f seconds") %
-                            (goal, self.archive_items.elapsed()))
+                            msg=_("Archiving: Completed %(num)s in %(secs).2f "
+                            "seconds") %
+                            {"num": goal, "secs": self.archive_items.elapsed()})
                         return
 
                 mbs = format_pair("%.1f", self.archive_bytes.items,
                     self.archive_bytes.goalitems, scale=(1024 * 1024))
                 self._pe.cprint(
-                    _("Archiving: %s items  %sMB  %d%% complete") %
-                    (self.archive_items.pair(), mbs,
-                    self.archive_bytes.pctdone()))
+                    _("Archiving: %(pair)s items  %(mbs)sMB  %(pctcomplete)d%% "
+                    "complete") %
+                    {"pair": self.archive_items.pair(), "mbs": mbs,
+                    "pctcomplete": self.archive_bytes.pctdone()})
 
         #
         # The progress tracking infrastructure wants to tell us about each
@@ -1960,9 +1978,10 @@
                     sum(x.items for x in self._actionitems.values())
                 total_goal = \
                     sum(x.goalitems for x in self._actionitems.values())
-                self._pe.cprint(self._phase_prefix() + _("%s actions (%s)") %
-                    (format_pair("%d", total_actions, total_goal),
-                    actionitem.name))
+                self._pe.cprint(self._phase_prefix() +
+                    _("%(num)s actions (%(type)s)") %
+                    {"num": format_pair("%d", total_actions, total_goal),
+                    "type": actionitem.name})
 
         def _act_output_all_done(self):
                 total_goal = \
@@ -1972,8 +1991,9 @@
                 if total_goal == 0:
                         return
                 self._pe.cprint(self._phase_prefix() +
-                    _("Completed %d actions in %.2f seconds.") %
-                    (total_goal, total_time))
+                    _("Completed %(numactions)d actions in %(time).2f "
+                    "seconds.") %
+                    {"numactions": total_goal, "time": total_time})
 
         def _job_output(self, outspec, jobitem):
                 if outspec.first:
@@ -2034,9 +2054,11 @@
                         return
 
                 running = " ".join([str(i) for i in self.linked_running])
-                msg = _("Linked images: %s done; %d working: %s") % \
-                    (format_pair("%d", done, self.linked_total),
-                    len(self.linked_running), running)
+                msg = _("Linked images: %(pair)s done; %(numworking)d working: "
+                    "%(running)s") % \
+                    {"pair": format_pair("%d", done, self.linked_total),
+                    "numworking": len(self.linked_running),
+                    "running": running}
                 self._pe.cprint(self._phase_prefix() + msg)
 
         def _li_recurse_progress_output(self, lin):
@@ -2206,8 +2228,10 @@
                 extra_info = ""
                 if isinstance(planitem, GoalTrackerItem):
                         extra_info = ": %s" % planitem.pair()
-                msg = _("Creating Plan (%s%s): %s") % \
-                    (planitem.name, extra_info, self._spinner())
+                msg = _("Creating Plan (%(name)s%(info)s): %(spinner)s") % \
+                    {"name": planitem.name,
+                    "info": extra_info,
+                    "spinner": self._spinner()}
                 self._pe.cprint(msg, sep='', end='', erase=True)
 
         def _plan_output_all_done(self):
@@ -2228,12 +2252,19 @@
                 # the output based on the major mode.
                 #
                 if self.major_phase == self.PHASE_PLAN:
-                        msg = _("Creating Plan (%s %s) %c") % \
-                            (self.mfst_fetch.name, self.mfst_fetch.pair(),
-                                self._spinner())
+                        msg = _("Creating Plan (%(name)s %(pair)s) "
+                            "%(spinner)c") % \
+                            {"name": self.mfst_fetch.name,
+                            "pair": self.mfst_fetch.pair(),
+                            "spinner": self._spinner()}
                 if self.major_phase == self.PHASE_UTILITY:
-                        msg = _("%s (%s) %c") % (self.mfst_fetch.name,
-                            self.mfst_fetch.pair(), self._spinner())
+                        # note to translators: the position of these strings
+                        # should probably be left alone, as they form part of
+                        # the progress output text.
+                        msg = _("%(name)s (%(fetchpair)s) %(spinchar)c") % {
+                            "name": self.mfst_fetch.name,
+                            "fetchpair": self.mfst_fetch.pair(),
+                            "spinchar": self._spinner()}
                 self._pe.cprint(msg, sep='', end='', erase=True)
 
                 if outspec.last:
@@ -2477,10 +2508,12 @@
                 assert self.major_phase in self.li_phase_names, self.major_phase
 
                 running = " ".join([str(i) for i in self.linked_running])
-                msg = _("%s linked: %s done; %d working: %s") % \
-                    (self.li_phase_names[self.major_phase],
-                    format_pair("%d", done, self.linked_total),
-                    len(self.linked_running), running)
+                msg = _("%(phase)s linked: %(numdone)s done; "
+                    "%(numworking)d working: %(running)s") % \
+                    {"phase": self.li_phase_names[self.major_phase],
+                    "numdone": format_pair("%d", done, self.linked_total),
+                    "numworking": len(self.linked_running),
+                    "running": running}
                 self._pe.cprint(msg, erase=True)
 
                 self.__linked_spinners = list(
--- a/src/modules/flavor/base.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/flavor/base.py	Fri Nov 02 11:42:49 2012 +1300
@@ -53,9 +53,11 @@
                 if not self.dirs:
                         return _("Couldn't find '%s'") % self.file_path
                 else:
-                        return _("Couldn't find '%s' in any of the specified "
-                            "search directories:\n%s") % (self.file_path,
-                            "\n".join(["\t" + d for d in sorted(self.dirs)]))
+                        return _("Couldn't find '%(path)s' in any of the "
+                            "specified search directories:\n%(dirs)s") % \
+                            {"path": self.file_path,
+                            "dirs": "\n".join(
+                            ["\t" + d for d in sorted(self.dirs)])}
 
 class MultipleDefaultRunpaths(DependencyAnalysisError):
         """Exception that is raised when multiple $PGKDEPEND_RUNPATH tokens
--- a/src/modules/flavor/elf.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/flavor/elf.py	Fri Nov 02 11:42:49 2012 +1300
@@ -42,7 +42,8 @@
                 self.ex = ex
 
         def __str__(self):
-                return _("%s had this elf error:%s") % (self.fp, self.ex)
+                return _("%(file)s had this elf error:%(err)s") % \
+                    {"file": "self.fp", "err": self.ex}
 
 class UnsupportedDynamicToken(base.DependencyAnalysisError):
         """Exception that is used for elf dependencies which have a dynamic
--- a/src/modules/gui/beadmin.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/gui/beadmin.py	Fri Nov 02 11:42:49 2012 +1300
@@ -391,8 +391,10 @@
                                 msg += _("<b>Couldn't rename Boot "
                                     "Environments:</b>\n")
                                 for orig in not_renamed:
-                                        msg += _("%s <b>to</b> %s\n") % (orig, \
-                                            not_renamed.get(orig))
+                                        msg += _("%(src)s <b>to</b> "
+                                            "%(targ)s\n") % \
+                                            {"src": orig,
+                                            "targ": not_renamed.get(orig)}
                         gobject.idle_add(self.__error_occurred, msg)
                         return
                 gobject.idle_add(self.__on_cancel_be_clicked, None)
--- a/src/modules/gui/misc.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/gui/misc.py	Fri Nov 02 11:42:49 2012 +1300
@@ -396,8 +396,10 @@
         try:
                 api_o = ngao(img_dir, progtrack)
         except api_errors.VersionException, ex:
-                message = _("Version mismatch: expected version %d, got version %d") % \
-                    (ex.expected_version, ex.received_version)
+                message = _("Version mismatch: expected version %(expected)d, "
+                    "got version %(found)d") % \
+                    {"expected": ex.expected_version,
+                    "found": ex.received_version}
         except api_errors.ImageNotFoundException, ex:
                 message = _("%s is not an install image") % ex.user_dir
         except api_errors.ImageLockedError, ex:
--- a/src/modules/gui/progress.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/gui/progress.py	Fri Nov 02 11:42:49 2012 +1300
@@ -142,9 +142,10 @@
                 self.display_download_info()
                 if "startpkg" in outspec.changed:
                         self.update_details_text(
-                            _("Package %d of %d: %s\n") % (
-                            self.dl_pkgs.items + 1,
-                            self.dl_pkgs.goalitems, self.dl_pkgs.curinfo),
+                            _("Package %(num)d of %(goal)d: %(info)s\n") % {
+                            "num": self.dl_pkgs.items + 1,
+                            "goal": self.dl_pkgs.goalitems,
+                            "info": self.dl_pkgs.curinfo},
                             "level1")
 
                 if outspec.last:
@@ -223,9 +224,11 @@
                 i = "level1" if self.indent else ""
 
                 running = " ".join([str(s) for s in self.linked_running])
-                msg = _("Linked images: %s done; %d working: %s\n") % \
-                    (progress.format_pair("%d", done, self.linked_total),
-                    len(self.linked_running), running)
+                msg = _("Linked images: %(num)s done; %(numworking)d working: "
+                    "%(running)s\n") % \
+                    {"num": progress.format_pair("%d", done, self.linked_total),
+                    "numworking": len(self.linked_running),
+                    "running": running}
                 self.update_details_text(msg, i)
 
         def _li_recurse_progress_output(self, lin):
--- a/src/modules/gui/uarenamebe.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/gui/uarenamebe.py	Fri Nov 02 11:42:49 2012 +1300
@@ -220,8 +220,9 @@
         def __g_be_rename_problem_dialog(new_name, orig_name):
                 msg_type = gtk.MESSAGE_INFO
                 error_msg = _("Could not change the BE name to:\n\t"
-                    "%s\n\nThe following name will be used instead:"
-                    "\n\t%s" % (new_name, orig_name))
+                    "%(targ)s\n\nThe following name will be used instead:"
+                    "\n\t%(instead)s") % \
+                    {"targ": new_name, "instead": orig_name}
                 msg_title = _("BE Name")
                 gui_misc.error_occurred(None, error_msg, msg_title, msg_type)
 
--- a/src/modules/misc.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/misc.py	Fri Nov 02 11:42:49 2012 +1300
@@ -1352,8 +1352,9 @@
                         if opt == opts_seen[k]:
                                 usage_cb(_("option '%s' repeated") % opt,
                                     cmd=op)
-                        usage_cb(_("'%s' and '%s' have the same meaning") %
-                            (opts_seen[k], opt), cmd=op)
+                        usage_cb(_("'%(optA)s' and '%(optB)s' have the same "
+                            "meaning") % {"optA": opts_seen[k], "optB": opt},
+                            cmd=op)
                 opts_seen[k] = opt
 
                 # update the return dict value
--- a/src/modules/server/transaction.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/modules/server/transaction.py	Fri Nov 02 11:42:49 2012 +1300
@@ -551,14 +551,16 @@
                         raise TransactionOperationError(_("A package may not "
                             " be marked for both obsoletion and renaming."))
                 elif self.obsolete and action.name not in ("set", "signature"):
-                        raise TransactionOperationError(_("A '%s' action cannot"
-                            " be present in an obsolete package: %s") %
-                            (action.name, action))
+                        raise TransactionOperationError(_("A '%(type)s' action "
+                            "cannot be present in an obsolete package: "
+                            "%(action)s") %
+                            {"type": action.name, "action": action})
                 elif self.renamed and action.name not in \
                     ("depend", "set", "signature"):
-                        raise TransactionOperationError(_("A '%s' action cannot"
-                            " be present in a renamed package: %s") %
-                            (action.name, action))
+                        raise TransactionOperationError(_("A '%(type)s' action "
+                            "cannot be present in a renamed package: "
+                            "%(action)s") %
+                            {"type": action.name, "action": action})
 
                 # Now that the action is known to be sane, we can add it to the
                 # manifest.
--- a/src/pkg/external_deps.txt	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/pkg/external_deps.txt	Fri Nov 02 11:42:49 2012 +1300
@@ -42,6 +42,7 @@
     pkg:/system/linker
     pkg:/system/locale/extra
     pkg:/system/network
+    pkg:/text/gnu-gettext
     pkg:/text/gnu-grep
     pkg:/text/locale
     pkg:/text/tidy
--- a/src/pkg/manifests/developer:opensolaris:pkg5.p5m	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/pkg/manifests/developer:opensolaris:pkg5.p5m	Fri Nov 02 11:42:49 2012 +1300
@@ -49,6 +49,7 @@
 depend type=require fmri=pkg:/system/header
 depend type=require fmri=pkg:/system/linker
 depend type=require fmri=pkg:/system/locale/extra
+depend type=require fmri=pkg:/text/gnu-gettext
 depend type=require fmri=pkg:/text/locale
 depend type=require fmri=pkg:/text/tidy
 depend type=require fmri=pkg:/web/server/apache-22
--- a/src/pkg/manifests/package:pkg.p5m	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/pkg/manifests/package:pkg.p5m	Fri Nov 02 11:42:49 2012 +1300
@@ -297,6 +297,70 @@
 file path=usr/share/lib/pkg/web/index.shtml
 file path=usr/share/lib/pkg/web/robots.txt
 file path=usr/share/lib/pkg/web/shared.shtml
+dir  path=usr/share/locale
+dir  path=usr/share/locale/ar
+dir  path=usr/share/locale/ar/LC_MESSAGES
+file path=usr/share/locale/ar/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/ca
+dir  path=usr/share/locale/ca/LC_MESSAGES
+file path=usr/share/locale/ca/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/cs
+dir  path=usr/share/locale/cs/LC_MESSAGES
+file path=usr/share/locale/cs/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/de
+dir  path=usr/share/locale/de/LC_MESSAGES
+file path=usr/share/locale/de/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/es
+dir  path=usr/share/locale/es/LC_MESSAGES
+file path=usr/share/locale/es/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/fr
+dir  path=usr/share/locale/fr/LC_MESSAGES
+file path=usr/share/locale/fr/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/he
+dir  path=usr/share/locale/he/LC_MESSAGES
+file path=usr/share/locale/he/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/hu
+dir  path=usr/share/locale/hu/LC_MESSAGES
+file path=usr/share/locale/hu/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/id
+dir  path=usr/share/locale/id/LC_MESSAGES
+file path=usr/share/locale/id/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/it
+dir  path=usr/share/locale/it/LC_MESSAGES
+file path=usr/share/locale/it/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/ja
+dir  path=usr/share/locale/ja/LC_MESSAGES
+file path=usr/share/locale/ja/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/ko
+dir  path=usr/share/locale/ko/LC_MESSAGES
+file path=usr/share/locale/ko/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/nl
+dir  path=usr/share/locale/nl/LC_MESSAGES
+file path=usr/share/locale/nl/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/pl
+dir  path=usr/share/locale/pl/LC_MESSAGES
+file path=usr/share/locale/pl/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/pt_BR
+dir  path=usr/share/locale/pt_BR/LC_MESSAGES
+file path=usr/share/locale/pt_BR/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/ru
+dir  path=usr/share/locale/ru/LC_MESSAGES
+file path=usr/share/locale/ru/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/sk
+dir  path=usr/share/locale/sk/LC_MESSAGES
+file path=usr/share/locale/sk/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/sv
+dir  path=usr/share/locale/sv/LC_MESSAGES
+file path=usr/share/locale/sv/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/zh_CN
+dir  path=usr/share/locale/zh_CN/LC_MESSAGES
+file path=usr/share/locale/zh_CN/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/zh_HK
+dir  path=usr/share/locale/zh_HK/LC_MESSAGES
+file path=usr/share/locale/zh_HK/LC_MESSAGES/pkg.mo
+dir  path=usr/share/locale/zh_TW
+dir  path=usr/share/locale/zh_TW/LC_MESSAGES
+file path=usr/share/locale/zh_TW/LC_MESSAGES/pkg.mo
 dir  path=usr/share/man
 dir  path=usr/share/man/ja_JP.UTF-8
 dir  path=usr/share/man/ja_JP.UTF-8/man1
--- a/src/pkg/manifests/package:pkg:package-manager.p5m	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/pkg/manifests/package:pkg:package-manager.p5m	Fri Nov 02 11:42:49 2012 +1300
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 set name=pkg.fmri value=pkg:/package/pkg/package-manager@$(PKGVERS)
@@ -132,70 +132,6 @@
 file path=usr/share/icons/hicolor/48x48/apps/packagemanager.png
 dir  path=usr/share/icons/hicolor/48x48/mimetypes
 file path=usr/share/icons/hicolor/48x48/mimetypes/gnome-mime-application-vnd.pkg5.info.png
-dir  path=usr/share/locale
-dir  path=usr/share/locale/ar
-dir  path=usr/share/locale/ar/LC_MESSAGES
-file path=usr/share/locale/ar/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/ca
-dir  path=usr/share/locale/ca/LC_MESSAGES
-file path=usr/share/locale/ca/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/cs
-dir  path=usr/share/locale/cs/LC_MESSAGES
-file path=usr/share/locale/cs/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/de
-dir  path=usr/share/locale/de/LC_MESSAGES
-file path=usr/share/locale/de/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/es
-dir  path=usr/share/locale/es/LC_MESSAGES
-file path=usr/share/locale/es/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/fr
-dir  path=usr/share/locale/fr/LC_MESSAGES
-file path=usr/share/locale/fr/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/he
-dir  path=usr/share/locale/he/LC_MESSAGES
-file path=usr/share/locale/he/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/hu
-dir  path=usr/share/locale/hu/LC_MESSAGES
-file path=usr/share/locale/hu/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/id
-dir  path=usr/share/locale/id/LC_MESSAGES
-file path=usr/share/locale/id/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/it
-dir  path=usr/share/locale/it/LC_MESSAGES
-file path=usr/share/locale/it/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/ja
-dir  path=usr/share/locale/ja/LC_MESSAGES
-file path=usr/share/locale/ja/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/ko
-dir  path=usr/share/locale/ko/LC_MESSAGES
-file path=usr/share/locale/ko/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/nl
-dir  path=usr/share/locale/nl/LC_MESSAGES
-file path=usr/share/locale/nl/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/pl
-dir  path=usr/share/locale/pl/LC_MESSAGES
-file path=usr/share/locale/pl/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/pt_BR
-dir  path=usr/share/locale/pt_BR/LC_MESSAGES
-file path=usr/share/locale/pt_BR/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/ru
-dir  path=usr/share/locale/ru/LC_MESSAGES
-file path=usr/share/locale/ru/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/sk
-dir  path=usr/share/locale/sk/LC_MESSAGES
-file path=usr/share/locale/sk/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/sv
-dir  path=usr/share/locale/sv/LC_MESSAGES
-file path=usr/share/locale/sv/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/zh_CN
-dir  path=usr/share/locale/zh_CN/LC_MESSAGES
-file path=usr/share/locale/zh_CN/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/zh_HK
-dir  path=usr/share/locale/zh_HK/LC_MESSAGES
-file path=usr/share/locale/zh_HK/LC_MESSAGES/pkg.mo
-dir  path=usr/share/locale/zh_TW
-dir  path=usr/share/locale/zh_TW/LC_MESSAGES
-file path=usr/share/locale/zh_TW/LC_MESSAGES/pkg.mo
 dir  path=usr/share/man
 dir  path=usr/share/man/ja_JP.UTF-8
 dir  path=usr/share/man/ja_JP.UTF-8/man1
--- a/src/pkgdep.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/pkgdep.py	Fri Nov 02 11:42:49 2012 +1300
@@ -489,8 +489,13 @@
                 try:
                         os.makedirs(out_dir)
                 except EnvironmentError, e:
-                        emsg(_("Out dir %s does not exist and could not be "
-                            "created. Error is: %s") % e)
+                        e_dic = {"dir": out_dir}
+                        if len(e.args) > 0:
+                                e_dic["err"] = e.args[1]
+                        else:
+                                e_dic["err"] = e.args[0]
+                        emsg(_("Out dir %(out_dir)s does not exist and could "
+                            "not be created. Error is: %(err)s") % e_dic)
                         return 1
         if suffix and suffix[0] != ".":
                 suffix = "." + suffix
--- a/src/publish.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/publish.py	Fri Nov 02 11:42:49 2012 +1300
@@ -359,7 +359,8 @@
                         filename = "???"
                         lineno = "???"
 
-                error(_("File %s line %s: %s") % (filename, lineno, e),
+                error(_("File %(filename)s line %(lineno)s: %(err)s") %
+                    {"filename": filename, "lineno": lineno, "err": e},
                     cmd="publish")
                 return 1
 
@@ -508,7 +509,8 @@
                         filename = "???"
                         lineno = "???"
 
-                error(_("File %s line %s: %s") % (filename, lineno, e),
+                error(_("File %(filename)s line %(lineno)s: %(err)s") %
+                    {"filename": filename, "lineno": lineno, "err": e},
                     cmd="include")
                 return 1
 
@@ -790,7 +792,8 @@
                 error(e, cmd=subcommand)
                 ret = 1
         except getopt.GetoptError, e:
-                usage(_("illegal %s option -- %s") % (subcommand, e.opt))
+                usage(_("illegal %(cmd)s option -- %(opt)s") % \
+                    {"cmd": subcommand, "opt": e.opt})
 
         return ret
 
--- a/src/pull.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/pull.py	Fri Nov 02 11:42:49 2012 +1300
@@ -747,7 +747,8 @@
                                         os.makedirs(basedir, misc.PKG_DIR_MODE)
                                 except Exception, e:
                                         error(_("Unable to create basedir "
-                                            "'%s': %s") % (basedir, e))
+                                            "'%(dir)s': %(err)s") %
+                                            {"dir": basedir, "err": e})
                                         abort()
 
                 xport_cfg.pkg_root = basedir
--- a/src/setup.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/setup.py	Fri Nov 02 11:42:49 2012 +1300
@@ -37,6 +37,7 @@
 import py_compile
 import hashlib
 import time
+import StringIO
 
 from distutils.errors import DistutilsError, DistutilsFileError
 from distutils.core import setup
@@ -730,7 +731,7 @@
                         rm_f(dst)
                         os.symlink(src, dst)
 
-def run_cmd(args, swdir, updenv=None, ignerr=False):
+def run_cmd(args, swdir, updenv=None, ignerr=False, savestderr=None):
                 if updenv:
                         # use temp environment modified with the given dict
                         env = os.environ.copy()
@@ -741,6 +742,8 @@
                 if ignerr:
                         # send stderr to devnull
                         stderr = open(os.devnull)
+                elif savestderr:
+                        stderr = savestderr
                 else:
                         # just use stderr of this (parent) process
                         stderr = None
@@ -877,6 +880,50 @@
         print " ".join(args)
         run_cmd(args, os.getcwd(), updenv={"LC_ALL": "C"})
 
+def i18n_check():
+        """Checks for common i18n messaging bugs in the source."""
+
+        src_files = []
+        # A list of the i18n errors we check for in the code
+        common_i18n_errors = [
+            # This checks that messages with multiple parameters are always
+            # written using "%(name)s" format, rather than just "%s"
+            "format string with unnamed arguments cannot be properly localized"
+        ]
+
+        for line in open("po/POTFILES.in", "r").readlines():
+                if line.startswith("["):
+                        continue
+                if line.startswith("#"):
+                        continue
+                src_files.append(line.rstrip())
+
+        args = [
+            "/usr/gnu/bin/xgettext", "--from-code=UTF-8", "-o", "/dev/null"]
+        args += src_files
+
+        xgettext_output_path = tempfile.mkstemp()[1]
+        xgettext_output = open(xgettext_output_path, "w")
+        run_cmd(args, os.getcwd(), updenv={"LC_ALL": "C"},
+            savestderr=xgettext_output)
+
+        found_errs = False
+        i18n_errs = open("po/i18n_errs.txt", "w")
+        for line in open(xgettext_output_path, "r").readlines():
+                for err in common_i18n_errors:
+                        if err in line:
+                                i18n_errs.write(line)
+                                found_errs = True
+        i18n_errs.close()
+        if found_errs:
+                print >> sys.stderr, \
+"The following i18n errors were detected and should be corrected:\n" \
+"(this list is saved in po/i18n_errs.txt)\n"
+                for line in open("po/i18n_errs.txt", "r"):
+                        print >> sys.stderr, line.rstrip()
+                sys.exit(1)
+        os.remove(xgettext_output_path)
+
 def msgfmt(src, dst):
         if not dep_util.newer(src, dst):
                 return
@@ -1227,6 +1274,7 @@
         def run(self):
                 # Anything that gets created here should get deleted in
                 # clean_func.run() below.
+                i18n_check()
                 for f in intl_files:
                         intltool_merge(f, f[:-3])
 
@@ -1292,6 +1340,7 @@
                 rm_f("gui/help/C/pkg_help.pot")
 
                 rm_f("gui/help/package-manager-__LOCALE__.omf")
+                rm_f("po/i18n_errs.txt")
 
 class clobber_func(Command):
         user_options = []
--- a/src/tests/cli/t_pkg_image_create.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/tests/cli/t_pkg_image_create.py	Fri Nov 02 11:42:49 2012 +1300
@@ -257,7 +257,7 @@
                 saved_sysrepo_env = os.environ.get("PKG_SYSREPO_URL")
                 os.environ["PKG_SYSREPO_URL"] = "http://localhost:1"
                 self.pkg("image-create --no-refresh --set-property \
-                    use-system-repo=true %s"  %(img_path))
+                    use-system-repo=true %s" % img_path)
                 shutil.rmtree(img_path)
                 if saved_sysrepo_env:
                         os.environ["PKG_SYSREPO_URL"] = saved_sysrepo_env
--- a/src/util/publish/pkgdiff.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/util/publish/pkgdiff.py	Fri Nov 02 11:42:49 2012 +1300
@@ -144,7 +144,8 @@
         # of the same name have the same values defined.
         for k in set(v1.keys()) & set(v2.keys()):
                 if v1[k] != v2[k]:
-                        error(_("Manifests support different variants %s %s") % (v1, v2))
+                        error(_("Manifests support different variants "
+                            "%(v1)s %(v2)s") % {"v1": v1, "v2": v2})
 
         # Now, get a list of all possible variant values, including None
         # across all variants and both manifests
--- a/src/util/publish/pkglint.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/util/publish/pkglint.py	Fri Nov 02 11:42:49 2012 +1300
@@ -239,13 +239,15 @@
                         f = codecs.open(filename, "rb", "utf-8")
                         data = f.read()
                 except UnicodeDecodeError, e:
-                        lint_logger.critical(_("Invalid file %s: "
-                            "manifest not encoded in UTF-8: %s") %
-                            (filename, e), msgid="lint.manifest002")
+                        lint_logger.critical(_("Invalid file %(file)s: "
+                            "manifest not encoded in UTF-8: %(err)s") %
+                            {"file": filename, "err": e},
+                            msgid="lint.manifest002")
                         continue
                 except IOError, e:
                         lint_logger.critical(_("Unable to read manifest file "
-                        "%s: %s") % (filename, e), msgid="lint.manifest001")
+                            "%(file)s: %(err)s") % {"file": filename, "err": e},
+                            msgid="lint.manifest001")
                         continue
                 lines.append(data)
                 linecnt = len(data.splitlines())
--- a/src/util/publish/pkgmogrify.py	Wed Oct 31 10:48:34 2012 -0700
+++ b/src/util/publish/pkgmogrify.py	Fri Nov 02 11:42:49 2012 +1300
@@ -79,8 +79,9 @@
                         attrdict[a] = re.compile(attrdict[a])
                 except re.error, e:
                         raise RuntimeError, \
-                            _("transform (%s) has regexp error (%s) in matching clause"
-                            ) % (transform, e)
+                            _("transform (%(transform)s) has regexp error "
+                            "(%(err)s) in matching clause"
+                            ) % {"transform": transform, "err": e}
 
         op = s[index+2:].strip().split(None, 1)
 
@@ -215,8 +216,9 @@
                         regexp = args[1]
                 except re.error, e:
                         raise RuntimeError, \
-                            _("transform (%s) has 'edit' operation with malformed "
-                              "regexp (%s)") % (transform, e)
+                            _("transform (%(transform)s) has 'edit' operation "
+                            "with malformed regexp (%(err)s)") % \
+                            {"transform": transform, "err": e}
 
                 if len(args) == 3:
                         replace = args[2]
@@ -249,8 +251,10 @@
                                 ]
                         except re.error, e:
                                 raise RuntimeError, \
-                                    _("transform (%s) has edit operation with replacement"
-                                      "string regexp error %e") % (transform, e)
+                                    _("transform (%(transform)s) has edit "
+                                    "operation with replacement string regexp "
+                                    "error %(err)e") % \
+                                    {"transform": transform, "err": e}
                         return action
 
                 operation = replace_func
@@ -272,8 +276,9 @@
                         regexp = re.compile(args[1])
                 except re.error, e:
                         raise RuntimeError, \
-                            _("transform (%s) has 'delete' operation with malformed "
-                            "regexp (%s)") % (transform, e)
+                            _("transform (%(transform)s) has 'delete' operation"
+                            "with malformed regexp (%(err)s)") % \
+                            {"transform": transform, "err": e}
 
                 def delete_func(action, matches, pkg_attrs, filename, lineno):
                         val = attrval_as_list(action.attrs, attr)
@@ -292,8 +297,10 @@
                                         del action.attrs[attr]
                         except re.error, e:
                                 raise RuntimeError, \
-                                    _("transform (%s) has delete operation with replacement"
-                                      "string regexp error %e") % (transform, e)
+                                    _("transform (%(transform)s) has delete "
+                                    "operation with replacement string regexp "
+                                    "error %(err)e") % \
+                                    {"transform": transform, "err": e}
                         return action
 
                 operation = delete_func
@@ -454,8 +461,9 @@
                 ref = int(i.string[slice(*i.span())][2:-1])
 
                 if ref == 0 or ref > len(backrefs) - 1:
-                        raise RuntimeError, _("no match group %d (max %d)") % \
-                            (ref, len(backrefs) - 1)
+                        raise RuntimeError, _("no match group %(group)d "
+                            "(max %(maxgroups)d)") % \
+                            {"group": ref, "maxgroups": len(backrefs) - 1}
 
                 newmsg += msg[prevend:i.start()] + backrefs[ref]
                 prevend = i.end()