Merge from custcol trunk

This commit is contained in:
Charles Haley 2010-05-22 08:40:34 +01:00
commit 064bda5feb
23 changed files with 927 additions and 378 deletions

View File

@ -4,6 +4,70 @@
# for important features/bug fixes. # for important features/bug fixes.
# Also, each release can have new and improved recipes. # Also, each release can have new and improved recipes.
- version: 0.6.54
date: 2010-05-21
new features:
- title: "EPUB Output: Add option to toggle preserving the aspect ratio of the cover."
type: major
description: >
"By default calibre creates an SVG based cover that scales with the screen size of the reader used to view it. Previosuly this scaling
was limited to preserve the aspect ratio of the image. This would often result in white borders at the sides or top and bottom of the image.
No, by default, calibre will setup the cover to not preserve aspect ratio, doing away with the white borders. The downside is that if the
aspect ratio of the cover is very different from the reader, it will look distorted. The old behavior can be restored via
Preferences->Conversion->EPUB Output."
- title: "Conversion pipeline: calibre will now automatically replace all ligatures in the input document."
type: major
description: >
"Conversion pipeline: calibre will now automatically replace all ligatures in the input document with the normal character
sequence they are meant to represent. This is because most readers lack the font support to display ligatures.
This can be turned off via an option under Look & Feel, in the Conversion settings."
- title: "Support for the iPapyrus and Newsmy readers and the Sony Ericsson XPERIA X10"
- title: "PDF Output: Set the first page to the cover."
tickets: [5581]
bug fixes:
- title: "Conversion pipeline: Handle input documents with no text. Allows conversion of MOBI files tha are only a sequence of images."
tickets: [5554]
- title: "Fix text justification control not working with translated version of calibre"
tickets: [5551]
- title: "HTML Input: Encoding detection fixed for <meta> tags that have newlines in their content attributes"
tickets: [5567]
- title: "EPUB Input: Handle malformed UUID in EPUB with obfuscated fonts."
tickets: [5552]
- title: "Don't resort when editing columns in the main GUI"
- title: "Fix regression in Kobo driver that caused it to only detect books in the root directory of the device"
new recipes:
- title: La Stampa and Libero
author: Gabriele Marini
- title: Der Tagesspiegel
author: ipaschke
- title: EMG and Agro Gerilla
author: Darko Miletic
- title: American Prospect, FactCheck and PolitiFact
author: Michael Heinz
improved recipes:
- Times Online
- The Atlantic
- Il Messagero
- Leggo
- Instapaper
- New York Review of Books
- NIN Online
- version: 0.6.53 - version: 0.6.53
date: 2010-05-15 date: 2010-05-15
@ -157,7 +221,7 @@
new features: new features:
- title: "Add merge book feature" - title: "Add merge book feature"
type: major type: major
desc: > description: >
"You can now merge multiple books into a single book, by clicking the arrow next to the edit meta information button. "You can now merge multiple books into a single book, by clicking the arrow next to the edit meta information button.
Meta information from the books will be merged as well as individual book files in different formats" Meta information from the books will be merged as well as individual book files in different formats"

View File

@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
''' '''
theatlantic.com theatlantic.com
''' '''
import string import string, re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag, NavigableString from calibre.ebooks.BeautifulSoup import Tag, NavigableString
@ -23,6 +23,8 @@ class TheAtlantic(BasicNewsRecipe):
remove_tags = [dict(id=['header', 'printAds', 'pageControls'])] remove_tags = [dict(id=['header', 'printAds', 'pageControls'])]
no_stylesheets = True no_stylesheets = True
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
def print_version(self, url): def print_version(self, url):
return url.replace('/archive/', '/print/') return url.replace('/archive/', '/print/')

View File

@ -22,7 +22,7 @@ class Economist(BasicNewsRecipe):
' Needs a subscription from ')+INDEX ' Needs a subscription from ')+INDEX
oldest_article = 7.0 oldest_article = 7.0
cover_url = 'http://www.economist.com/images/covers/currentcovereu_large.jpg' cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg'
remove_tags = [dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']), remove_tags = [dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
dict(attrs={'class':['dblClkTrk']})] dict(attrs={'class':['dblClkTrk']})]
remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body') remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body')

View File

@ -15,7 +15,7 @@ class Economist(BasicNewsRecipe):
' Much slower than the subscription based version.') ' Much slower than the subscription based version.')
oldest_article = 7.0 oldest_article = 7.0
cover_url = 'http://www.economist.com/images/covers/currentcovereu_large.jpg' cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg'
remove_tags = [dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']), remove_tags = [dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
dict(attrs={'class':['dblClkTrk']})] dict(attrs={'class':['dblClkTrk']})]
remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body') remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body')

View File

@ -0,0 +1,86 @@
__license__ = 'GPL v3'
__copyright__ = '2010 Ingo Paschke <ipaschke@gmail.com>'
'''
Fetch Tagesspiegel.
'''
import string, re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class TagesspiegelRSS(BasicNewsRecipe):
title = u'Der Tagesspiegel'
__author__ = 'ipaschke'
language = 'de'
oldest_article = 7
max_articles_per_feed = 100
extra_css = '''
.hcf-overline{color:#990000; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;display:block}
.hcf-teaser{font-family:Verdana,Arial,Helvetica;font-size:x-small;margin-top:0}
h1{font-family:Arial,Helvetica,sans-serif;font-size:large;clear:right;}
.hcf-caption{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.hcf-copyright{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.hcf-article{font-family:Arial,Helvetica;font-size:x-small}
.quote{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small}
.quote .cite{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small}
.hcf-inline-left{float:left;margin-right:15px;position:relative;}
.hcf-inline-right{float:right;margin-right:15px;position:relative;}
.hcf-smart-box{font-family: Arial, Helvetica, sans-serif; font-size: xx-small; margin: 0px 15px 8px 0px; width: 300px;}
'''
no_stylesheets = True
no_javascript = True
remove_empty_feeds = True
encoding = 'utf-8'
keep_only_tags = dict(name='div', attrs={'class':["hcf-article"]})
remove_tags = [
dict(name='link'), dict(name='iframe'),dict(name='style'),dict(name='meta'),dict(name='button'),
dict(name='div', attrs={'class':["hcf-jump-to-comments","hcf-clear","hcf-magnify hcf-media-control"] }),
dict(name='span', attrs={'class':["hcf-mainsearch",] }),
dict(name='ul', attrs={'class':["hcf-tools"] }),
]
def parse_index(self):
soup = self.index_to_soup('http://www.tagesspiegel.de/zeitung/')
def feed_title(div):
return ''.join(div.findAll(text=True, recursive=False)).strip()
articles = {}
key = None
ans = []
for div in soup.findAll(True, attrs={'class':['hcf-teaser', 'hcf-header', 'story headline']}):
if div['class'] == 'hcf-header':
key = string.capwords(feed_title(div.em.a))
articles[key] = []
ans.append(key)
elif div['class'] == 'hcf-teaser' and getattr(div.contents[0],'name','') == 'h2':
a = div.find('a', href=True)
if not a:
continue
url = 'http://www.tagesspiegel.de' + a['href']
title = self.tag_to_string(a, use_alt=True).strip()
description = ''
pubdate = strftime('%a, %d %b')
summary = div.find('p', attrs={'class':'hcf-teaser'})
if summary:
description = self.tag_to_string(summary, use_alt=False)
feed = key if key is not None else 'Uncategorized'
if not articles.has_key(feed):
articles[feed] = []
if not 'podcasts' in url:
articles[feed].append(
dict(title=title, url=url, date=pubdate,
description=re.sub('mehr$', '', description),
content=''))
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
return ans

View File

@ -5,6 +5,7 @@ __copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
''' '''
timesonline.co.uk timesonline.co.uk
''' '''
import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag from calibre.ebooks.BeautifulSoup import Tag
@ -26,6 +27,8 @@ class Timesonline(BasicNewsRecipe):
recursions = 9 recursions = 9
match_regexps = [r'http://www.timesonline.co.uk/.*page=[2-9]'] match_regexps = [r'http://www.timesonline.co.uk/.*page=[2-9]']
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
keep_only_tags = [ keep_only_tags = [
dict(name='div', attrs= {'id':['region-column1and2-layout2']}), dict(name='div', attrs= {'id':['region-column1and2-layout2']}),
{'class' : ['subheading']}, {'class' : ['subheading']},
@ -76,8 +79,7 @@ class Timesonline(BasicNewsRecipe):
soup = self.index_to_soup(index) soup = self.index_to_soup(index)
link_item = soup.find(name = 'div',attrs ={'class': "float-left margin-right-15"}) link_item = soup.find(name = 'div',attrs ={'class': "float-left margin-right-15"})
if link_item: if link_item:
cover_url = 'http://www.timesonline.co.uk' + link_item.img['src'] cover_url = link_item.img['src']
print cover_url
return cover_url return cover_url
def get_article_url(self, article): def get_article_url(self, article):
@ -85,9 +87,9 @@ class Timesonline(BasicNewsRecipe):
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang soup.html['xml:lang'] = self.language
soup.html['lang'] = self.lang soup.html['lang'] = self.language
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)]) mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.language)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=ISO-8859-1")]) mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=ISO-8859-1")])
soup.head.insert(0,mlang) soup.head.insert(0,mlang)
soup.head.insert(1,mcharset) soup.head.insert(1,mcharset)

View File

@ -46,8 +46,155 @@ block_level_tags = (
'ul', 'ul',
) )
class CoverManager(object):
class EPUBOutput(OutputFormatPlugin): '''
Manage the cover in the output document. Requires the opts object to have
the attributes:
no_svg_cover
no_default_epub_cover
preserve_cover_aspect_ratio
'''
NONSVG_TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
div { padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<div>
<img src="%s" alt="cover" style="height: 100%%" />
</div>
</body>
</html>
'''
TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%%" height="100%%" viewBox="0 0 600 800"
preserveAspectRatio="__ar__">
<image width="600" height="800" xlink:href="%s"/>
</svg>
</body>
</html>
'''
def default_cover(self):
'''
Create a generic cover for books that dont have a cover
'''
from calibre.utils.pil_draw import draw_centered_text
from calibre.ebooks.metadata import authors_to_string
if self.opts.no_default_epub_cover:
return None
self.log('Generating default cover')
m = self.oeb.metadata
title = unicode(m.title[0])
authors = [unicode(x) for x in m.creator if x.role == 'aut']
import cStringIO
cover_file = cStringIO.StringIO()
try:
try:
from PIL import Image, ImageDraw, ImageFont
Image, ImageDraw, ImageFont
except ImportError:
import Image, ImageDraw, ImageFont
font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
app = '['+__appname__ +' '+__version__+']'
COVER_WIDTH, COVER_HEIGHT = 590, 750
img = Image.new('RGB', (COVER_WIDTH, COVER_HEIGHT), 'white')
draw = ImageDraw.Draw(img)
# Title
font = ImageFont.truetype(font_path, 44)
bottom = draw_centered_text(img, draw, font, title, 15, ysep=9)
# Authors
bottom += 14
font = ImageFont.truetype(font_path, 32)
authors = authors_to_string(authors)
bottom = draw_centered_text(img, draw, font, authors, bottom, ysep=7)
# Vanity
font = ImageFont.truetype(font_path, 28)
width, height = draw.textsize(app, font=font)
left = max(int((COVER_WIDTH - width)/2.), 0)
top = COVER_HEIGHT - height - 15
draw.text((left, top), app, fill=(0,0,0), font=font)
# Logo
logo = Image.open(I('library.png'), 'r')
width, height = logo.size
left = max(int((COVER_WIDTH - width)/2.), 0)
top = max(int((COVER_HEIGHT - height)/2.), 0)
img.paste(logo, (left, max(bottom, top)))
img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE)
img.convert('RGB').save(cover_file, 'JPEG')
cover_file.flush()
id, href = self.oeb.manifest.generate('cover_image', 'cover_image.jpg')
item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0],
data=cover_file.getvalue())
m.clear('cover')
m.add('cover', item.id)
return item.href
except:
self.log.exception('Failed to generate default cover')
return None
def insert_cover(self):
from calibre.ebooks.oeb.base import urldefrag
from calibre import guess_type
g, m = self.oeb.guide, self.oeb.manifest
item = None
ar = 'xMidYMid meet' if self.opts.preserve_cover_aspect_ratio else \
'none'
svg_template = self.TITLEPAGE_COVER.replace('__ar__', ar)
if 'titlepage' not in g:
if 'cover' in g:
href = g['cover'].href
else:
href = self.default_cover()
if href is not None:
templ = self.NONSVG_TITLEPAGE_COVER if self.opts.no_svg_cover \
else svg_template
tp = templ%unquote(href)
id, href = m.generate('titlepage', 'titlepage.xhtml')
item = m.add(id, href, guess_type('t.xhtml')[0],
data=etree.fromstring(tp))
else:
item = self.oeb.manifest.hrefs[
urldefrag(self.oeb.guide['titlepage'].href)[0]]
if item is not None:
self.oeb.spine.insert(0, item, True)
if 'cover' not in self.oeb.guide.refs:
self.oeb.guide.add('cover', 'Title Page', 'a')
self.oeb.guide.refs['cover'].href = item.href
if 'titlepage' in self.oeb.guide.refs:
self.oeb.guide.refs['titlepage'].href = item.href
class EPUBOutput(OutputFormatPlugin, CoverManager):
name = 'EPUB Output' name = 'EPUB Output'
author = 'Kovid Goyal' author = 'Kovid Goyal'
@ -92,51 +239,21 @@ class EPUBOutput(OutputFormatPlugin):
'as a blank page.') 'as a blank page.')
), ),
OptionRecommendation(name='preserve_cover_aspect_ratio',
recommended_value=False, help=_(
'When using an SVG cover, this option will cause the cover to scale '
'to cover the available screen area, but still preserve its aspect ratio '
'(ratio of width to height). That means there may be white borders '
'at the sides or top and bottom of the image, but the image will '
'never be distorted. Without this option the image may be slightly '
'distorted, but there will be no borders.'
)
),
]) ])
recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)]) recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)])
NONSVG_TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
div { padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<div>
<img src="%s" alt="cover" style="height: 100%%" />
</div>
</body>
</html>
'''
TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%%" height="100%%" viewBox="0 0 600 800"
preserveAspectRatio="xMidYMid meet">
<image width="600" height="800" xlink:href="%s"/>
</svg>
</body>
</html>
'''
def workaround_webkit_quirks(self): def workaround_webkit_quirks(self):
from calibre.ebooks.oeb.base import XPath from calibre.ebooks.oeb.base import XPath
@ -259,97 +376,6 @@ class EPUBOutput(OutputFormatPlugin):
ans += '\n</encryption>' ans += '\n</encryption>'
return ans return ans
def default_cover(self):
'''
Create a generic cover for books that dont have a cover
'''
from calibre.utils.pil_draw import draw_centered_text
from calibre.ebooks.metadata import authors_to_string
if self.opts.no_default_epub_cover:
return None
self.log('Generating default cover')
m = self.oeb.metadata
title = unicode(m.title[0])
authors = [unicode(x) for x in m.creator if x.role == 'aut']
import cStringIO
cover_file = cStringIO.StringIO()
try:
try:
from PIL import Image, ImageDraw, ImageFont
Image, ImageDraw, ImageFont
except ImportError:
import Image, ImageDraw, ImageFont
font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
app = '['+__appname__ +' '+__version__+']'
COVER_WIDTH, COVER_HEIGHT = 590, 750
img = Image.new('RGB', (COVER_WIDTH, COVER_HEIGHT), 'white')
draw = ImageDraw.Draw(img)
# Title
font = ImageFont.truetype(font_path, 44)
bottom = draw_centered_text(img, draw, font, title, 15, ysep=9)
# Authors
bottom += 14
font = ImageFont.truetype(font_path, 32)
authors = authors_to_string(authors)
bottom = draw_centered_text(img, draw, font, authors, bottom, ysep=7)
# Vanity
font = ImageFont.truetype(font_path, 28)
width, height = draw.textsize(app, font=font)
left = max(int((COVER_WIDTH - width)/2.), 0)
top = COVER_HEIGHT - height - 15
draw.text((left, top), app, fill=(0,0,0), font=font)
# Logo
logo = Image.open(I('library.png'), 'r')
width, height = logo.size
left = max(int((COVER_WIDTH - width)/2.), 0)
top = max(int((COVER_HEIGHT - height)/2.), 0)
img.paste(logo, (left, max(bottom, top)))
img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE)
img.convert('RGB').save(cover_file, 'JPEG')
cover_file.flush()
id, href = self.oeb.manifest.generate('cover_image', 'cover_image.jpg')
item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0],
data=cover_file.getvalue())
m.clear('cover')
m.add('cover', item.id)
return item.href
except:
self.log.exception('Failed to generate default cover')
return None
def insert_cover(self):
from calibre.ebooks.oeb.base import urldefrag
from calibre import guess_type
g, m = self.oeb.guide, self.oeb.manifest
item = None
if 'titlepage' not in g:
if 'cover' in g:
href = g['cover'].href
else:
href = self.default_cover()
if href is not None:
templ = self.NONSVG_TITLEPAGE_COVER if self.opts.no_svg_cover \
else self.TITLEPAGE_COVER
tp = templ%unquote(href)
id, href = m.generate('titlepage', 'titlepage.xhtml')
item = m.add(id, href, guess_type('t.xhtml')[0],
data=etree.fromstring(tp))
else:
item = self.oeb.manifest.hrefs[
urldefrag(self.oeb.guide['titlepage'].href)[0]]
if item is not None:
self.oeb.spine.insert(0, item, True)
if 'cover' not in self.oeb.guide.refs:
self.oeb.guide.add('cover', 'Title Page', 'a')
self.oeb.guide.refs['cover'].href = item.href
if 'titlepage' in self.oeb.guide.refs:
self.oeb.guide.refs['titlepage'].href = item.href
def condense_ncx(self, ncx_path): def condense_ncx(self, ncx_path):
if not self.opts.pretty_print: if not self.opts.pretty_print:
tree = etree.parse(ncx_path) tree = etree.parse(ncx_path)

View File

@ -0,0 +1,111 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
'''
All fields must have a NULL value represented as None for simple types,
an empty list/dictionary for complex types and (None, None) for cover_data
'''
SOCIAL_METADATA_FIELDS = frozenset([
'tags', # Ordered list
# A floating point number between 0 and 10
'rating',
# A simple HTML enabled string
'comments',
# A simple string
'series',
# A floating point number
'series_index',
# Of the form { scheme1:value1, scheme2:value2}
# For example: {'isbn':'123456789', 'doi':'xxxx', ... }
'classifiers',
'isbn', # Pseudo field for convenience, should get/set isbn classifier
])
PUBLICATION_METADATA_FIELDS = frozenset([
# title must never be None. Should be _('Unknown')
'title',
# Pseudo field that can be set, but if not set is auto generated
# from title and languages
'title_sort',
# Ordered list of authors. Must never be None, can be [_('Unknown')]
'authors',
# Pseudo field that can be set, but if not set is auto generated
# from authors and languages
'author_sort',
'book_producer',
# Dates and times must be timezone aware
'timestamp',
'pubdate',
'rights',
# So far only known publication type is periodical:calibre
# If None, means book
'publication_type',
# A UUID usually of type 4
'uuid',
'languages', # ordered list
# Simple string, no special semantics
'publisher',
# Absolute path to image file encoded in filesystem_encoding
'cover',
# Of the form (format, data) where format is, for e.g. 'jpeg', 'png', 'gif'...
'cover_data',
# Either thumbnail data, or an object with the attribute
# image_path which is the path to an image file, encoded
# in filesystem_encoding
'thumbnail',
])
BOOK_STRUCTURE_FIELDS = frozenset([
# These are used by code, Null values are None.
'toc', 'spine', 'guide', 'manifest',
])
USER_METADATA_FIELDS = frozenset([
# A dict of a form to be specified
'user_metadata',
])
DEVICE_METADATA_FIELDS = frozenset([
# Ordered list of strings
'device_collections',
'lpath', # Unicode, / separated
# In bytes
'size',
# Mimetype of the book file being represented
'mime',
])
CALIBRE_METADATA_FIELDS = frozenset([
# An application id
# Semantics to be defined. Is it a db key? a db name + key? A uuid?
'application_id',
]
)
RESERVED_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
PUBLICATION_METADATA_FIELDS).union(
BOOK_STRUCTURE_FIELDS).union(
USER_METADATA_FIELDS).union(
DEVICE_METADATA_FIELDS).union(
CALIBRE_METADATA_FIELDS)
assert len(RESERVED_METADATA_FIELDS) == sum(map(len, (
SOCIAL_METADATA_FIELDS, PUBLICATION_METADATA_FIELDS,
BOOK_STRUCTURE_FIELDS, USER_METADATA_FIELDS,
DEVICE_METADATA_FIELDS, CALIBRE_METADATA_FIELDS,
)))
SERIALIZABLE_FIELDS = SOCIAL_METADATA_FIELDS.union(
USER_METADATA_FIELDS).union(
PUBLICATION_METADATA_FIELDS).union(
CALIBRE_METADATA_FIELDS).union(
frozenset(['lpath'])) # I don't think we need device_collections
# Serialization of covers/thumbnails will have to be handled carefully, maybe
# as an option to the serializer class

View File

@ -0,0 +1,129 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import copy
from calibre.ebooks.metadata.book import RESERVED_METADATA_FIELDS
NULL_VALUES = {
'user_metadata': {},
'cover_data' : (None, None),
'tags' : [],
'classifiers' : {},
'languages' : [],
'device_collections': [],
'authors' : [_('Unknown')],
'title' : _('Unknown'),
}
class Metadata(object):
'''
This class must expose a superset of the API of MetaInformation in terms
of attribute access and methods. Only the __init__ method is different.
MetaInformation will simply become a function that creates and fills in
the attributes of this class.
Please keep the method based API of this class to a minimum. Every method
becomes a reserved field name.
'''
def __init__(self):
object.__setattr__(self, '_data', copy.deepcopy(NULL_VALUES))
def __getattribute__(self, field):
_data = object.__getattribute__(self, '_data')
if field in RESERVED_METADATA_FIELDS:
return _data.get(field, None)
try:
return object.__getattribute__(self, field)
except AttributeError:
pass
if field in _data['user_metadata'].iterkeys():
# TODO: getting user metadata values
pass
raise AttributeError(
'Metadata object has no attribute named: '+ repr(field))
def __setattr__(self, field, val):
_data = object.__getattribute__(self, '_data')
if field in RESERVED_METADATA_FIELDS:
if field != 'user_metadata':
if not val:
val = NULL_VALUES[field]
_data[field] = val
else:
raise AttributeError('You cannot set user_metadata directly.')
elif field in _data['user_metadata'].iterkeys():
# TODO: Setting custom column values
pass
else:
# You are allowed to stick arbitrary attributes onto this object as
# long as they dont conflict with global or user metadata names
# Don't abuse this privilege
self.__dict__[field] = val
@property
def reserved_names(self):
'The set of names you cannot use for your own purposes on this object'
_data = object.__getattribute__(self, '_data')
return frozenset(RESERVED_FIELD_NAMES).union(frozenset(
_data['user_metadata'].iterkeys()))
@property
def user_metadata_names(self):
'The set of user metadata names this object knows about'
_data = object.__getattribute__(self, '_data')
return frozenset(_data['user_metadata'].iterkeys())
# Old MetaInformation API {{{
def copy(self):
pass
def print_all_attributes(self):
pass
def smart_update(self, other):
pass
def format_series_index(self):
pass
def authors_from_string(self, raw):
pass
def format_authors(self):
pass
def format_tags(self):
pass
def format_rating(self):
return unicode(self.rating)
def __unicode__(self):
pass
def to_html(self):
pass
def __str__(self):
return self.__unicode__().encode('utf-8')
def __nonzero__(self):
return True
# }}}
_m = Metadata()
RESERVED_FIELD_NAMES = \
frozenset(_m.__dict__.iterkeys()).union( # _data
RESERVED_METADATA_FIELDS).union(
frozenset(Metadata.__dict__.iterkeys())) # methods defined in Metadata
del _m

View File

@ -9,7 +9,6 @@ from threading import Thread
from calibre import prints from calibre import prints
from calibre.utils.config import OptionParser from calibre.utils.config import OptionParser
from calibre.utils.logging import default_log from calibre.utils.logging import default_log
from calibre.ebooks.metadata import MetaInformation
from calibre.customize import Plugin from calibre.customize import Plugin
metadata_config = None metadata_config = None
@ -53,7 +52,7 @@ class MetadataSource(Plugin):
if self.results: if self.results:
c = self.config_store().get(self.name, {}) c = self.config_store().get(self.name, {})
res = self.results res = self.results
if isinstance(res, MetaInformation): if hasattr(res, 'authors'):
res = [res] res = [res]
for mi in res: for mi in res:
if not c.get('rating', True): if not c.get('rating', True):

0
src/calibre/ebooks/metadata/odt.py Executable file → Normal file
View File

View File

@ -669,10 +669,19 @@ class OPF(object):
remove = list(self.authors_path(self.metadata)) remove = list(self.authors_path(self.metadata))
for elem in remove: for elem in remove:
elem.getparent().remove(elem) elem.getparent().remove(elem)
elems = []
for author in val: for author in val:
attrib = {'{%s}role'%self.NAMESPACES['opf']: 'aut'} attrib = {'{%s}role'%self.NAMESPACES['opf']: 'aut'}
elem = self.create_metadata_element('creator', attrib=attrib) elem = self.create_metadata_element('creator', attrib=attrib)
self.set_text(elem, author.strip()) self.set_text(elem, author.strip())
# Ensure new author element is at the top of the list
# for broken implementations that always use the first
# <dc:creator> element with no attention to the role
elems.append(elem)
for elem in reversed(elems):
parent = elem.getparent()
parent.remove(elem)
parent.insert(0, elem)
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)

View File

@ -15,11 +15,39 @@ from calibre.customize.conversion import OutputFormatPlugin, \
OptionRecommendation OptionRecommendation
from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata.opf2 import OPF
from calibre.ptempfile import TemporaryDirectory from calibre.ptempfile import TemporaryDirectory
from calibre.ebooks.pdf.writer import PDFWriter, ImagePDFWriter, PDFMetadata from calibre.ebooks.pdf.writer import PDFWriter, ImagePDFWriter, PDFMetadata, \
get_pdf_page_size
from calibre.ebooks.pdf.pageoptions import UNITS, PAPER_SIZES, \ from calibre.ebooks.pdf.pageoptions import UNITS, PAPER_SIZES, \
ORIENTATIONS ORIENTATIONS
from calibre.ebooks.epub.output import CoverManager
class PDFOutput(OutputFormatPlugin): class CoverManagerPDF(CoverManager):
def setup_cover(self, opts):
width, height = get_pdf_page_size(opts)
factor = opts.output_profile.dpi
self.NONSVG_TITLEPAGE_COVER = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="calibre:cover" content="true" />
<title>Cover</title>
<style type="text/css" title="override_css">
@page {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
div { padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<div>
<img src="%%s" alt="cover" width="%d" height="%d" />
</div>
</body>
</html>
'''%(int(width*factor), int(height*factor)-5)
class PDFOutput(OutputFormatPlugin, CoverManagerPDF):
name = 'PDF Output' name = 'PDF Output'
author = 'John Schember' author = 'John Schember'
@ -47,6 +75,7 @@ class PDFOutput(OutputFormatPlugin):
]) ])
def convert(self, oeb_book, output_path, input_plugin, opts, log): def convert(self, oeb_book, output_path, input_plugin, opts, log):
self.oeb = oeb_book
self.input_plugin, self.opts, self.log = input_plugin, opts, log self.input_plugin, self.opts, self.log = input_plugin, opts, log
self.output_path = output_path self.output_path = output_path
self.metadata = oeb_book.metadata self.metadata = oeb_book.metadata
@ -63,6 +92,10 @@ class PDFOutput(OutputFormatPlugin):
def convert_text(self, oeb_book): def convert_text(self, oeb_book):
self.log.debug('Serializing oeb input to disk for processing...') self.log.debug('Serializing oeb input to disk for processing...')
self.opts.no_svg_cover = True
self.opts.no_default_epub_cover = True
self.setup_cover(self.opts)
self.insert_cover()
with TemporaryDirectory('_pdf_out') as oeb_dir: with TemporaryDirectory('_pdf_out') as oeb_dir:
from calibre.customize.ui import plugin_for_output_format from calibre.customize.ui import plugin_for_output_format
oeb_output = plugin_for_output_format('oeb') oeb_output = plugin_for_output_format('oeb')

View File

@ -18,11 +18,70 @@ from calibre.ebooks.metadata import authors_to_string
from PyQt4 import QtCore from PyQt4 import QtCore
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, \ from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, \
QPrinter, QMetaObject, QSizeF, Qt QPrinter, QMetaObject, QSizeF, Qt, QPainter
from PyQt4.QtWebKit import QWebView from PyQt4.QtWebKit import QWebView
from pyPdf import PdfFileWriter, PdfFileReader from pyPdf import PdfFileWriter, PdfFileReader
def get_custom_size(opts):
custom_size = None
if opts.custom_size != None:
width, sep, height = opts.custom_size.partition('x')
if height != '':
try:
width = int(width)
height = int(height)
custom_size = (width, height)
except:
custom_size = None
return custom_size
def get_pdf_page_size(opts):
from calibre.gui2 import is_ok_to_use_qt
if not is_ok_to_use_qt():
raise Exception('Not OK to use Qt')
printer = QPrinter(QPrinter.HighResolution)
custom_size = get_custom_size(opts)
if opts.output_profile.short_name == 'default':
if custom_size is None:
printer.setPaperSize(paper_size(opts.paper_size))
else:
printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
else:
printer.setPaperSize(QSizeF(opts.output_profile.width / opts.output_profile.dpi,
opts.output_profile.height / opts.output_profile.dpi), QPrinter.Inch)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
size = printer.paperSize(QPrinter.Millimeter)
return size.width() / 10, size.height() / 10
def get_imagepdf_page_size(opts):
printer = QPrinter(QPrinter.HighResolution)
custom_size = get_custom_size(opts)
if opts.output_profile.short_name == 'default':
if custom_size == None:
printer.setPaperSize(paper_size(opts.paper_size))
else:
printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
else:
printer.setPaperSize(QSizeF(opts.output_profile.comic_screen_size[0] / opts.output_profile.dpi,
opts.output_profile.comic_screen_size[1] / opts.output_profile.dpi), QPrinter.Inch)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
size = printer.paperSize(QPrinter.Millimeter)
return size.width() / 10, size.height() / 10
class PDFMetadata(object): class PDFMetadata(object):
def __init__(self, oeb_metadata=None): def __init__(self, oeb_metadata=None):
self.title = _('Unknown') self.title = _('Unknown')
@ -36,6 +95,7 @@ class PDFMetadata(object):
class PDFWriter(QObject): class PDFWriter(QObject):
def __init__(self, opts, log): def __init__(self, opts, log):
from calibre.gui2 import is_ok_to_use_qt from calibre.gui2 import is_ok_to_use_qt
if not is_ok_to_use_qt(): if not is_ok_to_use_qt():
@ -46,25 +106,15 @@ class PDFWriter(QObject):
self.loop = QEventLoop() self.loop = QEventLoop()
self.view = QWebView() self.view = QWebView()
self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html) self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html)
self.render_queue = [] self.render_queue = []
self.combine_queue = [] self.combine_queue = []
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts') self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
self.custom_size = None
if opts.custom_size != None:
width, sep, height = opts.custom_size.partition('x')
if height != '':
try:
width = int(width)
height = int(height)
self.custom_size = (width, height)
except:
self.custom_size = None
self.opts = opts self.opts = opts
self.size = self._size() self.size = get_pdf_page_size(opts)
def dump(self, items, out_stream, pdf_metadata): def dump(self, items, out_stream, pdf_metadata):
self.metadata = pdf_metadata self.metadata = pdf_metadata
@ -77,27 +127,6 @@ class PDFWriter(QObject):
QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection) QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection)
self.loop.exec_() self.loop.exec_()
def _size(self):
'''
The size of a pdf page in cm.
'''
printer = QPrinter(QPrinter.HighResolution)
if self.opts.output_profile.short_name == 'default':
if self.custom_size == None:
printer.setPaperSize(paper_size(self.opts.paper_size))
else:
printer.setPaperSize(QSizeF(self.custom_size[0], self.custom_size[1]), unit(self.opts.unit))
else:
printer.setPaperSize(QSizeF(self.opts.output_profile.width / self.opts.output_profile.dpi, self.opts.output_profile.height / self.opts.output_profile.dpi), QPrinter.Inch)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(self.opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
size = printer.paperSize(QPrinter.Millimeter)
return size.width() / 10, size.height() / 10
@QtCore.pyqtSignature('_render_book()') @QtCore.pyqtSignature('_render_book()')
def _render_book(self): def _render_book(self):
@ -151,6 +180,10 @@ class PDFWriter(QObject):
class ImagePDFWriter(PDFWriter): class ImagePDFWriter(PDFWriter):
def __init__(self, opts, log):
PDFWriter.__init__(self, opts, log)
self.size = get_imagepdf_page_size(opts)
def _render_next(self): def _render_next(self):
item = str(self.render_queue.pop(0)) item = str(self.render_queue.pop(0))
self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1))) self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1)))
@ -163,22 +196,4 @@ class ImagePDFWriter(PDFWriter):
self.view.setHtml(html) self.view.setHtml(html)
def _size(self):
printer = QPrinter(QPrinter.HighResolution)
if self.opts.output_profile.short_name == 'default':
if self.custom_size == None:
printer.setPaperSize(paper_size(self.opts.paper_size))
else:
printer.setPaperSize(QSizeF(self.custom_size[0], self.custom_size[1]), unit(self.opts.unit))
else:
printer.setPaperSize(QSizeF(self.opts.output_profile.comic_screen_size[0] / self.opts.output_profile.dpi, self.opts.output_profile.comic_screen_size[1] / self.opts.output_profile.dpi), QPrinter.Inch)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
printer.setOrientation(orientation(self.opts.orientation))
printer.setOutputFormat(QPrinter.PdfFormat)
size = printer.paperSize(QPrinter.Millimeter)
return size.width() / 10, size.height() / 10

View File

@ -18,8 +18,11 @@ class PluginWidget(Widget, Ui_Form):
def __init__(self, parent, get_option, get_help, db=None, book_id=None): def __init__(self, parent, get_option, get_help, db=None, book_id=None):
Widget.__init__(self, parent, 'epub_output', Widget.__init__(self, parent, 'epub_output',
['dont_split_on_page_breaks', 'flow_size', ['dont_split_on_page_breaks', 'flow_size',
'no_default_epub_cover', 'no_svg_cover'] 'no_default_epub_cover', 'no_svg_cover',
'preserve_cover_aspect_ratio',]
) )
for i in range(2):
self.opt_no_svg_cover.toggle()
self.db, self.book_id = db, book_id self.db, self.book_id = db, book_id
self.initialize_options(get_option, get_help, db, book_id) self.initialize_options(get_option, get_help, db, book_id)

View File

@ -14,13 +14,34 @@
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2"> <item row="0" column="0">
<widget class="QCheckBox" name="opt_dont_split_on_page_breaks"> <widget class="QCheckBox" name="opt_dont_split_on_page_breaks">
<property name="text"> <property name="text">
<string>Do not &amp;split on page breaks</string> <string>Do not &amp;split on page breaks</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="opt_no_default_epub_cover">
<property name="text">
<string>No default &amp;cover</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="opt_no_svg_cover">
<property name="text">
<string>No &amp;SVG cover</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="opt_preserve_cover_aspect_ratio">
<property name="text">
<string>Preserve cover &amp;aspect ratio</string>
</property>
</widget>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
@ -60,22 +81,25 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="opt_no_default_epub_cover">
<property name="text">
<string>No default &amp;cover</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="opt_no_svg_cover">
<property name="text">
<string>No &amp;SVG cover</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections>
<connection>
<sender>opt_no_svg_cover</sender>
<signal>toggled(bool)</signal>
<receiver>opt_preserve_cover_aspect_ratio</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>81</x>
<y>73</y>
</hint>
<hint type="destinationlabel">
<x>237</x>
<y>68</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

View File

@ -8,9 +8,9 @@ from functools import partial
from PyQt4.QtCore import SIGNAL from PyQt4.QtCore import SIGNAL
from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant
from calibre.devices.metadata_serializer import metadata_serializer
from calibre.gui2.dialogs.config.create_custom_column_ui import Ui_QCreateCustomColumn from calibre.gui2.dialogs.config.create_custom_column_ui import Ui_QCreateCustomColumn
from calibre.gui2 import error_dialog from calibre.gui2 import error_dialog
from calibre.ebooks.metadata.book.base import RESERVED_FIELD_NAMES
class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
@ -103,7 +103,7 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
return self.simple_error('', _('No lookup name was provided')) return self.simple_error('', _('No lookup name was provided'))
if not col_heading: if not col_heading:
return self.simple_error('', _('No column heading was provided')) return self.simple_error('', _('No column heading was provided'))
if col in metadata_serializer.SERIALIZED_ATTRS: if col in RESERVED_FIELD_NAMES:
return self.simple_error('', _('The lookup name %s is reserved and cannot be used')%col) return self.simple_error('', _('The lookup name %s is reserved and cannot be used')%col)
bad_col = False bad_col = False
if col in self.parent.custcols: if col in self.parent.custcols:

View File

@ -135,7 +135,6 @@ class SearchBox2(QComboBox):
def text_edited_slot(self, text): def text_edited_slot(self, text):
if self.as_you_type: if self.as_you_type:
text = unicode(text)
self.timer = self.startTimer(self.__class__.INTERVAL) self.timer = self.startTimer(self.__class__.INTERVAL)
def timerEvent(self, event): def timerEvent(self, event):

View File

@ -145,7 +145,7 @@ First perform the following steps in |app|
For an iPad: For an iPad:
Install the ReadMe app on your iPad using iTunes. Open Safari and browse to:: Install the ReadMe app on your iPad using iTunes. Open the Readme builtin browser and browse to::
http://192.168.1.2:8080/ http://192.168.1.2:8080/

View File

@ -4,9 +4,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: calibre 0.6.53\n" "Project-Id-Version: calibre 0.6.54\n"
"POT-Creation-Date: 2010-05-15 21:26+MDT\n" "POT-Creation-Date: 2010-05-21 15:44+MDT\n"
"PO-Revision-Date: 2010-05-15 21:26+MDT\n" "PO-Revision-Date: 2010-05-21 15:44+MDT\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n" "Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -95,8 +95,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/rotate.py:63 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/rotate.py:63
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:81 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:81
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:82 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/split.py:82
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:28 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:87
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:29 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:88
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:233 #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:233
#: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:235 #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:235
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:279 #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:279
@ -135,7 +135,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/library/server.py:671 #: /home/kovid/work/calibre/src/calibre/library/server.py:671
#: /home/kovid/work/calibre/src/calibre/library/server.py:747 #: /home/kovid/work/calibre/src/calibre/library/server.py:747
#: /home/kovid/work/calibre/src/calibre/library/server.py:794 #: /home/kovid/work/calibre/src/calibre/library/server.py:794
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:113 #: /home/kovid/work/calibre/src/calibre/utils/localization.py:114
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:45 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:45
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:63 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:63
#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:77 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:77
@ -247,7 +247,7 @@ msgid "This profile tries to provide sane defaults and is useful if you know not
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:57 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:57
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:256 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:258
msgid "This profile is intended for the SONY PRS line. The 500/505/600/700 etc." msgid "This profile is intended for the SONY PRS line. The 500/505/600/700 etc."
msgstr "" msgstr ""
@ -256,62 +256,62 @@ msgid "This profile is intended for the SONY PRS 300."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:78 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:78
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:290 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:292
msgid "This profile is intended for the SONY PRS-900." msgid "This profile is intended for the SONY PRS-900."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:86 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:86
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:320 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:322
msgid "This profile is intended for the Microsoft Reader." msgid "This profile is intended for the Microsoft Reader."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:97 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:97
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:331 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:333
msgid "This profile is intended for the Mobipocket books." msgid "This profile is intended for the Mobipocket books."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:110 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:110
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:344 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:346
msgid "This profile is intended for the Hanlin V3 and its clones." msgid "This profile is intended for the Hanlin V3 and its clones."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:122 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:122
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:356 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:358
msgid "This profile is intended for the Hanlin V5 and its clones." msgid "This profile is intended for the Hanlin V5 and its clones."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:132 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:132
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:364 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:366
msgid "This profile is intended for the Cybook G3." msgid "This profile is intended for the Cybook G3."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:145 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:145
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:377 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:379
msgid "This profile is intended for the Cybook Opus." msgid "This profile is intended for the Cybook Opus."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:157 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:157
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:388 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:390
msgid "This profile is intended for the Amazon Kindle." msgid "This profile is intended for the Amazon Kindle."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:169 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:169
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:423 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:425
msgid "This profile is intended for the Irex Illiad." msgid "This profile is intended for the Irex Illiad."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:181 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:181
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:436 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:438
msgid "This profile is intended for the IRex Digital Reader 1000." msgid "This profile is intended for the IRex Digital Reader 1000."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:194 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:194
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:450 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:452
msgid "This profile is intended for the IRex Digital Reader 800." msgid "This profile is intended for the IRex Digital Reader 800."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:206 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:206
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:464 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:466
msgid "This profile is intended for the B&N Nook." msgid "This profile is intended for the B&N Nook."
msgstr "" msgstr ""
@ -323,23 +323,27 @@ msgstr ""
msgid "This profile tries to provide sane defaults and is useful if you want to produce a document intended to be read at a computer or on a range of devices." msgid "This profile tries to provide sane defaults and is useful if you want to produce a document intended to be read at a computer or on a range of devices."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:269 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:248
msgid "Intended for the iPad and similar devices with a resolution of 768x1024"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:271
msgid "This profile is intended for the Kobo Reader." msgid "This profile is intended for the Kobo Reader."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:281 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:283
msgid "This profile is intended for the SONY PRS-300." msgid "This profile is intended for the SONY PRS-300."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:299 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:301
msgid "This profile is intended for the 5-inch JetBook." msgid "This profile is intended for the 5-inch JetBook."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:308 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:310
msgid "This profile is intended for the SONY PRS line. The 500/505/700 etc, in landscape mode. Mainly useful for comics." msgid "This profile is intended for the SONY PRS line. The 500/505/700 etc, in landscape mode. Mainly useful for comics."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/profiles.py:406 #: /home/kovid/work/calibre/src/calibre/customize/profiles.py:408
msgid "This profile is intended for the Amazon Kindle DX." msgid "This profile is intended for the Amazon Kindle DX."
msgstr "" msgstr ""
@ -403,11 +407,11 @@ msgstr ""
msgid "Communicate with Android phones." msgid "Communicate with Android phones."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:36 #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:39
msgid "Comma separated list of directories to send e-books to on the device. The first one that exists will be used" msgid "Comma separated list of directories to send e-books to on the device. The first one that exists will be used"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:64 #: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:67
msgid "Communicate with S60 phones." msgid "Communicate with S60 phones."
msgstr "" msgstr ""
@ -523,7 +527,7 @@ msgstr ""
msgid "Communicate with the Kobo Reader" msgid "Communicate with the Kobo Reader"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/misc.py:55 #: /home/kovid/work/calibre/src/calibre/devices/misc.py:56
msgid "Communicate with the Booq Avant" msgid "Communicate with the Booq Avant"
msgstr "" msgstr ""
@ -604,6 +608,14 @@ msgstr ""
msgid "Communicate with the Teclast K3 reader." msgid "Communicate with the Teclast K3 reader."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:45
msgid "Communicate with the Newsmy reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/teclast/driver.py:60
msgid "Communicate with the iPapyrus reader."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:252 #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:252
msgid "Unable to detect the %s disk drive. Try rebooting." msgid "Unable to detect the %s disk drive. Try rebooting."
msgstr "" msgstr ""
@ -916,280 +928,288 @@ msgstr ""
msgid "Output saved to" msgid "Output saved to"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:94 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:95
msgid "Level of verbosity. Specify multiple times for greater verbosity." msgid "Level of verbosity. Specify multiple times for greater verbosity."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:101 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:102
msgid "Save the output from different stages of the conversion pipeline to the specified directory. Useful if you are unsure at which stage of the conversion process a bug is occurring." msgid "Save the output from different stages of the conversion pipeline to the specified directory. Useful if you are unsure at which stage of the conversion process a bug is occurring."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:110 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:111
msgid "Specify the input profile. The input profile gives the conversion system information on how to interpret various information in the input document. For example resolution dependent lengths (i.e. lengths in pixels). Choices are:" msgid "Specify the input profile. The input profile gives the conversion system information on how to interpret various information in the input document. For example resolution dependent lengths (i.e. lengths in pixels). Choices are:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:121 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:122
msgid "Specify the output profile. The output profile tells the conversion system how to optimize the created document for the specified device. In some cases, an output profile is required to produce documents that will work on a device. For example EPUB on the SONY reader. Choices are:" msgid "Specify the output profile. The output profile tells the conversion system how to optimize the created document for the specified device. In some cases, an output profile is required to produce documents that will work on a device. For example EPUB on the SONY reader. Choices are:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:132 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:133
msgid "The base font size in pts. All font sizes in the produced book will be rescaled based on this size. By choosing a larger size you can make the fonts in the output bigger and vice versa. By default, the base font size is chosen based on the output profile you chose." msgid "The base font size in pts. All font sizes in the produced book will be rescaled based on this size. By choosing a larger size you can make the fonts in the output bigger and vice versa. By default, the base font size is chosen based on the output profile you chose."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:142 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:143
msgid "Mapping from CSS font names to font sizes in pts. An example setting is 12,12,14,16,18,20,22,24. These are the mappings for the sizes xx-small to xx-large, with the final size being for huge fonts. The font rescaling algorithm uses these sizes to intelligently rescale fonts. The default is to use a mapping based on the output profile you chose." msgid "Mapping from CSS font names to font sizes in pts. An example setting is 12,12,14,16,18,20,22,24. These are the mappings for the sizes xx-small to xx-large, with the final size being for huge fonts. The font rescaling algorithm uses these sizes to intelligently rescale fonts. The default is to use a mapping based on the output profile you chose."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:154 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:155
msgid "Disable all rescaling of font sizes." msgid "Disable all rescaling of font sizes."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:161 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:162
msgid "The line height in pts. Controls spacing between consecutive lines of text. By default no line height manipulation is performed." msgid "The line height in pts. Controls spacing between consecutive lines of text. By default no line height manipulation is performed."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:169 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:170
msgid "Some badly designed documents use tables to control the layout of text on the page. When converted these documents often have text that runs off the page and other artifacts. This option will extract the content from the tables and present it in a linear fashion." msgid "Some badly designed documents use tables to control the layout of text on the page. When converted these documents often have text that runs off the page and other artifacts. This option will extract the content from the tables and present it in a linear fashion."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:179 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:180
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." 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 "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:188 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:189
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." 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 "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:196 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:197
msgid "XPath expression that specifies all tags that should be added to the Table of Contents at level three. Each entry is added under the previous level two entry." msgid "XPath expression that specifies all tags that should be added to the Table of Contents at level three. Each entry is added under the previous level two entry."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:204 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:205
msgid "Normally, if the source file already has a Table of Contents, it is used in preference to the auto-generated one. With this option, the auto-generated one is always used." msgid "Normally, if the source file already has a Table of Contents, it is used in preference to the auto-generated one. With this option, the auto-generated one is always used."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:212 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:213
msgid "Don't add auto-detected chapters to the Table of Contents." msgid "Don't add auto-detected chapters to the Table of Contents."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:219 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:220
msgid "If fewer than this number of chapters is detected, then links are added to the Table of Contents. Default: %default" msgid "If fewer than this number of chapters is detected, then links are added to the Table of Contents. Default: %default"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:226 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:227
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 threshold number of chapters were detected." 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 threshold number of chapters were detected."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:234 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:235
msgid "Remove entries from the Table of Contents whose titles match the specified regular expression. Matching entries and all their children are removed." msgid "Remove entries from the Table of Contents whose titles match the specified regular expression. Matching entries and all their children are removed."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:245 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:246
msgid "An XPath expression to detect chapter titles. The default is to consider <h1> or <h2> tags that contain the words \"chapter\",\"book\",\"section\" or \"part\" as chapter titles as well as any tags that have class=\"chapter\". The expression used must evaluate to a list of elements. To disable chapter detection, use the expression \"/\". See the XPath Tutorial in the calibre User Manual for further help on using this feature." msgid "An XPath expression to detect chapter titles. The default is to consider <h1> or <h2> tags that contain the words \"chapter\",\"book\",\"section\" or \"part\" as chapter titles as well as any tags that have class=\"chapter\". The expression used must evaluate to a list of elements. To disable chapter detection, use the expression \"/\". See the XPath Tutorial in the calibre User Manual for further help on using this feature."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:259 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:260
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." 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 "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:269 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:270
msgid "Either the path to a CSS stylesheet or raw CSS. This CSS will be appended to the style rules from the source file, so it can be used to override those rules." msgid "Either the path to a CSS stylesheet or raw CSS. This CSS will be appended to the style rules from the source file, so it can be used to override those rules."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:278 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:279
msgid "An XPath expression. Page breaks are inserted before the specified elements." msgid "An XPath expression. Page breaks are inserted before the specified elements."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:284 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:285
msgid "Set the top margin in pts. Default is %default. Note: 72 pts equals 1 inch" msgid "Set the top margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:289 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:290
msgid "Set the bottom margin in pts. Default is %default. Note: 72 pts equals 1 inch" msgid "Set the bottom margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:294 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:295
msgid "Set the left margin in pts. Default is %default. Note: 72 pts equals 1 inch" msgid "Set the left margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:299 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:300
msgid "Set the right margin in pts. Default is %default. Note: 72 pts equals 1 inch" msgid "Set the right margin in pts. Default is %default. Note: 72 pts equals 1 inch"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:305 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:306
msgid "Change text justification. A value of \"left\" converts all justified text in the source to left aligned (i.e. unjustified) text. A value of \"justify\" converts all unjustified text to justified. A value of \"original\" (the default) does not change justification in the source file. Note that only some output formats support justification." msgid "Change text justification. A value of \"left\" converts all justified text in the source to left aligned (i.e. unjustified) text. A value of \"justify\" converts all unjustified text to justified. A value of \"original\" (the default) does not change justification in the source file. Note that only some output formats support justification."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:315 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:316
msgid "Remove spacing between paragraphs. Also sets an indent on paragraphs of 1.5em. Spacing removal will not work if the source file does not use paragraphs (<p> or <div> tags)." msgid "Remove spacing between paragraphs. Also sets an indent on paragraphs of 1.5em. Spacing removal will not work if the source file does not use paragraphs (<p> or <div> tags)."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:322 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:323
msgid "When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent." msgid "When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:329 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:330
msgid "Use the cover detected from the source file in preference to the specified cover." msgid "Use the cover detected from the source file in preference to the specified cover."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:335 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:336
msgid "Insert a blank line between paragraphs. Will not work if the source file does not use paragraphs (<p> or <div> tags)." msgid "Insert a blank line between paragraphs. Will not work if the source file does not use paragraphs (<p> or <div> tags)."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:342 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:343
msgid "Remove the first image from the input ebook. Useful if the first image in the source file is a cover and you are specifying an external cover." msgid "Remove the first image from the input ebook. Useful if the first image in the source file is a cover and you are specifying an external cover."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:350 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:351
msgid "Insert the book metadata at the start of the book. This is useful if your ebook reader does not support displaying/searching metadata directly." msgid "Insert the book metadata at the start of the book. This is useful if your ebook reader does not support displaying/searching metadata directly."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:358 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:359
msgid "Attempt to detect and correct hard line breaks and other problems in the source file. This may make things worse, so use with care." msgid "Attempt to detect and correct hard line breaks and other problems in the source file. This may make things worse, so use with care."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:366 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:367
msgid "Use a regular expression to try and remove the header." msgid "Use a regular expression to try and remove the header."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:373 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:374
msgid "The regular expression to use to remove the header." msgid "The regular expression to use to remove the header."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:379 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:380
msgid "Use a regular expression to try and remove the footer." msgid "Use a regular expression to try and remove the footer."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:386 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:387
msgid "The regular expression to use to remove the footer." msgid "The regular expression to use to remove the footer."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:393 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:394
msgid "Read metadata from the specified OPF file. Metadata read from this file will override any metadata in the source file." msgid "Read metadata from the specified OPF file. Metadata read from this file will override any metadata in the source file."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:400 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:401
msgid "Transliterate unicode characters to an ASCII representation. Use with care because this will replace unicode characters with ASCII. For instance it will replace \"%s\" with \"Mikhail Gorbachiov\". Also, note that in cases where there are multiple representations of a character (characters shared by Chinese and Japanese for instance) the representation used by the largest number of people will be used (Chinese in the previous example)." msgid "Transliterate unicode characters to an ASCII representation. Use with care because this will replace unicode characters with ASCII. For instance it will replace \"%s\" with \"Mikhail Gorbachiov\". Also, note that in cases where there are multiple representations of a character (characters shared by Chinese and Japanese for instance) the representation used by the largest number of people will be used (Chinese in the previous example)."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:415 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:416
msgid "Preserve ligatures present in the input document. A ligature is a special rendering of a pair of characters like ff, fi, fl et cetera. Most readers do not have support for ligatures in their default fonts, so they are unlikely to render correctly. By default, calibre will turn a ligature into the corresponding pair of normal characters. This option will preserve them instead."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:428
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:38 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:38
msgid "Set the title." msgid "Set the title."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:419 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:432
msgid "Set the authors. Multiple authors should be separated by ampersands." msgid "Set the authors. Multiple authors should be separated by ampersands."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:424 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:437
msgid "The version of the title to be used for sorting. " msgid "The version of the title to be used for sorting. "
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:428 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:441
msgid "String to be used when sorting by author. " msgid "String to be used when sorting by author. "
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:432 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:445
msgid "Set the cover to the specified file or URL" msgid "Set the cover to the specified file or URL"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:436 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:449
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:54 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:54
msgid "Set the ebook description." msgid "Set the ebook description."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:440 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:453
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:56 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:56
msgid "Set the ebook publisher." msgid "Set the ebook publisher."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:444 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:457
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:60 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:60
msgid "Set the series this ebook belongs to." msgid "Set the series this ebook belongs to."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:448 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:461
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:62 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:62
msgid "Set the index of the book in this series." msgid "Set the index of the book in this series."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:452 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:465
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:64 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:64
msgid "Set the rating. Should be a number between 1 and 5." msgid "Set the rating. Should be a number between 1 and 5."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:456 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:469
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:66 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:66
msgid "Set the ISBN of the book." msgid "Set the ISBN of the book."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:460 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:473
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:68 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:68
msgid "Set the tags for the book. Should be a comma separated list." msgid "Set the tags for the book. Should be a comma separated list."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:464 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:477
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:70 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:70
msgid "Set the book producer." msgid "Set the book producer."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:468 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:481
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:72 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/cli.py:72
msgid "Set the language." msgid "Set the language."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:472 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:485
msgid "Set the publication date." msgid "Set the publication date."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:476 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:489
msgid "Set the book timestamp (used by the date column in calibre)." msgid "Set the book timestamp (used by the date column in calibre)."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:576 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:589
msgid "Could not find an ebook inside the archive" msgid "Could not find an ebook inside the archive"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:634 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:647
msgid "Values of series index and rating must be numbers. Ignoring" msgid "Values of series index and rating must be numbers. Ignoring"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:641 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:654
msgid "Failed to parse date/time" msgid "Failed to parse date/time"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:788 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:802
msgid "Converting input to HTML..." msgid "Converting input to HTML..."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:815 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:829
msgid "Running transforms on ebook..." msgid "Running transforms on ebook..."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:902 #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:916
msgid "Creating" msgid "Creating"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:58 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:205
msgid "Extract the contents of the generated EPUB file to the specified directory. The contents of the directory are first deleted, so be careful." msgid "Extract the contents of the generated EPUB file to the specified directory. The contents of the directory are first deleted, so be careful."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:64 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:211
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." 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 "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:75 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:222
msgid "Split all HTML files larger than this size (in KB). This is necessary as most EPUB readers cannot handle large file sizes. The default of %defaultKB is the size required for Adobe Digital Editions." msgid "Split all HTML files larger than this size (in KB). This is necessary as most EPUB readers cannot handle large file sizes. The default of %defaultKB is the size required for Adobe Digital Editions."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:82 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:229
msgid "Normally, if the input file has no cover and you don't specify one, a default cover is generated with the title, authors, etc. This option disables the generation of this cover." msgid "Normally, if the input file has no cover and you don't specify one, a default cover is generated with the title, authors, etc. This option disables the generation of this cover."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:88 #: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:235
msgid "Do not use SVG for the book cover. Use this option if your EPUB is going to be used ona device that does not support SVG, like the iPhone or the JetBook Lite. Without this option, such devices will display the cover as a blank page." msgid "Do not use SVG for the book cover. Use this option if your EPUB is going to be used ona device that does not support SVG, like the iPhone or the JetBook Lite. Without this option, such devices will display the cover as a blank page."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:243
msgid "When using an SVG cover, this option will cause the cover to scale to cover the available screen area, but still preserve its aspect ratio (ratio of width to height). That means there may be white borders at the sides or top and bottom of the image, but the image will never be distorted. Without this option the image may be slightly distorted, but there will be no borders."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/fb2ml.py:144 #: /home/kovid/work/calibre/src/calibre/ebooks/fb2/fb2ml.py:144
#: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:102 #: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:102
#: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:77 #: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:77
@ -2026,19 +2046,19 @@ msgstr ""
msgid "Split Options:" msgid "Split Options:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:31 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:59
msgid "The unit of measure. Default is inch. Choices are %s Note: This does not override the unit for margins!" msgid "The unit of measure. Default is inch. Choices are %s Note: This does not override the unit for margins!"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:36 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:64
msgid "The size of the paper. This size will be overridden when an output profile is used. Default is letter. Choices are %s" msgid "The size of the paper. This size will be overridden when an output profile is used. Default is letter. Choices are %s"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:40 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:68
msgid "Custom size of the document. Use the form widthxheight EG. `123x321` to specify the width and height. This overrides any specified paper-size." msgid "Custom size of the document. Use the form widthxheight EG. `123x321` to specify the width and height. This overrides any specified paper-size."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:45 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/output.py:73
msgid "The orientation of the page. Default is portrait. Choices are %s" msgid "The orientation of the page. Default is portrait. Choices are %s"
msgstr "" msgstr ""
@ -2307,10 +2327,10 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_tab_template_ui.py:27 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_tab_template_ui.py:27
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:88 #: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:88
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:49 #: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:44 #: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:48
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input_ui.py:28 #: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input_ui.py:28
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:28 #: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:28
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:125 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:119
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:115 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:115
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:166 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:166
#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:66 #: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:66
@ -2512,7 +2532,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:52 #: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:52
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:53 #: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:53
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:131 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:125
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:52 #: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:52
#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:76 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:76
@ -2558,26 +2578,30 @@ msgstr ""
msgid "EPUB Output" msgid "EPUB Output"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:45 #: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:49
msgid "Do not &split on page breaks" msgid "Do not &split on page breaks"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:46 #: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:50
msgid "Split files &larger than:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:47
msgid " KB"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:48
msgid "No default &cover" msgid "No default &cover"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:49 #: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:51
msgid "No &SVG cover" msgid "No &SVG cover"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:52
msgid "Preserve cover &aspect ratio"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:53
msgid "Split files &larger than:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:54
msgid " KB"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input.py:12 #: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input.py:12
msgid "FB2 Input" msgid "FB2 Input"
msgstr "" msgstr ""
@ -2618,15 +2642,15 @@ msgid "&Base font size:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:105 #: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:105
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:129 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:123
msgid "Font size &key:" msgid "Font size &key:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:106 #: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:106
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:110 #: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:110
#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:112 #: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:112
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:128 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:122
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:133 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:118 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:118
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:120 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:125 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:125
@ -2665,72 +2689,76 @@ msgstr ""
msgid "Control the look and feel of the output" msgid "Control the look and feel of the output"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:126 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:30
msgid "Original"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:31
msgid "Left align"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel.py:32
msgid "Justify text"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:120
msgid "&Disable font size rescaling" msgid "&Disable font size rescaling"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:127 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:121
msgid "Base &font size:" msgid "Base &font size:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:130 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:124
msgid "Wizard to help you choose an appropriate font size key" msgid "Wizard to help you choose an appropriate font size key"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:132 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:126
msgid "Line &height:" msgid "Line &height:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:134 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:128
msgid "Input character &encoding:" msgid "Input character &encoding:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:129
msgid "Remove &spacing between paragraphs" msgid "Remove &spacing between paragraphs"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:136 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:130
msgid "Indent size:" msgid "Indent size:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:137 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:131
msgid "<p>When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent." msgid "<p>When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:138 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:132
msgid " em" msgid " em"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:139 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:133
msgid "&Linearize tables"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:140
msgid "&Transliterate unicode characters to ASCII."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:141
msgid "Extra &CSS"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:142
msgid "Insert &blank line"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:143
msgid "Text justification:" msgid "Text justification:"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:144 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:134
msgid "justify" msgid "&Linearize tables"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:145 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:135
msgid "left" msgid "Extra &CSS"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:146 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:136
msgid "original" msgid "&Transliterate unicode characters to ASCII"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:137
msgid "Insert &blank line"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:138
msgid "Keep &ligatures"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:19 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:19
@ -7833,18 +7861,22 @@ msgid "English (Ireland)"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:109 #: /home/kovid/work/calibre/src/calibre/utils/localization.py:109
msgid "Spanish (Paraguay)" msgid "English (China)"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:110 #: /home/kovid/work/calibre/src/calibre/utils/localization.py:110
msgid "German (AT)" msgid "Spanish (Paraguay)"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:111 #: /home/kovid/work/calibre/src/calibre/utils/localization.py:111
msgid "Dutch (NL)" msgid "German (AT)"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:112 #: /home/kovid/work/calibre/src/calibre/utils/localization.py:112
msgid "Dutch (NL)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/localization.py:113
msgid "Dutch (BE)" msgid "Dutch (BE)"
msgstr "" msgstr ""
@ -7868,13 +7900,13 @@ msgstr ""
msgid "Control email delivery" msgid "Control email delivery"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:102 #: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:113
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:124 #: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:135
msgid "Unknown feed" msgid "Unknown feed"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:142 #: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:153
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:165 #: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:178
msgid "Untitled article" msgid "Untitled article"
msgstr "" msgstr ""
@ -7970,23 +8002,23 @@ msgstr ""
msgid "Untitled Article" msgid "Untitled Article"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1228 #: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1230
msgid "Article downloaded: %s" msgid "Article downloaded: %s"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1239 #: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1241
msgid "Article download failed: %s" msgid "Article download failed: %s"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1256 #: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1258
msgid "Fetching feed" msgid "Fetching feed"
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1403 #: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1405
msgid "Failed to log in, check your username and password for the calibre Periodicals service." msgid "Failed to log in, check your username and password for the calibre Periodicals service."
msgstr "" msgstr ""
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1419 #: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1421
msgid "You do not have permission to download this issue. Either your subscription has expired or you have exceeded the maximum allowed downloads for today." msgid "You do not have permission to download this issue. Either your subscription has expired or you have exceeded the maximum allowed downloads for today."
msgstr "" msgstr ""

View File

@ -49,6 +49,17 @@ class Article(object):
self.date = published self.date = published
self.utctime = dt_factory(self.date, assume_utc=True, as_utc=True) self.utctime = dt_factory(self.date, assume_utc=True, as_utc=True)
self.localtime = self.utctime.astimezone(local_tz) self.localtime = self.utctime.astimezone(local_tz)
self._formatted_date = None
@dynamic_property
def formatted_date(self):
def fget(self):
if self._formatted_date is None:
self._formatted_date = self.localtime.strftime(" [%a, %d %b %H:%M]")
return self._formatted_date
def fset(self, val):
self._formatted_date = val
return property(fget=fget, fset=fset)
@dynamic_property @dynamic_property
def title(self): def title(self):
@ -150,6 +161,8 @@ class Feed(object):
self.articles.append(article) self.articles.append(article)
else: else:
self.logger.debug('Skipping article %s (%s) from feed %s as it is too old.'%(title, article.localtime.strftime('%a, %d %b, %Y %H:%M'), self.title)) self.logger.debug('Skipping article %s (%s) from feed %s as it is too old.'%(title, article.localtime.strftime('%a, %d %b, %Y %H:%M'), self.title))
d = item.get('date', '')
article.formatted_date = d
def parse_article(self, item): def parse_article(self, item):

View File

@ -1179,6 +1179,8 @@ class BasicNewsRecipe(Recipe):
body.insert(len(body.contents), elem) body.insert(len(body.contents), elem)
with open(last, 'wb') as fi: with open(last, 'wb') as fi:
fi.write(unicode(soup).encode('utf-8')) fi.write(unicode(soup).encode('utf-8'))
if len(feeds) == 0:
raise Exception('All feeds are empty, aborting.')
if len(feeds) > 1: if len(feeds) > 1:
for i, f in enumerate(feeds): for i, f in enumerate(feeds):

View File

@ -160,7 +160,7 @@ class FeedTemplate(Template):
<li id="${'article_%d'%i}" py:if="getattr(article, 'downloaded', <li id="${'article_%d'%i}" py:if="getattr(article, 'downloaded',
False)" style="padding-bottom:0.5em" class="calibre_rescale_100"> False)" style="padding-bottom:0.5em" class="calibre_rescale_100">
<a class="article calibre_rescale_120" href="${article.url}">${article.title}</a> <a class="article calibre_rescale_120" href="${article.url}">${article.title}</a>
<span class="article_date">${article.localtime.strftime(" [%a, %d %b %H:%M]")}</span> <span class="article_date">${article.formatted_date}</span>
<div class="article_description calibre_rescale_70" py:if="article.summary"> <div class="article_description calibre_rescale_70" py:if="article.summary">
${Markup(cutoff(article.text_summary))} ${Markup(cutoff(article.text_summary))}
</div> </div>