def __call__ (self, gloss): self._indent = " " self._gloss = gloss # Resolve pivotal language and environment. self._lang = self._options.lang or gloss.lang if self._lang not in gloss.languages: error(p_("error message", "language '%(lang)s' not present in the glossary") % dict(lang=self._lang)) self._env = self._options.env or gloss.env[0] if self._env and self._env not in gloss.environments: error(p_("error message", "environment '%(env)s' not defined by the glossary") % dict(env=self._env)) # Determine concepts to present and in which order. concepts = self._select_concepts() # Prepare text formatters. self._tf = TextFormatterPlain(gloss, lang=self._lang, env=self._env, escape=escape_xml) # Create TBX. accl = LineAccumulator(self._indent) self._fmt_prologue(accl) self._fmt_concepts(accl.newind(2), concepts) self._fmt_epilogue(accl) if self._options.file: tbx_fname = self._options.file else: tbx_fname = gloss.id + ".tbx" accl.write(tbx_fname)
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)