include src/librarian/pdf/*
include src/librarian/fb2/*
include src/librarian/fonts/*
+recursive-include src/librarian/locale *.po *.mo
graft src/librarian/res
graft src/librarian/font-optimizer
--- /dev/null
+locale:
+ find src/librarian -name '*.py' |xargs xgettext --from-code utf-8 -o - | sed '/^"POT-Creation-Date:/d' > messages.pot
+ for lang in pl; do msgmerge -U src/librarian/locale/$${lang}/LC_MESSAGES/messages.po messages.pot; done
+ rm messages.pot
+
package_dir={"": "src"},
package_data={'librarian': ['xslt/*.xslt', 'xslt/*.xml', 'epub/*', 'pdf/*', 'fb2/*', 'fonts/*'] +
whole_tree(os.path.join(os.path.dirname(__file__), 'src/librarian'), 'res') +
- whole_tree(os.path.join(os.path.dirname(__file__), 'src/librarian'), 'font-optimizer')},
+ whole_tree(os.path.join(os.path.dirname(__file__), 'src/librarian'), 'font-optimizer') +
+ whole_tree(os.path.join(os.path.dirname(__file__), 'src/librarian'), 'locale')},
include_package_data=True,
install_requires=[
'lxml>=2.2,<=4.3',
+from collections import OrderedDict
from .txt import TxtBuilder
-from .html import HtmlBuilder
+from .html import HtmlBuilder, StandaloneHtmlBuilder
from .sanitize import Sanitizer
-builders = [
- TxtBuilder,
- HtmlBuilder,
- Sanitizer,
-]
-
-
-def get_builder_class(builder_id):
- return next(b for b in builders if b.identifier == builder_id)
+builders = OrderedDict([
+ ("txt", TxtBuilder),
+ ("html", HtmlBuilder),
+ ("html-standalone", StandaloneHtmlBuilder),
+ ("sanitizer", Sanitizer),
+])
+# coding: utf-8
+from __future__ import unicode_literals
+
from lxml import etree
+from librarian.html import add_anchors, add_table_of_contents, add_table_of_themes
from librarian import OutputFile
def __init__(self, image_location='https://wolnelektury.pl/media/book/pictures/marcos-historia-kolorow/'):
self.image_location = image_location
- #self.tree = etree.Element('html')
- #body = etree.SubElement(self.tree, 'body')
- #text = etree.SubElement(body, 'div', **{'id': 'book-text'})
self.tree = text = etree.Element('div', **{'id': 'book-text'})
- toc = etree.SubElement(text, 'div', id='toc')
- themes = etree.SubElement(text, 'div', id='themes')
- h1 = etree.SubElement(text, 'h1')
+ self.header = etree.SubElement(text, 'h1')
+
+ self.footnotes = etree.Element('div', id='footnotes')
+ self.footnote_counter = 0
+
+ self.nota_red = etree.Element('div', id='nota_red')
self.cursors = {
None: text,
- 'toc': toc,
- 'themes': themes,
- 'header': h1,
+ 'header': self.header,
+ 'footnotes': self.footnotes,
+ 'nota_red': self.nota_red,
}
self.current_cursors = [None]
+ @property
+ def cursor(self):
+ return self.cursors[self.current_cursors[-1]]
+
+ @cursor.setter
+ def cursor(self, value):
+ self.cursors[self.current_cursors[-1]] = value
+
def enter_fragment(self, fragment):
self.current_cursors.append(fragment)
def exit_fragment(self):
self.current_cursors.pop()
-
+
+ def create_fragment(self, name, element):
+ assert name not in self.cursors
+ self.cursors[name] = element
+
+ def forget_fragment(self, name):
+ del self.cursors[name]
+
+ def preprocess(self, document):
+ document._compat_assign_ordered_ids()
+ document._compat_assign_section_ids()
+
def build(self, document):
+ self.preprocess(document)
document.tree.getroot().html_build(self)
+ self.postprocess(document)
- head = etree.Element('head')
- self.tree.insert(0, head)
- etree.SubElement(
- head,
- 'link',
- href="https://static.wolnelektury.pl/css/compressed/book_text.b15153e56c0a.css",
- rel="stylesheet",
- type="text/css",
- )
-
return OutputFile.from_bytes(
etree.tostring(
self.tree,
)
)
- def start_element(self, tag, attrib):
- self.cursors[self.current_cursors[-1]] = etree.SubElement(
- self.cursors[self.current_cursors[-1]],
+ def postprocess(self, document):
+ _ = document.tree.getroot().master.gettext
+
+ if document.meta.translators:
+ self.enter_fragment('header')
+ self.start_element('span', {'class': 'translator'})
+ self.push_text(_("translated by") + " ")
+ self.push_text(
+ ", ".join(
+ translator.readable()
+ for translator in document.meta.translators
+ )
+ )
+ self.exit_fragment()
+
+ add_anchors(self.tree)
+ if len(self.nota_red):
+ self.tree.append(self.nota_red)
+ add_table_of_themes(self.tree)
+ add_table_of_contents(self.tree)
+
+ if self.footnote_counter:
+ fnheader = etree.Element("h3")
+ fnheader.text = _("Footnotes")
+ self.footnotes.insert(0, fnheader)
+ self.tree.append(self.footnotes)
+
+ def start_element(self, tag, attrib=None):
+ self.cursor = etree.SubElement(
+ self.cursor,
tag,
- **attrib
+ **(attrib or {})
)
- print(self.cursors)
def end_element(self):
- self.cursors[self.current_cursors[-1]] = self.cursors[self.current_cursors[-1]].getparent()
+ self.cursor = self.cursor.getparent()
def push_text(self, text):
- cursor = self.cursors[self.current_cursors[-1]]
+ if text == 'Między nami nic nie było':
+ print(self.cursors)
+ print(self.current_cursors)
+ cursor = self.cursor
if len(cursor):
- cursor.tail = (cursor[-1].tail or '') + text
+ cursor[-1].tail = (cursor[-1].tail or '') + text
else:
cursor.text = (cursor.text or '') + text
+
+
+class StandaloneHtmlBuilder(HtmlBuilder):
+ def postprocess(self, document):
+ super(StandaloneHtmlBuilder, self).postprocess(document)
+
+ tree = etree.Element('html')
+ body = etree.SubElement(tree, 'body')
+ body.append(self.tree)
+ self.tree = tree
+
+ head = etree.Element('head')
+ tree.insert(0, head)
+
+
+ etree.SubElement(head, 'meta', charset='utf-8')
+ etree.SubElement(head, 'title').text = document.meta.title
+
+ etree.SubElement(
+ head,
+ 'meta',
+ name="viewport",
+ content="width=device-width, initial-scale=1, maximum-scale=1"
+ )
+
+ etree.SubElement(
+ head,
+ 'link',
+ href="https://static.wolnelektury.pl/css/compressed/book_text.css",
+ rel="stylesheet",
+ type="text/css",
+ )
+
+ etree.SubElement(
+ body, 'script',
+ src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
+ )
+
+ etree.SubElement(
+ body,
+ "script",
+ src="http://malsup.github.io/min/jquery.cycle2.min.js"
+ )
self.enter_fragment('header')
if meta.translators:
- self.push_text("tłum. ", 'header')
- for translator in meta.translators:
- self.push_text(translator.readable())
+ self.push_text("tłum. ")
+ self.push_text(
+ ", ".join(
+ translator.readable()
+ for translator in meta.translators
+ )
+ )
#builder.push_margin(2)
self.push_legacy_margin(1)
parser.add_argument(
'builder',
- choices=[b.identifier for b in builders],
+ choices=builders.keys(),
help="Builder"
)
parser.add_argument('input_file')
)
args = parser.parse_args()
+ builder = builders[args.builder]
if args.output_file:
output_file_path = args.output_file
+import gettext
+import os
+import re
from lxml import etree
-from .builders import get_builder_class
+from .builders import builders
from .parser import parser
from . import dcparser
+from .functions import lang_code_3to2
class WLDocument:
return master.meta
def build(self, builder_id, **kwargs):
- return get_builder_class(builder_id)().build(self, **kwargs)
-
+ return builders[builder_id]().build(self, **kwargs)
+
+ def _compat_assign_ordered_ids(self):
+ """
+ Compatibility: ids in document order, to be roughly compatible with legacy
+ footnote ids. Just for testing consistency, change to some sane identifiers
+ at convenience.
+ """
+ EXPR = re.compile(r'/\s', re.MULTILINE | re.UNICODE)
+ def _compat_assign_ordered_ids_in_elem(elem, i):
+ elem.attrib['_compat_ordered_id'] = str(i)
+ i += 1
+ if getattr(elem, 'HTML_CLASS', None) == 'stanza':
+ if elem.text:
+ i += len(EXPR.split(elem.text)) - 1
+ for sub in elem:
+ i = _compat_assign_ordered_ids_in_elem(sub, i)
+ if sub.tail:
+ i += len(EXPR.split(sub.tail)) - 1
+ else:
+ if elem.tag in ('uwaga', 'extra'):
+ return i
+ for sub in elem:
+ i = _compat_assign_ordered_ids_in_elem(sub, i)
+ return i
+
+ _compat_assign_ordered_ids_in_elem(self.tree.getroot(), 4)
+
+ def _compat_assign_section_ids(self):
+ """
+ Ids in master-section order. These need to be compatible with the
+ #secN anchors used by WL search results page to link to fragments.
+ """
+ def _compat_assigns_section_ids_in_elem(elem, prefix='sec'):
+ for i, child in enumerate(elem):
+ idfier = '{}{}'.format(prefix, i + 1)
+ child.attrib['_compat_section_id'] = idfier
+ _compat_assigns_section_ids_in_elem(child, idfier + '-')
+ _compat_assigns_section_ids_in_elem(self.tree.getroot().master)
+
"dlugi_cytat": blocks.DlugiCytat,
"poezja_cyt": blocks.PoezjaCyt,
"dlugi_cyt": blocks.DlugiCytat, ### ???
+ "ramka": blocks.Ramka,
"slowo_obce": styles.SlowoObce,
"tytul_dziela": styles.TytulDziela,
"kwestia": drama.Kwestia,
"didask_tekst": drama.DidaskTekst,
- "dedykacja": paragraphs.Akap,
- "miejsce_czas": paragraphs.Akap,
+ "dedykacja": blocks.Dedykacja,
+ "miejsce_czas": drama.MiejsceCzas,
"uwaga": comments.Uwaga,
"wers": poetry.Wers,
"wers_wciety": poetry.WersWciety,
"wers_cd": poetry.WersCd,
- "wers_akap": poetry.Wers,
+ "wers_akap": poetry.WersAkap,
"zastepnik_wersu": poetry.ZastepnikWersu,
- "wers_do_prawej": poetry.Wers,
+ "wers_do_prawej": poetry.WersDoPrawej,
- "pa": footnotes.Footnote,
- "pe": footnotes.Footnote,
- "pr": footnotes.Footnote,
- "pt": footnotes.Footnote,
+ "pa": footnotes.PA,
+ "pe": footnotes.PE,
+ "pr": footnotes.PR,
+ "pt": footnotes.PT,
"begin": themes.Begin,
"end": themes.End,
"nota": blocks.Nota,
- "nota_red": comments.Abstrakt,
+ "nota_red": comments.NotaRed,
"extra": comments.Abstrakt,
"abstrakt": comments.Abstrakt,
"naglowek_rozdzial": headers.NaglowekRozdzial,
"naglowek_podrozdzial": headers.NaglowekPodrozdzial,
"srodtytul": headers.NaglowekCzesc,
+ "podtytul_czesc": headers.PodtytulCzesc,
+ "podtytul_akt": headers.PodtytulCzesc,
+ "podtytul_scena": headers.PodtytulRozdzial,
+ "podtytul_rozdzial": headers.PodtytulRozdzial,
+ "podtytul_podrozdzial": headers.PodtytulPodrozdzial,
"naglowek_listy": drama.NaglowekListy,
"sekcja_swiatlo": separators.SekcjaSwiatlo,
"separator_linia": separators.SeparatorLinia,
- "wieksze_odstepy": styles.Wyroznienie,
- "mat": styles.Wyroznienie,
- "www": styles.Wyroznienie,
- "indeks_dolny": styles.Wyroznienie,
+ "wieksze_odstepy": styles.WiekszeOdstepy,
+ "mat": styles.Mat,
+ "www": styles.WWW,
+ "indeks_dolny": styles.IndeksDolny,
- "tabela": paragraphs.Akap,
- "tabelka": paragraphs.Akap,
- "wiersz": paragraphs.Akap,
- "kol": paragraphs.Akap,
+ "tabela": figures.Tabela,
+ "tabelka": figures.Tabela,
+ "wiersz": figures.Wiersz,
+ "kol": figures.Kol,
+ "animacja": figures.Animacja,
"ilustr": figures.Ilustr,
-# sklodowska-badanie-cial-radioaktywnych.xml
- "mrow": paragraphs.Akap,
- "mi": paragraphs.Akap,
- "mo": paragraphs.Akap,
- "msup": paragraphs.Akap,
- "mn": paragraphs.Akap,
- "mfrac": paragraphs.Akap,
- "mfenced": paragraphs.Akap,
+ # Inline MathML, should really be namespaced.
+ "mrow": etree.ElementBase,
+ "mi": etree.ElementBase,
+ "mo": etree.ElementBase,
+ "msup": etree.ElementBase,
+ "mn": etree.ElementBase,
+ "mfrac": etree.ElementBase,
+ "mfenced": etree.ElementBase,
}
import re
from lxml import etree
from librarian import dcparser, RDFNS
+from librarian.util import get_translation
class WLElement(etree.ElementBase):
HTML_TAG = None
HTML_ATTR = {}
HTML_CLASS = None
- HTML_SECTION = False
CAN_HAVE_TEXT = True
STRIP = False
else:
self._meta_object = None
return self._meta_object
-
+
@property
def meta(self):
if self.meta_object is not None:
return self.getparent().meta
else:
return self.document.base_meta
-
+
+ @property
+ def gettext(self):
+ return get_translation(self.meta.language).gettext
+
def normalize_text(self, text):
text = text or ''
for e, s in self.text_substitutions:
# always copy the id attribute (?)
if self.attrib.get('id'):
attr['id'] = self.attrib['id']
+ elif '_compat_section_id' in self.attrib:
+ attr['id'] = self.attrib['_compat_section_id']
return attr
-
- def html_build(self, builder):
- if self.HTML_SECTION:
- builder.start_element(
- 'a', {"name": "f18", "class": "target"}
- )
- builder.push_text(" ")
- builder.end_element()
-
- builder.start_element(
- "a", {"href": "#f18", "class": "anchor"}
- )
- builder.push_text("18")
- builder.end_element()
-
+ def html_build(self, builder):
if self.HTML_TAG:
builder.start_element(
self.HTML_TAG,
self.get_html_attr(builder),
)
- if self.HTML_SECTION:
- builder.start_element(
- "a", {"name": "sec34"}
- )
- builder.end_element()
-
self._html_build_inner(builder)
if self.HTML_TAG:
builder.end_element()
+from .dedykacja import Dedykacja
from .dlugi_cytat import DlugiCytat
from .nota import Nota
from .poezja_cyt import PoezjaCyt
+from .ramka import Ramka
+
--- /dev/null
+from ..base import WLElement
+
+
+class Dedykacja(WLElement):
+ TXT_LEGACY_TOP_MARGIN = 2
+
+ HTML_TAG = "div"
+ HTML_CLASS = "dedication"
TXT_BOTTOM_MARGIN = 2
TXT_LEGACY_TOP_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 0
+
+ HTML_TAG = 'blockquote'
class Nota(WLElement):
CAN_HAVE_TEXT = False
+
+ HTML_TAG = "div"
+ HTML_CLASS = "note"
TXT_BOTTOM_MARGIN = 3
TXT_LEGACY_TOP_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 0
+
+ HTML_TAG = 'blockquote'
--- /dev/null
+from ..base import WLElement
+
+
+class Ramka(WLElement):
+ HTML_TAG = "div"
+ HTML_CLASS = "ramka"
+
from .abstrakt import Abstrakt
+from .nota_red import NotaRed
from .uwaga import Uwaga
--- /dev/null
+from ..base import WLElement
+
+
+class NotaRed(WLElement):
+ def txt_build(self, builder):
+ pass
+
+ def html_build(self, builder):
+ builder.enter_fragment('nota_red')
+ super(NotaRed, self).html_build(builder)
+ builder.exit_fragment()
def txt_build(self, builder):
pass
+ def html_build(self, builder):
+ pass
from .kwestia import Kwestia
from .lista_osoba import ListaOsoba
from .lista_osob import ListaOsob
+from .miejsce_czas import MiejsceCzas
from .naglowek_listy import NaglowekListy
from .naglowek_osoba import NaglowekOsoba
from .osoba import Osoba
class DidaskTekst(WLElement):
TXT_PREFIX = "/ "
TXT_SUFFIX = " /"
+
+ HTML_TAG = "em"
+ HTML_CLASS = "didaskalia"
TXT_PREFIX = "/ "
TXT_SUFFIX = " /"
+ HTML_TAG = "div"
+ HTML_CLASS = "didaskalia"
class Kwestia(WLElement):
CAN_HAVE_TEXT = False
+ HTML_TAG = "div"
+ HTML_CLASS = "kwestia"
+from lxml import etree
from ..base import WLElement
TXT_LEGACY_TOP_MARGIN = 3
TXT_LEGACY_BOTTOM_MARGIN = 1
+ HTML_TAG = "div"
+ HTML_CLASS = "person-list"
+
+ def _html_build_inner(self, builder):
+ ol = etree.Element('ol')
+ builder.create_fragment('list', ol)
+ super(ListaOsob, self)._html_build_inner(builder)
+ builder.cursor.append(ol)
+ builder.forget_fragment('list')
TXT_LEGACY_BOTTOM_MARGIN = 0
TXT_PREFIX = " * "
+ HTML_TAG = "li"
+
+ def html_build(self, builder):
+ builder.enter_fragment('list')
+ super(ListaOsoba, self).html_build(builder)
+ builder.exit_fragment()
+
--- /dev/null
+from ..paragraphs import Akap
+
+
+class MiejsceCzas(Akap):
+ HTML_CLASS = 'place-and-time'
class NaglowekListy(WLElement):
- pass
+ HTML_TAG = "h3"
TXT_LEGACY_TOP_MARGIN = 3
TXT_LEGACY_BOTTOM_MARGIN = 0
+ HTML_TAG = "h4"
class Osoba(WLElement):
- pass
+ HTML_TAG = "em"
+ HTML_CLASS = "person"
+from .animacja import Animacja
from .ilustr import Ilustr
+from .tabela import Tabela
+from .wiersz import Wiersz
+from .kol import Kol
--- /dev/null
+from ..base import WLElement
+
+
+class Animacja(WLElement):
+ HTML_TAG = 'div'
+ HTML_CLASS = "animacja cycle-slideshow"
+ HTML_ATTR = {
+ "data-cycle-pause-on-hover": "true",
+ "data-cycle-next": "> img",
+ "data-cycle-fx": "fadeout",
+ "data-cycle-paused": "true",
+ }
def get_html_attr(self, builder):
return {
- 'src': builder.image_location + self.attrib['src']
+ 'src': builder.image_location + self.attrib['src'],
+ 'alt': self.attr['alt'],
+ 'title': self.attr['alt'],
}
--- /dev/null
+from ..base import WLElement
+
+
+class Kol(WLElement):
+ HTML_TAG = 'td'
--- /dev/null
+from ..base import WLElement
+
+
+class Tabela(WLElement):
+ HTML_TAG = 'table'
+
+ def get_html_attr(self, builder):
+ if self.attrib['ramka'] == '1':
+ return {
+ 'class': 'border'
+ }
+ return {}
--- /dev/null
+from ..base import WLElement
+
+
+class Wiersz(WLElement):
+ HTML_TAG = 'tr'
def txt_build(self, builder):
pass
+ def html_build(self, builder):
+ builder.footnote_counter += 1
+ fn_no = builder.footnote_counter
+ footnote_id = 'footnote-idm{}'.format(self.attrib['_compat_ordered_id'])
+ anchor_id = 'anchor-idm{}'.format(self.attrib['_compat_ordered_id'])
+
+ builder.start_element('a', {"href": '#{}'.format(footnote_id), "class": "annotation"})
+ builder.push_text('[{}]'.format(fn_no))
+ builder.end_element()
+
+ builder.enter_fragment('footnotes')
+ builder.start_element('div', {'class': 'fn-{}'.format(self.tag)})
+ builder.push_text('\n') # Compat
+ builder.start_element('a', {'name': footnote_id})
+ builder.end_element()
+ builder.start_element('a', {
+ 'href': '#{}'.format(anchor_id), 'class': 'annotation'
+ })
+ builder.push_text('[{}]'.format(fn_no))
+ builder.end_element()
+
+ builder.start_element('p')
+ super(Footnote, self).html_build(builder)
+
+ builder.push_text(' [{}]'.format(self.qualifier))
+ builder.end_element()
+ builder.end_element()
+ builder.exit_fragment()
+
+
+class PA(Footnote):
+ """Przypis autorski."""
+ @property
+ def qualifier(self):
+ _ = self.gettext
+ return _("author's footnote")
+
+
+class PT(Footnote):
+ """Przypis tłumacza."""
+ @property
+ def qualifier(self):
+ _ = self.gettext
+ return _("translator's footnote")
+
+
+class PR(Footnote):
+ """Przypis redakcyjny."""
+ @property
+ def qualifier(self):
+ _ = self.gettext
+ return _("editor's footnote")
+
+
+class PE(Footnote):
+ """Przypis redakcji źródła."""
+ @property
+ def qualifier(self):
+ _ = self.gettext
+ return _("source editor's footnote")
class DzieloNadrzedne(HeaderElement):
TXT_BOTTOM_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 1
+
+ HTML_CLASS = "collection"
class Motto(WLElement):
TXT_LEGACY_TOP_MARGIN = 4
TXT_LEGACY_BOTTOM_MARGIN = 2
+
+ HTML_TAG = "div"
+ HTML_CLASS = "motto"
class MottoPodpis(WLElement):
- pass
+ HTML_TAG = "p"
+ HTML_CLASS = "motto_podpis"
+
TXT_BOTTOM_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 1
- HTML_TAG = 'span'
HTML_CLASS = 'title'
from .naglowek_czesc import NaglowekCzesc
from .naglowek_podrozdzial import NaglowekPodrozdzial
from .naglowek_rozdzial import NaglowekRozdzial
+from .podtytul_czesc import PodtytulCzesc
+from .podtytul_rozdzial import PodtytulRozdzial
+from .podtytul_podrozdzial import PodtytulPodrozdzial
TXT_BOTTOM_MARGIN = 2
TXT_LEGACY_TOP_MARGIN = 5
TXT_LEGACY_BOTTOM_MARGIN = 0
+
+ HTML_TAG = "h2"
TXT_BOTTOM_MARGIN = 2
TXT_LEGACY_TOP_MARGIN = 3
TXT_LEGACY_BOTTOM_MARGIN = 0
+
+ HTML_TAG = "h4"
--- /dev/null
+from ..base import WLElement
+
+
+class PodtytulCzesc(WLElement):
+ TXT_TOP_MARGIN = 2
+ TXT_BOTTOM_MARGIN = 2
+
+ HTML_TAG = "div"
+ HTML_CLASS = "subtitle2"
--- /dev/null
+from ..base import WLElement
+
+
+class PodtytulPodrozdzial(WLElement):
+ TXT_TOP_MARGIN = 2
+ TXT_BOTTOM_MARGIN = 2
+
+ HTML_TAG = "div"
+ HTML_CLASS = "subtitle4"
--- /dev/null
+from ..base import WLElement
+
+
+class PodtytulRozdzial(WLElement):
+ TXT_TOP_MARGIN = 2
+ TXT_BOTTOM_MARGIN = 2
+
+ HTML_TAG = "div"
+ HTML_CLASS = "subtitle3"
HTML_TAG = 'p'
HTML_CLASS = 'paragraph'
-
- HTML_SECTION = True
from .strofa import Strofa
+from .wers_akap import WersAkap
from .wers_cd import WersCd
+from .wers_do_prawej import WersDoPrawej
from .wers import Wers
from .wers_wciety import WersWciety
from .zastepnik_wersu import ZastepnikWersu
TXT_LEGACY_TOP_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 0
+ HTML_TAG = 'div'
+ HTML_CLASS = 'stanza'
+
def get_verses(self):
from librarian.parser import parser
verses[-1].append(child)
for verse in verses:
+ verse.stanza = self
if len(verse) == 1 and isinstance(verse[0], Wers):
assert not (verse.text or '').strip()
assert not (verse[0].tail or '').strip()
TXT_LEGACY_BOTTOM_MARGIN = 0
HTML_TAG = 'div'
- HTML_ATTRIB = {"class": "verse"}
+ HTML_CLASS = 'verse'
+
+ @property
+ def meta(self):
+ if hasattr(self, 'stanza'):
+ return self.stanza.meta
+ return super(Wers, self).meta
--- /dev/null
+from .wers import Wers
+
+
+class WersAkap(Wers):
+ TXT_PREFIX = ' '
+
+ HTML_ATTR = {
+ "style": "padding-left: 1em"
+ }
def _txt_build_inner(self, builder):
builder.push_text(' ' * 24, prepared=True)
super(WersCd, self)._txt_build_inner(builder)
+
+ HTML_ATTR = {
+ "style": "padding-left: 12em",
+ }
--- /dev/null
+from .wers import Wers
+
+
+class WersDoPrawej(Wers):
+ TXT_PREFIX = ' '
+
+ HTML_ATTR = {
+ "style": "text-align: right",
+ }
class WersWciety(Wers):
@property
def typ(self):
- ## Temporary legacy compatibility fix.
- return 2 if 'typ' in self.attrib else 1
-
v = self.attrib.get('typ')
return int(v) if v else 1
def _txt_build_inner(self, builder):
+ ## Temporary legacy compatibility fix.
+ typ = min(self.typ, 2)
+
builder.push_text(' ' * self.typ, prepared=True)
super(WersWciety, self)._txt_build_inner(builder)
+ def get_html_attr(self, builder):
+ attr = super(WersWciety, self).get_html_attr(builder)
+ attr['style'] = "padding-left: {}em".format(self.typ)
+ return attr
# This should not generally happen.
if self.getparent() is not None:
return self.getparent().meta
+
+ @property
+ def master(self):
+ for c in self:
+ if isinstance(c, Master):
+ return c
TXT_LEGACY_TOP_MARGIN = 2
TXT_LEGACY_BOTTOM_MARGIN = 2
+ HTML_TAG = "p"
+ HTML_CLASS = "spacer-asterisk"
+
def _txt_build_inner(self, builder):
builder.push_text('*')
+
+ def _html_build_inner(self, builder):
+ builder.push_text("*")
+
TXT_BOTTOM_MARGIN = 6
TXT_LEGACY_BOTTOM_MARGIN = 4
+ HTML_TAG = "hr"
+ HTML_CLASS = "spacer"
TXT_LEGACY_TOP_MARGIN = 2
TXT_LEGACY_BOTTOM_MARGIN = 2
+ HTML_TAG = "hr"
+ HTML_CLASS = "spacer-line"
+
def _txt_build_inner(self, builder):
builder.push_text('-' * 48)
+
+
+from .indeks_dolny import IndeksDolny
+from .mat import Mat
from .slowo_obce import SlowoObce
from .tytul_dziela import TytulDziela
+from .wieksze_odstepy import WiekszeOdstepy
from .wyroznienie import Wyroznienie
+from .www import WWW
--- /dev/null
+from ..base import WLElement
+
+
+class IndeksDolny(WLElement):
+ TXT_PREFIX = "_"
+
+ HTML_TAG = "sub"
--- /dev/null
+from copy import copy
+from ..base import WLElement
+
+
+class Mat(WLElement):
+ def html_build(self, builder):
+ e = copy(self)
+ e.tag = 'math'
+ e.attrib['xmlns'] = 'http://www.w3.org/1998/Math/MathML'
+ builder.cursor.append(e)
class SlowoObce(WLElement):
- pass
+ HTML_TAG = 'em'
+ HTML_CLASS = 'foreign-word'
class TytulDziela(WLElement):
+ HTML_TAG = 'em'
+ HTML_CLASS = 'book-title'
+
def normalize_text(self, text):
txt = super(TytulDziela, self).normalize_text(text)
if self.attrib.get('typ') == '1':
--- /dev/null
+from ..base import WLElement
+
+
+class WiekszeOdstepy(WLElement):
+ TXT_PREFIX = "*"
+ TXT_SUFFIX = "*"
+
+ HTML_TAG = "em"
+ HTML_CLASS = "wieksze-odstepy"
--- /dev/null
+from ..base import WLElement
+
+
+class WWW(WLElement):
+ pass
TXT_PREFIX = "*"
TXT_SUFFIX = "*"
+ HTML_TAG = "em"
+ HTML_CLASS = "author-emphasis"
class End(WLElement):
- pass
+ HTML_TAG = 'span'
+
+ def get_html_attr(self, builder):
+ fid = self.attrib['id'][1:]
+ return {
+ "class": "theme-end",
+ "fid": fid
+ }
class Motyw(WLElement):
+ HTML_TAG = "a"
+
def txt_build(self, builder):
pass
-
- def feed_to(self, builder):
- assert not len(self)
- themes = [
- normalize_text(t.strip()) for t in self.text.split(',')
- ]
- builder.set_themes(self.attrib['id'], themes)
+ def get_html_attr(self, builder):
+ fid = self.attrib['id'][1:]
+ return {
+ "class": "theme-begin",
+ "fid": fid,
+ "name": "m" + fid,
+ }
while parent.get('id', None) != 'book-text':
cparent = copy.deepcopy(parent)
cparent.text = None
+ if 'id' in cparent.attrib:
+ del cparent.attrib['id']
parents.append(cparent)
parent = parent.getparent()
)
else:
for fragment_id in open_fragments:
+ celem = copy.copy(element)
+ if 'id' in celem.attrib:
+ del celem.attrib['id']
open_fragments[fragment_id].append(
- event, copy.copy(element)
+ event, celem
)
return closed_fragments, open_fragments
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2020-10-07 12:11+0200\n"
+"Last-Translator: Radek Czajka <rczajka@rczajka.pl>\n"
+"Language-Team: \n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 2.3\n"
+
+#: src/librarian/builders/html.py:77
+msgid "translated by"
+msgstr "tłum."
+
+#: src/librarian/builders/html.py:94
+msgid "Footnotes"
+msgstr "Przypisy"
+
+#: src/librarian/elements/footnotes/__init__.py:43
+msgid "author's footnote"
+msgstr "przypis autorski"
+
+#: src/librarian/elements/footnotes/__init__.py:51
+msgid "translator's footnote"
+msgstr "przypis tłumacza"
+
+#: src/librarian/elements/footnotes/__init__.py:59
+msgid "editor's footnote"
+msgstr "przypis redakcyjny"
+
+#: src/librarian/elements/footnotes/__init__.py:67
+msgid "source editor's footnote"
+msgstr "przypis edytorski"
def makedirs(path):
if not os.path.isdir(path):
os.makedirs(path)
+
+
+def get_translation(language):
+ import gettext
+ from .functions import lang_code_3to2
+
+ return gettext.translation(
+ 'messages',
+ localedir=os.path.join(os.path.dirname(__file__), 'locale'),
+ languages=[lang_code_3to2(language)],
+ )
-<div xmlns:wl="http://wolnelektury.pl/functions" xmlns:dc="http://purl.org/dc/elements/1.1/" id="book-text">
+<div id="book-text">
<div id="toc">
<h2>Spis treści</h2>
<ol></ol>
</div>
<div id="themes"><ol>
-<li>Miłość platoniczna: <a href="#m1189062500041">1</a> <a href="#m1189062500041">2</a> </li>
+<li>Miłość platoniczna: <a href="#m1189062500041">1</a> </li>
<li>Natura: <a href="#m1189062528872">1</a> </li>
<li>Nicość: <a href="#m1">1</a> </li>
</ol></div>
<h1>
-<span class="author">Adam Asnyk</span><span class="title"><a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a>Między nami nic nie było</span>
+<span class="author" id="sec2">Adam Asnyk</span><span class="title" id="sec3"><a class="theme-begin" fid="1189062500041" name="m1189062500041">Miłość platoniczna</a>Między nami nic nie było</span>
</h1>
-<a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a><div class="stanza">
-<a name="sec4"></a><a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a><div class="verse">Między nami <a name="m1" class="theme-begin" fid="1">Nicość</a>nic nie było!<span class="theme-end" fid="1"></span>
+<div class="stanza" id="sec4">
+<a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a><div class="verse">Między nami <a class="theme-begin" fid="1" name="m1">Nicość</a>nic nie było!<span class="theme-end" fid="1"></span>
</div>
<div class="verse">Żadnych zwierzeń, wyznań żadnych!</div>
<div class="verse">Nic nas z sobą nie łączyło —</div>
<div class="verse">Prócz wiosennych marzeń zdradnych;</div>
</div>
-<div class="stanza">
-<a name="sec5"></a><a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a><div class="verse">
-<a name="m1189062528872" class="theme-begin" fid="1189062528872">Natura</a>Prócz tych woni, barw i blasków,</div>
+<div class="stanza" id="sec5">
+<a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a><div class="verse">
+<a class="theme-begin" fid="1189062528872" name="m1189062528872">Natura</a>Prócz tych woni, barw i blasków,</div>
<div class="verse">Unoszących się w przestrzeni;</div>
<div class="verse">Prócz szumiących śpiewem lasków</div>
<div class="verse">I tej świeżej łąk zieleni;</div>
</div>
-<div class="stanza">
-<a name="sec6"></a><div class="verse">Prócz tych kaskad i potoków,</div>
+<div class="stanza" id="sec6">
+<div class="verse">Prócz tych kaskad i potoków,</div>
<a name="f10" class="target"> </a><a href="#f10" class="anchor">10</a><div class="verse">Zraszających każdy parów,</div>
<div class="verse">Prócz girlandy tęcz, obłoków,</div>
<div class="verse">Prócz natury słodkich czarów;</div>
</div>
-<div class="stanza">
-<a name="sec7"></a><div class="verse">Prócz tych wspólnych, jasnych zdrojów,</div>
+<div class="stanza" id="sec7">
+<div class="verse">Prócz tych wspólnych, jasnych zdrojów,</div>
<div class="verse">Z których serce zachwyt piło;</div>
<a name="f15" class="target"> </a><a href="#f15" class="anchor">15</a><div class="verse">Prócz pierwiosnków i powojów,—</div>
<div class="verse">Między nami nic nie było!<span class="theme-end" fid="1189062528872"></span><span class="theme-end" fid="1189062500041"></span>
--- /dev/null
+<div xmlns:wl="http://wolnelektury.pl/functions" xmlns:dc="http://purl.org/dc/elements/1.1/" id="book-text">
+<div id="toc">
+<h2>Spis treści</h2>
+<ol></ol>
+</div>
+<div id="themes"><ol>
+<li>Miłość platoniczna: <a href="#m1189062500041">1</a> <a href="#m1189062500041">2</a> </li>
+<li>Natura: <a href="#m1189062528872">1</a> </li>
+<li>Nicość: <a href="#m1">1</a> </li>
+</ol></div>
+<h1>
+<span class="author">Adam Asnyk</span><span class="title"><a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a>Między nami nic nie było</span>
+</h1>
+<a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a><div class="stanza">
+<a name="sec4"></a><a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a><div class="verse">Między nami <a name="m1" class="theme-begin" fid="1">Nicość</a>nic nie było!<span class="theme-end" fid="1"></span>
+</div>
+<div class="verse">Żadnych zwierzeń, wyznań żadnych!</div>
+<div class="verse">Nic nas z sobą nie łączyło —</div>
+<div class="verse">Prócz wiosennych marzeń zdradnych;</div>
+</div>
+<div class="stanza">
+<a name="sec5"></a><a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a><div class="verse">
+<a name="m1189062528872" class="theme-begin" fid="1189062528872">Natura</a>Prócz tych woni, barw i blasków,</div>
+<div class="verse">Unoszących się w przestrzeni;</div>
+<div class="verse">Prócz szumiących śpiewem lasków</div>
+<div class="verse">I tej świeżej łąk zieleni;</div>
+</div>
+<div class="stanza">
+<a name="sec6"></a><div class="verse">Prócz tych kaskad i potoków,</div>
+<a name="f10" class="target"> </a><a href="#f10" class="anchor">10</a><div class="verse">Zraszających każdy parów,</div>
+<div class="verse">Prócz girlandy tęcz, obłoków,</div>
+<div class="verse">Prócz natury słodkich czarów;</div>
+</div>
+<div class="stanza">
+<a name="sec7"></a><div class="verse">Prócz tych wspólnych, jasnych zdrojów,</div>
+<div class="verse">Z których serce zachwyt piło;</div>
+<a name="f15" class="target"> </a><a href="#f15" class="anchor">15</a><div class="verse">Prócz pierwiosnków i powojów,—</div>
+<div class="verse">Między nami nic nie było!<span class="theme-end" fid="1189062528872"></span><span class="theme-end" fid="1189062500041"></span>
+</div>
+</div>
+</div>
1189062500041: Miłość platoniczna
+<h1 ><span class="title">Między nami nic nie było</span>
+</h1>
<div class="stanza">
<div class="verse">Między nami nic nie było!
</div>
import io
from unittest import TestCase
from librarian import NoDublinCore
-from librarian.parser import WLDocument
+from librarian.document import WLDocument
+from librarian.parser import WLDocument as LegacyWLDocument
from nose.tools import *
from .utils import get_fixture
class TransformTest(TestCase):
maxDiff = None
- def test_transform(self):
- expected_output_file_path = get_fixture('text', 'asnyk_miedzy_nami_expected.html')
+ def test_transform_legacy(self):
+ expected_output_file_path = get_fixture('text', 'asnyk_miedzy_nami_expected.legacy.html')
- html = WLDocument.from_file(
+ html = LegacyWLDocument.from_file(
get_fixture('text', 'miedzy-nami-nic-nie-bylo.xml')
).as_html().get_bytes().decode('utf-8')
self.assertEqual(html, io.open(expected_output_file_path).read())
+ def test_transform(self):
+ expected_output_file_path = get_fixture('text', 'asnyk_miedzy_nami_expected.html')
+ html = WLDocument(
+ filename=get_fixture('text', 'miedzy-nami-nic-nie-bylo.xml')
+ ).build('html').get_bytes().decode('utf-8')
+
+ self.assertEqual(html, io.open(expected_output_file_path).read())
+
@raises(NoDublinCore)
def test_no_dublincore():
- WLDocument.from_file(
+ LegacyWLDocument.from_file(
get_fixture('text', 'asnyk_miedzy_nami_nodc.xml')
).as_html()
def test_passing_parse_dublincore_to_transform():
"""Passing parse_dublincore=False to transform omits DublinCore parsing."""
- WLDocument.from_file(
+ LegacyWLDocument.from_file(
get_fixture('text', 'asnyk_miedzy_nami_nodc.xml'),
parse_dublincore=False,
).as_html()
def test_empty():
- assert not WLDocument.from_bytes(
+ assert not LegacyWLDocument.from_bytes(
b'<utwor />',
parse_dublincore=False,
).as_html()