[PATCH 1 of 1 STABLE] i18n: add the tool to check Mercurial specific translation problems in *.po

Martin Geisler martin at geisler.net
Fri Nov 29 02:35:56 CST 2013


FUJIWARA Katsunori <foozy at lares.dti.ne.jp> writes:

> # HG changeset patch
> # User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
> # Date 1385560052 -32400
> #      Wed Nov 27 22:47:32 2013 +0900
> # Branch stable
> # Node ID e55c09427e9ada3e218ee8cba0b598e35f293183
> # Parent  2ca325ea57fa13909e28cc2caeae3c73e60693f8
> i18n: add the tool to check Mercurial specific translation problems in *.po
>
> Existing tool like "msgfmt --check" can check typical translation
> problems (missing "%s" in msgstr, for example), but can't check
> Mercurial specific ones.
>
> For example, "msgfmt --check" can't check whether the translated
> string given to "ui.promptchoice()" is correct or not, even though
> problems like below cause run-time error or unexpected behavior:
>
>   - less or more choices than msgid,
>   - choices without '&', or
>   - choices with '&' followed by none
>
> This patch adds the tool to check Mercurial specific translation
> problems in *.po files.
>
> diff --git a/i18n/check-translation.py b/i18n/check-translation.py
> new file mode 100644
> --- /dev/null
> +++ b/i18n/check-translation.py
> @@ -0,0 +1,148 @@
> +#!/usr/bin/env python
> +#
> +# check-translation.py - check Mercurial specific translation problems
> +
> +import polib
> +import re
> +
> +checkers = []
> +
> +def checker(level, msgidpat):
> +    def decorator(func):
> +        if msgidpat:
> +            match = re.compile(msgidpat).search
> +        else:
> +            match = lambda msgid: True
> +        checkers.append((func, level))
> +        func.match = match
> +        return func
> +    return decorator
> +
> +def match(checker, pe):
> +    """Examine whether POEntry "pe" is target of specified checker or not
> +    """
> +    if not checker.match(pe.msgid):
> +        return
> +    # examine suppression by translator comment
> +    nochecker = 'no-%s-check' % checker.__name__
> +    for tc in pe.tcomment.split():
> +        if nochecker == tc:
> +            return
> +    return True
> +
> +####################
> +
> +def fatalchecker(msgidpat=None):
> +    return checker('fatal', msgidpat)
> +
> + at fatalchecker(r'\$\$')
> +def promptchoice(pe):
> +    """Check translation of the string given to "ui.promptchoice()"
> +
> +    >>> pe = polib.POEntry(
> +    ...     msgid ='prompt$$missing &sep$$missing &amp$$followed by &none',
> +    ...     msgstr='prompt  missing &sep$$missing  amp$$followed by none&')
> +    >>> match(promptchoice, pe)
> +    True
> +    >>> for e in promptchoice(pe): print e
> +    number of choices differs between msgid and msgstr
> +    msgstr has invalid choice missing '&'
> +    msgstr has invalid '&' followed by none
> +    """
> +    idchoices = [c.rstrip(' ') for c in pe.msgid.split('$$')[1:]]
> +    strchoices = [c.rstrip(' ') for c in pe.msgstr.split('$$')[1:]]

Super idea with such a tool!

My only comment is that you might want to reuse the code in ui.py that
does the splitting, stripping, and slicing. However, after looking it
up, I see that this code is burried inside promptchoice. I don't know if
refactoring this is worth the effort.

-- 
Martin Geisler


More information about the Mercurial-devel mailing list