def _fmt_header (self, accl, lang, title, stylepath=None, dctlpath=None, phpincpath=None): """ If C{phpincpath} is given, then PHP inclusion for it is issued in the body, while C{stylepath} and C{dctlpath} are ignored. Otherwise, HTML inclusions for C{stylepath} and C{dctlpath} are issued in the header (if given themselves). """ if not phpincpath: accl("<?xml version='1.0' encoding='UTF-8'?>"); accl( "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " + "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>"); accl( "<!-- " + p_('comment in generated files (warning to user)', '===== AUTOGENERATED FILE, DO NOT EDIT =====') + " -->") accl(stag("html", {"xmlns":"http://www.w3.org/1999/xhtml", "lang":lang, "xml:lang":lang})) accl(stag("head"), 1) accl(stag("meta", {"http-equiv":"Content-type", "content":"text/html; charset=UTF-8"}, close=True), 2) if not phpincpath: if stylepath: accl(stag("link", {"rel":"stylesheet", "type":"text/css", "href":stylepath}, close=True), 2) if dctlpath: accl(wtext("", "script", {"type":"text/javascript", "src":dctlpath}), 2) accl(wtext(title, "title"), 2) accl(etag("head"), 1) accl(stag("body"), 1) if phpincpath: accl("<?php include('%s'); ?>" % phpincpath, 2) accl()
def _fmt_concept (self, accl, concept): gloss, lang, env = self._gloss, self._lang, self._env tf = self._tf fle = self._by_langenv_fmt fdesc = fle(concept.desc) if fdesc: accl(wtext(fdesc, "descrip", {"type":"definition"})) for tkey in concept.topic: ftname = fle(gloss.topics[tkey].name) if ftname: accl(wtext(ftname, "descrip", {"type":"subjectField"})) # Sort languages by key, but pivotal first. alangs = concept.term.langs() alangs.remove(lang) alangs.sort() alangs.insert(0, lang) for clang in alangs: accl(stag("langSet", {"xml:lang":clang})) accl(stag("ntig"), 1) for term in concept.term(clang, env): tpack = [(term.nom, term.gr)] if clang in self._options.wdecl: tpack += [(x, x.gr) for x in term.decl] for gnode, gr in tpack: accl(stag("termGrp"), 2) fterm = tf(gnode.text) accl(wtext(fterm, "term"), 3) if gr: fgname = fle(gloss.grammar[gr].shortname) if fgname: accl(wtext(fgname, "termNote", {"type":"partOfSpeech"}), 3) accl(etag("termGrp"), 2) accl(etag("ntig"), 1) accl(etag("langSet"))
def _fmt_prologue (self, accl): gloss, lang, env = self._gloss, self._lang, self._env fle = self._by_langenv_fmt accl("<?xml version='1.0' encoding='UTF-8'?>"); accl( "<!DOCTYPE martif " + "PUBLIC 'ISO 12200:1999A//DTD MARTIF core (DXFcdV04)//EN' " + "'TBXcdv04.dtd' " + ">"); accl( "<!-- " + p_('comment in generated files (warning to user)', '===== AUTOGENERATED FILE, DO NOT EDIT =====') + " -->") accl(stag("martif", {"type":"TBX", "xml:lang":lang})) accl(stag("martifHeader"), 1) accl(stag("fileDesc"), 2) accl(stag("titleStmt"), 3) ftitle = fle(gloss.title) if not ftitle: ftitle = p_("glossary title, when undefined", "Unnamed") if env: fenv = fle(gloss.environments[env].name) if fenv: ftitle = p_("glossary title format", "%(title)s (%(env)s)") \ % dict(title=ftitle, env=fenv) accl(wtext(ftitle, "title"), 4) accl(etag("titleStmt"), 3) accl(etag("fileDesc"), 2) accl(etag("martifHeader"), 1) accl(stag("text"), 1)
def __call__ (self, gloss): self._indent = " " # Resolve languages and environment. olang = self._options.olang if olang not in gloss.languages: error(p_("error message", "origin language '%(lang)s' not present in the glossary") % dict(lang=olang)) tlang = self._options.tlang if tlang not in gloss.languages: error(p_("error message", "target language '%(lang)s' not present in the glossary") % dict(lang=tlang)) env = self._options.env or gloss.env[0] if env is not None and env not in gloss.environments: error(p_("error message", "environment '%(env)s' not defined by the glossary") % dict(env=env)) # Select all concepts which have a term in both langenvs. concepts = {} for ckey, concept in gloss.concepts.iteritems(): if concept.term(olang, env) and concept.term(tlang, env): concepts[ckey] = concept if not concepts: warning(p_("warning message", "no concepts found which have terms in both " "the origin and the target language and environment")) # Prepare text formatters. refbase = dict([(ckey, "") for ckey in concepts]) tfn = TextFormatterPlain(gloss, lang=tlang, env=env) tf = TextFormatterHtml(gloss, lang=tlang, env=env, refbase=refbase) tfp = TextFormatterHtml(gloss, lang=tlang, env=env, refbase=refbase, wtag="p") # Dictionary is presented as follows: # - all unique terms in the origin language presented # - for each unique origin term, all corresponding unique terms # in the target language presented # - for each unique (origin, target) term pair, the descriptions of # all concepts named by it are presented in the target language # Collect dict(oterm: dict(tterm: set(ckey))) # Collect dict(tterm: dict(gr: set(decl))) tdecls = {} bidict = {} for ckey, concept in concepts.iteritems(): oterms = concept.term(olang, env) tterms = concept.term(tlang, env) for oterm in oterms: otnom = tfn(oterm.nom.text) if otnom not in bidict: bidict[otnom] = {} for tterm in tterms: # Target terms. ttnom = tfn(tterm.nom.text) if ttnom not in bidict[otnom]: bidict[otnom][ttnom] = set() bidict[otnom][ttnom].add(ckey) # Declensions. if ttnom not in tdecls: tdecls[ttnom] = {} for decl in tterm.decl: gr = gloss.grammar[decl.gr] grnam = tfn(gr.shortname(tlang, env)[0].text) if grnam not in tdecls[ttnom]: tdecls[ttnom][grnam] = set() ttdecl = tfn(decl.text) tdecls[ttnom][grnam].add(ttdecl) # Alphabetically sort origin terms. oterms_sorted = bidict.keys() langsort(oterms_sorted, olang) # Compose the dictionary table. accl = LineAccumulator(self._indent, 2) accl(stag("table", {"class":"bd-table"})) accl() # Header. accl(stag("tr", {"class":"bd-header"}), 1) olname = tfn(gloss.languages[olang].name(tlang, env)[0].text) accl(wtext(olname, "th", {"class":"bd-header-ol"}), 2) tlname = tfn(gloss.languages[tlang].name(tlang, env)[0].text) accl(wtext(tlname, "th", {"class":"bd-header-tl"}), 2) accl(etag("tr"), 1) # Entries by origin term. anchored = {} n_entry = 0 n_entry_by_alpha = 0 curr_alpha = None for oterm in oterms_sorted: n_entry += 1 n_entry_by_alpha += 1 # Add new alphabetical separator if needed. prev_alpha = curr_alpha curr_alpha = _term_alpha(oterm) if prev_alpha != curr_alpha: n_entry_by_alpha = 1 accl(stag("tr", {"class":"bd-alsep"}), 1) accl(wtext(curr_alpha, "td", {"class":"bd-alsep-al", "colspan":"2"}), 2) accl(etag("tr"), 1) # Collapse all target terms which have same concepts. # Sort them alphabetically within the group, # then groups alphabetically by first term in the group. tterms_by_ckeygr = {} for tterm in bidict[oterm]: ckeys = list(bidict[oterm][tterm]) ckeys.sort() ckeygr = tuple(ckeys) if ckeygr not in tterms_by_ckeygr: tterms_by_ckeygr[ckeygr] = [] tterms_by_ckeygr[ckeygr].append(tterm) tterms_groups = [] for ckeys, tterms in tterms_by_ckeygr.iteritems(): langsort(tterms, tlang) tterms_groups.append((tterms[0], tterms, ckeys)) langsort_tuples(tterms_groups, 0, tlang) tterms_ckeys = [x[1:] for x in tterms_groups] if n_entry_by_alpha % 2 == 1: accl(stag("tr", {"class":"bd-entry-odd"}), 1) else: #accl(stag("tr", {"class":"bd-entry-even"}), 1) #... provide as option; randomly increases VCS deltas. accl(stag("tr", {"class":"bd-entry-odd"}), 1) # Column with origin term and anchors. accl(stag("td", {"class":"bd-oterm"}), 2) # Dummy anchors, for cross-references in descriptions to work. # Add anchors for all concepts covered by this entry, # and remember them, to avoid duplicate anchors on synonyms. new_ckeys = [] for tterms, ckeys in tterms_ckeys: for ckey in ckeys: if ckey not in anchored: anchored[ckey] = True new_ckeys.append(ckey) accl("".join([stag("span", {"id":x}, close=True) for x in new_ckeys]), 3) # Origin term. accl(wtext(oterm, "p", {"class":"bd-otline"}), 3) accl(etag("td"), 2) # Column with target terms. accl(stag("td", {"class":"bd-tterms"}), 2) n_ttgr = 0 for tterms, ckeys in tterms_ckeys: n_ttgr += 1 accl(stag("div", {"class":"bd-ttgroup"}), 3) # Equip each term with extra info. tterms_compgr = [] for tterm in tterms: # Declensions. lsep_dc = p_("list separator: " "acceptable variants of the same declension", ", ") fmt_dcgr = p_("declension group: single declension given " "by its name and acceptable variants", "<i>%(dname)s</i> %(dvars)s") lsep_gr = p_("list separator: " "declension groups", "; ") tdecl = None if tterm in tdecls: lst = [] for gr, decls in tdecls[tterm].iteritems(): lst2 = list(decls) langsort(lst2, tlang) lst.append((gr, lsep_dc.join(lst2))) langsort_tuples(lst, 0, tlang) tdecl = lsep_gr.join([fmt_dcgr % dict(dname=x[0], dvars=x[1]) for x in lst]) # Compose. if tdecl: ttcgr = p_("term with declensions", "%(term)s (%(decls)s)") \ % dict(term=tterm, decls=tdecl) else: ttcgr = tterm tterms_compgr.append(ttcgr) # Collect details for each term. has_details = False # - descriptions descstrs = [] for ckey in ckeys: for desc in concepts[ckey].desc(tlang, env): if tfn(desc.text): descstrs.append(tfp(desc.text, pclass="bd-desc")) has_details = True if len(descstrs) > 1: for i in range(len(descstrs)): dhead = "%d. " % (i + 1) descstrs[i] = descstrs[i].replace(">", ">" + dhead, 1) # Entry display control (if any details present). details_id = "opt_%s_%d" % (oterm.replace(" ", "_"), n_ttgr) if has_details: accl(stag("div", {"class":"bd-edctl"}), 4) accl(wtext("[+]", "a", {"class":"bd-edctl", "title":p_("tooltip", "Show details"), "href":"#", "onclick":"return show_hide(this, '%s')" % details_id}), 5) accl(etag("div"), 4) # Line with terms. lsep_tt = p_("list separator: synonymous terms", ", ") ttstr = lsep_tt.join(tterms_compgr) if len(tterms_ckeys) > 1: ttstr = p_("enumerated target term in the dictionary, " "one of the meanings of the original term", "%(num)d. %(term)s") \ % dict(num=n_ttgr, term=ttstr) accl(wtext(ttstr, "p", {"class":"bd-ttline"}), 4) # Optional details. if has_details: accl(stag("div", {"id":details_id, "style":"display: none;"}), 4) for descstr in descstrs: accl(descstr, 5) accl(etag("div"), 4) accl(etag("div"), 3) accl(etag("td"), 2) accl(etag("tr"), 1) accl() accl(etag("table")) accl() # Prepare style file path. stylepath = None if self._options.style: if self._options.cssfile: stylepath = self._options.cssfile else: stylepath = _replace_ext(os.path.basename(self._options.file), "css") stylepath_nr = os.path.join(os.path.dirname(self._options.file), stylepath) stylesrc = os.path.join( _src_style_dir, self._options.style + ".css.in") # Prepare JavaScript file path. dctlpath = None if self._options.jsfile: dctlpath = self._options.jsfile else: dctlpath = _replace_ext(os.path.basename(self._options.file), "js") dctlpath_nr = os.path.join(os.path.dirname(self._options.file), dctlpath) # Prepare PHP inclusion file path. phpincpath = None if self._options.incfile: phpincpath = self._options.incfile else: phpincpath = _replace_ext(os.path.basename(self._options.file), "inc") phpincpath_nr = os.path.join(os.path.dirname(self._options.file), phpincpath) # If style requested, fetch the .in file and resolve placeholders. if self._options.style: # Parse values given in the command line. stodict = dict([x[:2] for x in _styleopt_spec]) for sopt in self._options.styleopt: lst = [x.strip() for x in sopt.split("=", 1)] if len(lst) < 2: warning(p_("warning message", "malformed CSS style option '%(opt)s'") % dict(opt=sopt)) continue name, value = lst if name not in stodict: warning(p_("warning message", "unknown CSS style option '%(opt)s'") % dict(opt=sopt)) continue stodict[name] = value # Replace placeholders in the input style sheet. raccl = LineAccumulator() raccl.read(stylesrc) styleaccl = LineAccumulator() sto_rx = re.compile("@(\w+)@") for line in raccl.lines: nline = "" lastpos = 0 for m in sto_rx.finditer(line): nline += line[lastpos:m.span()[0]] lastpos = m.span()[1] soname = m.group(1) sovalue = stodict.get(soname) if soname not in stodict: error(p_("error message", "unknown CSS style option '%(opt)s' " "requested by the input style sheet " "'%(fname)s'") % dict(opt=soname, fname=stylesrc)) nline += sovalue nline += line[lastpos:] styleaccl(nline) # Create separate CSS and JS files, or raw inclusion file, # or collect everything for direct embedding. auxaccl = None if not self._options.phpinc and not self._options.allinone: shutil.copyfile(_src_dctl_file, dctlpath_nr) if self._options.style: styleaccl.write(stylepath_nr) phpincpath = None # _fmt_header checks this for what to include else: raccl = LineAccumulator() raccl("<script type='text/javascript'>") raccl.read(_src_dctl_file) raccl("</script>") raccl() if self._options.style: raccl("<style type='text/css'>") raccl(styleaccl) raccl("</style>") raccl() if not self._options.allinone: raccl.write(phpincpath_nr) else: auxaccl = raccl # Header. accl_head = LineAccumulator(self._indent, 0) if not self._options.header: gname = tfn(gloss.title(tlang, env)[0].text) if env: ename = tfn(gloss.environments[env].name(tlang, env)[0].text) title = p_("top page title", "%(gloss)s (%(env)s)") \ % dict(gloss=gname, env=ename) else: title = gname self._fmt_header(accl_head, tlang, title, stylepath, dctlpath, phpincpath) else: accl_head.read(self._options.header) # Footer. accl_foot = LineAccumulator(self._indent, 0) if not self._options.footer: self._fmt_footer(accl_foot) else: accl_foot.read(self._options.footer) # Collect everything and write out the HTML page. accl_all = LineAccumulator(self._indent, 0) accl_all(accl_head) if auxaccl: accl_all(auxaccl, 2) accl_all(accl) accl_all(accl_foot) accl_all.write(self._options.file)