view data/plugin/action/CheckTranslation.py @ 499:25702a913bdd

CheckTranslation: added supplying list of pages with the same master-page special comment for every page in page set.
author Eugene Syromyatnikov <evgsyr@gmail.com>
date Wed, 17 Feb 2010 04:22:17 +0300
parents c5ffd7c05b90
children 31e327c450ca
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - CheckTranslation.py

    shows a table of System Pages and their translations to the users language
    if the users language is anything else than en

    @copyright: 2009 MoinMoin:ReimarBauer,
                2009 MoinMoin:ThomasWaldmann,
                2009 MoinMoin:EugeneSyromyatnikov
    @license: GNU GPL, see COPYING for details.
"""

import re, time, calendar
from MoinMoin import i18n, search
from MoinMoin.i18n import strings
i18n.strings = strings

from MoinMoin.Page import Page
from MoinMoin.util.dataset import TupleDataset, Column
from MoinMoin.widget.browser import DataBrowserWidget

# for this action's output, we want everything RED that does not exist
css_style_defs = """
<style type="text/css">
a.nonexistent:link, a.nonexistent:visited, a.nonexistent:hover { color: red; }
</style>
"""

translation_warnings = {
    'missing_master_page_meta': True,
    'wrong_master_page': True,
    'missing_master_date_or_rev_meta': True,
    'outdated_master_rev': True,
    'outdated_master_date': True,
    'not_in_i18n_strings_pages': True,
}

master_meta_names = ['page', 'date', 'revision']

special_comment_re = r'(?im)^##master-%(meta)s[ :][ \t]*(?P<%(meta)s>[^\n]*)[ \t]*$'

date_format_guesses = [
    '%Y-%m-%dT%H:%M:%SZ',
    '%Y-%m-%d %H:%M:%S',
    '%Y-%m-%d',
]

def _get_master_metas(text):
    result = {}

    for meta in master_meta_names:
        m = re.search(special_comment_re % {'meta': meta}, text)
        if m:
            result[meta] = m.group(meta)

    return result

def execute(pagename, request):
    _ = request.getText

    pageset_name = request.values.get('pageset')
    if pageset_name not in i18n.strings.pagesets:
        pageset_name = 'all_pages'
    pageset = getattr(i18n.strings, pageset_name)
    not_translated_system_pages_set = getattr(i18n.strings, "not_translated_system_pages")

    if pagename.startswith(u"MoinI18n/"):
        # if we get called from one of the pages on MoinMaster that contain
        # the .po file data, we assume that user wants to check THAT language:
        lang_default = pagename[9:]
    else:
        # use browser/settings language
        lang_default = request.lang or 'en'
    lang = request.values.get('language') or lang_default
    wiki_languages = sorted(i18n.wikiLanguages().keys())
    if lang not in wiki_languages:
        msg = _("We have no translation for '%s', falling back to 'en'!") % lang
        request.theme.add_msg(msg, "err")
        lang = 'en'

    def trans(text, request=request, lang=lang, **kw):
        return i18n.getText(text, request, lang, **kw)

    data = TupleDataset()
    data.columns = [
           Column('en', label=_('Original page') + " " + _("(Link, Size, Last-Edit)")),
           Column(lang, label=_('Translated page') + " " + _("(Link, Size, Last-Edit)")),
        ]

    edit_querystr = {'action': 'edit', 'editor': 'text'}
    edit_attrs = {'name': 'editlink', 'rel': 'nofollow', }
    raw_querystr = {'action': 'raw'}

    search_results = set([p.page_name for p in search.searchPages(request, 'lang:%s' % lang,
                                     titlesearch=1, sort='page_name').hits])

    all_page_trans_set = set([trans(p) for p in i18n.strings.all_pages])
    all_related_page_set = search_results | all_page_trans_set
    not_listed_page_list = list(search_results - all_page_trans_set)

    not_listed_page_list.sort()

    page_objs = {}
    page_metas = {}
    page_translations = {}

    for page_name in all_related_page_set:
        page_objs[page_name] = Page(request, page_name)
        page_metas[page_name] = _get_master_metas(page_objs[page_name].body)

    for page_name, page_meta in page_metas.iteritems():
        if 'page' in page_meta and page_name != trans(page_meta['page']):
            if page_meta['page'] in page_translations:
                page_translations[page_meta['page']].append(page_name)
            else:
                page_translations[page_meta['page']] = [page_name]

    for orig_page_name in pageset:
        trans_page_name = trans(orig_page_name)
        orig_page = Page(request, orig_page_name)
        trans_page = page_objs[trans_page_name]

        orig_status = [
            orig_page.link_to(request, orig_page_name) + " " +
            orig_page.link_to(request, "[raw]", querystr=raw_querystr) + " " +
            orig_page.link_to(request, "[edit]", querystr=edit_querystr, **edit_attrs)
        ]
        info = "%d" % orig_page.size()
        last_edit = orig_page.lastEditInfo()
        if last_edit:
            info += " %(editor)s %(time)s" % last_edit
        orig_status.append(info)
        trans_status = [trans_page_name]
        if trans_page_name not in not_translated_system_pages_set:
            trans_status = [
                            trans_page.link_to(request, trans_page_name) + " " +
                            trans_page.link_to(request, "[raw]", querystr=raw_querystr) + " " +
                            trans_page.link_to(request, "[edit]", querystr=edit_querystr, **edit_attrs)
                            ]
            info = "%d" % trans_page.size()
            last_edit = trans_page.lastEditInfo()
            if last_edit:
                info += " %(editor)s %(time)s" % last_edit
            trans_status.append(info)

            if trans_page_name == orig_page_name and orig_page_name not in i18n.strings.admin_pages:
                 trans_status.append(_(u'/!\\ Page is untranslated.', wiki=True))

            if trans_page_name != orig_page_name and trans_page.exists():
                if trans_page.pi['language'] != lang:
                    trans_status.append(_('/!\\ Translated page language ("%(page_lang)s") is not "%(lang)s"', wiki=True) % {
                        'lang': request.formatter.text(lang),
                        'page_lang': request.formatter.text(trans_page.pi['language']),
                    })

                master_metas = page_metas[trans_page_name]

                if 'page' in master_metas:
                    if master_metas['page'] != orig_page_name and translation_warnings['wrong_master_page']:
                        trans_status.append(_(u'/!\\ Translated page has ##master-page special comment with value other than "%(orig_page)s" (current value is "%(master_page)s").', wiki=True) % {
                            'orig_page': request.formatter.text(orig_page_name),
                            'master_page': request.formatter.text(master_metas['page']),
                        })
                else:
                    if translation_warnings['missing_master_page_meta']:
                        trans_status.append(_('/!\\ Translated page has no ##master-page special comment. Please, add line "##master-page:%s" somewhere at beginning of the translated page.', wiki=True) % request.formatter.text(orig_page_name))

                if 'date' not in master_metas and 'revision' not in master_metas and translation_warnings['missing_master_date_or_rev_meta']:
                    trans_status.append(_('/!\\ Translated page has neither of ##master-date or ##master-revision special comments. Please, add at least one.', wiki=True))

                if 'revision' in master_metas:
                    orig_page_rev = orig_page.get_rev()[1]
                    master_rev = master_metas['revision']

                    try:
                        rev_num = int(master_rev)
                    except ValueError:
                        trans_status.append(_('/!\\ ##master-revision special comment can\'t be parsed. Value of special comment: "%s". Please use correct revision number.', wiki=True) % request.formatter.text(master_rev))
                    else:
                        if rev_num < orig_page_rev and translation_warnings['outdated_master_rev']:
                            trans_status.append(_('(!) Translated page is outdated: it is based on revision %(trans_rev)s, but original page has revision %(orig_rev)s. %(diff_link)s.', wiki=True) % {
                                'orig_rev': request.formatter.text(orig_page_rev),
                                'trans_rev': request.formatter.text(master_rev),
                                'diff_link': orig_page.link_to(request, on=1, querystr={
                                    'action': 'diff',
                                    'rev1': request.formatter.text(master_rev),
                                    }) + request.formatter.text(_("Diff of original page")) + orig_page.link_to(request, on=0),
                            })

                if 'date' in master_metas and translation_warnings['outdated_master_date']:
                    master_date = None
                    for guess in date_format_guesses:
                        try:
                            master_date = time.strptime(master_metas['date'], guess)
                            break
                        except ValueError:
                            pass

                    if not master_date:
                        trans_status.append(_('/!\\ ##master-date special comment can\'t be parsed. Value of special comment: "%s". Please use ISO format (yyyy-mm-dd HH:MM:SS) or @TIMESTAMP@ variable.', wiki=True) % request.formatter.text(master_metas['date']))
                    else:
                        orig_date = time.gmtime(orig_page.mtime_usecs() / 1000000.0)
                        orig_date_s = time.strftime('%Y-%m-%d %H:%M:%S', orig_date)

                        if master_date < orig_date:
                            trans_status.append(_('(!) Translated page is outdated: it has master date %(master_date)s, but original page last edited at %(orig_date)s. %(diff_link)s.', wiki=True) % {
                                'orig_date': request.formatter.text(orig_date_s),
                                'master_date': request.formatter.text(time.strftime('%Y-%m-%d %H:%M:%S', master_date)),
                                'diff_link': orig_page.link_to(request, on=1, querystr={
                                    'action': 'diff',
                                    'date': (calendar.timegm(master_date) * 1000000),
                                    }) + request.formatter.text(_("Diff of original page")) + orig_page.link_to(request, on=0),
                            })

        if orig_page_name in page_translations:
            trans_list = []

            for page in page_translations[orig_page_name]:
                trans_list.append(page_objs[page].link_to(request, page))

            trans_status.append(_('<!> List of pages with same #master-page:', wiki=True) + " " + ", ".join(trans_list))

        data.addRow(("<br>".join(orig_status), "<br>".join(trans_status)))


    not_listed = []

    if search_results and translation_warnings['not_in_i18n_strings_pages']:
        not_listed += [
                       request.formatter.heading(1, 3),
                       request.formatter.text(_('Pages with language "%s" not listed above:') % lang),
                       request.formatter.heading(0, 3),
                      ]

        not_listed.append(request.formatter.number_list(1))
        for page in not_listed_page_list:
            not_listed += [
                           request.formatter.listitem(1),
                           page_objs[page].link_to(request, page),
                           request.formatter.listitem(0),
                          ]
        not_listed.append(request.formatter.number_list(0))


    table = DataBrowserWidget(request)
    table.setData(data)
    page_table = ''.join(table.format(method='GET'))

    fmt = request.formatter
    this_page = Page(request, pagename)
    lang_links = [this_page.link_to_raw(request, _lang,
                                        querystr={'action': 'CheckTranslation',
                                                  'language': _lang,
                                                  'pageset': pageset_name, })
                  for _lang in wiki_languages if _lang != "en"]


    lang_selector = u''.join([fmt.paragraph(1), _("Choose:"), ' ', ' '.join(lang_links), fmt.paragraph(0)])

    pageset_links = [this_page.link_to_raw(request, _pageset_name,
                                           querystr={'action': 'CheckTranslation',
                                                     'language': lang,
                                                     'pageset': _pageset_name, })
                     for _pageset_name in i18n.strings.pagesets]

    po_pagename = "MoinI18n/%s" % lang
    po_page = Page(request, po_pagename)
    edit_po_page = ""
    if po_page.exists():
        edit_po_page = po_page.link_to(request, "[edit]", querystr=edit_querystr, **edit_attrs)
    lang_i18n = u''.join([fmt.paragraph(1), _("Based on: %s ") % po_pagename, edit_po_page, fmt.paragraph(0)])

    pageset_selector = u''.join([fmt.paragraph(1), _("Choose:"), ' ', ' '.join(pageset_links), fmt.paragraph(0)])
    title = _("Checking translation '%s' for page set '%s'") % (lang, pageset_name)
    request.theme.send_title(title, page=request.page, pagename=pagename)
    request.write(request.formatter.rawHTML(css_style_defs))
    request.write(request.formatter.startContent("content"))
    request.write(lang_i18n)
    request.write(lang_selector)
    request.write(pageset_selector)
    request.write(page_table)
    request.write(''.join(not_listed))
    request.write(request.formatter.endContent())
    request.theme.send_footer(pagename)
    request.theme.send_closing_html()