From fab5fc5d73444434464cf02336713727cc057836 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Feb 2009 12:57:02 -0800 Subject: [PATCH 01/54] Fix regression in scheduled news downloaded when using specific time of day --- src/calibre/gui2/dialogs/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index 62dd79ac9b..9c9204c398 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -432,7 +432,7 @@ class Scheduler(QObject): day_matches = day > 6 or day == now.tm_wday tnow = now.tm_hour*60 + now.tm_min matches = day_matches and (hour*60+minute) < tnow - if matches and nowt.toordinal() < date.today().toordinal(): + if matches and recipe.last_downloaded.toordinal() < date.today().toordinal(): needs_downloading.add(recipe) self.debug('Needs downloading:', needs_downloading) From 2f3680e563b59fdaaf5ac689925872253b5d7ad0 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Sun, 1 Feb 2009 19:45:21 -0500 Subject: [PATCH 02/54] Implement NCX and Adobe page-map parsing and generation. --- src/calibre/ebooks/oeb/base.py | 312 ++++++++++++++++++++++++++------- 1 file changed, 250 insertions(+), 62 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index b89be6b1ec..e9252c7609 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -17,8 +17,10 @@ import logging import re import uuid import copy +import mimetypes from lxml import etree from lxml import html +import calibre from calibre import LoggingInterface from calibre.translations.dynamic import translate from calibre.startup import get_lang @@ -64,6 +66,7 @@ XHTML_MIME = 'application/xhtml+xml' CSS_MIME = 'text/css' NCX_MIME = 'application/x-dtbncx+xml' OPF_MIME = 'application/oebps-package+xml' +PAGE_MAP_MIME = 'application/oebps-page-map+xml' OEB_DOC_MIME = 'text/x-oeb1-document' OEB_CSS_MIME = 'text/x-oeb1-css' OPENTYPE_MIME = 'font/opentype' @@ -892,25 +895,71 @@ class TOC(object): node.to_opf1(tour) return tour - def to_ncx(self, parent, order=None, depth=1): - if not order: order = [0] + def to_ncx(self, parent, depth=1): for node in self.nodes: - order[0] += 1 - playOrder = str(order[0]) - id = self.id or 'np' + playOrder - point = etree.SubElement(parent, - NCX('navPoint'), id=id, playOrder=playOrder) + id = self.id or unicode(uuid.uuid4()) + attrib = {'id': id, 'playOrder': '0'} if self.klass: - point.attrib['class'] = node.klass + attrib['class'] = node.klass + point = element(parent, NCX('navPoint'), attrib=attrib) label = etree.SubElement(point, NCX('navLabel')) - etree.SubElement(label, NCX('text')).text = node.title + element(label, NCX('text')).text = node.title href = node.href if depth > 1 else urldefrag(node.href)[0] - child = etree.SubElement(point, - NCX('content'), attrib={'src': href}) - node.to_ncx(point, order, depth+1) + element(point, NCX('content'), src=href) + node.to_ncx(point, depth+1) return parent + +class PageList(object): + class Page(object): + def __init__(self, name, href, type='normal', klass=None, id=None): + self.name = name + self.href = urlnormalize(href) + self.type = type + self.id = id + self.klass = klass + def __init__(self): + self.pages = [] + + def add(self, name, href, type='normal', klass=None, id=None): + page = self.Page(name, href, type, klass, id) + self.pages.append(page) + return page + + def __len__(self): + return len(self.pages) + + def __iter__(self): + for page in self.pages: + yield node + + def __getitem__(self, index): + return self.pages[index] + + def to_ncx(self, parent=None): + plist = element(parent, NCX('pageList'), id=str(uuid.uuid4())) + values = dict((t, count(1)) for t in ('front', 'normal', 'special')) + for page in self.pages: + id = page.id or unicode(uuid.uuid4()) + type = page.type + value = str(values[type].next()) + attrib = {'id': id, 'value': value, 'type': type, 'playOrder': '0'} + if page.klass: + attrib['class'] = page.klass + ptarget = element(plist, NCX('pageTarget'), attrib=attrib) + label = element(ptarget, NCX('navLabel')) + element(label, NCX('text')).text = page.name + element(ptarget, NCX('content'), src=page.href) + return plist + + def to_page_map(self): + pmap = etree.Element(OPF('page-map'), nsmap={None: OPF2_NS}) + for page in self.pages: + element(pmap, OPF('page'), name=page.name, href=page.href) + return pmap + + class OEBBook(object): COVER_SVG_XP = XPath('h:body//svg:svg[position() = 1]') COVER_OBJECT_XP = XPath('h:body//h:object[@data][position() = 1]') @@ -972,7 +1021,7 @@ class OEBBook(object): return opf def _metadata_from_opf(self, opf): - uid = opf.get('unique-identifier', 'calibre-uuid') + uid = opf.get('unique-identifier', None) self.uid = None self.metadata = metadata = Metadata(self) for elem in xpath(opf, '/o2:package/o2:metadata//*'): @@ -996,8 +1045,12 @@ class OEBBook(object): if not haveuuid and haveid: bookid = "urn:uuid:%s" % str(uuid.uuid4()) metadata.add('identifier', bookid, id='calibre-uuid') + if uid is None: + self.logger.warn(u'Unique-identifier not specified') for item in metadata.identifier: - if item.id == uid: + if not item.id: + continue + if uid is None or item.id == uid: self.uid = item break else: @@ -1023,7 +1076,10 @@ class OEBBook(object): href = elem.get('href') media_type = elem.get('media-type', None) if media_type is None: - media_type = elem.get('mediatype', BINARY_MIME) + media_type = elem.get('mediatype', None) + if media_type is None or media_type == 'text/xml': + guessed = mimetypes.guess_type(href)[0] + media_type = guessed or media_type or BINARY_MIME fallback = elem.get('fallback') if href in manifest.hrefs: self.logger.warn(u'Duplicate manifest entry for %r' % href) @@ -1055,7 +1111,7 @@ class OEBBook(object): spine.add(item, False) if len(spine) == 0: raise OEBError("Spine is empty") - + def _guide_from_opf(self, opf): self.guide = guide = Guide(self) for elem in xpath(opf, '/o2:package/o2:guide/o2:reference'): @@ -1065,49 +1121,74 @@ class OEBBook(object): self.logger.warn(u'Guide reference %r not found' % href) continue guide.add(elem.get('type'), elem.get('title'), href) - - def _toc_from_navpoint(self, toc, navpoint): + + def _find_ncx(self, opf): + result = xpath(opf, '/o2:package/o2:spine/@toc') + if result: + id = result[0] + if id not in self.manifest.ids: + return None + item = self.manifest.ids[id] + self.manifest.remove(item) + return item + for item in self.manifest.values(): + if item.media_type == NCX_MIME: + self.manifest.remove(item) + return item + return None + + def _toc_from_navpoint(self, item, toc, navpoint): children = xpath(navpoint, 'ncx:navPoint') for child in children: title = ''.join(xpath(child, 'ncx:navLabel/ncx:text/text()')) - href = xpath(child, 'ncx:content/@src')[0] + title = COLLAPSE_RE.sub(' ', title.strip()) + href = xpath(child, 'ncx:content/@src') + if not title or not href: + continue + href = item.abshref(urlnormalize(href[0])) + path, _ = urldefrag(href) + if path not in self.manifest.hrefs: + self.logger.warn('TOC reference %r not found' % href) + continue id = child.get('id') klass = child.get('class') node = toc.add(title, href, id=id, klass=klass) - self._toc_from_navpoint(node, child) - - def _toc_from_ncx(self, opf): - result = xpath(opf, '/o2:package/o2:spine/@toc') - if not result: - expr = '/o2:package/o2:manifest/o2:item[@media-type="%s"]/@id' - result = xpath(opf, expr % NCX_MIME) - if len(result) != 1: - return False - id = result[0] - if id not in self.manifest.ids: + self._toc_from_navpoint(item, node, child) + + def _toc_from_ncx(self, item): + if item is None: return False - item = self.manifest.ids[id] ncx = item.data - self.manifest.remove(item) - title = xpath(ncx, 'ncx:docTitle/ncx:text/text()') - title = title[0].strip() if title else unicode(self.metadata.title[0]) + title = ''.join(xpath(ncx, 'ncx:docTitle/ncx:text/text()')) + title = COLLAPSE_RE.sub(' ', title.strip()) + title = title or unicode(self.metadata.title[0]) self.toc = toc = TOC(title) navmaps = xpath(ncx, 'ncx:navMap') for navmap in navmaps: - self._toc_from_navpoint(toc, navmap) + self._toc_from_navpoint(item, toc, navmap) return True - + def _toc_from_tour(self, opf): - result = xpath(opf, '/o2:package/o2:tours/o2:tour') + result = xpath(opf, 'o2:tours/o2:tour') if not result: return False tour = result[0] self.toc = toc = TOC(tour.get('title')) sites = xpath(tour, 'o2:site') for site in sites: - toc.add(site.get('title'), site.get('href')) + title = site.get('title') + href = site.get('href') + if not title or not href: + continue + href = item.abshref(urlnormalize(href)) + path, _ = urldefrag(href) + if path not in self.manifest.hrefs: + self.logger.warn('TOC reference %r not found' % href) + continue + id = child.get('id') + toc.add(title, href, id=id) return True - + def _toc_from_html(self, opf): if 'toc' not in self.guide: return False @@ -1131,6 +1212,7 @@ class OEBBook(object): if not path: href = '#'.join((itempath, frag)) title = ' '.join(xpath(anchor, './/text()')) + title = COLLAPSE_RE.sub(' ', title.strip()) href = urlnormalize(href) if href not in titles: order.append(href) @@ -1146,15 +1228,17 @@ class OEBBook(object): for item in self.spine: if not item.linear: continue html = item.data - title = xpath(html, '/h:html/h:head/h:title/text()') - title = title[0].strip() if title else None - if title: titles.append(title) + title = ''.join(xpath(html, '/h:html/h:head/h:title/text()')) + title = COLLAPSE_RE(' ', title.strip()) + if title: + titles.append(title) headers.append('(unlabled)') for tag in ('h1', 'h2', 'h3', 'h4', 'h5', 'strong'): - expr = '/h:html/h:body//h:%s[position()=1]/text()' % (tag,) - header = xpath(html, expr) + expr = '/h:html/h:body//h:%s[position()=1]/text()' + header = ''.join(xpath(html % tag, expr)) + header = COLLAPSE_RE.sub(' ', header.strip()) if header: - headers[-1] = header[0] + headers[-1] = header break use = titles if len(titles) > len(set(titles)): @@ -1164,12 +1248,71 @@ class OEBBook(object): toc.add(title, item.href) return True - def _toc_from_opf(self, opf): - if self._toc_from_ncx(opf): return + def _toc_from_opf(self, opf, item): + if self._toc_from_ncx(item): return if self._toc_from_tour(opf): return + self.logger.warn('No metadata table of contents found') if self._toc_from_html(opf): return self._toc_from_spine(opf) - + + def _pages_from_ncx(self, opf, item): + if item is None: + return False + ncx = item.data + ptargets = xpath(ncx, 'ncx:pageList/ncx:pageTarget') + if not ptargets: + return False + pages = self.pages = PageList() + for ptarget in ptargets: + name = ''.join(xpath(ptarget, 'ncx:navLabel/ncx:text/text()')) + name = COLLAPSE_RE.sub(' ', name.strip()) + href = xpath(ptarget, 'ncx:content/@src') + if not href: + continue + href = item.abshref(urlnormalize(href[0])) + id = ptarget.get('id') + type = ptarget.get('type', 'normal') + klass = ptarget.get('class') + pages.add(name, href, type=type, id=id, klass=klass) + return True + + def _find_page_map(self, opf): + result = xpath(opf, '/o2:package/o2:spine/@page-map') + if result: + id = result[0] + if id not in self.manifest.ids: + return None + item = self.manifest.ids[id] + self.manifest.remove(item) + return item + for item in self.manifest.values(): + if item.media_type == PAGE_MAP_MIME: + self.manifest.remove(item) + return item + return None + + def _pages_from_page_map(self, opf): + item = self._find_page_map(opf) + if item is None: + return False + pmap = item.data + pages = self.pages = PageList() + for page in xpath(pmap, 'o2:page'): + name = page.get('name', '') + href = page.get('href') + if not href: + continue + name = COLLAPSE_RE.sub(' ', name.strip()) + href = item.abshref(urlnormalize(href)) + pages.add(name, href) + return True + + def _pages_from_opf(self, opf, item): + if self._pages_from_ncx(opf, item): return + if self._pages_from_page_map(opf): return + self.pages = PageList() + return + def _cover_from_html(self, hcover): with TemporaryDirectory('_html_cover') as tdir: writer = DirWriter() @@ -1228,7 +1371,9 @@ class OEBBook(object): self._manifest_from_opf(opf) self._spine_from_opf(opf) self._guide_from_opf(opf) - self._toc_from_opf(opf) + item = self._find_ncx(opf) + self._toc_from_opf(opf, item) + self._pages_from_opf(opf, item) self._ensure_cover_image() def translate(self, text): @@ -1249,6 +1394,34 @@ class OEBBook(object): guide = self.guide.to_opf1(package) return {OPF_MIME: ('content.opf', package)} + def _update_playorder(self, ncx): + hrefs = set(xpath(ncx, '//ncx:content/@src')) + playorder = {} + next = 1 + selector = XPath('h:body//*[@id or @name]') + for item in self.spine: + base = item.href + if base in hrefs: + playorder[base] = next + next += 1 + for elem in selector(item.data): + added = False + for attr in ('id', 'name'): + id = elem.get(attr) + if not id: + continue + href = '#'.join([base, id]) + if href in hrefs: + playorder[href] = next + added = True + if added: + next += 1 + selector = XPath('ncx:content/@src') + for elem in xpath(ncx, '//*[@playOrder and ./ncx:content[@src]]'): + order = playorder[selector(elem)[0]] + elem.attrib['playOrder'] = str(order) + return + def _to_ncx(self): lang = unicode(self.metadata.language[0]) ncx = etree.Element(NCX('ncx'), @@ -1256,35 +1429,50 @@ class OEBBook(object): nsmap={None: NCX_NS}) head = etree.SubElement(ncx, NCX('head')) etree.SubElement(head, NCX('meta'), - attrib={'name': 'dtb:uid', 'content': unicode(self.uid)}) + name='dtb:uid', content=unicode(self.uid)) etree.SubElement(head, NCX('meta'), - attrib={'name': 'dtb:depth', 'content': str(self.toc.depth())}) + name='dtb:depth', content=str(self.toc.depth())) + generator = ''.join(['calibre (', calibre.__version__, ')']) etree.SubElement(head, NCX('meta'), - attrib={'name': 'dtb:totalPageCount', 'content': '0'}) + name='dtb:generator', content=generator) etree.SubElement(head, NCX('meta'), - attrib={'name': 'dtb:maxPageNumber', 'content': '0'}) + name='dtb:totalPageCount', content=str(len(self.pages))) + maxpnum = etree.SubElement(head, NCX('meta'), + name='dtb:maxPageNumber', content='0') title = etree.SubElement(ncx, NCX('docTitle')) text = etree.SubElement(title, NCX('text')) text.text = unicode(self.metadata.title[0]) navmap = etree.SubElement(ncx, NCX('navMap')) self.toc.to_ncx(navmap) + if len(self.pages) > 0: + plist = self.pages.to_ncx(ncx) + value = max(int(x) for x in xpath(plist, '//@value')) + maxpnum.attrib['content'] = str(value) + self._update_playorder(ncx) return ncx - def to_opf2(self): + def to_opf2(self, page_map=False): + results = {} package = etree.Element(OPF('package'), attrib={'version': '2.0', 'unique-identifier': self.uid.id}, nsmap={None: OPF2_NS}) metadata = self.metadata.to_opf2(package) manifest = self.manifest.to_opf2(package) - id, href = self.manifest.generate('ncx', 'toc.ncx') - etree.SubElement(manifest, OPF('item'), - attrib={'id': id, 'href': href, 'media-type': NCX_MIME}) spine = self.spine.to_opf2(package) - spine.attrib['toc'] = id guide = self.guide.to_opf2(package) - ncx = self._to_ncx() - return {OPF_MIME: ('content.opf', package), - NCX_MIME: (href, ncx)} + results[OPF_MIME] = ('content.opf', package) + id, href = self.manifest.generate('ncx', 'toc.ncx') + etree.SubElement(manifest, OPF('item'), id=id, href=href, + attrib={'media-type': NCX_MIME}) + spine.attrib['toc'] = id + results[NCX_MIME] = (href, self._to_ncx()) + if page_map and len(self.pages) > 0: + id, href = self.manifest.generate('page-map', 'page-map.xml') + etree.SubElement(manifest, OPF('item'), id=id, href=href, + attrib={'media-type': PAGE_MAP_MIME}) + spine.attrib['page-map'] = id + results[PAGE_MAP_MIME] = (href, self.pages.to_page_map()) + return results def main(argv=sys.argv): @@ -1292,7 +1480,7 @@ def main(argv=sys.argv): oeb = OEBBook(arg) for name, doc in oeb.to_opf1().values(): print etree.tostring(doc, pretty_print=True) - for name, doc in oeb.to_opf2().values(): + for name, doc in oeb.to_opf2(page_map=True).values(): print etree.tostring(doc, pretty_print=True) return 0 From 6fbf78aa7fdef164a1f9faf9e39e729960e1f0c8 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Sun, 1 Feb 2009 21:20:41 -0500 Subject: [PATCH 03/54] Fix #1746. Improve handling of encoding. --- src/calibre/ebooks/oeb/base.py | 23 ++++++++++++++++++++--- src/calibre/ebooks/oeb/stylizer.py | 15 ++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index e9252c7609..854f8bef94 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -24,6 +24,7 @@ import calibre from calibre import LoggingInterface from calibre.translations.dynamic import translate from calibre.startup import get_lang +from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.oeb.entitydefs import ENTITYDEFS from calibre.ebooks.metadata.epub import CoverRenderer from calibre.ptempfile import TemporaryDirectory @@ -87,6 +88,7 @@ ENTITY_RE = re.compile(r'&([a-zA-Z_:][a-zA-Z0-9.-_:]+);') COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+') QNAME_RE = re.compile(r'^[{][^{}]+[}][^{}]+$') PREFIXNAME_RE = re.compile(r'^[^:]+[:][^:]+') +XMLDECL_RE = re.compile(r'^\s*<[?]xml.*?[?]>') def element(parent, *args, **kwargs): if parent is not None: @@ -447,9 +449,10 @@ class Manifest(object): % (self.id, self.href, self.media_type) def _force_xhtml(self, data): - # Possibly decode in user-specified encoding - if self.oeb.encoding is not None: - data = data.decode(self.oeb.encoding, 'replace') + # Convert to Unicode and normalize line endings + data = self.oeb.decode(data) + data = XMLDECL_RE.sub('', data) + data = data.replace('\r\n', '\n').replace('\r', '\n') # Handle broken XHTML w/ SVG (ugh) if 'svg:' in data and SVG_NS not in data: data = data.replace( @@ -1381,6 +1384,20 @@ class OEBBook(object): lang = lang.split('-', 1)[0].lower() return translate(lang, text) + def decode(self, data): + if isinstance(data, unicode): + return data + encodings = ['utf-8', 'utf-16'] + if self.encoding is not None: + encodings.append(self.encoding) + for encoding in encodings: + try: + return data.decode(encoding) + except UnicodeDecodeError: + pass + data, _ = xml_to_unicode(data) + return data + def to_opf1(self): package = etree.Element('package', attrib={'unique-identifier': self.uid.id}) diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index 03a1fade10..ae42e063b7 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -109,6 +109,7 @@ class Stylizer(object): STYLESHEETS = {} def __init__(self, tree, path, oeb, profile=PROFILES['PRS505']): + self.oeb = oeb self.profile = profile self.logger = oeb.logger item = oeb.manifest.hrefs[path] @@ -117,7 +118,7 @@ class Stylizer(object): stylesheets = [HTML_CSS_STYLESHEET] head = xpath(tree, '/h:html/h:head')[0] parser = cssutils.CSSParser() - parser.setFetcher(lambda path: ('utf-8', oeb.container.read(path))) + parser.setFetcher(self._fetch_css_file) for elem in head: if elem.tag == XHTML('style') and elem.text \ and elem.get('type', CSS_MIME) in OEB_STYLES: @@ -138,8 +139,7 @@ class Stylizer(object): if path in self.STYLESHEETS: stylesheet = self.STYLESHEETS[path] else: - data = XHTML_CSS_NAMESPACE - data += oeb.manifest.hrefs[path].data + data = self._fetch_css_file(path)[1] stylesheet = parser.parseString(data, href=path) stylesheet.namespaces['h'] = XHTML_NS self.STYLESHEETS[path] = stylesheet @@ -167,6 +167,15 @@ class Stylizer(object): for elem in xpath(tree, '//h:*[@style]'): self.style(elem)._apply_style_attr() + def _fetch_css_file(self, path): + hrefs = self.oeb.manifest.hrefs + if path not in hrefs: + return (None, None) + data = hrefs[path].data + data = self.oeb.decode(data) + data = XHTML_CSS_NAMESPACE + data + return (None, data) + def flatten_rule(self, rule, href, index): results = [] if isinstance(rule, CSSStyleRule): From 47e94f47cbd9247f65db086777b2539448a382ec Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Feb 2009 18:43:40 -0800 Subject: [PATCH 04/54] New recipes by Darko Miletic for Cuban, Brasilian, Chilean and Montenegran news sources --- .../gui2/images/news/el_mercurio_chile.png | Bin 0 -> 2370 bytes src/calibre/gui2/images/news/estadao.png | Bin 0 -> 1770 bytes src/calibre/gui2/images/news/granma.png | Bin 0 -> 685 bytes src/calibre/gui2/images/news/jb_online.png | Bin 0 -> 942 bytes src/calibre/gui2/images/news/la_cuarta.png | Bin 0 -> 514 bytes src/calibre/gui2/images/news/la_tercera.png | Bin 0 -> 534 bytes .../gui2/images/news/lanacion_chile.png | Bin 0 -> 393 bytes src/calibre/gui2/images/news/o_globo.png | Bin 0 -> 701 bytes src/calibre/gui2/images/news/vijesti.png | Bin 0 -> 636 bytes src/calibre/web/feeds/recipes/__init__.py | 4 +- .../feeds/recipes/recipe_el_mercurio_chile.py | 47 +++++++++++++++ .../web/feeds/recipes/recipe_estadao.py | 54 +++++++++++++++++ .../web/feeds/recipes/recipe_granma.py | 42 +++++++++++++ .../web/feeds/recipes/recipe_jb_online.py | 41 +++++++++++++ .../feeds/recipes/recipe_juventudrebelde.py | 42 +++++++++++++ .../recipes/recipe_juventudrebelde_english.py | 33 ++++++++++ .../web/feeds/recipes/recipe_la_cuarta.py | 42 +++++++++++++ .../web/feeds/recipes/recipe_la_segunda.py | 47 +++++++++++++++ .../web/feeds/recipes/recipe_la_tercera.py | 52 ++++++++++++++++ .../feeds/recipes/recipe_lanacion_chile.py | 44 ++++++++++++++ .../web/feeds/recipes/recipe_o_globo.py | 57 ++++++++++++++++++ .../web/feeds/recipes/recipe_vijesti.py | 42 +++++++++++++ 22 files changed, 546 insertions(+), 1 deletion(-) create mode 100644 src/calibre/gui2/images/news/el_mercurio_chile.png create mode 100644 src/calibre/gui2/images/news/estadao.png create mode 100644 src/calibre/gui2/images/news/granma.png create mode 100644 src/calibre/gui2/images/news/jb_online.png create mode 100644 src/calibre/gui2/images/news/la_cuarta.png create mode 100644 src/calibre/gui2/images/news/la_tercera.png create mode 100644 src/calibre/gui2/images/news/lanacion_chile.png create mode 100644 src/calibre/gui2/images/news/o_globo.png create mode 100644 src/calibre/gui2/images/news/vijesti.png create mode 100644 src/calibre/web/feeds/recipes/recipe_el_mercurio_chile.py create mode 100644 src/calibre/web/feeds/recipes/recipe_estadao.py create mode 100644 src/calibre/web/feeds/recipes/recipe_granma.py create mode 100644 src/calibre/web/feeds/recipes/recipe_jb_online.py create mode 100644 src/calibre/web/feeds/recipes/recipe_juventudrebelde.py create mode 100644 src/calibre/web/feeds/recipes/recipe_juventudrebelde_english.py create mode 100644 src/calibre/web/feeds/recipes/recipe_la_cuarta.py create mode 100644 src/calibre/web/feeds/recipes/recipe_la_segunda.py create mode 100644 src/calibre/web/feeds/recipes/recipe_la_tercera.py create mode 100644 src/calibre/web/feeds/recipes/recipe_lanacion_chile.py create mode 100644 src/calibre/web/feeds/recipes/recipe_o_globo.py create mode 100644 src/calibre/web/feeds/recipes/recipe_vijesti.py diff --git a/src/calibre/gui2/images/news/el_mercurio_chile.png b/src/calibre/gui2/images/news/el_mercurio_chile.png new file mode 100644 index 0000000000000000000000000000000000000000..1cba7a6aecd3a98ae8b11a605e1906d61c9ba299 GIT binary patch literal 2370 zcmV-I3BC4-P)pHn+%>kUwSRn2qFVyFkmnkAR+*`*VMki7KSetWH=Uu%?pYb&v_mL&vbwcvK0Zd1wW-*<~J4Z-{0_le#3&nGV@#9 z%3n?7S1r^~EFC501usv>yc`$&;rCyC)E+}OU2=JOg{S#Z zBp#fgp;%_ma{m1CoY!YVR5OBh!Px+Juc3yT4*dT8`hx8mBEn==ae4U$OEavR9mM$L z7|Z|hPv3EVT5uAClV`$*4<8!vHSj;k%<-{O-{nhXIb>yKp8qi7FZ9-l*cfiTb_+Rn8QMK{*}fsK^G1{<~3;Q+_+<{lEXY7v@d^8j7W8 zB+rM$AQVxXEqj(v=1gW)V|Dixfla)7)Bt8>qD;o?aj`|BPk1yOQk4~TeY;bI-3o{j z;*b~vF$hnee#tMt+~IXgpstzBDk?L~8aHSHx>I3?@d53BDUIu0P3Byj4gs(ogjI!N zIAUrQFnd@54aIVxC&ZW|BE%rgAyvb|oq-6mA8sjIx9R-ey#bI%B@epwAaiF{CZv~x zL|`^g%<@DYl~nD>QSQVT(2zquUZ!&L=pX?^8HDGEDnTKrv{tQIEMSm9S)~>5l?$13 zKF;~;%Ywz?p7#iZLB{mvCobNuttc(&X<1RkVY|k+yiWu|ELf!ZVFfe{mm-R2M3APM z6fmpty2gP;?NrH0Jq5alosV;FesIdlcDllN7%5`OWL}{n?HK|o^+LCOyZWYm6I7`* zqH(meYWip=0R%)9)v!8kX{~QTsGbFo(l;`Ky^K-3rg>0na*YUGP}3sMJu_;I+(lP{UGi@H!^J4eEr#b ze-aQ0WcRYe1_2R4L{X7dGqR|CC3W{&<@|dkn+Bl>viC5Hp%=i&dcCZEtUtSK>@O|8 zi~|H35{jyz(hzR~(zoRG&gAXxj&pi({a`JflCS2k!EPI4<49Z8>AIDlw_KL5D1%m11Wam6b0$VAd{d!QX$-=F($YnVyYXpBxvF zonF_0I54suyKXEtcfzXhe*lp6efr^{D!dvG8Rd~#X%CQPKtTA0PMTb$d3ayaF(tBzBr`@uWLBna zBs+SWCd>KGKO4SL7r7g5X)A^AAYhm!%p&s&M(T(N-qr*nO*d7Q)_mWy$m^>q7iU9a z&`mq-ki=QnPyitax&jZCftP7r0hl$$J*0qDvqu_-OSclUh-qM68Aa3$gb1V)?DK$l-RV*xR-BRp42iy{F2{Xk+ zm{&#&O3OqdS3{I$z+;1g6)p(!dEoxEwNv22U#46?|I+ zEX^OO$kI}YXdtzPU6l+oA!rk%SFc9A1}4+8yK-2a566dbf1WnA4uBi9MWwgacTXJO z69aA~mI5L|lGgfwx4Ao-@csFSVIFupDXEg}t&w&=pmz}1z0C}2db)CwXJ4`rSd`W4-&9y`bgt&X}#M3 z_eg*y=4b=9tG|y&-|n?;j;!nSJ_0-(d%Ye#gXebcP38Bdns_T2tV``i30PEV+ zE|8mCpSo-Hqre|cpdm3_0*FRbb0oy}_M+>d*UkJP0$uUh2i}wk6_!fes-wYw6oD0y zFkB*nhKOj6Xh0;a3%RbN>k(OZa=zg<9qH#$pqhtsbC{+kf!M#xW> zYe2h-k{ zwN@i23PlA?KPZ)o31|r_QL&K}q*OGJlq$7BlUkO(=&okl&~#sBcHZutx%WJNxU;i6 z-E23z{oo&lxtuxY`Tx#ypXZ!WY*7C__8UoN%P7wy92sVG&#h`BaV~q&GY|YoCLjI< zrd-8XaC`y4FF@$}0AvD;j)gA=9%f#3!PFY<6B z59NZi^EJ&^QsT^I_@4V1yM3S9Fu>96JEf3GZte;}XmEmzVt*h) zvWOlo;cSl3k&p5tY{LPSVk?&R`3A{knc08WdH0h~UDC^W?ZD&T{>}<>w*XF%;YEVu zgIh9~A%ipO;l9a3_xGU#ALWK%A|%n+GMIrnx)d@T&2ffZaw&)&fOC(WkiUNUV2?Q( zTn~c4;`rbVYIFh2fW{0NbpIywfJQ|Ir9$w1bQWTU`_VHMRFD^FRD-Ae-SVE3r+OfC z&+hO2dQK%vbAr$i1k$Z~?Sb+wx=&+93aI`z_>j|qaspHkphAV&+>bLlh13N-C z^=F*fe?Tq?aCHA?q$I+S?X;KenFoN|w+!CtJhyHBE!oNfb5nGmj~OgrMk3siKA1e) zGp7r1{`8Y8D?~%_x*cdOXv3P4EJo58ktPr?1932g0B0beSkydm^DVN>0)F|$uZjm0 zmj&B)$38wh`JB4(w~s1+`wr}DH<${x(L~xwZr-ZpEU5Jr5=|CljRC0)V z8CxkMNe3d$GoqXp0RQ~{1JVUhNz4semnxM~W&zu50?k9qH`>z$p z7rY3JuP_CLKUzW+^L^;R%}rJ3JI-4to3&)~P1^H{yTVDnM;#d=40l_2h zq~xV0{%F{#jm2Kgi!y6yY$HQrNULqqh9PYWnLy3vkZS@=9sapYJ#+-8RVIzWdP152 z2s8vQNsv_G4n{y5<%1+3)I-=dMfIsN<#E}eI<@^lDDvCI<%*{2aq>8#xj89FdF2K1*PRQ8@ ze}YU-QOKm{K3IeZMg~bMvjm}80kSAJ@^Cx{BtK-cMA4W}X|@yUbBaVOQYEC@xADo- zf6M{K$KEVkS}B`@h!Ri~!SCFNBk$YA*d6=2f3eQ&KOpl@oWcpfG5I@RgjtmBTn||a zNj-l~lO^-IQS7|;3%vK9yK{iU2frcbj{b_PT%WCD+j!UhecW)@fmJ)?u`O>C0LK;3 z;4I6$#-Y_pyQYgubpBj7PzLV)&xBgF2G-Idz~ySWc}*#To8H0r@nb3n-hi&yds{c? zTE;!*K*idw`Gx^*dhn21Zm`-1Kn)a$3w~}c!nTj!))Q-82T{+$P5q?vl}rA%wi@kNxH3x;ON?3%>I98^xU~Go%d#ZE%zVtqDtgjPCvb z^_O1e!r#vlC>Wob*ibg#upZj_7CC(N&ULlra&4#!mTSx2J-pnC-)NZspZ*7#7OI4@ zGge^$001R)MObuWa%Ew3Wi4c3bY%cCFfchSFfuJLGE^`!Ix{soG&n0TFgh?WcYK#0 z0000bbVXQnZEs|0W_c}SVRU5xGB7YXEif`IFfmjyI65^rIx{#cFfckWFtOX3V*mgE M07*qoM6N<$f(igbxc~qF literal 0 HcmV?d00001 diff --git a/src/calibre/gui2/images/news/granma.png b/src/calibre/gui2/images/news/granma.png new file mode 100644 index 0000000000000000000000000000000000000000..15eaa11feaa69289bf96ebbe8671bc5d95f416d0 GIT binary patch literal 685 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCwj^(N7l!{JxM1({$v_d#0*}aI zAngIhZYQ(tK!Rljj_E)ete@fByPj|c2F7ciE{-7?_pU}p_Z>3e@d>Y9|0HdPd9nYq zzbht0cufAN-LSOo;xW1OKPke3n(;dOCEMkW8~)jQ?bl3(cWu|N9eZzhym2B!Vw$3s zlIwqi&EDUibuwOgyg>c>JqF|1Hg+{Ui~gNTvJiZDKb84Ikqpx$HiaIc!bV=^fZ*e= zdpsB(9#c+l+V|HnXsMR3Td7)fh}2o1W=7Y%6`{_uNckvb9YB(Ts!aXx%O*(cJ3rOEv2YST!(*|h+HbL=Q<$LGR^7zgtR%DXOy2F ztSP!7p?`ky6I;0}hbOlGzqfFi`@wfJGk9+N$Y(D|z0)mwkwH#-ef1U*2A4E}-Niqz zt+#%$OI3xt((%f*Und<>>egwp>8U8MNEhOIU}I<}7nJ-U(&$m5Wa~Z0r6LUd&r5qb zStfEFsI_j;$$xesE?vDUo@dRcf84Du2h#LzR$R|AOuFzc`;%#f0Yk)1_KN>P2YTFQ z*#>;;xOLWP^T&5?Ea5)i@?=dSJ)D)Fh=u8Jocf@?IOy&EY4hG5OIR^|)8)9l=BA+N z*Jk-!w>I@E&lEAbkZ_fUAxJ~s+~|zYiV1@#7PsUcPgob9Q1j?D-^v~(S4b^<%O(*+_lF~ zowc*mSN?zG#6JTgj|2-P0j=X3Octr!>Q!6rFL(6%gQ=~SVPU)H*p<(mYxLk#22YdH z)Jdya81y8?l+1iAPHQ+ly7ZNI-@Ypkn?HwJ)MWI0kB?6%Thv)z*^t-RwZM>JLQ;zp zr{aSK$B=!yFD8Fp&v^R&`r?vpXQTCHl|ux-7i9Mwo$UXy;rknL!GLdG3j($XG-b=|y<4=0P*E8m?7|Mu{<{)Mb6v)`=o|MnccdA|PX#F>TD?pYkW6C$lz_}1^- z+PIU4l9NqTA3x5|`+PY|erAMCe)YyDoio{Q>bAVy|J!46BlED=%1Muothl;xS?QF5_u@^-Dt%cj(f0MM7 z#g;x_;^e-bsMYw-RPHuw`t5hmTY>3awZt`|B)KRxu_RSD1xPR$85mgV8W;glh=Gxn zv8k1bg|>l#m4QKd&2)K~hTQy=%(O~04Td3x7FMRlRt9De4b!`2wSXEJJYD@<);T3K F0RXg!orVAa literal 0 HcmV?d00001 diff --git a/src/calibre/gui2/images/news/la_cuarta.png b/src/calibre/gui2/images/news/la_cuarta.png new file mode 100644 index 0000000000000000000000000000000000000000..48a176e908f1f6debd8c2c66656ca2941cef9917 GIT binary patch literal 514 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#OuZT^vI!PS2f`n|s)Sr)_?S>H|j$F3A?{ z77-`5g$o5ZmQHZG5oo~byh5?WzUJj6wY$qAyF})`Jubgqy5Y6S-5>3HW&3@L=PsMg z%e;g|DWPk1;}s2dmkDzY^DpRHos@gJZrRe$lAfH>?i)Vt?rHd9`?6#gv(hn!8)qH$ zeOX@a@+gbnSw2z!bW{J&ShrhZ;dh_BH|st(pX1Wkj}fO%?dOfyHoEw`_ezY6S-&J$$eh_g<-zv&HbmQo0W(=EPI)`F;=5!XAZ-vptw_BW-qG+I_HLj zUSpV;ah=DU_e4!^ZK#Xsw@H_z6k^47!!{pgyb~uE&2VR-h|N+f=Uy}J`8sa1@6Thj z<6Cq3$Kn05_mq#xu3yM|ApM;A{T-j@pK0X3`i$GYx#nBsOXmx~FjOsZjVMVjN=+WnigoU|?lnzVWUg!R?@sR0bB%qjIgQ8c;G;u(9z|Z4J#lKm)%Yv<@7_QB^`|9lZG>V&V!*ThW@&r0FGIGr@l_`8r(NYf!7G1X_*1MmRa=;I?OLAJnm+m1 z`0hMTnFo7;;i_8V8c~v5l$uzQs+$5N7>o=IEOiZxfGEVk$jZ>%%D__Fz`)ADfb+)h swJ;62`6-!cmB<AbrQVfsXEcGN%oY9 zFZ;1GHsYV%vtKCPJNwl3-OfAJ=XNG#u9oxUbTTO9aF{K_CUhZ`)tSqrGISz~J;&$m zxi2)77`YW>j`px*Y+EG6;VE%c!(k57^}Okon|5(DT$a9MQ7?=(})8qiu?dJ;%+Md5gE% z`7ccPugrMp3fdGAy)H;YVo%NgR&n{h9i_Ql?cJgbX78t1 z%C)@NxtxQsal&J*5MKEik3WBBocp<9YHMWH>(3SG;trj^me02oZxhk@Z+64-k^~>~ zyZc)<^rl=7yS*?{31?$cNITuENhXOxhlz%b*3XWU%jj?fst9`-!TGm2GSPAbuU7Z{mr-e|BL zKG0L6&9gCCxb}gVP`0Hby8#gRoZoyzz`EustKZifGVT+Zzf5g4tSSEauX@g_MZ-#6sgpZO8H>$~3Jh2HxAjDe2*5pm+uHO8qE zt0Iox4v$GmNKnvcob-et=Ifz{rzgDe&{!DshJlTZt?d-Yn}rS9B`e-B#N6bG{T;urDwV_#)EkVcKNGzJR&tv;9>W z2Tg_3j2kMBhZ$Wu%DBx+hzA6Abu~T7SkBjxargiKho{erY-e{ns3B3nzz}JZ_MSsh zpa~drswJ)wCCNppi6yDJDL{h3$iTo-*T4vfLJW+oObo0HO|=aStPBh$Myl1oH00)| hWTsVOYB04j1}Zg!Xh?q)IRU7F!PC{xWt~$(699pE^ Date: Sun, 1 Feb 2009 21:10:03 -0800 Subject: [PATCH 05/54] Fix #1747 (Bug in TOC epub for level 2) --- src/calibre/ebooks/html.py | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/calibre/ebooks/html.py b/src/calibre/ebooks/html.py index a7883ed763..de863cca75 100644 --- a/src/calibre/ebooks/html.py +++ b/src/calibre/ebooks/html.py @@ -594,15 +594,21 @@ class Processor(Parser): ''' Populate the Table of Contents from detected chapters and links. ''' - - def add_item(href, fragment, text, target, type='link'): - for entry in toc.flat(): - if entry.href == href and entry.fragment == fragment: - return entry - if len(text) > 50: - text = text[:50] + u'\u2026' - return target.add_item(href, fragment, text, type=type) - + class Adder(object): + + def __init__(self, toc): + self.next_play_order = max([x.play_order for x in toc.flat()]) + + def __call__(self, href, fragment, text, target, type='link'): + for entry in toc.flat(): + if entry.href == href and entry.fragment == fragment: + return entry + if len(text) > 50: + text = text[:50] + u'\u2026' + self.next_play_order += 1 + return target.add_item(href, fragment, text, type=type, + play_order=self.next_play_order) + add_item = Adder(toc) name = self.htmlfile_map[self.htmlfile.path] href = 'content/'+name @@ -629,13 +635,15 @@ class Processor(Parser): if self.opts.level1_toc is not None: level1 = self.opts.level1_toc(self.root) + level1_order = [] if level1: added = {} for elem in level1: text, _href, frag = elem_to_link(elem, href, counter) counter += 1 if text: - added[elem] = add_item(_href, frag, text, toc, type='chapter') + level1_order.append(add_item(_href, frag, text, toc, type='chapter')) + added[elem] = level1_order[-1] add_item(_href, frag, 'Top', added[elem], type='chapter') if self.opts.level2_toc is not None: added2 = {} @@ -664,6 +672,15 @@ class Processor(Parser): if text: add_item(_href, frag, text, level2, type='chapter') + + if level1_order: # Fix play order + next_play_order = level1_order[0].play_order + for x in level1_order: + for y in x.flat(): + y.play_order = next_play_order + next_play_order += 1 + + if len(toc) > 0: return From 13ef549864529189476f55de2652c2d24ef74d4f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Feb 2009 22:03:26 -0800 Subject: [PATCH 06/54] IGN:Make downloading from web a little more robust --- src/calibre/web/fetch/simple.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/calibre/web/fetch/simple.py b/src/calibre/web/fetch/simple.py index f5ffaf08b8..0d073ecce7 100644 --- a/src/calibre/web/fetch/simple.py +++ b/src/calibre/web/fetch/simple.py @@ -15,7 +15,7 @@ from PIL import Image from cStringIO import StringIO from calibre import setup_cli_handlers, browser, sanitize_file_name, \ - relpath, LoggingInterface + relpath, LoggingInterface, unicode_path from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag from calibre.ebooks.chardet import xml_to_unicode from calibre.utils.config import OptionParser @@ -53,7 +53,7 @@ def save_soup(soup, target): nm = ns.find('meta') metas = soup.findAll('meta', content=True) for meta in metas: - if 'charset' in meta['content']: + if 'charset' in meta.get('content', '').lower(): meta.replaceWith(nm) selfdir = os.path.dirname(target) @@ -62,7 +62,7 @@ def save_soup(soup, target): for key in ('src', 'href'): path = tag.get(key, None) if path and os.path.isfile(path) and os.path.exists(path) and os.path.isabs(path): - tag[key] = relpath(path, selfdir).replace(os.sep, '/') + tag[key] = unicode_path(relpath(path, selfdir).replace(os.sep, '/')) html = unicode(soup) with open(target, 'wb') as f: @@ -227,7 +227,7 @@ class RecursiveFetcher(object, LoggingInterface): return True def process_stylesheets(self, soup, baseurl): - diskpath = os.path.join(self.current_dir, 'stylesheets') + diskpath = unicode_path(os.path.join(self.current_dir, 'stylesheets')) if not os.path.exists(diskpath): os.mkdir(diskpath) for c, tag in enumerate(soup.findAll(lambda tag: tag.name.lower()in ['link', 'style'] and tag.has_key('type') and tag['type'].lower() == 'text/css')): @@ -280,7 +280,7 @@ class RecursiveFetcher(object, LoggingInterface): def process_images(self, soup, baseurl): - diskpath = os.path.join(self.current_dir, 'images') + diskpath = unicode_path(os.path.join(self.current_dir, 'images')) if not os.path.exists(diskpath): os.mkdir(diskpath) c = 0 From ce1e99efc868a283a6bbfac87e47fbfa63f3c97e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Feb 2009 22:14:29 -0800 Subject: [PATCH 07/54] version 0.4.133 --- src/calibre/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/constants.py b/src/calibre/constants.py index b92fb0f0e1..ab5cc9f6b0 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -2,7 +2,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = 'calibre' -__version__ = '0.4.132' +__version__ = '0.4.133' __author__ = "Kovid Goyal " ''' Various run time constants. From 34a8245587150b38413da2419d0e13a3ac6cbf83 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Feb 2009 22:18:38 -0800 Subject: [PATCH 08/54] IGN:Tag release From bccea55bbb86e5b351e471f414390e8a0378988e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Feb 2009 01:43:09 -0800 Subject: [PATCH 09/54] IGN:... --- src/calibre/manual/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index f587a0122a..b5ec52dd7c 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -102,7 +102,7 @@ Device Integration What devices does |app| support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the moment |app| has full support for the SONY PRS 500/505/700, Cybook Gen 3 as well as the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk. +At the moment |app| has full support for the SONY PRS 500/505/700, Cybook Gen 3, Amazon Kindle as well as the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk. I used |app| to transfer some books to my reader, and now the SONY software hangs every time I connect the reader? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 682a130091cf2d6adb13eb76865b28d89a40883d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Feb 2009 07:40:53 -0800 Subject: [PATCH 10/54] IGN:Ensure download time is recorded for time based recipes --- src/calibre/gui2/dialogs/scheduler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index 9c9204c398..47d076f28c 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -464,7 +464,7 @@ class Scheduler(QObject): recipe = self.recipes[self.recipes.index(recipe)] now = datetime.utcnow() d = now - recipe.last_downloaded - if recipe.schedule is not None: + if recipe.schedule is not None and recipe.schedule < 1e4: interval = timedelta(days=recipe.schedule) if abs(d - interval) < timedelta(hours=1): recipe.last_downloaded += interval @@ -487,7 +487,7 @@ class Scheduler(QObject): if recipe not in self.queue: self.do_download(recipe) finally: - self.lock.unlock() + self.lock.unlock() def refresh_schedule(self, recipes): self.recipes = recipes From 02091a0fa631a12a04b03c4fa338a5f1d05206c0 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Mon, 2 Feb 2009 11:26:06 -0500 Subject: [PATCH 11/54] Fix super-nasty character decoding error. --- src/calibre/ebooks/oeb/base.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 854f8bef94..9ba5d95899 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -1387,12 +1387,18 @@ class OEBBook(object): def decode(self, data): if isinstance(data, unicode): return data - encodings = ['utf-8', 'utf-16'] - if self.encoding is not None: - encodings.append(self.encoding) - for encoding in encodings: + if data[:2] in ('\xff\xfe', '\xfe\xff'): try: - return data.decode(encoding) + return data.decode('utf-16') + except UnicodeDecodeError: + pass + try: + return data.decode('utf-8') + except UnicodeDecodeError: + pass + if self.encoding is not None: + try: + return data.decode(self.encoding) except UnicodeDecodeError: pass data, _ = xml_to_unicode(data) From 7b2064221eaab1f74b014b0c7eb064df5b45d69d Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Mon, 2 Feb 2009 11:41:00 -0500 Subject: [PATCH 12/54] Fix bug in reconstituting NCX @id and @class attributes. --- src/calibre/ebooks/oeb/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 9ba5d95899..d17973b88e 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -900,9 +900,9 @@ class TOC(object): def to_ncx(self, parent, depth=1): for node in self.nodes: - id = self.id or unicode(uuid.uuid4()) + id = node.id or unicode(uuid.uuid4()) attrib = {'id': id, 'playOrder': '0'} - if self.klass: + if node.klass: attrib['class'] = node.klass point = element(parent, NCX('navPoint'), attrib=attrib) label = etree.SubElement(point, NCX('navLabel')) From cecfa09b959052a05b6081bdb25ec24fe240bd6e Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Mon, 2 Feb 2009 11:46:52 -0500 Subject: [PATCH 13/54] Use same decoding logic for OPF as for (X)HTML. --- src/calibre/ebooks/oeb/base.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index d17973b88e..4642f36336 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -1009,13 +1009,16 @@ class OEBBook(object): return nroot def _read_opf(self, opfpath): - opf = self.container.read(opfpath) + data = self.container.read(opfpath) + data = self.decode(data) + data = XMLDECL_RE.sub('', data) + data = data.replace('\r\n', '\n').replace('\r', '\n') try: - opf = etree.fromstring(opf) + opf = etree.fromstring(data) except etree.XMLSyntaxError: repl = lambda m: ENTITYDEFS.get(m.group(1), m.group(0)) - opf = ENTITY_RE.sub(repl, opf) - opf = etree.fromstring(opf) + data = ENTITY_RE.sub(repl, data) + opf = etree.fromstring(data) self.logger.warn('OPF contains invalid HTML named entities') ns = namespace(opf.tag) if ns not in ('', OPF1_NS, OPF2_NS): From f524968ce263965500648526102b3c5a43d0038e Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Mon, 2 Feb 2009 17:57:52 -0500 Subject: [PATCH 14/54] Fix a few mindless OPF-parsing bugs. --- src/calibre/ebooks/oeb/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 4642f36336..7ed56bee0b 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -1048,7 +1048,7 @@ class OEBBook(object): haveuuid = True if 'id' in ident.attrib: haveid = True - if not haveuuid and haveid: + if not (haveuuid and haveid): bookid = "urn:uuid:%s" % str(uuid.uuid4()) metadata.add('identifier', bookid, id='calibre-uuid') if uid is None: @@ -1235,13 +1235,13 @@ class OEBBook(object): if not item.linear: continue html = item.data title = ''.join(xpath(html, '/h:html/h:head/h:title/text()')) - title = COLLAPSE_RE(' ', title.strip()) + title = COLLAPSE_RE.sub(' ', title.strip()) if title: titles.append(title) headers.append('(unlabled)') for tag in ('h1', 'h2', 'h3', 'h4', 'h5', 'strong'): expr = '/h:html/h:body//h:%s[position()=1]/text()' - header = ''.join(xpath(html % tag, expr)) + header = ''.join(xpath(html, expr % tag)) header = COLLAPSE_RE.sub(' ', header.strip()) if header: headers[-1] = header From 1fc09e826757a52c6e8c3f339bdddf355b7630ea Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Feb 2009 15:33:22 -0800 Subject: [PATCH 15/54] New recipe for El Mundo by Darko Miletic --- src/calibre/gui2/images/news/elmundo.png | Bin 0 -> 550 bytes src/calibre/parallel.py | 2 +- src/calibre/web/feeds/recipes/__init__.py | 2 +- .../web/feeds/recipes/recipe_elmundo.py | 45 ++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/calibre/gui2/images/news/elmundo.png create mode 100644 src/calibre/web/feeds/recipes/recipe_elmundo.py diff --git a/src/calibre/gui2/images/news/elmundo.png b/src/calibre/gui2/images/news/elmundo.png new file mode 100644 index 0000000000000000000000000000000000000000..754b3d0e154df866a55866b5b4174ad3e1ea1630 GIT binary patch literal 550 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#RIMT^vI!PA8jitp9!f*r78E^wiHJtWi6f zutMu#LVohm6Amf~Pqv@_{r}@@{v8c-EbN=xS8_G)@3m^)zM9#wS;BQL_rLxBKJYp_ z`AnFtc+PkJ!sR-Q>lJ-=sKo94f9k^KPZG_gHK+fdwdVh$ev?7MqUx!j^S73@Jl@ye z|L~v2$O8oZakVKLGd49RevI;Qp7HPBZ~q=ip7r)M$r|(aO-}r~tyV*7hQ*Bti5n3! zC2vGVay&AZ-)C5|*5XjXixY)A6nkcuz4`zD`F(pfH?~88|K~rnKm6XlUh>f2I~{)N z5eFwGs|)B|;9mXr|HIGxY;JCkc>jL>F5kSpRqODYV6qdUr9emXsF8NKy z;?w-j-l;2Q9AS8G|3AT^_OWE)O9pX^^52romw_TD%pTloHs{fqbjXG$XU!QN9~BlQ zW@hHY`~Ux!oH0{ElHu^D;w38SFB*X1tXkq4QIcGgnpl#mn*t;lj0_Acbq$PwD8$gx z%Fx2fz*yVBz{ Date: Mon, 2 Feb 2009 18:52:59 -0500 Subject: [PATCH 16/54] Fix #1715. Improve handling of paths which contain URI reserved characters. --- src/calibre/ebooks/html.py | 9 +++++---- src/calibre/ebooks/oeb/base.py | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/calibre/ebooks/html.py b/src/calibre/ebooks/html.py index de863cca75..0229fd6124 100644 --- a/src/calibre/ebooks/html.py +++ b/src/calibre/ebooks/html.py @@ -9,7 +9,7 @@ directory or zip file. All the action starts in :function:`create_dir`. ''' import sys, re, os, shutil, logging, tempfile, cStringIO, operator, functools -from urlparse import urlparse +from urlparse import urlparse, urlunparse from urllib import unquote from lxml import etree @@ -98,7 +98,8 @@ class Link(object): @classmethod def url_to_local_path(cls, url, base): - path = url.path + path = urlunparse(('', '', url.path, url.params, url.query, '')) + path = unquote(path) if os.path.isabs(path): return path return os.path.abspath(os.path.join(base, path)) @@ -111,11 +112,11 @@ class Link(object): ''' assert isinstance(url, unicode) and isinstance(base, unicode) self.url = url - self.parsed_url = urlparse(unquote(self.url)) + self.parsed_url = urlparse(self.url) self.is_local = self.parsed_url.scheme in ('', 'file') self.is_internal = self.is_local and not bool(self.parsed_url.path) self.path = None - self.fragment = self.parsed_url.fragment + self.fragment = unquote(self.parsed_url.fragment) if self.is_local and not self.is_internal: self.path = self.url_to_local_path(self.parsed_url, base) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 7ed56bee0b..94402ae882 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -154,6 +154,9 @@ def urlquote(href): def urlnormalize(href): parts = urlparse(href) + if not parts.scheme: + path, frag = urldefrag(href) + parts = ('', '', path, '', '', frag) parts = (part.replace('\\', '/') for part in parts) parts = (urlunquote(part) for part in parts) parts = (urlquote(part) for part in parts) @@ -1323,7 +1326,7 @@ class OEBBook(object): with TemporaryDirectory('_html_cover') as tdir: writer = DirWriter() writer.dump(self, tdir) - path = os.path.join(tdir, hcover.href) + path = os.path.join(tdir, urlunquote(hcover.href)) renderer = CoverRenderer(path) data = renderer.image_data id, href = self.manifest.generate('cover', 'cover.jpeg') From 168ef417875796e28d19d32ae1fba09c38ed783c Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Mon, 2 Feb 2009 23:24:11 -0500 Subject: [PATCH 17/54] Further improve OEBBook handling of bad OPF and strange URIs. --- src/calibre/__init__.py | 3 + src/calibre/ebooks/oeb/base.py | 200 ++++++++++++++---- src/calibre/ebooks/oeb/stylizer.py | 1 - .../ebooks/oeb/transforms/trimmanifest.py | 16 +- 4 files changed, 162 insertions(+), 58 deletions(-) diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py index 0828c15b98..ae8a837373 100644 --- a/src/calibre/__init__.py +++ b/src/calibre/__init__.py @@ -21,6 +21,9 @@ mimetypes.add_type('application/epub+zip', '.epub') mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs') mimetypes.add_type('application/x-sony-bbeb', '.lrf') mimetypes.add_type('application/x-dtbncx+xml', '.ncx') +mimetypes.add_type('application/adobe-page-template+xml', '.xpgt') +mimetypes.add_type('application/x-font-opentype', '.otf') +mimetypes.add_type('application/x-font-truetype', '.ttf') def to_unicode(raw, encoding='utf-8', errors='strict'): if isinstance(raw, unicode): diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 94402ae882..4e950d3cdb 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -62,6 +62,16 @@ def SVG(name): return '{%s}%s' % (SVG_NS, name) def XLINK(name): return '{%s}%s' % (XLINK_NS, name) def CALIBRE(name): return '{%s}%s' % (CALIBRE_NS, name) +def LINK_SELECTORS(): + results = [] + for expr in ('h:head/h:link/@href', 'h:body//h:a/@href', + 'h:body//h:img/@src', 'h:body//h:object/@data', + 'h:body//*/@xl:href', '//ncx:content/@src', + 'o2:page/@href'): + results.append(etree.XPath(expr, namespaces=XPNSMAP)) + return results +LINK_SELECTORS = LINK_SELECTORS() + EPUB_MIME = 'application/epub+zip' XHTML_MIME = 'application/xhtml+xml' CSS_MIME = 'text/css' @@ -89,6 +99,10 @@ COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+') QNAME_RE = re.compile(r'^[{][^{}]+[}][^{}]+$') PREFIXNAME_RE = re.compile(r'^[^:]+[:][^:]+') XMLDECL_RE = re.compile(r'^\s*<[?]xml.*?[?]>') +CSSURL_RE = re.compile(r'''url[(](?P["']?)(?P[^)]+)(?P=q)[)]''') + +RECOVER_PARSER = etree.XMLParser(recover=True) + def element(parent, *args, **kwargs): if parent is not None: @@ -140,14 +154,17 @@ def xml2str(root): return etree.tostring(root, encoding='utf-8', xml_declaration=True) ASCII_CHARS = set(chr(x) for x in xrange(128)) -URL_SAFE = set(u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - u'abcdefghijklmnopqrstuvwxyz' - u'0123456789' u'_.-/~') -URL_UNSAFE = ASCII_CHARS - URL_SAFE +UNIBYTE_CHARS = set(chr(x) for x in xrange(256)) +URL_SAFE = set('ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789' '_.-/~') +URL_UNSAFE = [ASCII_CHARS - URL_SAFE, UNIBYTE_CHARS - URL_SAFE] def urlquote(href): result = [] + unsafe = 0 if isinstance(href, unicode) else 1 + unsafe = URL_UNSAFE[unsafe] for char in href: - if char in URL_UNSAFE: + if char in unsafe: char = "%%%02x" % ord(char) result.append(char) return ''.join(result) @@ -185,7 +202,7 @@ class AbstractContainer(object): class DirContainer(AbstractContainer): def __init__(self, rootdir): - self.rootdir = rootdir + self.rootdir = unicode(rootdir) def read(self, path): path = os.path.join(self.rootdir, path) @@ -205,16 +222,23 @@ class DirContainer(AbstractContainer): return os.path.isfile(urlunquote(path)) class DirWriter(object): - def __init__(self, version=2.0): + def __init__(self, version='2.0', page_map=False): self.version = version + self.page_map = page_map def dump(self, oeb, path): + version = int(self.version[0]) if not os.path.isdir(path): os.mkdir(path) output = DirContainer(path) for item in oeb.manifest.values(): output.write(item.href, str(item)) - metadata = oeb.to_opf2() if self.version == 2 else oeb.to_opf1() + if version == 1: + metadata = oeb.to_opf1() + elif version == 2: + metadata = oeb.to_opf2(page_map=self.page_map) + else: + raise OEBError("Unrecognized OPF version %r" % self.version) for href, data in metadata.values(): output.write(href, xml2str(data)) return @@ -455,7 +479,6 @@ class Manifest(object): # Convert to Unicode and normalize line endings data = self.oeb.decode(data) data = XMLDECL_RE.sub('', data) - data = data.replace('\r\n', '\n').replace('\r', '\n') # Handle broken XHTML w/ SVG (ugh) if 'svg:' in data and SVG_NS not in data: data = data.replace( @@ -480,7 +503,10 @@ class Manifest(object): if elem.text: elem.text = elem.text.strip('-') data = etree.tostring(data, encoding=unicode) - data = etree.fromstring(data) + try: + data = etree.fromstring(data) + except etree.XMLSyntaxError: + data = etree.fromstring(data, parser=RECOVER_PARSER) # Force into the XHTML namespace if barename(data.tag) != 'html': raise OEBError( @@ -536,6 +562,8 @@ class Manifest(object): data = self._force_xhtml(data) elif self.media_type[-4:] in ('+xml', '/xml'): data = etree.fromstring(data) + elif self.media_type in OEB_STYLES: + data = self.oeb.decode(data) self._data = data return data def fset(self, value): @@ -549,6 +577,8 @@ class Manifest(object): data = self.data if isinstance(data, etree._Element): return xml2str(data) + if isinstance(data, unicode): + return data.encode('utf-8') return str(data) def __eq__(self, other): @@ -572,7 +602,9 @@ class Manifest(object): return cmp(skey, okey) def relhref(self, href): - if '/' not in self.href or ':' in href: + if urlparse(href).scheme: + return href + if '/' not in self.href: return href base = os.path.dirname(self.href).split('/') target, frag = urldefrag(href) @@ -588,7 +620,12 @@ class Manifest(object): return relhref def abshref(self, href): - if '/' not in self.href or ':' in href: + if urlparse(href).scheme: + return href + path, frag = urldefrag(href) + if not path: + return '#'.join((self.href, frag)) + if '/' not in self.href: return href dirname = os.path.dirname(self.href) href = os.path.join(dirname, href) @@ -615,18 +652,20 @@ class Manifest(object): if item in self.oeb.spine: self.oeb.spine.remove(item) - def generate(self, id, href): - href = urlnormalize(href) - base = id - index = 1 - while id in self.ids: - id = base + str(index) - index += 1 - base, ext = os.path.splitext(href) - index = 1 - while href in self.hrefs: - href = base + str(index) + ext - index += 1 + def generate(self, id=None, href=None): + if id is not None: + base = id + index = 1 + while id in self.ids: + id = base + str(index) + index += 1 + if href is not None: + href = urlnormalize(href) + base, ext = os.path.splitext(href) + index = 1 + while href in self.hrefs: + href = base + str(index) + ext + index += 1 return id, href def __iter__(self): @@ -996,13 +1035,11 @@ class OEBBook(object): metadata = etree.SubElement(nroot, OPF('metadata'), nsmap=nsmap) ignored = (OPF('dc-metadata'), OPF('x-metadata')) for elem in xpath(opf, 'o2:metadata//*'): + if elem.tag in ignored: + continue if namespace(elem.tag) in DC_NSES: tag = barename(elem.tag).lower() elem.tag = '{%s}%s' % (DC11_NS, tag) - for name in elem.attrib: - if name in ('role', 'file-as', 'scheme', 'event'): - nsname = '{%s}%s' % (OPF2_NS, name) - elem.attrib[nsname] = elem.attrib.pop(name) metadata.append(elem) for element in xpath(opf, 'o2:metadata//o2:meta'): metadata.append(element) @@ -1015,7 +1052,6 @@ class OEBBook(object): data = self.container.read(opfpath) data = self.decode(data) data = XMLDECL_RE.sub('', data) - data = data.replace('\r\n', '\n').replace('\r', '\n') try: opf = etree.fromstring(data) except etree.XMLSyntaxError: @@ -1077,6 +1113,43 @@ class OEBBook(object): if not metadata.title: self.logger.warn('Title not specified') metadata.add('title', self.translate(__('Unknown'))) + + def _manifest_add_missing(self): + manifest = self.manifest + unchecked = set(manifest.values()) + while unchecked: + new = set() + for item in unchecked: + if (item.media_type in OEB_DOCS or + item.media_type[-4:] in ('/xml', '+xml')) and \ + item.data is not None: + hrefs = [sel(item.data) for sel in LINK_SELECTORS] + for href in chain(*hrefs): + href, _ = urldefrag(href) + if not href: + continue + href = item.abshref(urlnormalize(href)) + scheme = urlparse(href).scheme + if not scheme and href not in manifest.hrefs: + new.add(href) + elif item.media_type == CSS_MIME: + for match in CSSURL_RE.finditer(item.data): + href = match.group('url') + href = item.abshref(urlnormalize(href)) + scheme = urlparse(href).scheme + if not scheme and href not in manifest.hrefs: + new.add(href) + unchecked.clear() + for href in new: + if not self.container.exists(href): + self.logger.warn('Referenced file %r not found' % href) + continue + self.logger.warn('Referenced file %r not in manifest' % href) + id, _ = manifest.generate(id='added') + guessed = mimetypes.guess_type(href)[0] + media_type = guessed or BINARY_MIME + added = manifest.add(id, href, media_type) + unchecked.add(added) def _manifest_from_opf(self, opf): self.manifest = manifest = Manifest(self) @@ -1100,6 +1173,40 @@ class OEBBook(object): self.logger.warn(u'Duplicate manifest id %r' % id) id, href = manifest.generate(id, href) manifest.add(id, href, media_type, fallback) + self._manifest_add_missing() + + def _spine_add_extra(self): + manifest = self.manifest + spine = self.spine + unchecked = set(spine) + selector = XPath('h:body//h:a/@href') + extras = set() + while unchecked: + new = set() + for item in unchecked: + if item.media_type not in OEB_DOCS: + # TODO: handle fallback chains + continue + for href in selector(item.data): + href, _ = urldefrag(href) + if not href: + continue + href = item.abshref(urlnormalize(href)) + if href not in manifest.hrefs: + continue + found = manifest.hrefs[href] + if found.media_type not in OEB_DOCS or \ + found in spine or found in extras: + continue + new.add(found) + extras.update(new) + unchecked = new + version = int(self.version[0]) + for item in sorted(extras): + if version >= 2: + self.logger.warn( + 'Spine-referenced file %r not in spine' % item.href) + spine.add(item, linear=False) def _spine_from_opf(self, opf): self.spine = spine = Spine(self) @@ -1110,16 +1217,9 @@ class OEBBook(object): continue item = self.manifest[idref] spine.add(item, elem.get('linear')) - extras = [] - for item in self.manifest.values(): - if item.media_type in OEB_DOCS \ - and item not in spine: - extras.append(item) - extras.sort() - for item in extras: - spine.add(item, False) if len(spine) == 0: raise OEBError("Spine is empty") + self._spine_add_extra() def _guide_from_opf(self, opf): self.guide = guide = Guide(self) @@ -1189,12 +1289,11 @@ class OEBBook(object): href = site.get('href') if not title or not href: continue - href = item.abshref(urlnormalize(href)) - path, _ = urldefrag(href) + path, _ = urldefrag(urlnormalize(href)) if path not in self.manifest.hrefs: self.logger.warn('TOC reference %r not found' % href) continue - id = child.get('id') + id = site.get('id') toc.add(title, href, id=id) return True @@ -1217,12 +1316,12 @@ class OEBBook(object): order = [] for anchor in xpath(html, './/h:a[@href]'): href = anchor.attrib['href'] + href = item.abshref(urlnormalize(href)) path, frag = urldefrag(href) - if not path: - href = '#'.join((itempath, frag)) + if path not in self.manifest.hrefs: + continue title = ' '.join(xpath(anchor, './/text()')) title = COLLAPSE_RE.sub(' ', title.strip()) - href = urlnormalize(href) if href not in titles: order.append(href) titles[href].append(title) @@ -1313,7 +1412,12 @@ class OEBBook(object): continue name = COLLAPSE_RE.sub(' ', name.strip()) href = item.abshref(urlnormalize(href)) - pages.add(name, href) + type = 'normal' + if not name: + type = 'special' + elif name.lower().strip('ivxlcdm') == '': + type = 'front' + pages.add(name, href, type=type) return True def _pages_from_opf(self, opf, item): @@ -1376,6 +1480,7 @@ class OEBBook(object): self.metadata.add('cover', cover.id) def _all_from_opf(self, opf): + self.version = opf.get('version', '1.2') self._metadata_from_opf(opf) self._manifest_from_opf(opf) self._spine_from_opf(opf) @@ -1384,7 +1489,7 @@ class OEBBook(object): self._toc_from_opf(opf, item) self._pages_from_opf(opf, item) self._ensure_cover_image() - + def translate(self, text): lang = str(self.metadata.language[0]) lang = lang.split('-', 1)[0].lower() @@ -1408,6 +1513,8 @@ class OEBBook(object): except UnicodeDecodeError: pass data, _ = xml_to_unicode(data) + data = data.replace('\r\n', '\n') + data = data.replace('\r', '\n') return data def to_opf1(self): @@ -1447,7 +1554,8 @@ class OEBBook(object): next += 1 selector = XPath('ncx:content/@src') for elem in xpath(ncx, '//*[@playOrder and ./ncx:content[@src]]'): - order = playorder[selector(elem)[0]] + href = selector(elem)[0] + order = playorder.get(href, 0) elem.attrib['playOrder'] = str(order) return diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index ae42e063b7..34f3293c32 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -172,7 +172,6 @@ class Stylizer(object): if path not in hrefs: return (None, None) data = hrefs[path].data - data = self.oeb.decode(data) data = XHTML_CSS_NAMESPACE + data return (None, data) diff --git a/src/calibre/ebooks/oeb/transforms/trimmanifest.py b/src/calibre/ebooks/oeb/transforms/trimmanifest.py index 643952c03d..a1d28e5a99 100644 --- a/src/calibre/ebooks/oeb/transforms/trimmanifest.py +++ b/src/calibre/ebooks/oeb/transforms/trimmanifest.py @@ -13,13 +13,9 @@ from urlparse import urldefrag from lxml import etree import cssutils from calibre.ebooks.oeb.base import XPNSMAP, CSS_MIME, OEB_DOCS +from calibre.ebooks.oeb.base import LINK_SELECTORS, CSSURL_RE from calibre.ebooks.oeb.base import urlnormalize -LINK_SELECTORS = [] -for expr in ('//h:link/@href', '//h:img/@src', '//h:object/@data', - '//*/@xl:href'): - LINK_SELECTORS.append(etree.XPath(expr, namespaces=XPNSMAP)) - class ManifestTrimmer(object): def transform(self, oeb, context): oeb.logger.info('Trimming unused files from manifest...') @@ -53,15 +49,13 @@ class ManifestTrimmer(object): if found not in used: new.add(found) elif item.media_type == CSS_MIME: - def replacer(uri): - absuri = item.abshref(urlnormalize(uri)) - if absuri in oeb.manifest.hrefs: + for match in CSSURL_RE.finditer(item.data): + href = match.group('url') + href = item.abshref(urlnormalize(href)) + if href in oeb.manifest.hrefs: found = oeb.manifest.hrefs[href] if found not in used: new.add(found) - return uri - sheet = cssutils.parseString(item.data, href=item.href) - cssutils.replaceUrls(sheet, replacer) used.update(new) unchecked = new for item in oeb.manifest.values(): From beb45413fe4cd9fd93e56c9675a361f1f6b4fd03 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Tue, 3 Feb 2009 09:02:11 -0500 Subject: [PATCH 18/54] Fix a handful of additional encoding issues. I don't like patching cssutils, but cssutils as-is insists on decoding the contents of @imported files itself. Another option would be to just encode everything back into UTF-8 and then let cssutils decode it again, but that seems even worse than a two-line patch. --- src/calibre/ebooks/lit/writer.py | 4 +++- src/calibre/ebooks/oeb/stylizer.py | 2 +- src/cssutils/util.py | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/lit/writer.py b/src/calibre/ebooks/lit/writer.py index 5026c9e267..52957acb92 100644 --- a/src/calibre/ebooks/lit/writer.py +++ b/src/calibre/ebooks/lit/writer.py @@ -474,7 +474,7 @@ class LitWriter(object): name = '/data/' + item.id data = item.data secnum = 0 - if not isinstance(data, basestring): + if isinstance(data, etree._Element): self._add_folder(name) rebin = ReBinary(data, item, self._oeb, map=HTML_MAP) self._add_file(name + '/ahc', rebin.ahc, 0) @@ -483,6 +483,8 @@ class LitWriter(object): data = rebin.content name = name + '/content' secnum = 1 + elif isinstance(data, unicode): + data = data.encode('utf-8') self._add_file(name, data, secnum) item.size = len(data) diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index 34f3293c32..e4a0cfd7fe 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -173,7 +173,7 @@ class Stylizer(object): return (None, None) data = hrefs[path].data data = XHTML_CSS_NAMESPACE + data - return (None, data) + return ('utf-8', data) def flatten_rule(self, rule, href, index): results = [] diff --git a/src/cssutils/util.py b/src/cssutils/util.py index f2845de590..7b5b9b3857 100644 --- a/src/cssutils/util.py +++ b/src/cssutils/util.py @@ -840,7 +840,9 @@ def _readUrl(url, fetcher=None, overrideEncoding=None, parentEncoding=None): try: # encoding may still be wrong if encoding *is lying*! - if content is not None: + if isinstance(content, unicode): + decodedCssText = content + elif content is not None: decodedCssText = codecs.lookup("css")[1](content, encoding=encoding)[0] else: decodedCssText = None From 8367902cb1bd3aa64cee52d97564789f7d4e5c78 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Tue, 3 Feb 2009 12:43:36 -0500 Subject: [PATCH 19/54] Fix LIT strange pagination bug. --- src/calibre/ebooks/lit/writer.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/lit/writer.py b/src/calibre/ebooks/lit/writer.py index 52957acb92..4a059b6433 100644 --- a/src/calibre/ebooks/lit/writer.py +++ b/src/calibre/ebooks/lit/writer.py @@ -23,7 +23,7 @@ from urllib import unquote as urlunquote from lxml import etree from calibre.ebooks.lit.reader import DirectoryEntry import calibre.ebooks.lit.maps as maps -from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES, OEB_CSS_MIME, \ +from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_MIME, OEB_STYLES, \ CSS_MIME, OPF_MIME, XML_NS, XML from calibre.ebooks.oeb.base import namespace, barename, prefixname, \ urlnormalize, xpath @@ -495,7 +495,7 @@ class LitWriter(object): if item.spine_position is not None: key = 'linear' if item.linear else 'nonlinear' manifest[key].append(item) - elif item.media_type == CSS_MIME: + elif item.media_type in OEB_STYLES: manifest['css'].append(item) elif item.media_type in LIT_IMAGES: manifest['images'].append(item) @@ -508,6 +508,11 @@ class LitWriter(object): data.write(pack(' Date: Tue, 3 Feb 2009 12:46:40 -0500 Subject: [PATCH 20/54] A few minor clean-ups to OEBBook bad OPF handling. --- src/calibre/ebooks/oeb/base.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 4e950d3cdb..9c118b3a6e 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -1116,6 +1116,7 @@ class OEBBook(object): def _manifest_add_missing(self): manifest = self.manifest + known = set(manifest.hrefs) unchecked = set(manifest.values()) while unchecked: new = set() @@ -1130,17 +1131,18 @@ class OEBBook(object): continue href = item.abshref(urlnormalize(href)) scheme = urlparse(href).scheme - if not scheme and href not in manifest.hrefs: + if not scheme and href not in known: new.add(href) - elif item.media_type == CSS_MIME: + elif item.media_type in OEB_STYLES: for match in CSSURL_RE.finditer(item.data): - href = match.group('url') + href, _ = urldefrag(match.group('url')) href = item.abshref(urlnormalize(href)) scheme = urlparse(href).scheme - if not scheme and href not in manifest.hrefs: + if not scheme and href not in known: new.add(href) unchecked.clear() for href in new: + known.add(href) if not self.container.exists(href): self.logger.warn('Referenced file %r not found' % href) continue @@ -1441,8 +1443,10 @@ class OEBBook(object): if self.metadata.cover: id = str(self.metadata.cover[0]) item = self.manifest.ids.get(id, None) - if item is not None: + if item is not None and item.media_type in OEB_IMAGES: return item + else: + self.logger.warn('Invalid cover image @id %r' % id) hcover = self.spine[0] if 'cover' in self.guide: href = self.guide['cover'].href From df05652dbc89fc0fd6c47024d2246eb6eedf37b2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 Feb 2009 12:36:24 -0800 Subject: [PATCH 21/54] IGN:... --- src/calibre/trac/donations/server.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/calibre/trac/donations/server.py b/src/calibre/trac/donations/server.py index c3e0337290..51b1ed612b 100644 --- a/src/calibre/trac/donations/server.py +++ b/src/calibre/trac/donations/server.py @@ -196,7 +196,7 @@ class Server(object): def calculate_month_trend(self, days=31): stats = self.get_slice(date.today()-timedelta(days=days-1), date.today()) - fig = plt.figure(2, (8, 3), 96)#, facecolor, edgecolor, frameon, FigureClass) + fig = plt.figure(2, (12, 4), 96)#, facecolor, edgecolor, frameon, FigureClass) ax = fig.add_subplot(111) x = list(range(days-1, -1, -1)) y = stats.daily_totals @@ -205,6 +205,18 @@ class Server(object): ax.set_ylabel('Income ($)') ax.hlines([stats.daily_average], 0, days-1) ax.set_xlim([0, days-1]) + text = u'''\ +Total: $%(total).2f +Daily average: $%(da).2f \u00b1 %(dd).2f +Average contribution: $%(ac).2f \u00b1 %(ad).2f +Donors per day: %(dpd).2f + '''%dict(total=stats.total, da=stats.daily_average, + dd=stats.daily_deviation, ac=stats.average, + ad=stats.average_deviation, + dpd=len(stats.totals)/float(stats.period.days), + ) + text = ax.annotate(text, (0.6, 0.65), textcoords='axes fraction') + text.update_bbox_position_size(fig) fig.savefig(self.MONTH_TRENDS) def calculate_trend(self): @@ -223,7 +235,7 @@ class Server(object): x = [m.min for m in _months] y = [m.total for m in _months] ml = mdates.MonthLocator() # every month - fig = plt.figure(1, (8, 3), 96)#, facecolor, edgecolor, frameon, FigureClass) + fig = plt.figure(1, (8, 4), 96)#, facecolor, edgecolor, frameon, FigureClass) ax = fig.add_subplot(111) ax.bar(x, y, align='center', width=20, color='g') ax.xaxis.set_major_locator(ml) From 2304bca566b90667428776d6b1dac86999281c39 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 Feb 2009 12:46:25 -0800 Subject: [PATCH 22/54] IGN:... --- src/calibre/trac/donations/server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/calibre/trac/donations/server.py b/src/calibre/trac/donations/server.py index 51b1ed612b..0141c6a317 100644 --- a/src/calibre/trac/donations/server.py +++ b/src/calibre/trac/donations/server.py @@ -216,7 +216,6 @@ Donors per day: %(dpd).2f dpd=len(stats.totals)/float(stats.period.days), ) text = ax.annotate(text, (0.6, 0.65), textcoords='axes fraction') - text.update_bbox_position_size(fig) fig.savefig(self.MONTH_TRENDS) def calculate_trend(self): From b7085bc8da673a5614cb06b5595dbf52c71a119f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 3 Feb 2009 13:45:20 -0800 Subject: [PATCH 23/54] New recipe for The Australian by MAtthew Briggs --- src/calibre/gui2/images/news/the_oz.png | Bin 0 -> 701 bytes src/calibre/web/feeds/recipes/__init__.py | 2 +- .../web/feeds/recipes/recipe_the_oz.py | 53 ++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/calibre/gui2/images/news/the_oz.png create mode 100644 src/calibre/web/feeds/recipes/recipe_the_oz.py diff --git a/src/calibre/gui2/images/news/the_oz.png b/src/calibre/gui2/images/news/the_oz.png new file mode 100644 index 0000000000000000000000000000000000000000..93f68f962648a04ac82d9bf61acc11dc59f7ee51 GIT binary patch literal 701 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#N>c zw5E>MV|=VHm4aN_#Y)~hVxQQxqoZ4)qxm1>)yU~VEbQzD4|c8PPzqzW4^mu^(BAQ2 z!k5D)y}tKU-v2H+kv%Iz>to~Tr*?CmTRxvxe8E1T>a*9mOX8KYSv`X+r%u^DFS~2w zmZl@?XI6{o%~zXm(YkvU>w-^7V&;3Vh)Dejp1pt4f=@4P-`(O`wxdb&_=js|3;Dge z>h&X2cMpn9I3P?!9n zKNdGu1}wO;NZR_q>d-`YKcU_B-I4e5m&D%ED^>sTRQZ3T;f;-+Yb51X7VbZ~ZvN8D zH4aM;uHf3_l>dC=?&b3nf3t0Kl?&K9%!%caR&Dw&@j_SD7gRWYCaGkb3L&eEml zWWv?@rnLu{^%=1rD%!V9)pLb!%6YlqG=Wrhrc-n0ulfAdHH&@f`}-UMN4|Z(YI%E| zgv097Id}HmJo0xsqpfX9)$iFWbkC%kn+Z)}Is=S;)e_f;lH{V)#FA9q6d=K1WME*a zYha{nU>ss(Xk}t#WooHyU|?lnpwhM47N#LLKP5A*l7NP4>${vl4Gf;HelF{r5}E+x C)F&_i literal 0 HcmV?d00001 diff --git a/src/calibre/web/feeds/recipes/__init__.py b/src/calibre/web/feeds/recipes/__init__.py index 8fd6badc62..14cbbfb634 100644 --- a/src/calibre/web/feeds/recipes/__init__.py +++ b/src/calibre/web/feeds/recipes/__init__.py @@ -26,7 +26,7 @@ recipe_modules = ['recipe_' + r for r in ( 'laprensa', 'amspec', 'freakonomics', 'criticadigital', 'elcronista', 'shacknews', 'teleread', 'granma', 'juventudrebelde', 'juventudrebelde_english', 'la_tercera', 'el_mercurio_chile', 'la_cuarta', 'lanacion_chile', 'la_segunda', - 'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', + 'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', 'the_oz', )] import re, imp, inspect, time, os diff --git a/src/calibre/web/feeds/recipes/recipe_the_oz.py b/src/calibre/web/feeds/recipes/recipe_the_oz.py new file mode 100644 index 0000000000..b5911b1c67 --- /dev/null +++ b/src/calibre/web/feeds/recipes/recipe_the_oz.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +__copyright__ = '2009, Matthew Briggs' +__docformat__ = 'restructuredtext en' + +''' +http://www.theaustralian.news.com.au/ +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class DailyTelegraph(BasicNewsRecipe): + title = u'The Australian' + __author__ = u'Matthew Briggs' + description = u'National broadsheet newspaper from down under - colloquially known as The Oz' + oldest_article = 2 + max_articles_per_feed = 10 + remove_javascript = True + no_stylesheets = True + encoding = 'utf8' + + html2lrf_options = [ + '--comment' , description + , '--category' , 'news, Australia' + , '--publisher' , title + ] + + keep_only_tags = [ + dict(name='h1', attrs={'class':'section-heading'}) + ,dict(name='div', attrs={'id':'article'}) + ] + + remove_tags = [dict(name=['object','link'])] + + feeds = [ + (u'News', u'http://feeds.news.com.au/public/rss/2.0/aus_news_807.xml'), + (u'World News', u'http://feeds.news.com.au/public/rss/2.0/aus_world_808.xml'), + (u'Opinion', u'http://feeds.news.com.au/public/rss/2.0/aus_opinion_58.xml'), + (u'Business', u'http://feeds.news.com.au/public/rss/2.0/aus_business_811.xml'), + (u'Media', u'http://feeds.news.com.au/public/rss/2.0/aus_media_57.xml'), + (u'Higher Education', u'http://feeds.news.com.au/public/rss/2.0/aus_higher_education_56.xml'), + (u'The Arts', u'http://feeds.news.com.au/public/rss/2.0/aus_arts_51.xml'), + (u'Commercial Property', u'http://feeds.news.com.au/public/rss/2.0/aus_business_commercial_property_708.xml'), + (u'The Nation', u'http://feeds.news.com.au/public/rss/2.0/aus_the_nation_62.xml'), + (u'Sport', u'http://feeds.news.com.au/public/rss/2.0/aus_sport_61.xml'), + (u'Travel', u'http://feeds.news.com.au/public/rss/2.0/aus_travel_and_indulgence_63.xml'), + (u'Defence', u'http://feeds.news.com.au/public/rss/2.0/aus_defence_54.xml'), + (u'Aviation', u'http://feeds.news.com.au/public/rss/2.0/aus_business_aviation_706.xml'), + (u'Mining', u'http://feeds.news.com.au/public/rss/2.0/aus_business_mining_704.xml'), + (u'Climate', u'http://feeds.news.com.au/public/rss/2.0/aus_climate_809.xml'), + (u'Property', u'http://feeds.news.com.au/public/rss/2.0/aus_property_59.xml'), + (u'US Election', u'http://feeds.news.com.au/public/rss/2.0/aus_uselection_687.xml') + ] From 9e0f5fe52766939c7e462f3a5eec6bf162729935 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Tue, 3 Feb 2009 18:56:28 -0500 Subject: [PATCH 24/54] Fix #1772. Ensure content in prior to adding anchors. --- src/calibre/ebooks/mobi/mobiml.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py index 50d7b298b9..7ecd127452 100644 --- a/src/calibre/ebooks/mobi/mobiml.py +++ b/src/calibre/ebooks/mobi/mobiml.py @@ -138,7 +138,8 @@ class MobiMLizer(object): return result def mobimlize_content(self, tag, text, bstate, istates): - bstate.content = True + if text or tag != 'br': + bstate.content = True istate = istates[-1] para = bstate.para if tag in SPECIAL_TAGS and not text: @@ -188,11 +189,6 @@ class MobiMLizer(object): vspace -= 1 if istate.halign != 'auto': para.attrib['align'] = istate.halign - if istate.ids: - last = bstate.body[-1] - for id in istate.ids: - last.addprevious(etree.Element(XHTML('a'), attrib={'id': id})) - istate.ids.clear() pstate = bstate.istate if tag in CONTENT_TAGS: bstate.inline = para @@ -200,6 +196,11 @@ class MobiMLizer(object): etree.SubElement(para, XHTML(tag), attrib=istate.attrib) elif tag in TABLE_TAGS: para.attrib['valign'] = 'top' + if istate.ids: + last = bstate.body[-1] + for id in istate.ids: + last.addprevious(etree.Element(XHTML('a'), attrib={'id': id})) + istate.ids.clear() if not text: return if not pstate or istate != pstate: From 88ba45cbaaf81edab13b57d92dab6fea83c75ed5 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Tue, 3 Feb 2009 20:52:00 -0500 Subject: [PATCH 25/54] MobiReader refactor to handle book attached to #1772. --- src/calibre/ebooks/mobi/reader.py | 67 ++++++++++++++++--------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index e2bb6f6d5f..2de7ee97d4 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -121,6 +121,7 @@ class BookHeader(object): sublangid = (langcode >> 10) & 0xFF self.language = main_language.get(langid, 'ENGLISH') self.sublanguage = sub_language.get(sublangid, 'NEUTRAL') + self.mobi_version = struct.unpack('>I', raw[0x68:0x6c])[0] self.first_image_index = struct.unpack('>L', raw[0x6c:0x6c+4])[0] self.exth_flag, = struct.unpack('>L', raw[0x80:0x84]) @@ -132,11 +133,8 @@ class BookHeader(object): class MobiReader(object): - PAGE_BREAK_PAT = re.compile(r'(<[/]{0,1}mbp:pagebreak\s*[/]{0,1}>)+', re.IGNORECASE) - IMAGE_PATS = map(re.compile, (r'\shirecindex=[\'"]{0,1}(\d+)[\'"]{0,1}', - r'\srecindex=[\'"]{0,1}(\d+)[\'"]{0,1}', - r'\slorecindex=[\'"]{0,1}(\d+)[\'"]{0,1}')) + IMAGE_ATTRS = ('lowrecindex', 'recindex', 'hirecindex') def __init__(self, filename_or_stream, verbose=False): self.verbose = verbose @@ -247,6 +245,7 @@ class MobiReader(object): self.processed_html = re.sub(r'
', '', self.processed_html) if self.book_header.ancient and '')+'' + self.processed_html = self.processed_html.replace('\r\n', '\n') self.processed_html = self.processed_html.replace('> <', '>\n<') for t, c in [('b', 'bold'), ('i', 'italic')]: self.processed_html = re.sub(r'(?i)<%s>'%t, r''%c, self.processed_html) @@ -264,6 +263,7 @@ class MobiReader(object): 'x-large' : '5', 'xx-large' : '6', } + mobi_version = self.book_header.mobi_version for tag in root.iter(etree.Element): if tag.tag in ('country-region', 'place', 'placetype', 'placename', 'state', 'city'): @@ -290,6 +290,11 @@ class MobiReader(object): align = attrib.pop('align').strip() if align: styles.append('text-align: %s' % align) + if mobi_version == 1 and tag.tag == 'hr': + tag.tag = 'div' + styles.append('page-break-before: always') + styles.append('display: block') + styles.append('margin: 0') if styles: attrib['style'] = '; '.join(styles) @@ -300,6 +305,17 @@ class MobiReader(object): except ValueError: if sz in size_map.keys(): attrib['size'] = size_map[sz] + if 'filepos-id' in attrib: + attrib['id'] = attrib.pop('filepos-id') + if 'filepos' in attrib: + filepos = int(attrib.pop('filepos')) + attrib['href'] = "#filepos%d" % filepos + if tag.tag == 'img': + recindex = None + for attr in self.IMAGE_ATTRS: + recindex = attrib.pop(attr, None) or recindex + if recindex is not None: + attrib['src'] = 'images/%s.jpg' % recindex def create_opf(self, htmlfile, guide=None): mi = self.book_header.exth.mi @@ -399,8 +415,9 @@ class MobiReader(object): def replace_page_breaks(self): - self.processed_html = self.PAGE_BREAK_PAT.sub('
', - self.processed_html) + self.processed_html = self.PAGE_BREAK_PAT.sub( + '
', + self.processed_html) def add_anchors(self): if self.verbose: @@ -409,28 +426,27 @@ class MobiReader(object): link_pattern = re.compile(r'<[^<>]+filepos=[\'"]{0,1}(\d+)[^<>]*>', re.IGNORECASE) for match in link_pattern.finditer(self.mobi_html): positions.add(int(match.group(1))) - positions = list(positions) - positions.sort() pos = 0 self.processed_html = '' - for end in positions: + for end in sorted(positions): if end == 0: continue oend = end l = self.mobi_html.find('<', end) r = self.mobi_html.find('>', end) - if r > -1 and r < l: # Move out of tag - end = r+1 - self.processed_html += self.mobi_html[pos:end] + ''%(oend, oend) + p = self.mobi_html.rfind('>', end) + if r > -1 and (r < l or l == end or l == -1): + end = r + anchor = ' filepos-id="filepos%d"' % oend + elif p > pos: + end = p + anchor = ' filepos-id="filepos%d"' % oend + else: + anchor = '' % oend + self.processed_html += self.mobi_html[pos:end] + anchor pos = end - self.processed_html += self.mobi_html[pos:] - fpat = re.compile(r'filepos=[\'"]{0,1}(\d+)[\'"]{0,1}', re.IGNORECASE) - def fpos_to_href(match): - return fpat.sub('href="#filepos%d"'%int(match.group(1)), match.group()) - self.processed_html = link_pattern.sub(fpos_to_href, - self.processed_html) - + def extract_images(self, processed_records, output_dir): if self.verbose: print 'Extracting images...' @@ -454,19 +470,6 @@ class MobiReader(object): path = os.path.join(output_dir, '%05d.jpg'%image_index) self.image_names.append(os.path.basename(path)) im.convert('RGB').save(open(path, 'wb'), format='JPEG') - - def fix_images(match): - tag = match.group() - for pat in self.IMAGE_PATS: - m = pat.search(tag) - if m: - return pat.sub(' src="images/%s.jpg"'%m.group(1), tag) - - - if hasattr(self, 'processed_html'): - self.processed_html = \ - re.compile(r'', re.IGNORECASE|re.DOTALL)\ - .sub(fix_images, self.processed_html) def get_metadata(stream): mr = MobiReader(stream) From 7f97d458dbede2defaf13634e23573be9fdc82e4 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Tue, 3 Feb 2009 22:58:55 -0500 Subject: [PATCH 26/54] Further improve logic for inserting Mobi filepos anchors. --- src/calibre/ebooks/mobi/reader.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index 2de7ee97d4..760f9407cb 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -434,16 +434,15 @@ class MobiReader(object): oend = end l = self.mobi_html.find('<', end) r = self.mobi_html.find('>', end) - p = self.mobi_html.rfind('>', end) + anchor = '' if r > -1 and (r < l or l == end or l == -1): - end = r - anchor = ' filepos-id="filepos%d"' % oend - elif p > pos: - end = p - anchor = ' filepos-id="filepos%d"' % oend - else: - anchor = '' % oend - self.processed_html += self.mobi_html[pos:end] + anchor + p = self.mobi_html.rfind('<', 0, end + 1) + if p > -1 and self.mobi_html[p + 1] != '/': + anchor = ' filepos-id="filepos%d"' + end = r + else: + end = r + 1 + self.processed_html += self.mobi_html[pos:end] + (anchor % oend) pos = end self.processed_html += self.mobi_html[pos:] From 4b467bfbad55c3e95a0537e85bf0fb08002a8f75 Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Wed, 4 Feb 2009 01:45:04 -0500 Subject: [PATCH 27/54] Fix #1730 (MOBI: missing page break) --- src/odf/odf2xhtml.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/odf/odf2xhtml.py b/src/odf/odf2xhtml.py index 8a55fbd036..28ea9dc838 100644 --- a/src/odf/odf2xhtml.py +++ b/src/odf/odf2xhtml.py @@ -77,6 +77,8 @@ class StyleToCSS: (FONS,u"border-left"): self.c_fo, (FONS,u"border-right"): self.c_fo, (FONS,u"border-top"): self.c_fo, + (FONS,u"break-after"): self.c_break, + (FONS,u"break-before"): self.c_break, (FONS,u"color"): self.c_fo, (FONS,u"font-family"): self.c_fo, (FONS,u"font-size"): self.c_fo, @@ -139,6 +141,13 @@ class StyleToCSS: selector = rule[1] sdict[selector] = val + def c_break(self, ruleset, sdict, rule, val): + property = 'page-' + rule[1] + values = {'auto': 'auto', 'column': 'always', 'page': 'always', + 'even-page': 'left', 'odd-page': 'right', + 'inherit': 'inherit'} + sdict[property] = values.get(val, 'auto') + def c_border_model(self, ruleset, sdict, rule, val): """ Convert to CSS2 border model """ if val == 'collapsing': @@ -1169,6 +1178,9 @@ class ODF2XHTML(handler.ContentHandler): if specialtag is None: specialtag = 'p' self.writedata() + if not self.data: + # Give substance to empty paragraphs, as rendered by OOo + self.writeout(' ') self.closetag(specialtag) self.purgedata() From a1126014bf1056ab181189a5a0d42e9132e0dced Mon Sep 17 00:00:00 2001 From: "Marshall T. Vandegrift" Date: Wed, 4 Feb 2009 09:46:12 -0500 Subject: [PATCH 28/54] Be smarter about not putting @id attributes in bad places --- src/calibre/ebooks/mobi/reader.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index 760f9407cb..6811f9ccda 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -423,11 +423,13 @@ class MobiReader(object): if self.verbose: print 'Adding anchors...' positions = set([]) - link_pattern = re.compile(r'<[^<>]+filepos=[\'"]{0,1}(\d+)[^<>]*>', re.IGNORECASE) + link_pattern = re.compile(r'''<[^<>]+filepos=['"]{0,1}(\d+)[^<>]*>''', + re.IGNORECASE) for match in link_pattern.finditer(self.mobi_html): positions.add(int(match.group(1))) pos = 0 self.processed_html = '' + end_tag_re = re.compile(r'<\s*/') for end in sorted(positions): if end == 0: continue @@ -437,7 +439,8 @@ class MobiReader(object): anchor = '' if r > -1 and (r < l or l == end or l == -1): p = self.mobi_html.rfind('<', 0, end + 1) - if p > -1 and self.mobi_html[p + 1] != '/': + if pos < end and p > -1 and \ + not end_tag_re.match(self.mobi_html[p:r]): anchor = ' filepos-id="filepos%d"' end = r else: From 8ab65e399ec8ab3ec48373bd88f435787968d8c1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 4 Feb 2009 13:15:47 -0800 Subject: [PATCH 29/54] IGN:Updated translations --- src/calibre/translations/ar.po | 5427 +++++++++++++++++++++++++++++++ src/calibre/translations/bg.po | 2 +- src/calibre/translations/ca.po | 2 +- src/calibre/translations/cs.po | 2 +- src/calibre/translations/de.po | 2 +- src/calibre/translations/el.po | 2 +- src/calibre/translations/es.po | 2 +- src/calibre/translations/fr.po | 2 +- src/calibre/translations/gl.po | 2 +- src/calibre/translations/hu.po | 106 +- src/calibre/translations/it.po | 2 +- src/calibre/translations/nb.po | 2 +- src/calibre/translations/nds.po | 2 +- src/calibre/translations/nl.po | 2 +- src/calibre/translations/pl.po | 2 +- src/calibre/translations/pt.po | 2 +- src/calibre/translations/ro.po | 2 +- src/calibre/translations/ru.po | 2 +- src/calibre/translations/sk.po | 2 +- src/calibre/translations/sl.po | 2 +- src/calibre/translations/sv.po | 2 +- src/calibre/translations/te.po | 2 +- src/calibre/translations/zh.po | 2349 +++++++------ 23 files changed, 6816 insertions(+), 1106 deletions(-) create mode 100644 src/calibre/translations/ar.po diff --git a/src/calibre/translations/ar.po b/src/calibre/translations/ar.po new file mode 100644 index 0000000000..f615c21206 --- /dev/null +++ b/src/calibre/translations/ar.po @@ -0,0 +1,5427 @@ +# Arabic translation for calibre +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the calibre package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: calibre\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2009-01-27 01:54+0000\n" +"PO-Revision-Date: 2009-02-04 10:04+0000\n" +"Last-Translator: Abdellah Chelli \n" +"Language-Team: Arabic \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41 +msgid "Does absolutely nothing" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:44 +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_any.py:71 +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:497 +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:989 +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1002 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:77 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:79 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:81 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:86 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:295 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:61 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:95 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:97 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:99 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:101 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/convert_from.py:69 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/rtf/convert_from.py:179 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/txt/convert_from.py:70 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:199 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:229 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:232 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:255 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:277 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:45 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:47 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:87 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:89 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:145 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf.py:334 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf.py:449 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:820 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/pdf.py:12 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:36 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:66 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:477 +#: /home/kovid/work/calibre/src/calibre/ebooks/odt/to_oeb.py:46 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:361 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:366 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:858 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:861 +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:53 +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:48 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:168 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:170 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:365 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:37 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:38 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:362 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:376 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:899 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:700 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:942 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:945 +#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:61 +#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:123 +#: /home/kovid/work/calibre/src/calibre/library/cli.py:257 +#: /home/kovid/work/calibre/src/calibre/library/database.py:920 +#: /home/kovid/work/calibre/src/calibre/library/database.py:1405 +#: /home/kovid/work/calibre/src/calibre/library/database.py:1434 +#: /home/kovid/work/calibre/src/calibre/library/database.py:1468 +#: /home/kovid/work/calibre/src/calibre/library/database.py:1594 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:473 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:485 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:828 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:861 +msgid "Unknown" +msgstr "مجهول" + +#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:62 +msgid "Base" +msgstr "أساس" + +#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:148 +msgid "File type" +msgstr "نوع الملف" + +#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:182 +msgid "Metadata reader" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:209 +msgid "Metadata writer" +msgstr "كاتب البيانات الوصفية" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:12 +msgid "" +"Follow all local links in an HTML file and create a ZIP file containing all " +"linked files. This plugin is run every time you add an HTML file to the " +"library." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:32 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:43 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:53 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:64 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:74 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:84 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:94 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:105 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:116 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:126 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:136 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:146 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:156 +msgid "Read metadata from %s files" +msgstr "إقرأ البيانات الوصفية من الملفات %s" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:166 +msgid "Extract cover from comic files" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:186 +msgid "Read metadata from ebooks in ZIP archives" +msgstr "إقرأ البيانات الوصفية من كتب إلكترونية في محفوظات ZIP" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:196 +msgid "Read metadata from ebooks in RAR archives" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:207 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:217 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:227 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:237 +msgid "Set metadata in %s files" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:28 +msgid "Installed plugins" +msgstr "ملحقات مثبتة" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:29 +msgid "Mapping for filetype plugins" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:30 +msgid "Local plugin customization" +msgstr "تخصيص ملحقات محلية" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:31 +msgid "Disabled plugins" +msgstr "ملحقات معطلة" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:66 +msgid "No valid plugin found in " +msgstr "لم يعثر على أي ملحق صالح في " + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:184 +msgid "Initialization of plugin %s failed with traceback:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:261 +msgid "" +" %prog options\n" +" \n" +" Customize calibre by loading external plugins.\n" +" " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:267 +msgid "Add a plugin by specifying the path to the zip file containing it." +msgstr "أضف ملحقا بتعيين المسار إلى ملف zip الذي يحتويه." + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:269 +msgid "Remove a custom plugin by name. Has no effect on builtin plugins" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:271 +msgid "" +"Customize plugin. Specify name of plugin and customization string separated " +"by a comma." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:273 +msgid "List all installed plugins" +msgstr "أسرد كل الملحقات المثبتة" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:275 +msgid "Enable the named plugin" +msgstr "شغل الملحق المسمى" + +#: /home/kovid/work/calibre/src/calibre/customize/ui.py:277 +msgid "Disable the named plugin" +msgstr "عطل الملحق المسمى" + +#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:41 +#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:384 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:70 +msgid "The reader has no storage card connected." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:60 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:89 +msgid "There is insufficient free space on the storage card" +msgstr "لا توجد مساحة كافية في بطاقة التخزين" + +#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:62 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:91 +msgid "There is insufficient free space in main memory" +msgstr "لا توجد مساحة كافية في الذاكرة الرئيسية" + +#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:140 +#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:167 +#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:195 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:191 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:227 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:254 +msgid "Unable to detect the %s disk drive. Try rebooting." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:94 +msgid "Options to control the conversion to EPUB" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:105 +msgid "" +"The output EPUB file. If not specified, it is derived from the input file " +"name." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:107 +msgid "" +"Profile of the target device this EPUB is meant for. Set to None to create a " +"device independent EPUB. The profile is used for device specific " +"restrictions on the EPUB. Choices are: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:109 +msgid "" +"Either the path to a CSS stylesheet or raw CSS. This CSS will override any " +"existing CSS declarations in the source files." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:110 +msgid "Control auto-detection of document structure." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:112 +msgid "" +"An XPath expression to detect chapter titles. The default is to consider " +"

or\n" +"

tags that contain the words \"chapter\",\"book\",\"section\" or " +"\"part\" as chapter titles as \n" +"well as any tags that have class=\"chapter\". \n" +"The expression used must evaluate to a list of elements. To disable chapter " +"detection,\n" +"use the expression \"/\". See the XPath Tutorial in the calibre User Manual " +"for further\n" +"help on using this feature.\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:121 +msgid "" +"Specify how to mark detected chapters. A value of \"pagebreak\" will insert " +"page breaks before chapters. A value of \"rule\" will insert a line before " +"chapters. A value of \"none\" will disable chapter marking and a value of " +"\"both\" will use both page breaks and lines to mark chapters." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:123 +msgid "Path to the cover to be used for this book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:126 +msgid "" +"Use the cover detected from the source file in preference to the specified " +"cover." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:128 +msgid "" +"Turn off splitting at page breaks. Normally, input files are automatically " +"split at every page break into two files. This gives an output ebook that " +"can be parsed faster and with less resources. However, splitting is slow and " +"if your source file contains a very large number of page breaks, you should " +"turn off splitting on page breaks." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:130 +msgid "" +"Control the automatic generation of a Table of Contents. If an OPF file is " +"detected\n" +"and it specifies a Table of Contents, then that will be used rather than " +"trying\n" +"to auto-generate a Table of Contents.\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:136 +msgid "" +"Maximum number of links to insert into the TOC. Set to 0 to disable. Default " +"is: %default. Links are only added to the TOC if less than the --toc-" +"threshold number of chapters were detected." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:138 +msgid "Don't add auto-detected chapters to the Table of Contents." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:140 +msgid "" +"If fewer than this number of chapters is detected, then links are added to " +"the Table of Contents. Default: %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:142 +msgid "" +"XPath expression that specifies all tags that should be added to the Table " +"of Contents at level one. If this is specified, it takes precedence over " +"other forms of auto-detection." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:144 +msgid "" +"XPath expression that specifies all tags that should be added to the Table " +"of Contents at level two. Each entry is added under the previous level one " +"entry." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:146 +msgid "" +"Path to a .ncx file that contains the table of contents to use for this " +"ebook. The NCX file should contain links relative to the directory it is " +"placed in. See http://www.niso.org/workrooms/daisy/Z39-86-2005.html#NCX for " +"an overview of the NCX format." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:148 +msgid "" +"Normally, if the source file already has a Table of Contents, it is used in " +"preference to the autodetected one. With this option, the autodetected one " +"is always used." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:150 +msgid "Control page layout" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:152 +msgid "Set the top margin in pts. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:154 +msgid "Set the bottom margin in pts. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:156 +msgid "Set the left margin in pts. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:158 +msgid "Set the right margin in pts. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:160 +msgid "" +"The base font size in pts. Default is %defaultpt. Set to 0 to disable " +"rescaling of fonts." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:162 +msgid "" +"Remove spacing between paragraphs. Will not work if the source file forces " +"inter-paragraph spacing." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:164 +msgid "" +"Preserve the HTML tag structure while splitting large HTML files. This is " +"only neccessary if the HTML files contain CSS that uses sibling selectors. " +"Enabling this greatly slows down processing of large HTML files." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:167 +msgid "Print generated OPF file to stdout" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:169 +msgid "Print generated NCX file to stdout" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:171 +msgid "Keep intermediate files during processing by html2epub" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:173 +msgid "" +"Extract the contents of the produced EPUB file to the specified directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_any.py:184 +msgid "" +"%%prog [options] filename\n" +"\n" +"Convert any of a large number of ebook formats to a %s file. Supported " +"formats are: %s\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:102 +msgid "Could not find an ebook inside the archive" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:214 +msgid "" +"%prog [options] file.html|opf\n" +"\n" +"Convert a HTML file to an EPUB ebook. Recursively follows links in the HTML " +"file.\n" +"If you specify an OPF file instead of an HTML file, the list of links is " +"takes from\n" +"the element of the OPF file. \n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:465 +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:746 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:589 +msgid "Output written to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:487 +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1087 +msgid "You must specify an input HTML file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/iterator.py:36 +msgid "%s format books are not supported" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/split.py:30 +msgid "" +"Could not find reasonable point at which to split: %s Sub-tree size: %d KB" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/split.py:142 +msgid "" +"\t\tToo much markup. Re-splitting without structure preservation. This may " +"cause incorrect rendering." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:509 +msgid "Written processed HTML to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:872 +msgid "Options to control the traversal of HTML" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:879 +msgid "The output directory. Default is the current directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:881 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:537 +msgid "Character encoding for HTML files. Default is to auto detect." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:883 +msgid "" +"Create the output in a zip file. If this option is specified, the --output " +"should be the name of a file not a directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:885 +msgid "Control the following of links in HTML files." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:887 +msgid "" +"Traverse links in HTML files breadth first. Normally, they are traversed " +"depth first" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:889 +msgid "" +"Maximum levels of recursion when following links in HTML files. Must be non-" +"negative. 0 implies that no links in the root HTML file are followed." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:891 +msgid "Set metadata of the generated ebook" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:893 +msgid "Set the title. Default is to autodetect." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:895 +msgid "The author(s) of the ebook, as a comma separated list." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:897 +msgid "The subject(s) of this book, as a comma separated list." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:899 +msgid "Set the publisher of this book." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:901 +msgid "A summary of this book." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:903 +msgid "Load metadata from the specified OPF file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:905 +msgid "Options useful for debugging" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:907 +msgid "" +"Be more verbose while processing. Can be specified multiple times to " +"increase verbosity." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:909 +msgid "Output HTML is \"pretty printed\" for easier parsing by humans" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:915 +msgid "" +"%prog [options] file.html|opf\n" +"\n" +"Follow all links in an HTML file and collect them into the specified " +"directory.\n" +"Also collects any resources like images, stylesheets, scripts, etc. \n" +"If an OPF file is specified instead, the list of files in its " +"element\n" +"is used.\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/from_any.py:47 +msgid "Creating LIT file from EPUB..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:852 +msgid "%prog [options] LITFILE" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:855 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:501 +msgid "Output directory. Defaults to current directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:858 +msgid "Legibly format extracted markup. May modify meaningful whitespace." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:861 +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:719 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:549 +msgid "Useful for debugging." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:872 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:525 +msgid "OEB ebook created in" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:713 +msgid "%prog [options] OPFFILE" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:716 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/from_feeds.py:26 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:546 +msgid "Output file. Default is derived from input filename." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:74 +msgid "Set the title. Default: filename." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:76 +msgid "" +"Set the author(s). Multiple authors should be set as a comma separated list. " +"Default: %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:79 +msgid "Set the comment." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:81 +msgid "Set the category" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:83 +msgid "Sort key for the title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:85 +msgid "Sort key for the author" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:87 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:278 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:39 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:108 +msgid "Publisher" +msgstr "ناشر" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:89 +msgid "Path to file containing image to be used as cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:91 +msgid "" +"If there is a cover graphic detected in the source file, use that instead of " +"the specified cover." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:94 +msgid "Output file name. Default is derived from input filename" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:96 +msgid "" +"Render HTML tables as blocks of text instead of actual tables. This is " +"neccessary if the HTML contains very large or complex tables." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:99 +msgid "" +"Specify the base font size in pts. All fonts are rescaled accordingly. This " +"option obsoletes the --font-delta option and takes precedence over it. To " +"use --font-delta, set this to 0. Default: %defaultpt" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:101 +msgid "Enable autorotation of images that are wider than the screen width." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:104 +msgid "Set the space between words in pts. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:106 +msgid "Separate paragraphs by blank lines." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:108 +msgid "Add a header to all the pages with title and author." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:110 +msgid "" +"Set the format of the header. %a is replaced by the author and %t by the " +"title. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:112 +msgid "Add extra spacing below the header. Default is %default px." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:114 +msgid "" +"Override the CSS. Can be either a path to a CSS stylesheet or a string. If " +"it is a string it is interpreted as CSS." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:116 +msgid "" +"Use the element from the OPF file to determine the order in which " +"the HTML files are appended to the LRF. The .opf file must be in the same " +"directory as the base HTML file." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:118 +msgid "" +"Minimum paragraph indent (the indent of the first line of a paragraph) in " +"pts. Default: %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:120 +msgid "" +"Increase the font size by 2 * FONT_DELTA pts and the line spacing by " +"FONT_DELTA pts. FONT_DELTA can be a fraction.If FONT_DELTA is negative, the " +"font size is decreased." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:125 +msgid "" +"Render all content as black on white instead of the colors specified by the " +"HTML or CSS." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:131 +msgid "" +"Profile of the target device for which this LRF is being generated. The " +"profile determines things like the resolution and screen size of the target " +"device. Default: %s Supported profiles: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:137 +msgid "Left margin of page. Default is %default px." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:139 +msgid "Right margin of page. Default is %default px." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:141 +msgid "Top margin of page. Default is %default px." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:143 +msgid "Bottom margin of page. Default is %default px." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:145 +msgid "" +"Render tables in the HTML as images (useful if the document has large or " +"complex tables)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:147 +msgid "" +"Multiply the size of text in rendered tables by this factor. Default is " +"%default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:152 +msgid "" +"The maximum number of levels to recursively process links. A value of 0 " +"means thats links are not followed. A negative value means that tags are " +"ignored." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:156 +msgid "" +"A regular expression. tags whose href matches will be ignored. Defaults " +"to %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:160 +msgid "Don't add links to the table of contents." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:164 +msgid "Prevent the automatic detection chapters." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:167 +msgid "" +"The regular expression used to detect chapter titles. It is searched for in " +"heading tags (h1-h6). Defaults to %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:170 +msgid "" +"Detect a chapter beginning at an element having the specified attribute. The " +"format for this option is tagname regexp,attribute name,attribute value " +"regexp. For example to match all heading tags that have the attribute " +"class=\"chapter\" you would use \"h\\d,class,chapter\". You can set the " +"attribute to \"none\" to match only on tag names. So for example, to match " +"all h2 tags, you would use \"h2,none,\". Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:172 +msgid "" +"If html2lrf does not find any page breaks in the html file and cannot detect " +"chapter headings, it will automatically insert page-breaks before the tags " +"whose names match this regular expression. Defaults to %default. You can " +"disable it by setting the regexp to \"$\". The purpose of this option is to " +"try to ensure that there are no really long pages as this degrades the page " +"turn performance of the LRF. Thus this option is ignored if the current page " +"has only a few elements." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:182 +msgid "" +"Force a page break before tags whose names match this regular expression." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:184 +msgid "" +"Force a page break before an element having the specified attribute. The " +"format for this option is tagname regexp,attribute name,attribute value " +"regexp. For example to match all heading tags that have the attribute " +"class=\"chapter\" you would use \"h\\d,class,chapter\". Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:187 +msgid "Add detected chapters to the table of contents." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:190 +msgid "Preprocess Baen HTML files to improve generated LRF." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:192 +msgid "" +"You must add this option if processing files generated by pdftohtml, " +"otherwise conversion will fail." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:194 +msgid "Use this option on html0 files from Book Designer." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:197 +msgid "" +"Specify trutype font families for serif, sans-serif and monospace fonts. " +"These fonts will be embedded in the LRF file. Note that custom fonts lead to " +"slower page turns. For example: --serif-family \"Times New Roman\"\n" +" " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:205 +msgid "The serif family of fonts to embed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:208 +msgid "The sans-serif family of fonts to embed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:211 +msgid "The monospace family of fonts to embed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:215 +msgid "Be verbose while processing" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:217 +msgid "Convert to LRS" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:219 +msgid "" +"Minimize memory usage at the cost of longer processing times. Use this " +"option if you are on a memory constrained machine." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:221 +msgid "" +"Specify the character encoding of the source file. If the output LRF file " +"contains strange characters, try changing this option. A common encoding for " +"files from windows computers is cp-1252. Another common choice is utf-8. The " +"default is to try and guess the encoding." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/any/convert_from.py:164 +msgid "Converting from %s to LRF is not supported." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/any/convert_from.py:175 +msgid "" +"any2lrf [options] myfile\n" +"\n" +"Convert any ebook format into LRF. Supported formats are:\n" +"LIT, RTF, TXT, HTML, EPUB, MOBI, PRC and PDF. any2lrf will also process a " +"RAR or\n" +"ZIP archive, looking for an ebook inside the archive.\n" +" " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/any/convert_from.py:190 +msgid "No file to convert specified." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:224 +msgid "Rendered %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:227 +msgid "Failed %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:279 +msgid "" +"Failed to process comic: %s\n" +"\n" +"%s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:286 +msgid "" +"Options to control the conversion of comics (CBR, CBZ) files into ebooks" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:292 +msgid "Title for generated ebook. Default is to use the filename." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:294 +msgid "" +"Set the author in the metadata of the generated ebook. Default is %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:297 +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:22 +msgid "" +"Path to output file. By default a file is created in the current directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:299 +msgid "Number of colors for grayscale image conversion. Default: %default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:301 +msgid "" +"Disable normalize (improve contrast) color range for pictures. Default: False" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:303 +msgid "Maintain picture aspect ratio. Default is to fill the screen." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:305 +msgid "Disable sharpening." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:307 +msgid "Don't split landscape images into two portrait images" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:309 +msgid "" +"Keep aspect ratio and scale image using screen height as image width for " +"viewing in landscape mode." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:311 +msgid "" +"Used for right-to-left publications like manga. Causes landscape pages to be " +"split into portrait pages from right to left." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:313 +msgid "" +"Enable Despeckle. Reduces speckle noise. May greatly increase processing " +"time." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:315 +msgid "" +"Don't sort the files found in the comic alphabetically by name. Instead use " +"the order they were added to the comic." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:317 +msgid "" +"Choose a profile for the device you are generating this file for. The " +"default is the SONY PRS-500 with a screen size of 584x754 pixels. This is " +"suitable for any reader with the same screen size. Choices are %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:319 +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:20 +msgid "" +"Be verbose, useful for debugging. Can be specified multiple times for " +"greater verbosity." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:321 +msgid "Don't show progress bar." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:324 +msgid "Apply no processing to the image" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:329 +msgid "" +"%prog [options] comic.cb[z|r]\n" +"\n" +"Convert a comic in a CBZ or CBR file to an ebook. \n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:389 +msgid "Output written to" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:549 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/from_comic.py:35 +msgid "Rendering comic pages..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/epub/convert_from.py:17 +msgid "" +"Usage: %prog [options] mybook.epub\n" +" \n" +" \n" +"%prog converts mybook.epub to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:23 +msgid "" +"%prog [options] mybook.fb2\n" +"\n" +"\n" +"%prog converts mybook.fb2 to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:28 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/txt/convert_from.py:24 +msgid "Print generated HTML to stdout and quit." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:30 +msgid "Keep generated HTML files after completing conversion to LRF." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:20 +msgid "Options to control the behavior of feeds2disk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:22 +msgid "Options to control the behavior of html2lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:44 +msgid "Fetching of recipe failed: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:317 +msgid "\tBook Designer file detected." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:319 +msgid "\tParsing HTML..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:342 +msgid "\tBaen file detected. Re-parsing..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:358 +msgid "Written preprocessed HTML to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:376 +msgid "Processing %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:390 +msgid "\tConverting to BBeB..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:536 +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:549 +msgid "Could not parse file: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:541 +msgid "%s is an empty file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:561 +msgid "Failed to parse link %s %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:605 +msgid "Cannot add link %s to TOC" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:957 +msgid "Unable to process image %s. Error: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:995 +msgid "Unable to process interlaced PNG %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1010 +msgid "" +"Could not process image: %s\n" +"%s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1763 +msgid "" +"An error occurred while processing a table: %s. Ignoring table markup." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1765 +msgid "" +"Bad table:\n" +"%s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1787 +msgid "Table has cell that is too large" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1817 +msgid "" +"You have to save the website %s as an html file first and then run html2lrf " +"on it." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1860 +msgid "Could not read cover image: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1863 +msgid "Cannot read from: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1988 +msgid "Failed to process opf file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1994 +msgid "" +"Usage: %prog [options] mybook.html\n" +"\n" +"\n" +"%prog converts mybook.html to mybook.lrf. \n" +"%prog follows all links in mybook.html that point \n" +"to local files recursively. Thus, you can use it to \n" +"convert a whole tree of HTML files." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lit/convert_from.py:15 +msgid "" +"Usage: %prog [options] mybook.lit\n" +"\n" +"\n" +"%prog converts mybook.lit to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:136 +msgid "" +"%prog book.lrf\n" +"Convert an LRF file into an LRS (XML UTF-8 encoded) file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:137 +msgid "Output LRS file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:139 +msgid "Do not save embedded image and font files to disk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:158 +msgid "Parsing LRF..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:161 +msgid "Creating XML..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:163 +msgid "LRS written to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:249 +msgid "Could not read from thumbnail file:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:269 +msgid "" +"%prog [options] file.lrs\n" +"Compile an LRS file into an LRF file." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:270 +msgid "Path to output file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:272 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:115 +msgid "Verbose processing" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:274 +msgid "Convert LRS to LRS, useful for debugging." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:455 +msgid "Invalid LRF file. Could not set metadata." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:580 +msgid "" +"%prog [options] mybook.lrf\n" +"\n" +"\n" +"Show/edit the metadata in an LRF file.\n" +"\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:587 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:43 +msgid "Set the book title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:589 +msgid "Set sort key for the title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:591 +msgid "Set the author" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:593 +msgid "Set sort key for the author" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:595 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:47 +msgid "The category this book belongs to. E.g.: History" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:598 +msgid "Path to a graphic that will be set as this files' thumbnail" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:601 +msgid "" +"Path to a txt file containing the comment to be stored in the lrf file." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:605 +msgid "Extract thumbnail from LRF file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:606 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:182 +msgid "Set the publisher" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:607 +msgid "Set the book classification" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:608 +msgid "Set the book creator" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:609 +msgid "Set the book producer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:611 +msgid "" +"Extract cover from LRF file. Note that the LRF format has no defined cover, " +"so we use some heuristics to guess the cover." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:613 +msgid "Set book ID" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/mobi/convert_from.py:43 +msgid "" +"Usage: %prog [options] mybook.mobi|prc\n" +"\n" +"\n" +"%prog converts mybook.mobi to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/convert_from.py:47 +msgid "Could not find pdftohtml, check it is in your PATH" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/convert_from.py:61 +msgid "" +" is an image based PDF. Only conversion of text based PDFs is supported." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/convert_from.py:80 +msgid "" +"%prog [options] mybook.pdf\n" +"\n" +"\n" +"%prog converts mybook.pdf to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/reflow.py:403 +msgid "" +"Path to output directory in which to create the HTML file. Defaults to " +"current directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/reflow.py:405 +msgid "Be more verbose." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/reflow.py:417 +msgid "You must specify a single PDF file." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/rtf/convert_from.py:21 +msgid "" +"%prog [options] mybook.rtf\n" +"\n" +"\n" +"%prog converts mybook.rtf to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/rtf/convert_from.py:146 +msgid "" +"This RTF file has a feature calibre does not support. Convert it to HTML and " +"then convert it." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/txt/convert_from.py:19 +msgid "" +"%prog [options] mybook.txt\n" +"\n" +"\n" +"%prog converts mybook.txt to mybook.lrf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:45 +msgid "Set the authors" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:49 +msgid "Set the comment" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:276 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:69 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:70 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:36 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:103 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:359 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:969 +msgid "Title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:277 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:37 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:104 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:364 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:970 +msgid "Author(s)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:279 +msgid "Producer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:280 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:493 +msgid "Category" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:281 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:71 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:64 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:432 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:515 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:320 +#: /home/kovid/work/calibre/src/calibre/gui2/status.py:58 +msgid "Comments" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:283 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:109 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:309 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:909 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:973 +#: /home/kovid/work/calibre/src/calibre/gui2/status.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50 +msgid "Tags" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:284 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:110 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:325 +#: /home/kovid/work/calibre/src/calibre/gui2/status.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50 +msgid "Series" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:285 +msgid "Language" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:199 +msgid "A comma separated list of tags to set" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:201 +msgid "The series to which this book belongs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:203 +msgid "The series index" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:205 +msgid "The book language" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:207 +msgid "Extract the cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:54 +msgid "Usage:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/imp.py:53 +msgid "Usage: imp-meta file.imp" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/imp.py:54 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/pdf.py:59 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/rb.py:60 +msgid "No filename specified." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:97 +msgid "" +"\n" +"%prog [options] key\n" +"\n" +"Fetch metadata for books from isndb.com. You can specify either the \n" +"books ISBN ID or its title and author. If you specify the title and author,\n" +"then more than one book may be returned.\n" +"\n" +"key is the account key you generate after signing up for a free account from " +"isbndb.com.\n" +"\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:108 +msgid "The ISBN ID of the book you want metadata for." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:110 +msgid "The author whose book to search for." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:112 +msgid "The title of the book to search for." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:114 +msgid "The publisher of the book to search for." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:47 +msgid "" +"Could not fetch cover as server is experiencing high load. Please try again " +"later." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:48 +msgid " not found." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:51 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:82 +msgid "LibraryThing.com server error. Try again later." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:60 +msgid "" +"\n" +"%prog [options] ISBN\n" +"\n" +"Fetch a cover image for the book identified by ISBN from LibraryThing.com\n" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/lit.py:35 +msgid "Usage: %s file.lit" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/lit.py:45 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:227 +msgid "Cover saved to" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:178 +msgid "Set the subject tags" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:180 +msgid "Set the language" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:184 +msgid "Set the ISBN" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:965 +msgid "Set the dc:language field" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/pdf.py:58 +msgid "Usage: pdf-meta file.pdf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/rb.py:59 +msgid "Usage: rb-meta file.rb" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/from_any.py:55 +msgid "Creating Mobipocket file from EPUB..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:499 +msgid "%prog [options] myebook.mobi" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:523 +msgid "Raw MOBI HTML saved in" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:512 +msgid "Options to control the conversion to MOBI" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:519 +msgid "Mobipocket-specific options." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:521 +msgid "" +"Compress file text using PalmDOC compression. Results in smaller files, but " +"takes a long time to run." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:524 +msgid "Modify images to meet Palm device size limitations." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:526 +msgid "Title for any generated in-line table of contents." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:527 +msgid "" +"Device renderer profiles. Affects conversion of font sizes, image rescaling " +"and rasterization of tables. Valid profiles are: %s." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:532 +msgid "Source renderer profile. Default is %default." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:535 +msgid "Destination renderer profile. Default is %default." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:543 +msgid "[options]" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:561 +msgid "Unknown source profile %r" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:565 +msgid "Unknown destination profile %r" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/odt/to_oeb.py:57 +msgid "The output directory. Defaults to the current directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:586 +msgid "Cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:587 +msgid "Title Page" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:588 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/htmltoc.py:18 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:47 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:160 +msgid "Table of Contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:589 +msgid "Index" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:590 +msgid "Glossary" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:591 +msgid "Acknowledgements" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:592 +msgid "Bibliography" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:593 +msgid "Colophon" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:594 +msgid "Copyright" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:595 +msgid "Dedication" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:596 +msgid "Epigraph" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:597 +msgid "Foreword" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:598 +msgid "List of Illustrations" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:599 +msgid "List of Tables" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:600 +msgid "Notes" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:601 +msgid "Preface" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:602 +msgid "Main Text" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:13 +msgid "Options to control the transformation of pdf" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:24 +msgid "Number of pixels to crop from the left most x (default is %d) " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:26 +msgid "Number of pixels to crop from the left most y (default is %d) " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:28 +msgid "Number of pixels to crop from the right most x (default is %d) " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:30 +msgid "Number of pixels to crop from the right most y (default is %d)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:32 +msgid "" +"A file generated by ghostscript which allows each page to be individually " +"cropped [gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=bbox > bounding] " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:38 +msgid "" +"\t%prog [options] file.pdf\n" +"\n" +"\tCrops a pdf. \n" +"\t" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:25 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:433 +msgid "Frequently used directories" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:27 +msgid "Send file to storage card instead of main memory by default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:29 +msgid "The format to use when saving single files to disk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:31 +msgid "Confirm before deleting" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:33 +msgid "Toolbar icon size" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:35 +msgid "Show button labels in the toolbar" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:37 +msgid "Main window geometry" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:39 +msgid "Notify when a new version is available" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:41 +msgid "Use Roman numerals for series number" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:43 +msgid "Sort tags list by popularity" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:45 +msgid "Number of covers to show in the cover browsing mode" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:47 +msgid "Defaults for conversion to LRF" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:49 +msgid "Options for the LRF ebook viewer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:51 +msgid "Formats that are viewed using the internal viewer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:53 +msgid "Columns to be displayed in the book list" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:54 +msgid "Automatically launch content server on application startup" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:55 +msgid "Oldest news kept in database" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:56 +msgid "Show system tray icon" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:58 +msgid "Upload downloaded news to device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:60 +msgid "Delete books from library after uploading to device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:62 +msgid "" +"Show the cover flow in a separate window instead of in the main calibre " +"window" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:64 +msgid "Disable notifications from the system tray icon" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:72 +msgid "Device no longer connected." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:117 +msgid "Get device information" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:128 +msgid "Get list of books on device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:137 +msgid "Send metadata to device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:146 +msgid "Upload %d books to device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:161 +msgid "Delete books from device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:176 +msgid "Download books from device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:186 +msgid "View book on device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:84 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:86 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:316 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:904 +#: /home/kovid/work/calibre/src/calibre/gui2/status.py:56 +msgid "Path" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:88 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:89 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:315 +#: /home/kovid/work/calibre/src/calibre/gui2/status.py:57 +#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50 +msgid "Formats" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:61 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:88 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:48 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/warning_ui.py:52 +msgid "Dialog" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:62 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:63 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:41 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:49 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:56 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:49 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/warning_ui.py:53 +msgid "TextLabel" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:65 +msgid "&Previous" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:66 +msgid "&Next" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:40 +msgid "Choose Format" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:34 +msgid "Set defaults for conversion of comics (CBR/CBZ files)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:49 +msgid "Set options for converting %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:89 +msgid "&Title:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:90 +msgid "&Author(s):" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:91 +msgid "&Number of Colors:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:440 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:538 +msgid "&Profile:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:93 +msgid "Disable &normalize" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:94 +msgid "Keep &aspect ratio" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:95 +msgid "Disable &Sharpening" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96 +msgid "&Landscape" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97 +msgid "Don't so&rt" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98 +msgid "&Right to left" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:99 +msgid "De&speckle" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:100 +msgid "&Wide" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:100 +msgid " plugins" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:106 +msgid "by" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:123 +msgid "Advanced" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:123 +msgid "General" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:123 +msgid "Interface" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:124 +msgid "" +"Content\n" +"Server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:124 +msgid "Plugins" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:257 +msgid "No valid plugin path" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:258 +msgid "%s is not a valid plugin path" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:261 +msgid "Choose plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:272 +msgid "Plugin cannot be disabled" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:273 +msgid "The plugin: %s cannot be disabled" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:283 +msgid "Plugin not customizable" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:284 +msgid "Plugin: %s does not need customization" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:287 +msgid "Customize %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:297 +msgid "Cannot remove builtin plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:298 +msgid " cannot be removed. It is a builtin plugin. Try disabling it instead." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:319 +msgid "Error log:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:323 +msgid "Access log:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:345 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:385 +msgid "Failed to start content server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:385 +msgid "Invalid size" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:385 +msgid "The size %s is invalid. must be of the form widthxheight" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:423 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:427 +msgid "Invalid database location" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:424 +msgid "
Must be a directory." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:424 +msgid "Invalid database location " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:428 +msgid "Invalid database location.
Cannot write to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:440 +msgid "Compacting database. This may take a while." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:440 +msgid "Compacting..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:417 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:343 +msgid "Configuration" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:418 +msgid "" +"&Location of ebooks (The ebooks are stored in folders sorted by author and " +"metadata is stored in the file metadata.db)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:419 +msgid "Browse for the new database location" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:420 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:435 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:437 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:452 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:453 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:478 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:414 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:497 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:308 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:313 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:327 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:336 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:338 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:340 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:344 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:346 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:126 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:128 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:267 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:269 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:336 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:342 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:344 +msgid "..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:421 +msgid "Show notification when &new version is available" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:422 +msgid "" +"If you disable this setting, metadata is guessed from the filename instead. " +"This can be configured in the Advanced section." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:423 +msgid "Read &metadata from files" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:424 +msgid "Format for &single file save:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:425 +msgid "Default network &timeout:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:426 +msgid "" +"Set the default timeout for network fetches (i.e. anytime we go out to the " +"internet to get information)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:427 +msgid " seconds" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:428 +msgid "Choose &language (requires restart):" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:429 +msgid "Normal" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:430 +msgid "High" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:431 +msgid "Low" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:432 +msgid "Job &priority:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:434 +msgid "Add a directory to the frequently used directories list" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:436 +msgid "Remove a directory from the frequently used directories list" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:438 +msgid "Use &Roman numerals for series number" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:439 +msgid "Enable system &tray icon (needs restart)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:440 +msgid "Show ¬ifications in system tray" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:441 +msgid "Show cover &browser in a separate window (needs restart)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:442 +msgid "Automatically send downloaded &news to ebook reader" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:443 +msgid "&Delete news from library when it is sent to reader" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:444 +msgid "&Number of covers to show in browse mode (needs restart):" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:445 +msgid "Toolbar" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:446 +msgid "Large" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:447 +msgid "Medium" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:448 +msgid "Small" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:449 +msgid "&Button size in toolbar" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:450 +msgid "Show &text in toolbar buttons" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:451 +msgid "Select visible &columns in library view" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:454 +msgid "Use internal &viewer for:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:455 +msgid "Free unused diskspace from the database" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:456 +msgid "&Compact database" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:457 +msgid "&Metadata from file name" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:458 +msgid "" +"calibre contains a network server that allows you to access your book " +"collection using a browser from anywhere in the world. Any changes to the " +"settings will only take effect after a server restart." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:459 +msgid "Server &port:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:460 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:57 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:174 +msgid "&Username:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:461 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:58 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:175 +msgid "&Password:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:462 +msgid "" +"If you leave the password blank, anyone will be able to access your book " +"collection using the web interface." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:463 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:176 +msgid "&Show password" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:464 +msgid "" +"The maximum size (widthxheight) for displayed covers. Larger covers are " +"resized. " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:465 +msgid "Max. &cover size:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:466 +msgid "&Start Server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:467 +msgid "St&op Server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:468 +msgid "&Test Server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:469 +msgid "Run server &automatically on startup" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:470 +msgid "View &server logs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:471 +msgid "" +"If you want to use the content server to access your ebook collection on " +"your iphone with Stanza, you will need to add the URL " +"http://myhostname:8080/stanza as a new catalog in the stanza reader on your " +"iphone. Here myhostname should be the fully qualified hostname or the IP " +"address of this computer." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:472 +msgid "" +"Here you can customize the behavior of Calibre by controlling what plugins " +"it uses." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:473 +msgid "Enable/&Disable plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:474 +msgid "&Customize plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:475 +msgid "&Remove plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:476 +msgid "Add new plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:477 +msgid "Plugin &file:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:479 +msgid "&Add" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:48 +msgid "Are you sure?" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:50 +msgid "&Show this warning again" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/conversion_error_ui.py:41 +msgid "ERROR" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:52 +msgid "Bulk convert to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:54 +msgid "Convert %s to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:95 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:55 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:296 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:143 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:161 +msgid "Metadata" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:70 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:96 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:57 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:297 +msgid "Look & Feel" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:72 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:97 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:298 +msgid "Page Setup" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:74 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:98 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:61 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:299 +msgid "Chapter Detection" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:95 +msgid "" +"Specify metadata such as title and author for the book.\n" +"\n" +"Metadata will be updated in the database as well as the generated %s file." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:96 +msgid "" +"Adjust the look of the generated ebook by specifying things like font sizes." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:97 +msgid "Specify the page layout settings like margins." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:98 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:299 +msgid "Fine tune the detection of chapter and section headings." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:104 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:167 +msgid "Choose cover for " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:111 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:59 +msgid "Cannot read" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:112 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:175 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:60 +msgid "You do not have permission to read the file: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:120 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:183 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:68 +msgid "Error reading file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:121 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:69 +msgid "

There was an error reading from file:
" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:190 +msgid " is not a valid picture" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:238 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1053 +msgid "Cannot convert" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:239 +msgid "This book has no available formats" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:244 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:93 +msgid "No available formats" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:245 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:94 +msgid "Cannot convert %s as this book has no supported formats" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:249 +msgid "Choose the format to convert to " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:260 +msgid "Invalid XPath expression" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:261 +msgid "The expression %s is invalid. Error: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:410 +msgid "Convert to EPUB" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:411 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:494 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:341 +msgid "Book Cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:412 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:495 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:342 +msgid "Change &cover image:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:413 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:496 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:343 +msgid "Browse for an image to use as the cover of this book." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:415 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:498 +msgid "Use cover from &source file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:416 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:499 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:305 +msgid "&Title: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:417 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:500 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:306 +msgid "Change the title of this book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:418 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:501 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:128 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:309 +msgid "&Author(s): " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:419 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:502 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:129 +msgid "" +"Change the author(s) of this book. Multiple authors should be separated by " +"an &. If the author name contains an &, use && to represent it." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:420 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:503 +msgid "Author So&rt:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:421 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:504 +msgid "" +"Change the author(s) of this book. Multiple authors should be separated by a " +"comma" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:422 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:505 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:136 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:318 +msgid "&Publisher: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:423 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:506 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:137 +msgid "Change the publisher of this book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:424 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:507 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:319 +msgid "Ta&gs: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:425 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:508 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:320 +msgid "" +"Tags categorize the book. This is particularly useful while searching. " +"

They can be any words or phrases, separated by commas." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:426 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:509 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:144 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:323 +msgid "&Series:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:427 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:428 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:510 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:511 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:145 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:146 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:324 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:325 +msgid "List of known series. You can add new series." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:429 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:430 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:512 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:513 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:329 +msgid "Series index." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:431 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:514 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:330 +msgid "Book " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:433 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:522 +msgid "Source en&coding:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:434 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:516 +msgid "Base &font size:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:435 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:442 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:444 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:446 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:448 +msgid " pt" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:436 +msgid "Remove &spacing between paragraphs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:437 +msgid "Preserve &tag structure when splitting" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:438 +msgid "&Rescale images" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:439 +msgid "Override &CSS" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:441 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:539 +msgid "&Left Margin:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:443 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:541 +msgid "&Right Margin:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:445 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:543 +msgid "&Top Margin:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:447 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:545 +msgid "&Bottom Margin:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:449 +msgid "Do not &split on page breaks" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:450 +msgid "&Source profile:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:451 +msgid "&Destination profile:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:452 +msgid "Automatic &chapter detection" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:453 +msgid "&XPath:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:454 +msgid "" +"\n" +"\n" +"

You can control how " +"calibre detects chapters using a XPath expression. To learn how to use XPath " +"expressions see the XPath " +"tutorial

" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:459 +msgid "Chapter &mark:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:460 +msgid "Automatic &Table of Contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:461 +msgid "Number of &links to add to Table of Contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:462 +msgid "Do not add &detected chapters to the Table of Contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:463 +msgid "Chapter &threshold" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:464 +msgid "&Force use of auto-generated Table of Contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:465 +msgid "Level &1 TOC" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:466 +msgid "Level &2 TOC" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:467 +msgid "&Title for generated TOC" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:38 +msgid "Author Sort" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:40 +msgid "ISBN" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:104 +msgid "Cannot connect" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:105 +msgid "You must specify a valid access key for isbndb.com" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:139 +msgid "Error fetching metadata" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:144 +msgid "No metadata found" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:144 +msgid "" +"No metadata found, try adjusting the title and author or the ISBN key." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:77 +msgid "Fetch metadata" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:78 +msgid "Fetching metadata for %1" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:79 +msgid "" +"Sign up for a free account from ISBNdb.com to get an access key." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:80 +msgid "&Access Key:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:81 +msgid "Fetch" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:82 +msgid "Matches" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:83 +msgid "" +"Select the book that most closely matches your copy from the list below" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/job_view_ui.py:32 +msgid "Details of job" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs.py:27 +msgid "Unavailable" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs.py:38 +msgid " - Jobs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:38 +msgid "Active Jobs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:39 +msgid "&Stop selected job" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:98 +msgid "Choose the format to convert into LRF" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:106 +msgid "Convert %s to LRF" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:109 +#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:360 +msgid "Set conversion defaults" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:260 +msgid "" +"Preprocess the file before converting to LRF. This is useful if you know " +"that the file is from a specific source. Known sources:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:261 +msgid "
  1. baen - Books from BAEN Publishers
  2. " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:262 +msgid "" +"
  3. pdftohtml - HTML files that are the output of the program " +"pdftohtml
  4. " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:263 +msgid "
  5. book-designer - HTML0 files from Book Designer
  6. " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:296 +msgid "" +"Specify metadata such as title and author for the book.

    Metadata will be " +"updated in the database as well as the generated LRF file." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:297 +msgid "" +"Adjust the look of the generated LRF file by specifying things like font " +"sizes and the spacing between words." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:298 +msgid "" +"Specify the page settings like margins and the screen size of the target " +"device." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:308 +msgid "No help available" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:411 +msgid "Bulk convert ebooks to LRF" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:492 +msgid "Convert to LRF" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:517 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:524 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:526 +msgid " pts" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:518 +msgid "Embedded Fonts" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:519 +msgid "&Serif:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:520 +msgid "S&ans-serif:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:521 +msgid "&Monospace:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:523 +msgid "Minimum &indent:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:525 +msgid "&Word spacing:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:527 +msgid "Enable auto &rotation of images" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:528 +msgid "Insert &blank lines between paragraphs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:529 +msgid "Ignore &tables" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:530 +msgid "Ignore &colors" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:531 +msgid "&Preprocess:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:532 +msgid "Header" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:533 +msgid "&Show header" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:534 +msgid "&Header format:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:535 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:540 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:542 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:544 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:546 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:107 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:109 +msgid " px" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:536 +msgid "Header &separation:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:537 +msgid "Override
    CSS" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:547 +msgid "&Convert tables to images (good for large/complex tables)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:548 +msgid "&Multiplier for text size in rendered tables:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:549 +msgid "Title based detection" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:550 +msgid "&Disable chapter detection" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:551 +msgid "&Regular expression:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:552 +msgid "Add &chapters to table of contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:553 +msgid "Don't add &links to the table of contents" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:554 +msgid "Tag based detection" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:555 +msgid "&Page break before tag:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:556 +msgid "&Force page break before tag:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:557 +msgid "Force page break before &attribute:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:558 +msgid "Detect chapter &at tag:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:559 +msgid "" +"\n" +"\n" +"

    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:126 +msgid "Edit Meta information" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:304 +msgid "Meta information" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:130 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:310 +msgid "Author S&ort: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:311 +msgid "" +"Specify how the author(s) of this book should be sorted. For example Charles " +"Dickens should be sorted as Dickens, Charles." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:314 +msgid "&Rating:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:315 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:316 +msgid "Rating of this book. 0-5 stars" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:317 +msgid " stars" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:138 +msgid "Add Ta&gs: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:140 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:141 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:321 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:322 +msgid "Open Tag Editor" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:142 +msgid "&Remove tags:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:143 +msgid "Comma separated list of tags to remove from the books. " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:147 +msgid "Remove &format:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:148 +msgid "A&utomatically set author sort" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:124 +msgid "Could not read metadata" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:125 +msgid "Could not read metadata from %s format" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:139 +msgid "Could not read cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:134 +msgid "Could not read cover from %s format" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:140 +msgid "The cover in the %s format is invalid" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:319 +msgid "" +"

    Enter your username and password for LibraryThing.com.
    If you " +"do not have one, you can register " +"for free!.

    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:349 +msgid "Could not fetch cover.
    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:349 +msgid "Could not fetch cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:355 +msgid "Cannot fetch cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:355 +msgid "You must specify the ISBN identifier for this book." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:303 +msgid "Edit Meta Information" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:307 +msgid "Swap the author and title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:312 +msgid "" +"Automatically create the author sort entry based on the current author entry" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:326 +msgid "Remove unused series (Series that have no books)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:331 +msgid "IS&BN:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:333 +msgid "Fetch metadata from server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:334 +msgid "Available Formats" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:335 +msgid "Add a new format for this book to the database" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:337 +msgid "Remove the selected formats for this book from the database." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:339 +msgid "Set the cover for the book from the selected format" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:345 +msgid "Reset cover to default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:347 +msgid "Fetch cover image from server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:348 +msgid "" +"Change the username and/or password for your account at LibraryThing.com" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:349 +msgid "Change password" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:55 +msgid "Password needed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress.py:42 +msgid "Aborting..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:39 +msgid "You" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:218 +msgid "Search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:261 +msgid "%d recipes" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:262 +msgid "Monday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:262 +msgid "Tuesday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:262 +msgid "Wednesday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:262 +msgid "day" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:263 +msgid "Friday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:263 +msgid "Saturday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:263 +msgid "Sunday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:263 +msgid "Thursday" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:292 +msgid "Must set account information" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:292 +msgid "This recipe requires a username and password" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:317 +msgid "Created by: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:355 +msgid "Last downloaded: %s days ago" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:357 +msgid "Last downloaded: never" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:384 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:161 +msgid "Schedule news download" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:387 +msgid "Add a custom news source" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:394 +#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:772 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:776 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1083 +msgid "News" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:221 +msgid "Recipes" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:163 +msgid "Schedule for download" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:164 +msgid "title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:165 +msgid "description" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:166 +msgid "author" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:167 +msgid "&Schedule for download:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:168 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:170 +msgid "Every " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:169 +msgid "at" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:171 +msgid "" +"Interval at which to download this recipe. A value of zero means that the " +"recipe will be downloaded every hour." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:180 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:263 +msgid " days" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:173 +msgid "&Account" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:177 +msgid "For the scheduling to work, you must leave calibre running." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:178 +msgid "&Download now" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:179 +msgid "" +"Delete downloaded news older than the specified number of days. Set to zero " +"to disable." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:181 +msgid "Delete downloaded news older than " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_item_ui.py:35 +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:96 +msgid "Form" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_item_ui.py:36 +msgid "contains" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_item_ui.py:37 +msgid "The text to search for. It is interpreted as a regular expression." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_item_ui.py:38 +msgid "" +"

    Negate this match. That is, only return results that do not match " +"this query." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_item_ui.py:39 +msgid "Negate" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:87 +msgid "Advanced Search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:88 +msgid "Find entries that have..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:89 +msgid "&All these words:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:90 +msgid "This exact &phrase:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:91 +msgid "&One or more of these words:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:92 +msgid "But dont show entries that have..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:93 +msgid "Any of these &unwanted words:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:94 +msgid "" +"See the User Manual for more help" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:123 +msgid "Tag Editor" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:124 +msgid "A&vailable tags" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:125 +msgid "" +"Delete tag from database. This will unapply the tag from all books and then " +"remove it from the database." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:127 +msgid "Apply tag to current book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:129 +msgid "A&pplied tags" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:130 +msgid "Unapply (remove) tag from current book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:132 +msgid "&Add tag:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:133 +msgid "" +"If the tag you want is not in the available list, you can add it here. " +"Accepts a comma separated list of tags." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:134 +msgid "Add tag to available tags and apply it to current book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:62 +msgid "No recipe selected" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:68 +msgid "The attached file: %s is a recipe to download %s." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:69 +msgid "Recipe for " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:96 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:255 +msgid "Switch to Advanced mode" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:91 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:99 +msgid "Switch to Basic mode" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:109 +msgid "Feed must have a title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:110 +msgid "The feed must have a title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:114 +msgid "Feed must have a URL" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:115 +msgid "The feed %s must have a URL" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:120 +msgid "Already exists" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:121 +msgid "This feed has already been added to the recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:171 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:228 +msgid "Invalid input" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:163 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:229 +msgid "

    Could not create recipe. Error:
    %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:178 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:210 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:234 +msgid "Replace recipe?" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:179 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:211 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:235 +msgid "A custom recipe named %s already exists. Do you want to replace it?" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:201 +msgid "Pick recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:201 +msgid "Pick the recipe to customize" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:221 +msgid "Choose a recipe file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:248 +msgid "Add custom news source" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:249 +msgid "Available user recipes" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:250 +msgid "Add/Update &recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:251 +msgid "&Remove recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:252 +msgid "&Share recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:253 +msgid "Customize &builtin recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:254 +msgid "&Load recipe from file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:256 +msgid "" +"\n" +"

    Create a basic news " +"recipe, by adding RSS feeds to it.
    For most feeds, you will have to " +"use the \"Advanced mode\" to further customize the fetch " +"process.

    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:260 +msgid "Recipe &title:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:261 +msgid "&Oldest article:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:262 +msgid "The oldest article to download" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:264 +msgid "&Max. number of articles per feed:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:265 +msgid "Maximum number of articles to download per feed." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:266 +msgid "Feeds in recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:268 +msgid "Remove feed from recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:271 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:274 +msgid "Add feed to recipe" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:272 +msgid "&Feed title:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:273 +msgid "Feed &URL:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:275 +msgid "&Add feed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:276 +msgid "" +"For help with writing advanced news recipes, please visit User Recipes" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:277 +msgid "Recipe source code (python)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:97 +msgid "" +"\n" +"\n" +"

    Set a regular expression " +"pattern to use when trying to guess ebook metadata from filenames.

    \n" +"

    A reference on the syntax " +"of regular expressions is available.

    \n" +"

    Use the Test functionality below to test your regular " +"expression on a few sample filenames. The group names for the various " +"metadata entries are documented in tooltips.

    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:104 +msgid "Regular &expression" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:105 +msgid "&Test" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:106 +msgid "File &name:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:107 +msgid "Test" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:108 +msgid "Title:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:109 +msgid "Regular expression (?P<title>)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:110 +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:113 +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:116 +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:119 +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:58 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:63 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:70 +msgid "No match" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:111 +msgid "Authors:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:112 +msgid "Regular expression (?P)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:114 +msgid "Series:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:115 +msgid "Regular expression (?P)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:117 +msgid "Series index:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:118 +msgid "Regular expression (?P)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:120 +msgid "ISBN:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:121 +msgid "Regular expression (?P)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:46 +msgid "Job" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:47 +msgid "Status" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:48 +msgid "Progress" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:49 +msgid "Running time" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:65 +msgid "Unknown job" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:70 +msgid "Finished" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:72 +msgid "Error" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:74 +msgid "Waiting" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:76 +msgid "Working" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:176 +msgid "Cannot kill job" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:173 +msgid "Cannot kill jobs that communicate with the device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/jobs2.py:177 +msgid "Job has already run" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:105 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:971 +msgid "Size (MB)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:106 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:972 +msgid "Date" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:107 +msgid "Rating" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:308 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:314 +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:319 +msgid "None" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:325 +msgid "Book %s of %s." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:739 +msgid "Not allowed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:740 +msgid "" +"Dropping onto a device is not supported. First add the book to the calibre " +"library." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:903 +msgid "Format" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:908 +msgid "Timestamp" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/library.py:1006 +msgid "Search (For Advanced Search click the button to the left)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/config_ui.py:47 +msgid "Configure Viewer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/config_ui.py:48 +msgid "Use white background" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/config_ui.py:49 +msgid "Hyphenate" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/config_ui.py:50 +msgid "Changes will only take effect after a restart." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:64 +msgid " - LRF Viewer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:157 +msgid "No matches for the search phrase %s were found." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:157 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:378 +msgid "No matches found" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:128 +msgid "LRF Viewer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:129 +msgid "Parsing LRF file" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:130 +msgid "LRF Viewer toolbar" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:131 +msgid "Next Page" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:132 +msgid "Previous Page" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:154 +msgid "Back" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:155 +msgid "Forward" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:135 +msgid "Next match" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:136 +#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:162 +msgid "Open ebook" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:137 +msgid "Configure" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:90 +msgid "Error communicating with device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:102 +msgid "&Restore" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:103 +msgid "&Donate to support calibre" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:106 +msgid "&Restart" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:142 +msgid "" +"

    For help visit %s.kovidgoyal.net
    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:143 +msgid "%s: %s by Kovid Goyal %%(version)s
    %%(device)s

    " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:161 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:163 +msgid "Send to main memory" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:164 +msgid "Send to storage card" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:163 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:164 +msgid "and delete from library" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:166 +msgid "Send to storage card by default" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:179 +msgid "Edit metadata individually" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:181 +msgid "Edit metadata in bulk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:184 +msgid "Add books from a single directory" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:185 +msgid "" +"Add books from directories, including sub-directories (One book per " +"directory, assumes every ebook file is the same book in a different format)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:186 +msgid "" +"Add books from directories, including sub directories (Multiple books per " +"directory, assumes every ebook file is a different book)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:201 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:356 +msgid "Save to disk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:202 +msgid "Save to disk in a single directory" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:203 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1258 +msgid "Save only %s format to disk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:206 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:362 +msgid "View" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:207 +msgid "View specific format" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:224 +msgid "Convert individually" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:225 +msgid "Bulk convert" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:227 +msgid "Set defaults for conversion" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:228 +msgid "Set defaults for conversion of comics" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:250 +msgid "Similar books..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:298 +msgid "Bad database location" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:300 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1391 +msgid "Choose a location for your ebook library." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:424 +msgid "Browse by covers" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:513 +msgid "Device: " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:514 +msgid " detected." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:536 +msgid "Connected " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:547 +msgid "Device database corrupted" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:548 +msgid "" +"\n" +"

    The database of books on the reader is corrupted. Try the " +"following:\n" +"

      \n" +"
    1. Unplug the reader. Wait for it to finish regenerating " +"the database (i.e. wait till it is ready to be used). Plug it back in. Now " +"it should work with %(app)s. If not try the next step.
    2. \n" +"
    3. Quit %(app)s. Find the file media.xml in the reader's " +"main memory. Delete it. Unplug the reader. Wait for it to regenerate the " +"file. Re-connect it and start %(app)s.
    4. \n" +"
    \n" +" " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:597 +msgid "Adding books recursively..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:602 +msgid "Added " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:602 +msgid "Searching..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:612 +#: /home/kovid/work/calibre/src/calibre/gui2/main.py:716 +msgid "" +"

    Books with the same title as the following already exist in the database. " +"Add them anyway?