view data/plugin/action/ @ 465:fc9cdf513432 Added several features to action. * List of pages in translated language not in i18n.strings['all_pges'] * Warnings about missing or wrong special comments * Information about outdated translations based on special comments
author Eugene Syromyatnikov <>
date Mon, 21 Dec 2009 12:58:23 +0300
parents cbc739f4e5eb
children b7757d0badd7
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
    MoinMoin -

    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
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; }

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,

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

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

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:]
        # 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'}

    for orig_page_name in pageset:
        trans_page_name = trans(orig_page_name)
        orig_page = Page(request, orig_page_name)
        trans_page = Page(request, 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
        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

            if 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_meta_names = ['page', 'date', 'rev']
                master_metas = {}

                for meta in master_meta_names:
                    m = % {'meta': meta}, trans_page.body)
                    if m:
                        master_metas[meta] =

                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']),
                    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 'rev' 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-rev special comments. Please, add at least one.', wiki=True))

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

                        rev_num = int(master_rev)
                    except ValueError:
                        trans_status.append(_('/!\\ ##master_date special comment can\'t be parsed. Value of special comment: "%s". Please use correct revision number.', wiki=True) % request.formatter.text(master_rev))
                        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.', wiki=True) % {
                                'orig_rev': request.formatter.text(orig_page_rev),
                                'trans_rev': request.formatter.text(master_rev),

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

                    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 @DATE@/@TIME@ variables.', wiki=True) % request.formatter.text(master_metas['date']))
                        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.', 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)),

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

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

    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),

        for page in search_results:
            not_listed += [
                           request.formatter.pagelink(1, page),

    table = DataBrowserWidget(request)
    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,, pagename=pagename)