# 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: shared-mime-info, " "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. " "Most of the other domains are used by a relatively " "small number of people.


") write(' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n') for domain in registry.domain_list(): if domain.disclaim: hue = "#fff3f3" word = "Yes" else: hue = "#f3fff3" word = "" write(' \n' ' \n' % (hue, domain.name, domain.name)) if postats.potstats.has_key(domain.name): hints = registry.hints(postats.potstats[domain.name][0]) write(' \n' % (hue, hints.template_url(), hints.version)) else: write(' \n') sys.stderr.write(" * No stats for '%s'\n" % domain.name) write('' % (hue, word)) if domain.ref: write(' \n' % (hue, domain.ref[0][1], domain.ref[0][1])) else: write(' \n' % hue) write(' \n') write('
DomainCurrent
version
Disclaimer
required
Reference
%s%s-%s%s--
\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' ' \n' ' \n' ' \n' % domain.name) for ref in domain.ref: write(' \n' ' \n' ' \n' ' \n' % (ref[0], ref[1], ref[1])) write('
TopicURL
%s%s
\n') if domain.note: write(' \n') if domain.disclaim: write('

The maintainer of this package requires that' ' disclaimers be filled out and sent to the' ' Free Software Foundation before accepting PO files' ' from the Translation Project.

\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') write('

The following table lists (under Version) all the' ' PO files that are available for this domain:

\n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \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 = "#f8d0f8" # Magenta: external but file is present. else: color = "#e8e8e8" # Grey: plain external. write('' '' '' '' '\n' % (team.code, team.language, team.code, color, numbers)) else: build_language_cell(postats, write, team, domain) write('
LanguageCodePackage versionLast translatorTranslated
%s%s--external%s
\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 national 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' ' \n' ' \n' ' \n' ' \n') for team in registry.team_list(): write(' \n' ' \n' ' \n' % (team.code, team.language, team.code)) if team.mailto: write(' \n' % (team.mailto[0], team.mailto[0])) else: write(' \n') write(' \n') write('
LanguageCodeTeam address
%s%s%s
\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.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' ' \n' ' \n' ' \n' % team.language) for ref in team.ref: write(' \n' ' \n' ' \n' ' \n' % (ref[0], ref[1], ref[1])) write('
TopicURL
%s%s
\n') write('

The %s team currently consists of' ' the following translators:

\n' ' \n' ' \n' ' \n' ' \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' ' \n' % translator_best_href(translator)) if domain_count: write(' \n' % domain_count) else: write(' \n') if translator.disclaimer: write(' \n') else: write(' \n') if translator.autosend == "compress": write(' \n') elif translator.autosend: write(' \n') else: write(' \n') write(' \n') write('
TranslatorAssignmentsDisclaimedAutosend
%s%dyescompressplain-
\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' ' \n' ' \n' ' \n' ' \n') # Construct the table of packages. for domain in registry.domain_list(): if domain.disclaim: hue = "#fff3f3" else: hue = "#f3fff3" write(' \n' ' \n' % (hue, domain.name, domain.name)) extstats = None file = '%s/%s/%s.po' % (config.last_path, domain.name, team.name) try: template, tally = 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 = "#f8d0f8" # Magenta: external but file present. else: color = "#e8e8e8" # Grey: external. if extstats: numbers = ("%d / %d" % (extstats['translated'], tally)) else: numbers = "unknown" 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) else: reference = ('%s' % (config.pots_dir, domain.name, version, version)) color = "#d0f0f8" # Blue: fully untranslated. numbers = "%d / %d" % (0, tally) write(' \n' ' \n' % (reference, color, numbers)) else: write(' \n') if assigned_domains.has_key(domain.name): write(' \n' % translator_best_href(assigned_domains[domain.name])) elif team.code in domain.ext: write(' \n') extstats = get_extstats().get((domain.name, team.code)) else: write(' \n') write(' \n') write('
DomainLast
known
version
 Translated  Assigned translator 
' '%s%s%s%sexternal
\n') 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 palette = ['#ff7777', '#f7bf77', '#efdf77', '#efef8f', '#dfef77', '#bff777', '#77ff77'] def colorize(translated, total): if total == 0: return "#d7d7d7" if translated > total: return "#00f8f8" return palette[6 * translated / total]