# Project-specific webpage generation services.
# -*- mode: python; coding: utf-8 -*-
# Copyright © 2001, 2002, 2003, 2004, 2007 Translation Project.
# Copyright © 2000 Progiciels Bourbeau-Pinard inc.
# François Pinard , 2000.
import os, string, sys, glob
import config, htmlpage, registry, data
try:
unicode
have_unicode = 1
except NameError:
have_unicode = 0
_extstats = None
def get_extstats():
global _extstats
if _extstats is None:
_extstats = data.load_extstats()
return _extstats
def generate_domain_page(domain):
if domain == "index":
file = "%s/index.html" % config.domain_path
return produce_domain_index(file)
sys.stderr.write("Generating domain page for %s...\n" % domain)
file = "%s/%s.html" % (config.domain_path, domain)
produce_domain_page(data.load_postats(), domain, file)
def generate_team_page(team):
if team == "index":
file = "%s/index.html" % config.team_path
return produce_team_index(file)
sys.stderr.write("Generating team page for %s...\n" % team)
file = "%s/%s.html" % (config.team_path, team)
produce_team_page(data.load_postats(), team, file)
# Generation of webpages describing domains.
def produce_domain_index(output=None):
DomainIndex(output)
class DomainIndex(htmlpage.Htmlpage):
def __init__(self, output):
htmlpage.Htmlpage.__init__(self, None, output)
write = self.writer
if not write:
return
postats = data.load_postats()
self.prologue("Textual domains", 'utf-8')
write("When looking for something to translate and wishing "
"to reach the largest amount of users, one of the basic "
"system tools is a good choice: grep, sed, tar, findutils, "
"coreutils, and bash. After those: "
"xdg-user-dirs, parts of libc and parts of util-linux-ng. "
"And then maybe aspell, dialog, diffutils, e2fsprogs, gawk, "
"kbd, make, psmisc, texinfo, wget, and xkeyboard-config.
")
write(' \n'
' \n'
' Domain | \n'
' Current version | \n'
' Made | \n'
' Disclaimer required | \n'
' Reference | \n'
'
\n')
for domain in registry.domain_list():
if domain.disclaim:
hue = "needsDisclaimer"
word = "Yes"
else:
hue = "noDisclaimer"
word = " "
write(' \n'
' %s | \n'
% (hue, domain.name, domain.name))
if postats.potstats.has_key(domain.name):
hints = registry.hints(postats.potstats[domain.name][0])
write(' %s | \n'
% (hints.template_url(), hints.version))
write(' %s | \n'
% (postats.potstats[domain.name][2]))
else:
write(' --- | \n | \n')
sys.stderr.write(" * No stats for '%s'\n" % domain.name)
write(' %s | \n' % (word))
if domain.ref:
write(' %s | \n'
% (domain.ref[0][1], domain.ref[0][1]))
else:
write(' -- | \n')
write('
\n')
write('
\n')
self.epilogue()
def produce_domain_page(postats, name, output=None):
DomainPage(postats, registry.domain(name), output)
class DomainPage(htmlpage.Htmlpage):
def __init__(self, postats, domain, output):
htmlpage.Htmlpage.__init__(self, None, output)
write = self.writer
if not write:
return
self.prologue("The %s textual domain" % domain.name, 'utf-8')
if not domain.ref:
write(' This page is about the translation of the messages'
' for the %s textual domain.
\n' % domain.name)
else:
write(' This page is about the translation of the messages'
' for the %s textual domain. More information'
' about the package can be found here:
\n'
' \n'
' \n'
' Topic | \n'
' URL | \n'
'
\n'
% domain.name)
for ref in domain.ref:
write(' \n'
' %s | \n'
' %s | \n'
'
\n'
% (ref[0], ref[1], ref[1]))
write('
\n')
if domain.note:
write(' \n')
for note in domain.note:
write(' - %s
' % note)
write('
\n')
write(' If you\'ve found a translation mistake in one of the messages'
' of %s, please report it to the email address that is'
' given on the relevant language page.
\n' % domain.name)
if domain.disclaim:
write(' The maintainer of this package requires that'
' a disclaimer be filled out and sent to the'
' Free Software Foundation before accepting'
' a PO file from the translator.
\n')
else:
write(' The maintainer does not require any special papers'
' prior to accepting translations.
\n')
if postats.potstats.has_key(domain.name):
file = postats.potstats[domain.name][0]
url = registry.hints(file).template_url()
write(' The current template for this domain is'
' %s.\n' % (url, file))
if domain.url:
write('
The following URL may help translators that need'
' a finer context in order to make their translation. '
' Be aware that the indicated package could be just'
' a pre-release, and might not even compile:
\n')
write(' \n')
for url in domain.url:
write(' - %s
\n' % (url, url))
write('
\n')
write(' The following table lists (under Version) all the'
' PO files that are available for this domain:
\n'
' \n'
' \n'
' Language | \n'
' Code | \n'
' Package version | \n'
' Last translator | \n'
' Translated | \n'
'
\n')
for team in registry.team_list():
if team.code in domain.ext:
stats = get_extstats().get((domain.name, team.name))
if stats:
trans = stats['translated']
total = trans + stats['untranslated'] + stats['fuzzy']
numbers = "%s / %s" % (trans, total)
else:
numbers = "unknown"
if os.path.isfile('%s/%s/%s.po'
% (config.last_path, domain.name, team.name)):
color = "externalButPresent"
else:
color = "external"
write(''
'%s | '
'%s | -- | '
'external | '
'%s |
\n'
% (team.code, team.language, team.code, color, numbers))
else:
build_language_cell(postats, write, team, domain)
write('
\n')
self.epilogue()
def build_language_cell(postats, write, team, domain):
table = []
names = glob.glob("%s/%s/%s-[0-9]*.%s.po" %
(config.pos_path, team.name, domain.name, team.name))
for filename in names:
try:
hints = registry.Hints(filename)
except KeyError:
sys.stderr.write(" * Nonexistent domain or team: %s\n" % filename)
continue
except ValueError:
sys.stderr.write(" * No hints found for %s\n" % filename)
continue
if hints.domain != domain and hints.team != team:
sys.stderr.write(" * Wrong domain or team in %s\n" % filename)
continue
if hints.version is None:
sys.stderr.write(" * Missing version number in %s\n" % filename)
continue
key = hints.domain.name, hints.version.name, hints.team.name
if not postats.has_key(key):
sys.stderr.write(" * Not in stats database: %s\n" % filename)
continue
(translator, mailto, translated, total) = postats[key][:4]
table.append((hints.version, translator, mailto, translated, total))
if table:
table.sort()
for counter in range(len(table)):
write(' \n')
if counter == 0:
write(' '
'%s | \n'
' %s | \n'
% (len(table), team.code, team.language,
len(table), team.code))
version, translator, mailto, translated, total = table[counter]
write(' %s | \n'
% (config.pos_dir, team.name, domain.name,
version.name, team.name, version.name))
try:
transinfo = registry.registry.translator_info
email = transinfo(team, translator)['mailto'][0]
except (IndexError, KeyError):
email = mailto
if email:
write(' %s | \n'
% (scramble(email), translator))
else:
write(' %s | \n' % translator)
write(' %d / %d | \n'
% (colorize(translated, total), translated, total))
write('
\n')
# Generation of webpages describing language teams.
def produce_team_index(output=None):
TeamIndex(output)
class TeamIndex(htmlpage.Htmlpage):
def __init__(self, output):
htmlpage.Htmlpage.__init__(self, None, output)
write = self.writer
if not write:
return
self.prologue("Translation teams", 'utf-8')
write(' \n'
' \n'
' Language | \n'
' Code | \n'
' Team address | \n'
'
\n')
for team in registry.team_list():
write(' \n'
' %s | \n'
' %s | \n'
% (team.code, team.language, team.code))
if team.mailto:
write(' %s | \n'
% (team.mailto[0], team.mailto[0]))
else:
write(' | \n')
write('
\n')
write('
\n')
self.epilogue()
def produce_team_page(postats, name, output=None):
TeamPage(postats, registry.team(name), output)
class TeamPage(htmlpage.Htmlpage):
def __init__(self, postats, team, output):
htmlpage.Htmlpage.__init__(self, None, output)
write = self.writer
if not write:
return
self.prologue("Translation team for %s" % team.language, 'utf-8')
assigned_domains = {}
seen_translators = []
write(' The %s translation team uses %s
as'
' its language code. This code is part of the %s PO file'
' names. It is also sometimes used as a short identification'
' for the team.
\n'
% (team.language, team.code, team.language))
write(' \n')
if team.mailto:
write(' The team uses %s as official'
' email address, which reaches either a mailing list or'
' someone who broadcasts information to all other team'
' members.\n'
% (team.mailto[0], team.mailto[0]))
if team.leader and team.leader.mailto:
name = uni2html(team.leader.uniname()[0],'utf-8')
if team.leader.can_show_mail():
write(' %s'
' currently acts as the team leader,'
% (team.leader.mailto[0], name))
elif team.leader.url:
write(' %s'
' currently acts as the team leader,'
% (team.leader.url[0], name))
else:
write(' %s currently acts as the team leader,' % name)
write(' and you may write to him or her for all matters related'
' to team coordination.\n')
elif team.mailto:
write(' The team does not seem to have appointed a leader, so'
' for any questions you may write to the above team address.'
' To get a package assigned, you can write directly to a'
' '
'TP coordinator while CC\'ing the team list.\n')
else:
write(' The team does not seem to have appointed a leader, so'
' for any questions or to get a package assigned, you may'
' write directly to a'
' '
'TP coordinator.\n')
if team.mailto:
write(' If you\'ve found a translation error in one of the'
' PO files listed below, please report it to the above'
' email address.\n')
if team.charset:
write(' Team members expressed a preference towards using the'
' %s
charset. '
' You may want to consider using it whenever you send email'
' to the team list or members, or if you produce any'
' translation file meant for this team.\n'
% team.charset)
write('
\n')
if team.ref:
write(' You can get more information about the'
' %s effort here:
\n'
' \n'
' \n'
' Topic | \n'
' URL | \n'
'
\n'
% team.language)
for ref in team.ref:
write(' \n'
' %s | \n'
' %s | \n'
'
\n'
% (ref[0], ref[1], ref[1]))
write('
\n')
write(' The %s team currently consists of'
' the following translators:
\n'
' \n'
' \n'
' \n'
' Translator | \n'
' Assignments | \n'
' Disclaimed | \n'
' Autosend | \n'
'
\n'
' \n'
' \n'
% team.language)
# Construct the table of translators.
for name in team.translators:
translator = registry.translator(team, name)
domain_count = 0
if translator.name[0] in seen_translators:
continue
seen_translators.append(translator.name[0])
for domain in translator.do:
if assigned_domains.has_key(domain.name):
sys.stderr.write(" * Domain multiply assigned: %s.%s\n"
% (domain.name, team.name))
assigned_domains[domain.name] = translator
domain_count = domain_count + 1
write(' \n'
' %s | \n'
% translator_best_href(translator))
if domain_count:
write(' %d | \n' % domain_count)
else:
write(' | \n')
if translator.disclaimer:
write(' yes | \n')
else:
write(' | \n')
if translator.autosend == "compress":
write(' compress | \n')
elif translator.autosend:
write(' plain | \n')
else:
write(' - | \n')
write('
\n')
write(' \n
\n')
write(' The Autosend column is for translators who want the PO'
' file sent to them when a new POT file is added to the project'
' -- they don\'t want to fetch the PO file themselves, but'
' wish to receive it together with the notice. '
' '
'Just ask if you want this service for yourself.
\n')
write(' Here is the current list of assignments of textual domains'
' to translators, as known to the Translation Project registry. '
' The robot relies on this information for directly accepting'
' submissions from translators. '
' The domains with a pinkish background'
' require that the translator has filled out a disclaimer;'
' those with a greenish background are freely translatable.'
' If you find some error or omission on this page, please write')
if team.leader and team.leader.mailto and team.leader.can_show_mail():
write(' to %s to get it corrected.
\n'
% (team.leader.mailto[0],
uni2html(team.leader.uniname()[0],'utf-8')))
elif team.leader and team.leader.url:
write(' to %s to get it corrected.
\n'
% (team.leader.url[0],
uni2html(team.leader.uniname()[0],'utf-8')))
else:
write(' to a '
'TP coordinator to get it corrected.\n')
write(' \n'
' \n'
' \n'
' Domain | \n'
' Version | \n'
' Translated | \n'
' Updated | \n'
' Assigned translator | \n'
'
\n'
' \n'
' \n')
# Construct the table of packages.
for domain in registry.domain_list():
if domain.disclaim:
hue = "restricted"
else:
hue = "liberal"
write(' \n'
' '
'%s | \n'
% (hue, domain.name, domain.name))
extstats = None
file = '%s/%s/%s.po' % (config.last_path, domain.name, team.name)
try:
template, tally, date = postats.potstats[domain.name]
version = registry.hints(template).version
except KeyError:
version = None
if version:
key = domain.name, version.name, team.name
if team.code in domain.ext:
reference = '%s' % version
if os.path.isfile(file):
color = "externalButPresent"
else:
color = "external"
if extstats:
numbers = ("%d / %d" % (extstats['translated'], tally))
else:
numbers = "unknown"
date = ' '
elif postats.has_key(key):
reference = ('%s'
% (config.pos_dir, team.name,
domain.name, version, team.name, version))
translated = postats[key][2]
numbers = "%d / %d" % (translated, tally)
color = colorize(translated, tally)
date = postats[key][7]
else:
reference = ('%s'
% (config.pots_dir, domain.name, version,
version))
color = "untranslated"
numbers = "%d / %d" % (0, tally)
date = " "
write(' %s | \n'
' %s | \n'
' %s | \n'
% (reference, color, numbers, date))
else:
write(' | \n')
if assigned_domains.has_key(domain.name):
write(' %s | \n'
% translator_best_href(assigned_domains[domain.name]))
elif team.code in domain.ext:
write(' external | \n')
extstats = get_extstats().get((domain.name, team.code))
else:
write(' | \n')
write('
\n')
write(' \n
\n
')
write(' For backup purposes, each month a '
' tarball containing all the above PO files is made.
\n' % team.code)
self.epilogue()
def translator_best_href(translator):
name = uni2html(translator.uniname()[0], 'utf-8')
if translator.mailto and translator.can_show_mail():
return ('%s'
% (scramble(translator.mailto[0]), name))
else:
return name
_entities = {}
def _uni2html(char):
if not _entities:
for i in range(32,128):
_entities[unichr(i)] = chr(i)
import htmlentitydefs
for k,v in htmlentitydefs.entitydefs.items():
if len(v) == 1:
v = unicode(v,"latin-1")
else:
v = unichr(int(v[2:-1]))
_entities[v] = '&'+k+';'
try:
return _entities[char]
except KeyError:
return '%d;' % ord(char)
if have_unicode:
def uni2html(str, code = None):
if code:
try:
return str.encode(code)
except UnicodeError:
pass
return string.join(map(_uni2html, str), "")
else:
def uni2html(str, code = None):
assert string.lower(code)=="utf-8"
return str
def scramble(email):
email = string.replace(email, "@", " (at) ")
email = string.replace(email, ".", " (dot) ")
return email
def colorize(translated, total):
if total == 0:
return "empty"
if translated > total:
return "overflow"
else:
return "level" + str(6 * translated / total)