mirror of
https://github.com/gryf/ebook-converter.git
synced 2026-04-21 13:41:30 +02:00
Removed gettext related functions
This commit is contained in:
@@ -55,10 +55,10 @@ class Plugin(object):
|
||||
version = (1, 0, 0)
|
||||
|
||||
#: A short string describing what this plugin does
|
||||
description = _('Does absolutely nothing')
|
||||
description = 'Does absolutely nothing'
|
||||
|
||||
#: The author of this plugin
|
||||
author = _('Unknown')
|
||||
author = 'Unknown'
|
||||
|
||||
#: When more than one plugin exists for a filetype,
|
||||
#: the plugins are run in order of decreasing priority.
|
||||
@@ -76,7 +76,7 @@ class Plugin(object):
|
||||
|
||||
#: The type of this plugin. Used for categorizing plugins in the
|
||||
#: GUI
|
||||
type = _('Base')
|
||||
type = 'Base'
|
||||
|
||||
def __init__(self, plugin_path):
|
||||
self.plugin_path = plugin_path
|
||||
@@ -264,7 +264,7 @@ class FileTypePlugin(Plugin):
|
||||
#: on the final file produced by the conversion output plugin.
|
||||
on_postprocess = False
|
||||
|
||||
type = _('File type')
|
||||
type = 'File type'
|
||||
|
||||
def run(self, path_to_ebook):
|
||||
"""
|
||||
@@ -335,7 +335,7 @@ class MetadataReaderPlugin(Plugin):
|
||||
version = numeric_version
|
||||
author = 'Kovid Goyal'
|
||||
|
||||
type = _('Metadata reader')
|
||||
type = 'Metadata reader'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Plugin.__init__(self, *args, **kwargs)
|
||||
@@ -367,7 +367,7 @@ class MetadataWriterPlugin(Plugin):
|
||||
version = numeric_version
|
||||
author = 'Kovid Goyal'
|
||||
|
||||
type = _('Metadata writer')
|
||||
type = 'Metadata writer'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Plugin.__init__(self, *args, **kwargs)
|
||||
@@ -398,7 +398,7 @@ class CatalogPlugin(Plugin):
|
||||
#: For example: 'epub' or 'xml'
|
||||
file_types = set()
|
||||
|
||||
type = _('Catalog generator')
|
||||
type = 'Catalog generator'
|
||||
|
||||
#: CLI parser options specific to this plugin, declared as namedtuple
|
||||
#: Option:
|
||||
@@ -406,8 +406,8 @@ class CatalogPlugin(Plugin):
|
||||
#: from collections import namedtuple
|
||||
#: Option = namedtuple('Option', 'option, default, dest, help')
|
||||
#: cli_options = [Option('--catalog-title', default = 'My Catalog',
|
||||
#: dest = 'catalog_title', help = (_('Title of generated catalog. '
|
||||
#: '\nDefault:') +
|
||||
#: dest = 'catalog_title', help = ('Title of generated catalog. '
|
||||
#: '\nDefault:' +
|
||||
#: " '" + '%default' + "'"))]
|
||||
#: cli_options parsed in
|
||||
#: ebook_converter.db.cli.cmd_catalog:option_parser()
|
||||
@@ -511,7 +511,7 @@ class InterfaceActionBase(Plugin):
|
||||
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
author = 'Kovid Goyal'
|
||||
type = _('User interface action')
|
||||
type = 'User interface action'
|
||||
can_be_disabled = False
|
||||
|
||||
actual_plugin = None
|
||||
@@ -544,7 +544,7 @@ class PreferencesPlugin(Plugin):
|
||||
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
author = 'Kovid Goyal'
|
||||
type = _('Preferences')
|
||||
type = 'Preferences'
|
||||
can_be_disabled = False
|
||||
|
||||
#: Import path to module that contains a class named ConfigWidget
|
||||
@@ -596,11 +596,11 @@ class StoreBase(Plugin):
|
||||
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
author = 'John Schember'
|
||||
type = _('Store')
|
||||
type = 'Store'
|
||||
# Information about the store. Should be in the primary language
|
||||
# of the store. This should not be translatable when set by
|
||||
# a subclass.
|
||||
description = _('An e-book store.')
|
||||
description = 'An e-book store.'
|
||||
minimum_calibre_version = (0, 8, 0)
|
||||
version = (1, 0, 1)
|
||||
|
||||
@@ -643,7 +643,7 @@ class StoreBase(Plugin):
|
||||
|
||||
class EditBookToolPlugin(Plugin):
|
||||
|
||||
type = _('Edit book tool')
|
||||
type = 'Edit book tool'
|
||||
minimum_calibre_version = (1, 46, 0)
|
||||
|
||||
|
||||
@@ -653,7 +653,7 @@ class LibraryClosedPlugin(Plugin):
|
||||
when the library is changed, or when a library is used in some other way.
|
||||
At the moment these plugins won't be called by the CLI functions.
|
||||
"""
|
||||
type = _('Library closed')
|
||||
type = 'Library closed'
|
||||
|
||||
# minimum version 2.54 because that is when support was added
|
||||
minimum_calibre_version = (2, 54, 0)
|
||||
|
||||
@@ -19,7 +19,7 @@ plugins = []
|
||||
class PML2PMLZ(FileTypePlugin):
|
||||
name = 'PML to PMLZ'
|
||||
author = 'John Schember'
|
||||
description = _('Create a PMLZ archive containing the PML file '
|
||||
description = ('Create a PMLZ archive containing the PML file '
|
||||
'and all images in the directory pmlname_img or images. '
|
||||
'This plugin is run every time you add '
|
||||
'a PML file to the library.')
|
||||
@@ -50,9 +50,10 @@ class PML2PMLZ(FileTypePlugin):
|
||||
class TXT2TXTZ(FileTypePlugin):
|
||||
name = 'TXT to TXTZ'
|
||||
author = 'John Schember'
|
||||
description = _('Create a TXTZ archive when a TXT file is imported '
|
||||
'containing Markdown or Textile references to images. The referenced '
|
||||
'images as well as the TXT file are added to the archive.')
|
||||
description = ('Create a TXTZ archive when a TXT file is imported '
|
||||
'containing Markdown or Textile references to images. The '
|
||||
'referenced images as well as the TXT file are added to '
|
||||
'the archive.')
|
||||
version = numeric_version
|
||||
file_types = {'txt', 'text'}
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
@@ -133,7 +134,7 @@ class ComicMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read comic metadata'
|
||||
file_types = {'cbr', 'cbz'}
|
||||
description = _('Extract cover from comic files')
|
||||
description = 'Extract cover from comic files'
|
||||
|
||||
def customization_help(self, gui=False):
|
||||
return 'Read series number from volume or issue number. Default is volume, set this to issue to use issue number instead.'
|
||||
@@ -174,7 +175,7 @@ class CHMMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read CHM metadata'
|
||||
file_types = {'chm'}
|
||||
description = _('Read metadata from %s files') % 'CHM'
|
||||
description = 'Read metadata from CHM files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.chm.metadata import get_metadata
|
||||
@@ -185,7 +186,7 @@ class EPUBMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read EPUB metadata'
|
||||
file_types = {'epub'}
|
||||
description = _('Read metadata from %s files')%'EPUB'
|
||||
description = 'Read metadata from EPUB files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.epub import get_metadata, get_quick_metadata
|
||||
@@ -198,7 +199,7 @@ class FB2MetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read FB2 metadata'
|
||||
file_types = {'fb2', 'fbz'}
|
||||
description = _('Read metadata from %s files')%'FB2'
|
||||
description = 'Read metadata from FB2 files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.fb2 import get_metadata
|
||||
@@ -209,7 +210,7 @@ class HTMLMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read HTML metadata'
|
||||
file_types = {'html'}
|
||||
description = _('Read metadata from %s files')%'HTML'
|
||||
description = 'Read metadata from HTML files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.html import get_metadata
|
||||
@@ -220,7 +221,7 @@ class HTMLZMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read HTMLZ metadata'
|
||||
file_types = {'htmlz'}
|
||||
description = _('Read metadata from %s files') % 'HTMLZ'
|
||||
description = 'Read metadata from HTMLZ files'
|
||||
author = 'John Schember'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -232,7 +233,7 @@ class IMPMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read IMP metadata'
|
||||
file_types = {'imp'}
|
||||
description = _('Read metadata from %s files')%'IMP'
|
||||
description = 'Read metadata from IMP files'
|
||||
author = 'Ashish Kulkarni'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -244,7 +245,7 @@ class LITMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read LIT metadata'
|
||||
file_types = {'lit'}
|
||||
description = _('Read metadata from %s files')%'LIT'
|
||||
description = 'Read metadata from LIT files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.lit import get_metadata
|
||||
@@ -255,7 +256,7 @@ class LRFMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read LRF metadata'
|
||||
file_types = {'lrf'}
|
||||
description = _('Read metadata from %s files')%'LRF'
|
||||
description = 'Read metadata from LRF files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.lrf.meta import get_metadata
|
||||
@@ -266,7 +267,7 @@ class LRXMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read LRX metadata'
|
||||
file_types = {'lrx'}
|
||||
description = _('Read metadata from %s files')%'LRX'
|
||||
description = 'Read metadata from LRX files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.lrx import get_metadata
|
||||
@@ -277,7 +278,7 @@ class MOBIMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read MOBI metadata'
|
||||
file_types = {'mobi', 'prc', 'azw', 'azw3', 'azw4', 'pobi'}
|
||||
description = _('Read metadata from %s files')%'MOBI'
|
||||
description = 'Read metadata from MOBI files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.mobi import get_metadata
|
||||
@@ -288,7 +289,7 @@ class ODTMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read ODT metadata'
|
||||
file_types = {'odt'}
|
||||
description = _('Read metadata from %s files')%'ODT'
|
||||
description = 'Read metadata from ODT files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.odt import get_metadata
|
||||
@@ -299,7 +300,7 @@ class DocXMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read DOCX metadata'
|
||||
file_types = {'docx'}
|
||||
description = _('Read metadata from %s files')%'DOCX'
|
||||
description = 'Read metadata from DOCX files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.docx import get_metadata
|
||||
@@ -310,7 +311,7 @@ class OPFMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read OPF metadata'
|
||||
file_types = {'opf'}
|
||||
description = _('Read metadata from %s files')%'OPF'
|
||||
description = 'Read metadata from OPF files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.opf import get_metadata
|
||||
@@ -321,7 +322,7 @@ class PDBMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read PDB metadata'
|
||||
file_types = {'pdb', 'updb'}
|
||||
description = _('Read metadata from %s files') % 'PDB'
|
||||
description = 'Read metadata from PDB files'
|
||||
author = 'John Schember'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -333,7 +334,7 @@ class PDFMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read PDF metadata'
|
||||
file_types = {'pdf'}
|
||||
description = _('Read metadata from %s files')%'PDF'
|
||||
description = 'Read metadata from PDF files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.pdf import get_metadata, get_quick_metadata
|
||||
@@ -346,7 +347,7 @@ class PMLMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read PML metadata'
|
||||
file_types = {'pml', 'pmlz'}
|
||||
description = _('Read metadata from %s files') % 'PML'
|
||||
description = 'Read metadata from PML files'
|
||||
author = 'John Schember'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -358,7 +359,7 @@ class RARMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read RAR metadata'
|
||||
file_types = {'rar'}
|
||||
description = _('Read metadata from e-books in RAR archives')
|
||||
description = 'Read metadata from e-books in RAR archives'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.rar import get_metadata
|
||||
@@ -369,7 +370,7 @@ class RBMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read RB metadata'
|
||||
file_types = {'rb'}
|
||||
description = _('Read metadata from %s files')%'RB'
|
||||
description = 'Read metadata from RB files'
|
||||
author = 'Ashish Kulkarni'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -381,7 +382,7 @@ class RTFMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read RTF metadata'
|
||||
file_types = {'rtf'}
|
||||
description = _('Read metadata from %s files')%'RTF'
|
||||
description = 'Read metadata from RTF files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.rtf import get_metadata
|
||||
@@ -392,7 +393,7 @@ class SNBMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read SNB metadata'
|
||||
file_types = {'snb'}
|
||||
description = _('Read metadata from %s files') % 'SNB'
|
||||
description = 'Read metadata from SNB files'
|
||||
author = 'Li Fanxi'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -404,7 +405,7 @@ class TOPAZMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read Topaz metadata'
|
||||
file_types = {'tpz', 'azw1'}
|
||||
description = _('Read metadata from %s files')%'MOBI'
|
||||
description = 'Read metadata from MOBI files'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.topaz import get_metadata
|
||||
@@ -415,7 +416,7 @@ class TXTMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read TXT metadata'
|
||||
file_types = {'txt'}
|
||||
description = _('Read metadata from %s files') % 'TXT'
|
||||
description = 'Read metadata from TXT files'
|
||||
author = 'John Schember'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -427,7 +428,7 @@ class TXTZMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read TXTZ metadata'
|
||||
file_types = {'txtz'}
|
||||
description = _('Read metadata from %s files') % 'TXTZ'
|
||||
description = 'Read metadata from TXTZ files'
|
||||
author = 'John Schember'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
@@ -439,7 +440,7 @@ class ZipMetadataReader(MetadataReaderPlugin):
|
||||
|
||||
name = 'Read ZIP metadata'
|
||||
file_types = {'zip', 'oebzip'}
|
||||
description = _('Read metadata from e-books in ZIP archives')
|
||||
description = 'Read metadata from e-books in ZIP archives'
|
||||
|
||||
def get_metadata(self, stream, ftype):
|
||||
from ebook_converter.ebooks.metadata.zip import get_metadata
|
||||
@@ -458,7 +459,7 @@ class EPUBMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set EPUB metadata'
|
||||
file_types = {'epub'}
|
||||
description = _('Set metadata in %s files')%'EPUB'
|
||||
description = 'Set metadata in EPUB files'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
from ebook_converter.ebooks.metadata.epub import set_metadata
|
||||
@@ -469,15 +470,16 @@ class EPUBMetadataWriter(MetadataWriterPlugin):
|
||||
h = 'disable-add-missing-cover'
|
||||
if gui:
|
||||
h = '<i>' + h + '</i>'
|
||||
return _('Enter {0} below to have the EPUB metadata writer plugin not'
|
||||
' add cover images to EPUB files that have no existing cover image.').format(h)
|
||||
return ('Enter {0} below to have the EPUB metadata writer plugin not '
|
||||
'add cover images to EPUB files that have no existing cover '
|
||||
'image.'.format(h))
|
||||
|
||||
|
||||
class FB2MetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set FB2 metadata'
|
||||
file_types = {'fb2', 'fbz'}
|
||||
description = _('Set metadata in %s files')%'FB2'
|
||||
description = 'Set metadata in FB2 files'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
from ebook_converter.ebooks.metadata.fb2 import set_metadata
|
||||
@@ -488,7 +490,7 @@ class HTMLZMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set HTMLZ metadata'
|
||||
file_types = {'htmlz'}
|
||||
description = _('Set metadata from %s files') % 'HTMLZ'
|
||||
description = 'Set metadata from HTMLZ files'
|
||||
author = 'John Schember'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
@@ -500,7 +502,7 @@ class LRFMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set LRF metadata'
|
||||
file_types = {'lrf'}
|
||||
description = _('Set metadata in %s files')%'LRF'
|
||||
description = 'Set metadata in LRF files'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
from ebook_converter.ebooks.lrf.meta import set_metadata
|
||||
@@ -511,7 +513,7 @@ class MOBIMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set MOBI metadata'
|
||||
file_types = {'mobi', 'prc', 'azw', 'azw3', 'azw4'}
|
||||
description = _('Set metadata in %s files')%'MOBI'
|
||||
description = 'Set metadata in MOBI files'
|
||||
author = 'Marshall T. Vandegrift'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
@@ -523,7 +525,7 @@ class PDBMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set PDB metadata'
|
||||
file_types = {'pdb'}
|
||||
description = _('Set metadata from %s files') % 'PDB'
|
||||
description = 'Set metadata from PDB files'
|
||||
author = 'John Schember'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
@@ -535,7 +537,7 @@ class PDFMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set PDF metadata'
|
||||
file_types = {'pdf'}
|
||||
description = _('Set metadata in %s files') % 'PDF'
|
||||
description = 'Set metadata in PDF files'
|
||||
author = 'Kovid Goyal'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
@@ -547,7 +549,7 @@ class RTFMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set RTF metadata'
|
||||
file_types = {'rtf'}
|
||||
description = _('Set metadata in %s files')%'RTF'
|
||||
description = 'Set metadata in RTF files'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
from ebook_converter.ebooks.metadata.rtf import set_metadata
|
||||
@@ -558,7 +560,7 @@ class TOPAZMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set TOPAZ metadata'
|
||||
file_types = {'tpz', 'azw1'}
|
||||
description = _('Set metadata in %s files')%'TOPAZ'
|
||||
description = 'Set metadata in TOPAZ files'
|
||||
author = 'Greg Riker'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
@@ -570,7 +572,7 @@ class TXTZMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set TXTZ metadata'
|
||||
file_types = {'txtz'}
|
||||
description = _('Set metadata from %s files') % 'TXTZ'
|
||||
description = 'Set metadata from TXTZ files'
|
||||
author = 'John Schember'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
@@ -582,7 +584,7 @@ class ODTMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set ODT metadata'
|
||||
file_types = {'odt'}
|
||||
description = _('Set metadata from %s files')%'ODT'
|
||||
description = 'Set metadata from ODT files'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
from ebook_converter.ebooks.metadata.odt import set_metadata
|
||||
@@ -593,7 +595,7 @@ class DocXMetadataWriter(MetadataWriterPlugin):
|
||||
|
||||
name = 'Set DOCX metadata'
|
||||
file_types = {'docx'}
|
||||
description = _('Set metadata from %s files')%'DOCX'
|
||||
description = 'Set metadata from DOCX files'
|
||||
|
||||
def set_metadata(self, stream, mi, type):
|
||||
from ebook_converter.ebooks.metadata.docx import set_metadata
|
||||
@@ -828,228 +830,231 @@ plugins += input_profiles + output_profiles
|
||||
class ActionAdd(InterfaceActionBase):
|
||||
name = 'Add Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.add:AddAction'
|
||||
description = _('Add books to calibre or the connected device')
|
||||
description = 'Add books to calibre or the connected device'
|
||||
|
||||
|
||||
class ActionFetchAnnotations(InterfaceActionBase):
|
||||
name = 'Fetch Annotations'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.annotate:FetchAnnotationsAction'
|
||||
description = _('Fetch annotations from a connected Kindle (experimental)')
|
||||
description = 'Fetch annotations from a connected Kindle (experimental)'
|
||||
|
||||
|
||||
class ActionGenerateCatalog(InterfaceActionBase):
|
||||
name = 'Generate Catalog'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.catalog:GenerateCatalogAction'
|
||||
description = _('Generate a catalog of the books in your calibre library')
|
||||
description = 'Generate a catalog of the books in your calibre library'
|
||||
|
||||
|
||||
class ActionConvert(InterfaceActionBase):
|
||||
name = 'Convert Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.convert:ConvertAction'
|
||||
description = _('Convert books to various e-book formats')
|
||||
description = 'Convert books to various e-book formats'
|
||||
|
||||
|
||||
class ActionPolish(InterfaceActionBase):
|
||||
name = 'Polish Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.polish:PolishAction'
|
||||
description = _('Fine tune your e-books')
|
||||
description = 'Fine tune your e-books'
|
||||
|
||||
|
||||
class ActionEditToC(InterfaceActionBase):
|
||||
name = 'Edit ToC'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.toc_edit:ToCEditAction'
|
||||
description = _('Edit the Table of Contents in your books')
|
||||
description = 'Edit the Table of Contents in your books'
|
||||
|
||||
|
||||
class ActionDelete(InterfaceActionBase):
|
||||
name = 'Remove Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.delete:DeleteAction'
|
||||
description = _('Delete books from your calibre library or connected device')
|
||||
description = 'Delete books from your calibre library or connected device'
|
||||
|
||||
|
||||
class ActionEmbed(InterfaceActionBase):
|
||||
name = 'Embed Metadata'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.embed:EmbedAction'
|
||||
description = _('Embed updated metadata into the actual book files in your calibre library')
|
||||
description = ('Embed updated metadata into the actual book files in '
|
||||
'your calibre library')
|
||||
|
||||
|
||||
class ActionEditMetadata(InterfaceActionBase):
|
||||
name = 'Edit Metadata'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.edit_metadata:EditMetadataAction'
|
||||
description = _('Edit the metadata of books in your calibre library')
|
||||
description = 'Edit the metadata of books in your calibre library'
|
||||
|
||||
|
||||
class ActionView(InterfaceActionBase):
|
||||
name = 'View'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.view:ViewAction'
|
||||
description = _('Read books in your calibre library')
|
||||
description = 'Read books in your calibre library'
|
||||
|
||||
|
||||
class ActionFetchNews(InterfaceActionBase):
|
||||
name = 'Fetch News'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.fetch_news:FetchNewsAction'
|
||||
description = _('Download news from the internet in e-book form')
|
||||
description = 'Download news from the internet in e-book form'
|
||||
|
||||
|
||||
class ActionQuickview(InterfaceActionBase):
|
||||
name = 'Quickview'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.show_quickview:ShowQuickviewAction'
|
||||
description = _('Show a list of related books quickly')
|
||||
description = 'Show a list of related books quickly'
|
||||
|
||||
|
||||
class ActionTagMapper(InterfaceActionBase):
|
||||
name = 'Tag Mapper'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.tag_mapper:TagMapAction'
|
||||
description = _('Filter/transform the tags for books in the library')
|
||||
description = 'Filter/transform the tags for books in the library'
|
||||
|
||||
|
||||
class ActionAuthorMapper(InterfaceActionBase):
|
||||
name = 'Author Mapper'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.author_mapper:AuthorMapAction'
|
||||
description = _('Transform the authors for books in the library')
|
||||
description = 'Transform the authors for books in the library'
|
||||
|
||||
|
||||
class ActionTemplateTester(InterfaceActionBase):
|
||||
name = 'Template Tester'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.show_template_tester:ShowTemplateTesterAction'
|
||||
description = _('Show an editor for testing templates')
|
||||
description = 'Show an editor for testing templates'
|
||||
|
||||
|
||||
class ActionSaveToDisk(InterfaceActionBase):
|
||||
name = 'Save To Disk'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.save_to_disk:SaveToDiskAction'
|
||||
description = _('Export books from your calibre library to the hard disk')
|
||||
description = 'Export books from your calibre library to the hard disk'
|
||||
|
||||
|
||||
class ActionShowBookDetails(InterfaceActionBase):
|
||||
name = 'Show Book Details'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.show_book_details:ShowBookDetailsAction'
|
||||
description = _('Show Book details in a separate popup')
|
||||
description = 'Show Book details in a separate popup'
|
||||
|
||||
|
||||
class ActionRestart(InterfaceActionBase):
|
||||
name = 'Restart'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.restart:RestartAction'
|
||||
description = _('Restart calibre')
|
||||
description = 'Restart calibre'
|
||||
|
||||
|
||||
class ActionOpenFolder(InterfaceActionBase):
|
||||
name = 'Open Folder'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.open:OpenFolderAction'
|
||||
description = _('Open the folder that contains the book files in your'
|
||||
description = ('Open the folder that contains the book files in your'
|
||||
' calibre library')
|
||||
|
||||
|
||||
class ActionSendToDevice(InterfaceActionBase):
|
||||
name = 'Send To Device'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.device:SendToDeviceAction'
|
||||
description = _('Send books to the connected device')
|
||||
description = 'Send books to the connected device'
|
||||
|
||||
|
||||
class ActionConnectShare(InterfaceActionBase):
|
||||
name = 'Connect Share'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.device:ConnectShareAction'
|
||||
description = _('Send books via email or the web. Also connect to'
|
||||
description = ('Send books via email or the web. Also connect to'
|
||||
' folders on your computer as if they are devices')
|
||||
|
||||
|
||||
class ActionHelp(InterfaceActionBase):
|
||||
name = 'Help'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.help:HelpAction'
|
||||
description = _('Browse the calibre User Manual')
|
||||
description = 'Browse the calibre User Manual'
|
||||
|
||||
|
||||
class ActionPreferences(InterfaceActionBase):
|
||||
name = 'Preferences'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.preferences:PreferencesAction'
|
||||
description = _('Customize calibre')
|
||||
description = 'Customize calibre'
|
||||
|
||||
|
||||
class ActionSimilarBooks(InterfaceActionBase):
|
||||
name = 'Similar Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.similar_books:SimilarBooksAction'
|
||||
description = _('Easily find books similar to the currently selected one')
|
||||
description = 'Easily find books similar to the currently selected one'
|
||||
|
||||
|
||||
class ActionChooseLibrary(InterfaceActionBase):
|
||||
name = 'Choose Library'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.choose_library:ChooseLibraryAction'
|
||||
description = _('Switch between different calibre libraries and perform'
|
||||
' maintenance on them')
|
||||
description = ('Switch between different calibre libraries and perform '
|
||||
'maintenance on them')
|
||||
|
||||
|
||||
class ActionAddToLibrary(InterfaceActionBase):
|
||||
name = 'Add To Library'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.add_to_library:AddToLibraryAction'
|
||||
description = _('Copy books from the device to your calibre library')
|
||||
description = 'Copy books from the device to your calibre library'
|
||||
|
||||
|
||||
class ActionEditCollections(InterfaceActionBase):
|
||||
name = 'Edit Collections'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.edit_collections:EditCollectionsAction'
|
||||
description = _('Edit the collections in which books are placed on your device')
|
||||
description = ('Edit the collections in which books are placed on your '
|
||||
'device')
|
||||
|
||||
|
||||
class ActionMatchBooks(InterfaceActionBase):
|
||||
name = 'Match Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.match_books:MatchBookAction'
|
||||
description = _('Match book on the devices to books in the library')
|
||||
description = 'Match book on the devices to books in the library'
|
||||
|
||||
|
||||
class ActionCopyToLibrary(InterfaceActionBase):
|
||||
name = 'Copy To Library'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.copy_to_library:CopyToLibraryAction'
|
||||
description = _('Copy a book from one calibre library to another')
|
||||
description = 'Copy a book from one calibre library to another'
|
||||
|
||||
|
||||
class ActionTweakEpub(InterfaceActionBase):
|
||||
name = 'Tweak ePub'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.tweak_epub:TweakEpubAction'
|
||||
description = _('Edit e-books in the EPUB or AZW3 formats')
|
||||
description = 'Edit e-books in the EPUB or AZW3 formats'
|
||||
|
||||
|
||||
class ActionUnpackBook(InterfaceActionBase):
|
||||
name = 'Unpack Book'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.unpack_book:UnpackBookAction'
|
||||
description = _('Make small changes to EPUB or HTMLZ files in your calibre library')
|
||||
description = ('Make small changes to EPUB or HTMLZ files in your '
|
||||
'calibre library')
|
||||
|
||||
|
||||
class ActionNextMatch(InterfaceActionBase):
|
||||
name = 'Next Match'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.next_match:NextMatchAction'
|
||||
description = _('Find the next or previous match when searching in '
|
||||
description = ('Find the next or previous match when searching in '
|
||||
'your calibre library in highlight mode')
|
||||
|
||||
|
||||
class ActionPickRandom(InterfaceActionBase):
|
||||
name = 'Pick Random Book'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.random:PickRandomAction'
|
||||
description = _('Choose a random book from your calibre library')
|
||||
description = 'Choose a random book from your calibre library'
|
||||
|
||||
|
||||
class ActionSortBy(InterfaceActionBase):
|
||||
name = 'Sort By'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.sort:SortByAction'
|
||||
description = _('Sort the list of books')
|
||||
description = 'Sort the list of books'
|
||||
|
||||
|
||||
class ActionMarkBooks(InterfaceActionBase):
|
||||
name = 'Mark Books'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.mark_books:MarkBooksAction'
|
||||
description = _('Temporarily mark books')
|
||||
description = 'Temporarily mark books'
|
||||
|
||||
|
||||
class ActionVirtualLibrary(InterfaceActionBase):
|
||||
name = 'Virtual Library'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.virtual_library:VirtualLibraryAction'
|
||||
description = _('Change the current Virtual library')
|
||||
description = 'Change the current Virtual library'
|
||||
|
||||
|
||||
class ActionStore(InterfaceActionBase):
|
||||
name = 'Store'
|
||||
author = 'John Schember'
|
||||
actual_plugin = 'ebook_converter.gui2.actions.store:StoreAction'
|
||||
description = _('Search for books from different book sellers')
|
||||
description = 'Search for books from different book sellers'
|
||||
|
||||
def customization_help(self, gui=False):
|
||||
return 'Customize the behavior of the store search.'
|
||||
@@ -1066,7 +1071,8 @@ class ActionStore(InterfaceActionBase):
|
||||
class ActionPluginUpdater(InterfaceActionBase):
|
||||
name = 'Plugin Updater'
|
||||
author = 'Grant Drake'
|
||||
description = _('Get new ebook_converter plugins or update your existing ones')
|
||||
description = ('Get new ebook_converter plugins or update your existing '
|
||||
'ones')
|
||||
actual_plugin = 'calibre.gui2.actions.plugin_updates:PluginUpdaterAction'
|
||||
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class InputFormatPlugin(Plugin):
|
||||
The main action happens in :meth:`convert`.
|
||||
'''
|
||||
|
||||
type = _('Conversion input')
|
||||
type = 'Conversion input'
|
||||
can_be_disabled = False
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
commit_name = None # unique name under which options for this plugin are saved
|
||||
@@ -137,11 +137,11 @@ class InputFormatPlugin(Plugin):
|
||||
common_options = {
|
||||
OptionRecommendation(name='input_encoding',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the input document. If '
|
||||
help='Specify the character encoding of the input document. If '
|
||||
'set this option will override any encoding declared by the '
|
||||
'document itself. Particularly useful for documents that '
|
||||
'do not declare an encoding or that have erroneous '
|
||||
'encoding declarations.')
|
||||
'encoding declarations.'
|
||||
)}
|
||||
|
||||
#: Options to customize the behavior of this plugin. Every option must be an
|
||||
@@ -239,7 +239,7 @@ class OutputFormatPlugin(Plugin):
|
||||
The main action happens in :meth:`convert`.
|
||||
'''
|
||||
|
||||
type = _('Conversion output')
|
||||
type = 'Conversion output'
|
||||
can_be_disabled = False
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
commit_name = None # unique name under which options for this plugin are saved
|
||||
@@ -255,9 +255,9 @@ class OutputFormatPlugin(Plugin):
|
||||
common_options = {
|
||||
OptionRecommendation(name='pretty_print',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('If specified, the output plugin will try to create output '
|
||||
'that is as human readable as possible. May not have any effect '
|
||||
'for some output plugins.')
|
||||
help='If specified, the output plugin will try to create output '
|
||||
'that is as human readable as possible. May not have any '
|
||||
'effect for some output plugins.'
|
||||
)}
|
||||
|
||||
#: Options to customize the behavior of this plugin. Every option must be an
|
||||
@@ -270,7 +270,7 @@ class OutputFormatPlugin(Plugin):
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return _('Convert e-books to the %s format')%self.file_type
|
||||
return 'Convert e-books to the %s format' % self.file_type
|
||||
|
||||
def __init__(self, *args):
|
||||
Plugin.__init__(self, *args)
|
||||
|
||||
@@ -43,11 +43,11 @@ class InputProfile(Plugin):
|
||||
author = 'Kovid Goyal'
|
||||
supported_platforms = {'windows', 'osx', 'linux'}
|
||||
can_be_disabled = False
|
||||
type = _('Input profile')
|
||||
type = 'Input profile'
|
||||
|
||||
name = 'Default Input Profile'
|
||||
short_name = 'default' # Used in the CLI so dont use spaces etc. in it
|
||||
description = _('This profile tries to provide sane defaults and is useful '
|
||||
description = ('This profile tries to provide sane defaults and is useful '
|
||||
'if you know nothing about the input document.')
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class SonyReaderInput(InputProfile):
|
||||
|
||||
name = 'Sony Reader'
|
||||
short_name = 'sony'
|
||||
description = _('This profile is intended for the SONY PRS line. '
|
||||
description = ('This profile is intended for the SONY PRS line. '
|
||||
'The 500/505/600/700 etc.')
|
||||
|
||||
screen_size = (584, 754)
|
||||
@@ -68,7 +68,7 @@ class SonyReader300Input(SonyReaderInput):
|
||||
|
||||
name = 'Sony Reader 300'
|
||||
short_name = 'sony300'
|
||||
description = _('This profile is intended for the SONY PRS 300.')
|
||||
description = 'This profile is intended for the SONY PRS 300.'
|
||||
|
||||
dpi = 200
|
||||
|
||||
@@ -78,7 +78,7 @@ class SonyReader900Input(SonyReaderInput):
|
||||
author = 'John Schember'
|
||||
name = 'Sony Reader 900'
|
||||
short_name = 'sony900'
|
||||
description = _('This profile is intended for the SONY PRS-900.')
|
||||
description = 'This profile is intended for the SONY PRS-900.'
|
||||
|
||||
screen_size = (584, 978)
|
||||
|
||||
@@ -87,7 +87,7 @@ class MSReaderInput(InputProfile):
|
||||
|
||||
name = 'Microsoft Reader'
|
||||
short_name = 'msreader'
|
||||
description = _('This profile is intended for the Microsoft Reader.')
|
||||
description = 'This profile is intended for the Microsoft Reader.'
|
||||
|
||||
screen_size = (480, 652)
|
||||
dpi = 96
|
||||
@@ -99,7 +99,7 @@ class MobipocketInput(InputProfile):
|
||||
|
||||
name = 'Mobipocket Books'
|
||||
short_name = 'mobipocket'
|
||||
description = _('This profile is intended for the Mobipocket books.')
|
||||
description = 'This profile is intended for the Mobipocket books.'
|
||||
|
||||
# Unfortunately MOBI books are not narrowly targeted, so this information is
|
||||
# quite likely to be spurious
|
||||
@@ -113,7 +113,7 @@ class HanlinV3Input(InputProfile):
|
||||
|
||||
name = 'Hanlin V3'
|
||||
short_name = 'hanlinv3'
|
||||
description = _('This profile is intended for the Hanlin V3 and its clones.')
|
||||
description = 'This profile is intended for the Hanlin V3 and its clones.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (584, 754)
|
||||
@@ -126,7 +126,7 @@ class HanlinV5Input(HanlinV3Input):
|
||||
|
||||
name = 'Hanlin V5'
|
||||
short_name = 'hanlinv5'
|
||||
description = _('This profile is intended for the Hanlin V5 and its clones.')
|
||||
description = 'This profile is intended for the Hanlin V5 and its clones.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (584, 754)
|
||||
@@ -137,7 +137,7 @@ class CybookG3Input(InputProfile):
|
||||
|
||||
name = 'Cybook G3'
|
||||
short_name = 'cybookg3'
|
||||
description = _('This profile is intended for the Cybook G3.')
|
||||
description = 'This profile is intended for the Cybook G3.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (600, 800)
|
||||
@@ -151,7 +151,7 @@ class CybookOpusInput(InputProfile):
|
||||
author = 'John Schember'
|
||||
name = 'Cybook Opus'
|
||||
short_name = 'cybook_opus'
|
||||
description = _('This profile is intended for the Cybook Opus.')
|
||||
description = 'This profile is intended for the Cybook Opus.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (600, 800)
|
||||
@@ -164,7 +164,7 @@ class KindleInput(InputProfile):
|
||||
|
||||
name = 'Kindle'
|
||||
short_name = 'kindle'
|
||||
description = _('This profile is intended for the Amazon Kindle.')
|
||||
description = 'This profile is intended for the Amazon Kindle.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (525, 640)
|
||||
@@ -177,7 +177,7 @@ class IlliadInput(InputProfile):
|
||||
|
||||
name = 'Illiad'
|
||||
short_name = 'illiad'
|
||||
description = _('This profile is intended for the Irex Illiad.')
|
||||
description = 'This profile is intended for the Irex Illiad.'
|
||||
|
||||
screen_size = (760, 925)
|
||||
dpi = 160.0
|
||||
@@ -190,7 +190,7 @@ class IRexDR1000Input(InputProfile):
|
||||
author = 'John Schember'
|
||||
name = 'IRex Digital Reader 1000'
|
||||
short_name = 'irexdr1000'
|
||||
description = _('This profile is intended for the IRex Digital Reader 1000.')
|
||||
description = 'This profile is intended for the IRex Digital Reader 1000.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (1024, 1280)
|
||||
@@ -204,7 +204,7 @@ class IRexDR800Input(InputProfile):
|
||||
author = 'Eric Cronin'
|
||||
name = 'IRex Digital Reader 800'
|
||||
short_name = 'irexdr800'
|
||||
description = _('This profile is intended for the IRex Digital Reader 800.')
|
||||
description = 'This profile is intended for the IRex Digital Reader 800.'
|
||||
|
||||
screen_size = (768, 1024)
|
||||
dpi = 160
|
||||
@@ -217,7 +217,7 @@ class NookInput(InputProfile):
|
||||
author = 'John Schember'
|
||||
name = 'Nook'
|
||||
short_name = 'nook'
|
||||
description = _('This profile is intended for the B&N Nook.')
|
||||
description = 'This profile is intended for the B&N Nook.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (600, 800)
|
||||
@@ -241,13 +241,13 @@ class OutputProfile(Plugin):
|
||||
author = 'Kovid Goyal'
|
||||
supported_platforms = {'windows', 'osx', 'linux'}
|
||||
can_be_disabled = False
|
||||
type = _('Output profile')
|
||||
type = 'Output profile'
|
||||
|
||||
name = 'Default Output Profile'
|
||||
short_name = 'default' # Used in the CLI so dont use spaces etc. in it
|
||||
description = _('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.')
|
||||
description = ('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.')
|
||||
|
||||
#: The image size for comics
|
||||
comic_screen_size = (584, 754)
|
||||
@@ -282,7 +282,7 @@ class iPadOutput(OutputProfile):
|
||||
|
||||
name = 'iPad'
|
||||
short_name = 'ipad'
|
||||
description = _('Intended for the iPad and similar devices with a '
|
||||
description = ('Intended for the iPad and similar devices with a '
|
||||
'resolution of 768x1024')
|
||||
screen_size = (768, 1024)
|
||||
comic_screen_size = (768, 1024)
|
||||
@@ -445,14 +445,15 @@ class iPad3Output(iPadOutput):
|
||||
dpi = 264.0
|
||||
name = 'iPad 3'
|
||||
short_name = 'ipad3'
|
||||
description = _('Intended for the iPad 3 and similar devices with a '
|
||||
description = ('Intended for the iPad 3 and similar devices with a '
|
||||
'resolution of 1536x2048')
|
||||
|
||||
|
||||
class TabletOutput(iPadOutput):
|
||||
name = 'Tablet'
|
||||
short_name = 'tablet'
|
||||
description = _('Intended for generic tablet devices, does no resizing of images')
|
||||
description = ('Intended for generic tablet devices, does no resizing of '
|
||||
'images')
|
||||
|
||||
screen_size = (10000, 10000)
|
||||
comic_screen_size = (10000, 10000)
|
||||
@@ -461,15 +462,15 @@ class TabletOutput(iPadOutput):
|
||||
class SamsungGalaxy(TabletOutput):
|
||||
name = 'Samsung Galaxy'
|
||||
short_name = 'galaxy'
|
||||
description = _('Intended for the Samsung Galaxy and similar tablet devices with '
|
||||
'a resolution of 600x1280')
|
||||
description = ('Intended for the Samsung Galaxy and similar tablet '
|
||||
'devices with a resolution of 600x1280')
|
||||
screen_size = comic_screen_size = (600, 1280)
|
||||
|
||||
|
||||
class NookHD(TabletOutput):
|
||||
name = 'Nook HD+'
|
||||
short_name = 'nook_hd_plus'
|
||||
description = _('Intended for the Nook HD+ and similar tablet devices with '
|
||||
description = ('Intended for the Nook HD+ and similar tablet devices with '
|
||||
'a resolution of 1280x1920')
|
||||
screen_size = comic_screen_size = (1280, 1920)
|
||||
|
||||
@@ -478,7 +479,7 @@ class SonyReaderOutput(OutputProfile):
|
||||
|
||||
name = 'Sony Reader'
|
||||
short_name = 'sony'
|
||||
description = _('This profile is intended for the SONY PRS line. '
|
||||
description = ('This profile is intended for the SONY PRS line. '
|
||||
'The 500/505/600/700 etc.')
|
||||
|
||||
screen_size = (590, 775)
|
||||
@@ -496,7 +497,7 @@ class KoboReaderOutput(OutputProfile):
|
||||
name = 'Kobo Reader'
|
||||
short_name = 'kobo'
|
||||
|
||||
description = _('This profile is intended for the Kobo Reader.')
|
||||
description = 'This profile is intended for the Kobo Reader.'
|
||||
|
||||
screen_size = (536, 710)
|
||||
comic_screen_size = (536, 710)
|
||||
@@ -510,7 +511,7 @@ class SonyReader300Output(SonyReaderOutput):
|
||||
author = 'John Schember'
|
||||
name = 'Sony Reader 300'
|
||||
short_name = 'sony300'
|
||||
description = _('This profile is intended for the SONY PRS-300.')
|
||||
description = 'This profile is intended for the SONY PRS-300.'
|
||||
|
||||
dpi = 200
|
||||
|
||||
@@ -520,7 +521,7 @@ class SonyReader900Output(SonyReaderOutput):
|
||||
author = 'John Schember'
|
||||
name = 'Sony Reader 900'
|
||||
short_name = 'sony900'
|
||||
description = _('This profile is intended for the SONY PRS-900.')
|
||||
description = 'This profile is intended for the SONY PRS-900.'
|
||||
|
||||
screen_size = (600, 999)
|
||||
comic_screen_size = screen_size
|
||||
@@ -531,7 +532,7 @@ class SonyReaderT3Output(SonyReaderOutput):
|
||||
author = 'Kovid Goyal'
|
||||
name = 'Sony Reader T3'
|
||||
short_name = 'sonyt3'
|
||||
description = _('This profile is intended for the SONY PRS-T3.')
|
||||
description = 'This profile is intended for the SONY PRS-T3.'
|
||||
|
||||
screen_size = (758, 934)
|
||||
comic_screen_size = screen_size
|
||||
@@ -541,7 +542,7 @@ class GenericEink(SonyReaderOutput):
|
||||
|
||||
name = 'Generic e-ink'
|
||||
short_name = 'generic_eink'
|
||||
description = _('Suitable for use with any e-ink device')
|
||||
description = 'Suitable for use with any e-ink device'
|
||||
epub_periodical_format = None
|
||||
|
||||
|
||||
@@ -549,7 +550,7 @@ class GenericEinkLarge(GenericEink):
|
||||
|
||||
name = 'Generic e-ink large'
|
||||
short_name = 'generic_eink_large'
|
||||
description = _('Suitable for use with any large screen e-ink device')
|
||||
description = 'Suitable for use with any large screen e-ink device'
|
||||
|
||||
screen_size = (600, 999)
|
||||
comic_screen_size = screen_size
|
||||
@@ -559,7 +560,8 @@ class GenericEinkHD(GenericEink):
|
||||
|
||||
name = 'Generic e-ink HD'
|
||||
short_name = 'generic_eink_hd'
|
||||
description = _('Suitable for use with any modern high resolution e-ink device')
|
||||
description = ('Suitable for use with any modern high resolution e-ink '
|
||||
'device')
|
||||
|
||||
screen_size = (10000, 10000)
|
||||
comic_screen_size = (10000, 10000)
|
||||
@@ -569,7 +571,7 @@ class JetBook5Output(OutputProfile):
|
||||
|
||||
name = 'JetBook 5-inch'
|
||||
short_name = 'jetbook5'
|
||||
description = _('This profile is intended for the 5-inch JetBook.')
|
||||
description = 'This profile is intended for the 5-inch JetBook.'
|
||||
|
||||
screen_size = (480, 640)
|
||||
dpi = 168.451
|
||||
@@ -579,7 +581,7 @@ class SonyReaderLandscapeOutput(SonyReaderOutput):
|
||||
|
||||
name = 'Sony Reader Landscape'
|
||||
short_name = 'sony-landscape'
|
||||
description = _('This profile is intended for the SONY PRS line. '
|
||||
description = ('This profile is intended for the SONY PRS line. '
|
||||
'The 500/505/700 etc, in landscape mode. Mainly useful '
|
||||
'for comics.')
|
||||
|
||||
@@ -591,7 +593,7 @@ class MSReaderOutput(OutputProfile):
|
||||
|
||||
name = 'Microsoft Reader'
|
||||
short_name = 'msreader'
|
||||
description = _('This profile is intended for the Microsoft Reader.')
|
||||
description = 'This profile is intended for the Microsoft Reader.'
|
||||
|
||||
screen_size = (480, 652)
|
||||
dpi = 96
|
||||
@@ -603,7 +605,7 @@ class MobipocketOutput(OutputProfile):
|
||||
|
||||
name = 'Mobipocket Books'
|
||||
short_name = 'mobipocket'
|
||||
description = _('This profile is intended for the Mobipocket books.')
|
||||
description = 'This profile is intended for the Mobipocket books.'
|
||||
|
||||
# Unfortunately MOBI books are not narrowly targeted, so this information is
|
||||
# quite likely to be spurious
|
||||
@@ -617,7 +619,7 @@ class HanlinV3Output(OutputProfile):
|
||||
|
||||
name = 'Hanlin V3'
|
||||
short_name = 'hanlinv3'
|
||||
description = _('This profile is intended for the Hanlin V3 and its clones.')
|
||||
description = 'This profile is intended for the Hanlin V3 and its clones.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (584, 754)
|
||||
@@ -630,7 +632,7 @@ class HanlinV5Output(HanlinV3Output):
|
||||
|
||||
name = 'Hanlin V5'
|
||||
short_name = 'hanlinv5'
|
||||
description = _('This profile is intended for the Hanlin V5 and its clones.')
|
||||
description = 'This profile is intended for the Hanlin V5 and its clones.'
|
||||
|
||||
dpi = 200
|
||||
|
||||
@@ -639,7 +641,7 @@ class CybookG3Output(OutputProfile):
|
||||
|
||||
name = 'Cybook G3'
|
||||
short_name = 'cybookg3'
|
||||
description = _('This profile is intended for the Cybook G3.')
|
||||
description = 'This profile is intended for the Cybook G3.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (600, 800)
|
||||
@@ -654,7 +656,7 @@ class CybookOpusOutput(SonyReaderOutput):
|
||||
author = 'John Schember'
|
||||
name = 'Cybook Opus'
|
||||
short_name = 'cybook_opus'
|
||||
description = _('This profile is intended for the Cybook Opus.')
|
||||
description = 'This profile is intended for the Cybook Opus.'
|
||||
|
||||
# Screen size is a best guess
|
||||
dpi = 200
|
||||
@@ -668,7 +670,7 @@ class KindleOutput(OutputProfile):
|
||||
|
||||
name = 'Kindle'
|
||||
short_name = 'kindle'
|
||||
description = _('This profile is intended for the Amazon Kindle.')
|
||||
description = 'This profile is intended for the Amazon Kindle.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (525, 640)
|
||||
@@ -688,7 +690,7 @@ class KindleDXOutput(OutputProfile):
|
||||
|
||||
name = 'Kindle DX'
|
||||
short_name = 'kindle_dx'
|
||||
description = _('This profile is intended for the Amazon Kindle DX.')
|
||||
description = 'This profile is intended for the Amazon Kindle DX.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (744, 1022)
|
||||
@@ -706,7 +708,8 @@ class KindlePaperWhiteOutput(KindleOutput):
|
||||
|
||||
name = 'Kindle PaperWhite'
|
||||
short_name = 'kindle_pw'
|
||||
description = _('This profile is intended for the Amazon Kindle PaperWhite 1 and 2')
|
||||
description = ('This profile is intended for the Amazon Kindle '
|
||||
'PaperWhite 1 and 2')
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (658, 940)
|
||||
@@ -718,7 +721,7 @@ class KindleVoyageOutput(KindleOutput):
|
||||
|
||||
name = 'Kindle Voyage'
|
||||
short_name = 'kindle_voyage'
|
||||
description = _('This profile is intended for the Amazon Kindle Voyage')
|
||||
description = 'This profile is intended for the Amazon Kindle Voyage'
|
||||
|
||||
# Screen size is currently just the spec size, actual renderable area will
|
||||
# depend on someone with the device doing tests.
|
||||
@@ -731,7 +734,8 @@ class KindlePaperWhite3Output(KindleVoyageOutput):
|
||||
|
||||
name = 'Kindle PaperWhite 3'
|
||||
short_name = 'kindle_pw3'
|
||||
description = _('This profile is intended for the Amazon Kindle PaperWhite 3 and above')
|
||||
description = ('This profile is intended for the Amazon Kindle '
|
||||
'PaperWhite 3 and above')
|
||||
# Screen size is currently just the spec size, actual renderable area will
|
||||
# depend on someone with the device doing tests.
|
||||
screen_size = (1072, 1430)
|
||||
@@ -743,7 +747,8 @@ class KindleOasisOutput(KindlePaperWhite3Output):
|
||||
|
||||
name = 'Kindle Oasis'
|
||||
short_name = 'kindle_oasis'
|
||||
description = _('This profile is intended for the Amazon Kindle Oasis 2017 and above')
|
||||
description = ('This profile is intended for the Amazon Kindle Oasis '
|
||||
'2017 and above')
|
||||
# Screen size is currently just the spec size, actual renderable area will
|
||||
# depend on someone with the device doing tests.
|
||||
screen_size = (1264, 1680)
|
||||
@@ -755,7 +760,7 @@ class KindleFireOutput(KindleDXOutput):
|
||||
|
||||
name = 'Kindle Fire'
|
||||
short_name = 'kindle_fire'
|
||||
description = _('This profile is intended for the Amazon Kindle Fire.')
|
||||
description = 'This profile is intended for the Amazon Kindle Fire.'
|
||||
|
||||
screen_size = (570, 1016)
|
||||
dpi = 169.0
|
||||
@@ -766,7 +771,7 @@ class IlliadOutput(OutputProfile):
|
||||
|
||||
name = 'Illiad'
|
||||
short_name = 'illiad'
|
||||
description = _('This profile is intended for the Irex Illiad.')
|
||||
description = 'This profile is intended for the Irex Illiad.'
|
||||
|
||||
screen_size = (760, 925)
|
||||
comic_screen_size = (760, 925)
|
||||
@@ -780,7 +785,7 @@ class IRexDR1000Output(OutputProfile):
|
||||
author = 'John Schember'
|
||||
name = 'IRex Digital Reader 1000'
|
||||
short_name = 'irexdr1000'
|
||||
description = _('This profile is intended for the IRex Digital Reader 1000.')
|
||||
description = 'This profile is intended for the IRex Digital Reader 1000.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (1024, 1280)
|
||||
@@ -795,7 +800,7 @@ class IRexDR800Output(OutputProfile):
|
||||
author = 'Eric Cronin'
|
||||
name = 'IRex Digital Reader 800'
|
||||
short_name = 'irexdr800'
|
||||
description = _('This profile is intended for the IRex Digital Reader 800.')
|
||||
description = 'This profile is intended for the IRex Digital Reader 800.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (768, 1024)
|
||||
@@ -810,7 +815,7 @@ class NookOutput(OutputProfile):
|
||||
author = 'John Schember'
|
||||
name = 'Nook'
|
||||
short_name = 'nook'
|
||||
description = _('This profile is intended for the B&N Nook.')
|
||||
description = 'This profile is intended for the B&N Nook.'
|
||||
|
||||
# Screen size is a best guess
|
||||
screen_size = (600, 730)
|
||||
@@ -823,7 +828,7 @@ class NookOutput(OutputProfile):
|
||||
class NookColorOutput(NookOutput):
|
||||
name = 'Nook Color'
|
||||
short_name = 'nook_color'
|
||||
description = _('This profile is intended for the B&N Nook Color.')
|
||||
description = 'This profile is intended for the B&N Nook Color.'
|
||||
|
||||
screen_size = (600, 900)
|
||||
comic_screen_size = (594, 900)
|
||||
@@ -835,7 +840,8 @@ class PocketBook900Output(OutputProfile):
|
||||
author = 'Chris Lockfort'
|
||||
name = 'PocketBook Pro 900'
|
||||
short_name = 'pocketbook_900'
|
||||
description = _('This profile is intended for the PocketBook Pro 900 series of devices.')
|
||||
description = ('This profile is intended for the PocketBook Pro 900 '
|
||||
'series of devices.')
|
||||
|
||||
screen_size = (810, 1180)
|
||||
dpi = 150.0
|
||||
@@ -847,7 +853,8 @@ class PocketBookPro912Output(OutputProfile):
|
||||
author = 'Daniele Pizzolli'
|
||||
name = 'PocketBook Pro 912'
|
||||
short_name = 'pocketbook_pro_912'
|
||||
description = _('This profile is intended for the PocketBook Pro 912 series of devices.')
|
||||
description = ('This profile is intended for the PocketBook Pro 912 '
|
||||
'series of devices.')
|
||||
|
||||
# According to http://download.pocketbook-int.com/user-guides/E_Ink/912/User_Guide_PocketBook_912(EN).pdf
|
||||
screen_size = (825, 1200)
|
||||
|
||||
@@ -12,7 +12,6 @@ from ebook_converter.customize import profiles
|
||||
from ebook_converter.customize import builtins
|
||||
from ebook_converter.ebooks import metadata
|
||||
from ebook_converter.utils import config as cfg
|
||||
from ebook_converter import constants
|
||||
|
||||
|
||||
builtin_names = frozenset(p.name for p in builtins.plugins)
|
||||
@@ -25,13 +24,13 @@ class NameConflict(ValueError):
|
||||
|
||||
def _config():
|
||||
c = cfg.Config('customize')
|
||||
c.add_opt('plugins', default={}, help=_('Installed plugins'))
|
||||
c.add_opt('plugins', default={}, help='Installed plugins')
|
||||
c.add_opt('filetype_mapping', default={},
|
||||
help=_('Mapping for filetype plugins'))
|
||||
help='Mapping for filetype plugins')
|
||||
c.add_opt('plugin_customization', default={},
|
||||
help=_('Local plugin customization'))
|
||||
c.add_opt('disabled_plugins', default=set(), help=_('Disabled plugins'))
|
||||
c.add_opt('enabled_plugins', default=set(), help=_('Enabled plugins'))
|
||||
help='Local plugin customization')
|
||||
c.add_opt('disabled_plugins', default=set(), help='Disabled plugins')
|
||||
c.add_opt('enabled_plugins', default=set(), help='Enabled plugins')
|
||||
|
||||
return cfg.ConfigProxy(c)
|
||||
|
||||
@@ -459,8 +458,8 @@ def initialize_plugin(plugin, path_to_zip_file):
|
||||
except Exception:
|
||||
print('Failed to initialize plugin:', plugin.name, plugin.version)
|
||||
tb = traceback.format_exc()
|
||||
raise customize.InvalidPlugin((_('Initialization of plugin %s failed '
|
||||
'with traceback:') % tb) + '\n'+tb)
|
||||
raise customize.InvalidPlugin(('Initialization of plugin %s failed '
|
||||
'with traceback:' % tb) + '\n'+tb)
|
||||
|
||||
|
||||
def has_external_plugins():
|
||||
@@ -501,25 +500,29 @@ def initialized_plugins():
|
||||
# CLI
|
||||
|
||||
def option_parser():
|
||||
parser = cfg.OptionParser(usage=_('''\
|
||||
parser = cfg.OptionParser(usage='''\
|
||||
%prog options
|
||||
|
||||
Customize calibre by loading external plugins.
|
||||
'''))
|
||||
''')
|
||||
parser.add_option('-a', '--add-plugin', default=None,
|
||||
help=_('Add a plugin by specifying the path to the ZIP file containing it.'))
|
||||
help='Add a plugin by specifying the path to the ZIP '
|
||||
'file containing it.')
|
||||
parser.add_option('-b', '--build-plugin', default=None,
|
||||
help=_('For plugin developers: Path to the directory where you are'
|
||||
' developing the plugin. This command will automatically zip '
|
||||
'up the plugin and update it in calibre.'))
|
||||
help='For plugin developers: Path to the directory '
|
||||
'where you are developing the plugin. This command will '
|
||||
'automatically zip up the plugin and update it in '
|
||||
'calibre.')
|
||||
parser.add_option('-r', '--remove-plugin', default=None,
|
||||
help=_('Remove a custom plugin by name. Has no effect on builtin plugins'))
|
||||
help='Remove a custom plugin by name. Has no effect on '
|
||||
'builtin plugins')
|
||||
parser.add_option('--customize-plugin', default=None,
|
||||
help=_('Customize plugin. Specify name of plugin and customization string separated by a comma.'))
|
||||
parser.add_option('-l', '--list-plugins', default=False, action='store_true',
|
||||
help=_('List all installed plugins'))
|
||||
help='Customize plugin. Specify name of plugin and '
|
||||
'customization string separated by a comma.')
|
||||
parser.add_option('-l', '--list-plugins', default=False,
|
||||
action='store_true', help='List all installed plugins')
|
||||
parser.add_option('--enable-plugin', default=None,
|
||||
help=_('Enable the named plugin'))
|
||||
help='Enable the named plugin')
|
||||
parser.add_option('--disable-plugin', default=None,
|
||||
help=_('Disable the named plugin'))
|
||||
help='Disable the named plugin')
|
||||
return parser
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
"""
|
||||
PEP 302 based plugin loading mechanism, works around the bug in zipimport in
|
||||
python 2.x that prevents importing from zip files in locations whose paths
|
||||
have non ASCII characters
|
||||
"""
|
||||
import os, zipfile, posixpath, importlib, threading, re, imp, sys
|
||||
from collections import OrderedDict
|
||||
from functools import partial
|
||||
|
||||
from ebook_converter import as_unicode
|
||||
from ebook_converter.customize import (Plugin, numeric_version, platform,
|
||||
InvalidPlugin, PluginNotFound)
|
||||
from ebook_converter.polyglot.builtins import reload
|
||||
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
def get_resources(zfp, name_or_list_of_names):
|
||||
'''
|
||||
Load resources from the plugin zip file
|
||||
|
||||
:param name_or_list_of_names: List of paths to resources in the zip file using / as
|
||||
separator, or a single path
|
||||
|
||||
:return: A dictionary of the form ``{name : file_contents}``. Any names
|
||||
that were not found in the zip file will not be present in the
|
||||
dictionary. If a single path is passed in the return value will
|
||||
be just the bytes of the resource or None if it wasn't found.
|
||||
'''
|
||||
names = name_or_list_of_names
|
||||
if isinstance(names, (str, bytes)):
|
||||
names = [names]
|
||||
ans = {}
|
||||
with zipfile.ZipFile(zfp) as zf:
|
||||
for name in names:
|
||||
try:
|
||||
ans[name] = zf.read(name)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
if len(names) == 1:
|
||||
ans = ans.pop(names[0], None)
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def get_icons(zfp, name_or_list_of_names):
|
||||
'''
|
||||
Load icons from the plugin zip file
|
||||
|
||||
:param name_or_list_of_names: List of paths to resources in the zip file using / as
|
||||
separator, or a single path
|
||||
|
||||
:return: A dictionary of the form ``{name : QIcon}``. Any names
|
||||
that were not found in the zip file will be null QIcons.
|
||||
If a single path is passed in the return value will
|
||||
be A QIcon.
|
||||
'''
|
||||
from PyQt5.Qt import QIcon, QPixmap
|
||||
names = name_or_list_of_names
|
||||
ans = get_resources(zfp, names)
|
||||
if isinstance(names, (str, bytes)):
|
||||
names = [names]
|
||||
if ans is None:
|
||||
ans = {}
|
||||
if isinstance(ans, (str, bytes)):
|
||||
ans = dict([(names[0], ans)])
|
||||
|
||||
ians = {}
|
||||
for name in names:
|
||||
p = QPixmap()
|
||||
raw = ans.get(name, None)
|
||||
if raw:
|
||||
p.loadFromData(raw)
|
||||
ians[name] = QIcon(p)
|
||||
if len(names) == 1:
|
||||
ians = ians.pop(names[0])
|
||||
return ians
|
||||
|
||||
|
||||
_translations_cache = {}
|
||||
|
||||
|
||||
def load_translations(namespace, zfp):
|
||||
null = object()
|
||||
trans = _translations_cache.get(zfp, null)
|
||||
if trans is None:
|
||||
return
|
||||
if trans is null:
|
||||
from ebook_converter.utils.localization import get_lang
|
||||
lang = get_lang()
|
||||
if not lang or lang == 'en': # performance optimization
|
||||
_translations_cache[zfp] = None
|
||||
return
|
||||
with zipfile.ZipFile(zfp) as zf:
|
||||
try:
|
||||
mo = zf.read('translations/%s.mo' % lang)
|
||||
except KeyError:
|
||||
mo = None # No translations for this language present
|
||||
if mo is None:
|
||||
_translations_cache[zfp] = None
|
||||
return
|
||||
from gettext import GNUTranslations
|
||||
from io import BytesIO
|
||||
trans = _translations_cache[zfp] = GNUTranslations(BytesIO(mo))
|
||||
|
||||
namespace['_'] = getattr(trans, 'gettext')
|
||||
namespace['ngettext'] = getattr(trans, 'ngettext')
|
||||
@@ -15,7 +15,7 @@ class DevicePlugin(Plugin):
|
||||
Defines the interface that should be implemented by backends that
|
||||
communicate with an e-book reader.
|
||||
"""
|
||||
type = _('Device interface')
|
||||
type = 'Device interface'
|
||||
|
||||
#: Ordered list of supported formats
|
||||
FORMATS = ["lrf", "rtf", "pdf", "txt"]
|
||||
@@ -60,7 +60,7 @@ class DevicePlugin(Plugin):
|
||||
|
||||
# Set this to None if the books on the device are files that the GUI can
|
||||
# access in order to add the books from the device to the library
|
||||
BACKLOADING_ERROR_MESSAGE = _('Cannot get files from this device')
|
||||
BACKLOADING_ERROR_MESSAGE = 'Cannot get files from this device'
|
||||
|
||||
#: Path separator for paths to books on device
|
||||
path_sep = os.sep
|
||||
|
||||
@@ -14,7 +14,7 @@ from ebook_converter import patheq
|
||||
from ebook_converter.utils.localization import localize_user_manual_link
|
||||
|
||||
|
||||
USAGE = '%prog ' + _('''\
|
||||
USAGE = '%prog ' + '''\
|
||||
input_file output_file [options]
|
||||
|
||||
Convert an e-book from one format to another.
|
||||
@@ -38,7 +38,8 @@ To get help on them specify the input and output file and then use the -h \
|
||||
option.
|
||||
|
||||
For full documentation of the conversion system see
|
||||
''') + localize_user_manual_link('https://manual.calibre-ebook.com/conversion.html')
|
||||
https://manual.calibre-ebook.com/conversion.html
|
||||
'''
|
||||
|
||||
HEURISTIC_OPTIONS = ['markup_chapter_headings',
|
||||
'italicize_common_cases', 'fix_indents',
|
||||
@@ -98,21 +99,20 @@ def option_recommendation_to_cli_option(add_option, rec):
|
||||
if opt.name == 'read_metadata_from_opf':
|
||||
switches.append('--from-opf')
|
||||
if opt.name == 'transform_css_rules':
|
||||
attrs['help'] = _(
|
||||
'Path to a file containing rules to transform the CSS styles'
|
||||
' in this book. The easiest way to create such a file is to'
|
||||
' use the wizard for creating rules in the calibre GUI. Access'
|
||||
' it in the "Look & feel->Transform styles" section of the conversion'
|
||||
' dialog. Once you create the rules, you can use the "Export" button'
|
||||
' to save them to a file.'
|
||||
)
|
||||
attrs['help'] = ('Path to a file containing rules to transform the '
|
||||
'CSS styles in this book. The easiest way to create '
|
||||
'such a file is to use the wizard for creating rules '
|
||||
'in the calibre GUI. Access it in the "Look & '
|
||||
'feel->Transform styles" section of the conversion '
|
||||
'dialog. Once you create the rules, you can use the '
|
||||
'"Export" button to save them to a file.')
|
||||
if opt.name in DEFAULT_TRUE_OPTIONS and rec.recommended_value is True:
|
||||
switches = ['--disable-'+opt.long_switch]
|
||||
add_option(optparse.Option(*switches, **attrs))
|
||||
|
||||
|
||||
def group_titles():
|
||||
return _('INPUT OPTIONS'), _('OUTPUT OPTIONS')
|
||||
return 'INPUT OPTIONS', 'OUTPUT OPTIONS'
|
||||
|
||||
|
||||
def recipe_test(option, opt_str, value, parser):
|
||||
@@ -160,15 +160,17 @@ def add_input_output_options(parser, plumber):
|
||||
|
||||
if input_options:
|
||||
title = group_titles()[0]
|
||||
io = optparse.OptionGroup(parser, title, _('Options to control the processing'
|
||||
' of the input %s file')%plumber.input_fmt)
|
||||
io = optparse.OptionGroup(parser, title, 'Options to control the '
|
||||
'processing of the input %s file' %
|
||||
plumber.input_fmt)
|
||||
add_options(io.add_option, input_options)
|
||||
parser.add_option_group(io)
|
||||
|
||||
if output_options:
|
||||
title = group_titles()[1]
|
||||
oo = optparse.OptionGroup(parser, title, _('Options to control the processing'
|
||||
' of the output %s')%plumber.output_fmt)
|
||||
oo = optparse.OptionGroup(parser, title, 'Options to control the '
|
||||
'processing of the output %s' %
|
||||
plumber.output_fmt)
|
||||
add_options(oo.add_option, output_options)
|
||||
parser.add_option_group(oo)
|
||||
|
||||
@@ -181,8 +183,8 @@ def add_pipeline_options(parser, plumber):
|
||||
'output_profile',
|
||||
]
|
||||
)),
|
||||
(_('LOOK AND FEEL') , (
|
||||
_('Options to control the look and feel of the output'),
|
||||
('LOOK AND FEEL' , (
|
||||
'Options to control the look and feel of the output',
|
||||
[
|
||||
'base_font_size', 'disable_font_rescaling',
|
||||
'font_size_mapping', 'embed_font_family',
|
||||
@@ -200,26 +202,23 @@ def add_pipeline_options(parser, plumber):
|
||||
]
|
||||
)),
|
||||
|
||||
(_('HEURISTIC PROCESSING') , (
|
||||
_('Modify the document text and structure using common'
|
||||
' patterns. Disabled by default. Use %(en)s to enable. '
|
||||
' Individual actions can be disabled with the %(dis)s options.')
|
||||
% dict(en='--enable-heuristics', dis='--disable-*'),
|
||||
('HEURISTIC PROCESSING' ,
|
||||
('Modify the document text and structure using common '
|
||||
'patterns. Disabled by default. Use %(en)s to enable. '
|
||||
'Individual actions can be disabled with the %(dis)s '
|
||||
'options.' % dict(en='--enable-heuristics', dis='--disable-*'),
|
||||
['enable_heuristics'] + HEURISTIC_OPTIONS
|
||||
)),
|
||||
|
||||
(_('SEARCH AND REPLACE') , (
|
||||
_('Modify the document text and structure using user defined patterns.'),
|
||||
[
|
||||
'sr1_search', 'sr1_replace',
|
||||
'sr2_search', 'sr2_replace',
|
||||
'sr3_search', 'sr3_replace',
|
||||
'search_replace',
|
||||
]
|
||||
('SEARCH AND REPLACE' ,
|
||||
('Modify the document text and structure using user defined '
|
||||
'patterns.',
|
||||
['sr1_search', 'sr1_replace', 'sr2_search', 'sr2_replace',
|
||||
'sr3_search', 'sr3_replace', 'search_replace']
|
||||
)),
|
||||
|
||||
(_('STRUCTURE DETECTION') , (
|
||||
_('Control auto-detection of document structure.'),
|
||||
('STRUCTURE DETECTION' , (
|
||||
'Control auto-detection of document structure.',
|
||||
[
|
||||
'chapter', 'chapter_mark',
|
||||
'prefer_metadata_cover', 'remove_first_image',
|
||||
@@ -228,21 +227,20 @@ def add_pipeline_options(parser, plumber):
|
||||
]
|
||||
)),
|
||||
|
||||
(_('TABLE OF CONTENTS') , (
|
||||
_('Control the automatic generation of a Table of Contents. By '
|
||||
('TABLE OF CONTENTS' ,
|
||||
('Control the automatic generation of a Table of Contents. By '
|
||||
'default, if the source file has a Table of Contents, it will '
|
||||
'be used in preference to the automatically generated one.'),
|
||||
[
|
||||
'level1_toc', 'level2_toc', 'level3_toc',
|
||||
'toc_threshold', 'max_toc_links', 'no_chapters_in_toc',
|
||||
'use_auto_toc', 'toc_filter', 'duplicate_links_in_toc',
|
||||
]
|
||||
)),
|
||||
'be used in preference to the automatically generated one.',
|
||||
['level1_toc', 'level2_toc', 'level3_toc', 'toc_threshold',
|
||||
'max_toc_links', 'no_chapters_in_toc', 'use_auto_toc',
|
||||
'toc_filter', 'duplicate_links_in_toc']
|
||||
)
|
||||
),
|
||||
|
||||
(_('METADATA') , (_('Options to set metadata in the output'),
|
||||
('METADATA' , ('Options to set metadata in the output',
|
||||
plumber.metadata_option_names + ['read_metadata_from_opf'],
|
||||
)),
|
||||
(_('DEBUG'), (_('Options to help with debugging the conversion'),
|
||||
('DEBUG', ('Options to help with debugging the conversion',
|
||||
[
|
||||
'verbose',
|
||||
'debug_pipeline',
|
||||
@@ -265,9 +263,9 @@ def add_pipeline_options(parser, plumber):
|
||||
def option_parser():
|
||||
parser = OptionParser(usage=USAGE)
|
||||
parser.add_option('--list-recipes', default=False, action='store_true',
|
||||
help=_('List builtin recipe names. You can create an e-book from '
|
||||
'a builtin recipe like this: ebook-convert "Recipe Name.recipe" '
|
||||
'output.epub'))
|
||||
help='List builtin recipe names. You can create an e-book from '
|
||||
'a builtin recipe like this: ebook-convert "Recipe '
|
||||
'Name.recipe" output.epub')
|
||||
return parser
|
||||
|
||||
|
||||
@@ -393,20 +391,20 @@ def main(args=sys.argv):
|
||||
|
||||
plumber.run()
|
||||
|
||||
log(_('Output saved to'), ' ', plumber.output)
|
||||
log('Output saved to', ' ', plumber.output)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def manual_index_strings():
|
||||
return _('''\
|
||||
return '''\
|
||||
The options and default values for the options change depending on both the
|
||||
input and output formats, so you should always check with::
|
||||
|
||||
%s
|
||||
|
||||
Below are the options that are common to all conversion, followed by the
|
||||
options specific to every input and output format.''')
|
||||
options specific to every input and output format.'''
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -191,7 +191,7 @@ class CHMInput(InputFormatPlugin):
|
||||
title = param.attrib['value']
|
||||
elif match_string(param.attrib['name'], 'local'):
|
||||
href = param.attrib['value']
|
||||
child = toc.add(title or _('Unknown'), href)
|
||||
child = toc.add(title or 'Unknown', href)
|
||||
ancestor_map[node] = child
|
||||
|
||||
def _process_nodes(self, root):
|
||||
|
||||
@@ -25,51 +25,54 @@ class ComicInput(InputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='colors', recommended_value=0,
|
||||
help=_('Reduce the number of colors used in the image. This works only'
|
||||
' if you choose the PNG output format. It is useful to reduce file sizes.'
|
||||
' Set to zero to turn off. Maximum value is 256. It is off by default.')),
|
||||
help='Reduce the number of colors used in the image. This works '
|
||||
'only if you choose the PNG output format. It is useful to '
|
||||
'reduce file sizes. Set to zero to turn off. Maximum value '
|
||||
'is 256. It is off by default.'),
|
||||
OptionRecommendation(name='dont_normalize', recommended_value=False,
|
||||
help=_('Disable normalize (improve contrast) color range '
|
||||
'for pictures. Default: False')),
|
||||
help='Disable normalize (improve contrast) color range '
|
||||
'for pictures. Default: False'),
|
||||
OptionRecommendation(name='keep_aspect_ratio', recommended_value=False,
|
||||
help=_('Maintain picture aspect ratio. Default is to fill the screen.')),
|
||||
help='Maintain picture aspect ratio. Default is to fill the '
|
||||
'screen.'),
|
||||
OptionRecommendation(name='dont_sharpen', recommended_value=False,
|
||||
help=_('Disable sharpening.')),
|
||||
help='Disable sharpening.'),
|
||||
OptionRecommendation(name='disable_trim', recommended_value=False,
|
||||
help=_('Disable trimming of comic pages. For some comics, '
|
||||
'trimming might remove content as well as borders.')),
|
||||
help='Disable trimming of comic pages. For some comics, trimming '
|
||||
'might remove content as well as borders.'),
|
||||
OptionRecommendation(name='landscape', recommended_value=False,
|
||||
help=_("Don't split landscape images into two portrait images")),
|
||||
help="Don't split landscape images into two portrait images"),
|
||||
OptionRecommendation(name='wide', recommended_value=False,
|
||||
help=_("Keep aspect ratio and scale image using screen height as "
|
||||
"image width for viewing in landscape mode.")),
|
||||
help="Keep aspect ratio and scale image using screen height as "
|
||||
"image width for viewing in landscape mode."),
|
||||
OptionRecommendation(name='right2left', recommended_value=False,
|
||||
help=_('Used for right-to-left publications like manga. '
|
||||
help='Used for right-to-left publications like manga. '
|
||||
'Causes landscape pages to be split into portrait pages '
|
||||
'from right to left.')),
|
||||
'from right to left.'),
|
||||
OptionRecommendation(name='despeckle', recommended_value=False,
|
||||
help=_('Enable Despeckle. Reduces speckle noise. '
|
||||
'May greatly increase processing time.')),
|
||||
help='Enable Despeckle. Reduces speckle noise. May greatly '
|
||||
'increase processing time.'),
|
||||
OptionRecommendation(name='no_sort', recommended_value=False,
|
||||
help=_("Don't sort the files found in the comic "
|
||||
help="Don't sort the files found in the comic "
|
||||
"alphabetically by name. Instead use the order they were "
|
||||
"added to the comic.")),
|
||||
"added to the comic."),
|
||||
OptionRecommendation(name='output_format', choices=['png', 'jpg'],
|
||||
recommended_value='png', help=_('The format that images in the created e-book '
|
||||
'are converted to. You can experiment to see which format gives '
|
||||
'you optimal size and look on your device.')),
|
||||
recommended_value='png',
|
||||
help='The format that images in the created e-book are '
|
||||
'converted to. You can experiment to see which format '
|
||||
'gives you optimal size and look on your device.'),
|
||||
OptionRecommendation(name='no_process', recommended_value=False,
|
||||
help=_("Apply no processing to the image")),
|
||||
help="Apply no processing to the image"),
|
||||
OptionRecommendation(name='dont_grayscale', recommended_value=False,
|
||||
help=_('Do not convert the image to grayscale (black and white)')),
|
||||
help='Do not convert the image to grayscale (black and white)'),
|
||||
OptionRecommendation(name='comic_image_size', recommended_value=None,
|
||||
help=_('Specify the image size as widthxheight pixels. Normally,'
|
||||
help='Specify the image size as widthxheight pixels. Normally,'
|
||||
' an image size is automatically calculated from the output '
|
||||
'profile, this option overrides it.')),
|
||||
'profile, this option overrides it.'),
|
||||
OptionRecommendation(name='dont_add_comic_pages_to_toc', recommended_value=False,
|
||||
help=_('When converting a CBC do not add links to each page to'
|
||||
' the TOC. Note this only applies if the TOC has more than one'
|
||||
' section')),
|
||||
help='When converting a CBC do not add links to each page to'
|
||||
' the TOC. Note this only applies if the TOC has more than '
|
||||
'one section'),
|
||||
}
|
||||
|
||||
recommendations = {
|
||||
@@ -192,7 +195,7 @@ class ComicInput(InputFormatPlugin):
|
||||
raise ValueError('No comic pages found in %s'%stream.name)
|
||||
|
||||
mi = MetaInformation(os.path.basename(stream.name).rpartition('.')[0],
|
||||
[_('Unknown')])
|
||||
['Unknown'])
|
||||
opf = OPFCreator(os.getcwd(), mi)
|
||||
entries = []
|
||||
|
||||
@@ -222,7 +225,7 @@ class ComicInput(InputFormatPlugin):
|
||||
if len(comics) == 1:
|
||||
wrappers = comics[0][2]
|
||||
for i, x in enumerate(wrappers):
|
||||
toc.add_item(href(x), None, _('Page')+' %d'%(i+1),
|
||||
toc.add_item(href(x), None, 'Page %d' % (i+1),
|
||||
play_order=i)
|
||||
else:
|
||||
po = 0
|
||||
@@ -234,7 +237,7 @@ class ComicInput(InputFormatPlugin):
|
||||
if not opts.dont_add_comic_pages_to_toc:
|
||||
for i, x in enumerate(wrappers):
|
||||
stoc.add_item(href(x), None,
|
||||
_('Page')+' %d'%(i+1), play_order=po)
|
||||
'Page %d' % (i+1), play_order=po)
|
||||
po += 1
|
||||
opf.set_toc(toc)
|
||||
with open('metadata.opf', 'wb') as m, open('toc.ncx', 'wb') as n:
|
||||
|
||||
@@ -8,19 +8,21 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
class DOCXInput(InputFormatPlugin):
|
||||
name = 'DOCX Input'
|
||||
author = 'Kovid Goyal'
|
||||
description = _('Convert DOCX files (.docx and .docm) to HTML')
|
||||
description = 'Convert DOCX files (.docx and .docm) to HTML'
|
||||
file_types = {'docx', 'docm'}
|
||||
commit_name = 'docx_input'
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='docx_no_cover', recommended_value=False,
|
||||
help=_('Normally, if a large image is present at the start of the document that looks like a cover, '
|
||||
'it will be removed from the document and used as the cover for created e-book. This option '
|
||||
'turns off that behavior.')),
|
||||
help='Normally, if a large image is present at the start of the '
|
||||
'document that looks like a cover, it will be removed from '
|
||||
'the document and used as the cover for created e-book. This '
|
||||
'option turns off that behavior.'),
|
||||
OptionRecommendation(name='docx_no_pagebreaks_between_notes', recommended_value=False,
|
||||
help=_('Do not insert a page break after every endnote.')),
|
||||
help='Do not insert a page break after every endnote.'),
|
||||
OptionRecommendation(name='docx_inline_subsup', recommended_value=False,
|
||||
help=_('Render superscripts and subscripts so that they do not affect the line height.')),
|
||||
help='Render superscripts and subscripts so that they do not '
|
||||
'affect the line height.'),
|
||||
}
|
||||
|
||||
recommendations = {('page_breaks_before', '/', OptionRecommendation.MED)}
|
||||
|
||||
@@ -19,52 +19,52 @@ class DOCXOutput(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='docx_page_size', recommended_value='letter',
|
||||
level=OptionRecommendation.LOW, choices=PAGE_SIZES,
|
||||
help=_('The size of the page. Default is letter. Choices '
|
||||
'are %s') % PAGE_SIZES),
|
||||
help='The size of the page. Default is letter. Choices '
|
||||
'are %s' % PAGE_SIZES),
|
||||
|
||||
OptionRecommendation(name='docx_custom_page_size', recommended_value=None,
|
||||
help=_('Custom size of the document. Use the form widthxheight '
|
||||
help='Custom size of the document. Use the form widthxheight '
|
||||
'EG. `123x321` to specify the width and height (in pts). '
|
||||
'This overrides any specified page-size.')),
|
||||
'This overrides any specified page-size.'),
|
||||
|
||||
OptionRecommendation(name='docx_no_cover', recommended_value=False,
|
||||
help=_('Do not insert the book cover as an image at the start of the document.'
|
||||
' If you use this option, the book cover will be discarded.')),
|
||||
help='Do not insert the book cover as an image at the start of the document.'
|
||||
' If you use this option, the book cover will be discarded.'),
|
||||
|
||||
OptionRecommendation(name='preserve_cover_aspect_ratio', recommended_value=False,
|
||||
help=_('Preserve the aspect ratio of the cover image instead of stretching'
|
||||
' it out to cover the entire page.')),
|
||||
help='Preserve the aspect ratio of the cover image instead of stretching'
|
||||
' it out to cover the entire page.'),
|
||||
|
||||
OptionRecommendation(name='docx_no_toc', recommended_value=False,
|
||||
help=_('Do not insert the table of contents as a page at the start of the document.')),
|
||||
help='Do not insert the table of contents as a page at the start of the document.'),
|
||||
|
||||
OptionRecommendation(name='extract_to',
|
||||
help=_('Extract the contents of the generated %s file to the '
|
||||
help='Extract the contents of the generated %s file to the '
|
||||
'specified directory. The contents of the directory are first '
|
||||
'deleted, so be careful.') % 'DOCX'),
|
||||
'deleted, so be careful.' % 'DOCX'),
|
||||
|
||||
OptionRecommendation(name='docx_page_margin_left', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the left page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common left page margin setting.')
|
||||
help='The size of the left page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common left page margin setting.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='docx_page_margin_top', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the top page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common top page margin setting, unless set to zero.')
|
||||
help='The size of the top page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common top page margin setting, unless set to zero.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='docx_page_margin_right', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the right page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common right page margin setting, unless set to zero.')
|
||||
help='The size of the right page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common right page margin setting, unless set to zero.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='docx_page_margin_bottom', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the bottom page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common bottom page margin setting, unless set to zero.')
|
||||
help='The size of the bottom page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common bottom page margin setting, unless set to zero.'
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ import re
|
||||
import shutil
|
||||
import urllib.parse
|
||||
|
||||
from ebook_converter.customize.conversion import (OutputFormatPlugin,
|
||||
OptionRecommendation)
|
||||
from ebook_converter.customize.conversion import OutputFormatPlugin
|
||||
from ebook_converter.customize.conversion import OptionRecommendation
|
||||
|
||||
from ebook_converter.ptempfile import TemporaryDirectory
|
||||
from ebook_converter import CurrentDir
|
||||
from ebook_converter.polyglot.builtins import as_bytes
|
||||
@@ -53,78 +54,79 @@ class EPUBOutput(OutputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='extract_to',
|
||||
help=_('Extract the contents of the generated %s file to the '
|
||||
'specified directory. The contents of the directory are first '
|
||||
'deleted, so be careful.') % 'EPUB'),
|
||||
help='Extract the contents of the generated %s file to the '
|
||||
'specified directory. The contents of the directory are '
|
||||
'first deleted, so be careful.' % 'EPUB'),
|
||||
|
||||
OptionRecommendation(name='dont_split_on_page_breaks',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Turn off splitting at page breaks. Normally, input '
|
||||
help='Turn off splitting at page breaks. Normally, input '
|
||||
'files are automatically split at every page break into '
|
||||
'two files. This gives an output e-book 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.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='flow_size', recommended_value=260,
|
||||
help=_('Split all HTML files larger than this size (in KB). '
|
||||
help='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. Set to 0 to disable size based splitting.')
|
||||
'for Adobe Digital Editions. Set to 0 to disable size based '
|
||||
'splitting.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='no_default_epub_cover', recommended_value=False,
|
||||
help=_('Normally, if the input file has no cover and you don\'t'
|
||||
help='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.')
|
||||
'authors, etc. This option disables the generation of this cover.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='no_svg_cover', recommended_value=False,
|
||||
help=_('Do not use SVG for the book cover. Use this option if '
|
||||
help='Do not use SVG for the book cover. Use this option if '
|
||||
'your EPUB is going to be used on a 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.')
|
||||
'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.'
|
||||
)
|
||||
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.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='epub_flatten', recommended_value=False,
|
||||
help=_('This option is needed only if you intend to use the EPUB'
|
||||
help='This option is needed only if you intend to use the EPUB'
|
||||
' with FBReaderJ. It will flatten the file system inside the'
|
||||
' EPUB, putting all files into the top level.')
|
||||
' EPUB, putting all files into the top level.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='epub_inline_toc', recommended_value=False,
|
||||
help=_('Insert an inline Table of Contents that will appear as part of the main book content.')
|
||||
help='Insert an inline Table of Contents that will appear as part '
|
||||
'of the main book content.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='epub_toc_at_end', recommended_value=False,
|
||||
help=_('Put the inserted inline Table of Contents at the end of the book instead of the start.')
|
||||
help='Put the inserted inline Table of Contents at the end of '
|
||||
'the book instead of the start.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='toc_title', recommended_value=None,
|
||||
help=_('Title for any generated in-line table of contents.')
|
||||
help='Title for any generated in-line table of contents.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='epub_version', recommended_value='2', choices=ui_data['versions'],
|
||||
help=_('The version of the EPUB file to generate. EPUB 2 is the'
|
||||
' most widely compatible, only use EPUB 3 if you know you'
|
||||
' actually need it.')
|
||||
),
|
||||
|
||||
help='The version of the EPUB file to generate. EPUB 2 is the '
|
||||
'most widely compatible, only use EPUB 3 if you know you '
|
||||
'actually need it.'
|
||||
)
|
||||
}
|
||||
|
||||
recommendations = {('pretty_print', True, OptionRecommendation.HIGH)}
|
||||
@@ -219,7 +221,7 @@ class EPUBOutput(OutputFormatPlugin):
|
||||
self.log.warn('This EPUB file has no Table of Contents. '
|
||||
'Creating a default TOC')
|
||||
first = next(iter(self.oeb.spine))
|
||||
self.oeb.toc.add(_('Start'), first.href)
|
||||
self.oeb.toc.add('Start', first.href)
|
||||
|
||||
from ebook_converter.ebooks.oeb.base import OPF
|
||||
identifiers = oeb.metadata['identifier']
|
||||
|
||||
@@ -32,8 +32,7 @@ class FB2Input(InputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='no_inline_fb2_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Do not insert a Table of Contents at the beginning of the book.'
|
||||
)
|
||||
help='Do not insert a Table of Contents at the beginning of the book.'
|
||||
)}
|
||||
|
||||
def convert(self, stream, options, file_ext, log,
|
||||
@@ -129,9 +128,9 @@ class FB2Input(InputFormatPlugin):
|
||||
stream.seek(0)
|
||||
mi = get_metadata(stream, 'fb2')
|
||||
if not mi.title:
|
||||
mi.title = _('Unknown')
|
||||
mi.title = 'Unknown'
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
mi.authors = ['Unknown']
|
||||
cpath = None
|
||||
if mi.cover_data and mi.cover_data[1]:
|
||||
with open('fb2_cover_calibre_mi.jpg', 'wb') as f:
|
||||
|
||||
@@ -141,31 +141,31 @@ class FB2Output(OutputFormatPlugin):
|
||||
'home_sex', # Erotica & sex
|
||||
'home', # Other
|
||||
]
|
||||
ui_data = {
|
||||
'sectionize': {
|
||||
'toc': _('Section per entry in the ToC'),
|
||||
'files': _('Section per file'),
|
||||
'nothing': _('A single section')
|
||||
},
|
||||
'genres': FB2_GENRES,
|
||||
}
|
||||
ui_data = {'sectionize': {'toc': 'Section per entry in the ToC',
|
||||
'files': 'Section per file',
|
||||
'nothing': 'A single section'},
|
||||
'genres': FB2_GENRES}
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='sectionize',
|
||||
recommended_value='files', level=OptionRecommendation.LOW,
|
||||
choices=list(ui_data['sectionize']),
|
||||
help=_('Specify how sections are created:\n'
|
||||
help='Specify how sections are created:\n'
|
||||
' * nothing: {nothing}\n'
|
||||
' * files: {files}\n'
|
||||
' * toc: {toc}\n'
|
||||
'If ToC based generation fails, adjust the "Structure detection" and/or "Table of Contents" settings '
|
||||
'(turn on "Force use of auto-generated Table of Contents").').format(**ui_data['sectionize'])
|
||||
'If ToC based generation fails, adjust the "Structure '
|
||||
'detection" and/or "Table of Contents" settings (turn on '
|
||||
'"Force use of auto-generated Table of Contents")'
|
||||
'.'.format(**ui_data['sectionize'])
|
||||
),
|
||||
OptionRecommendation(name='fb2_genre',
|
||||
recommended_value='antique', level=OptionRecommendation.LOW,
|
||||
choices=FB2_GENRES,
|
||||
help=(_('Genre for the book. Choices: %s\n\n See: ') % ', '.join(FB2_GENRES)
|
||||
) + 'http://www.fictionbook.org/index.php/Eng:FictionBook_2.1_genres ' + _('for a complete list with descriptions.')),
|
||||
help='Genre for the book. Choices: %s\n\n See: http://www.'
|
||||
'fictionbook.org/index.php/Eng:FictionBook_2.1_genres for a '
|
||||
'complete list with descriptions.' % ', '.join(FB2_GENRES)),
|
||||
|
||||
}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
|
||||
@@ -35,27 +35,24 @@ class HTMLInput(InputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='breadth_first',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Traverse links in HTML files breadth first. Normally, '
|
||||
help='Traverse links in HTML files breadth first. Normally, '
|
||||
'they are traversed depth first.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='max_levels',
|
||||
recommended_value=5, level=OptionRecommendation.LOW,
|
||||
help=_('Maximum levels of recursion when following links in '
|
||||
help='Maximum levels of recursion when following links in '
|
||||
'HTML files. Must be non-negative. 0 implies that no '
|
||||
'links in the root HTML file are followed. Default is '
|
||||
'%default.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='dont_package',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Normally this input plugin re-arranges all the input '
|
||||
help='Normally this input plugin re-arranges all the input '
|
||||
'files into a standard folder hierarchy. Only use this option '
|
||||
'if you know what you are doing as it can result in various '
|
||||
'nasty side effects in the rest of the conversion pipeline.'
|
||||
)
|
||||
),
|
||||
|
||||
}
|
||||
@@ -129,12 +126,12 @@ class HTMLInput(InputFormatPlugin):
|
||||
a = string_to_authors(a)
|
||||
if not a:
|
||||
oeb.logger.warn('Creator not specified')
|
||||
a = [self.oeb.translate(__('Unknown'))]
|
||||
a = [self.oeb.translate('Unknown')]
|
||||
for aut in a:
|
||||
metadata.add('creator', aut)
|
||||
if not metadata.title:
|
||||
oeb.logger.warn('Title not specified')
|
||||
metadata.add('title', self.oeb.translate(__('Unknown')))
|
||||
metadata.add('title', self.oeb.translate('Unknown'))
|
||||
bookid = str(uuid.uuid4())
|
||||
metadata.add('identifier', bookid, id='uuid_id', scheme='uuid')
|
||||
for ident in metadata.identifier:
|
||||
|
||||
@@ -30,18 +30,18 @@ class HTMLOutput(OutputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='template_css',
|
||||
help=_('CSS file used for the output instead of the default file')),
|
||||
help='CSS file used for the output instead of the default file'),
|
||||
|
||||
OptionRecommendation(name='template_html_index',
|
||||
help=_('Template used for generation of the HTML index file instead of the default file')),
|
||||
help='Template used for generation of the HTML index file instead of the default file'),
|
||||
|
||||
OptionRecommendation(name='template_html',
|
||||
help=_('Template used for the generation of the HTML contents of the book instead of the default file')),
|
||||
help='Template used for the generation of the HTML contents of the book instead of the default file'),
|
||||
|
||||
OptionRecommendation(name='extract_to',
|
||||
help=_('Extract the contents of the generated ZIP file to the '
|
||||
help='Extract the contents of the generated ZIP file to the '
|
||||
'specified directory. WARNING: The contents of the directory '
|
||||
'will be deleted.')
|
||||
'will be deleted.'
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -59,16 +59,17 @@ class HTMLZInput(InputFormatPlugin):
|
||||
# HTMLZ archive probably won't turn out as the user expects. With
|
||||
# Multiple HTML files ZIP input should be used in place of HTMLZ.
|
||||
if multiple_html:
|
||||
log.warn(_('Multiple HTML files found in the archive. Only %s will be used.') % index)
|
||||
log.warn('Multiple HTML files found in the archive. Only %s will '
|
||||
'be used.' % index)
|
||||
|
||||
if index:
|
||||
with open(index, 'rb') as tf:
|
||||
html = tf.read()
|
||||
else:
|
||||
raise Exception(_('No top level HTML file found.'))
|
||||
raise Exception('No top level HTML file found.')
|
||||
|
||||
if not html:
|
||||
raise Exception(_('Top level HTML file %s is empty') % index)
|
||||
raise Exception('Top level HTML file %s is empty' % index)
|
||||
|
||||
# Encoding
|
||||
if options.input_encoding:
|
||||
|
||||
@@ -17,40 +17,33 @@ class HTMLZOutput(OutputFormatPlugin):
|
||||
author = 'John Schember'
|
||||
file_type = 'htmlz'
|
||||
commit_name = 'htmlz_output'
|
||||
ui_data = {
|
||||
'css_choices': {
|
||||
'class': _('Use CSS classes'),
|
||||
'inline': _('Use the style attribute'),
|
||||
'tag': _('Use HTML tags wherever possible')
|
||||
},
|
||||
'sheet_choices': {
|
||||
'external': _('Use an external CSS file'),
|
||||
'inline': _('Use a <style> tag in the HTML file')
|
||||
}
|
||||
}
|
||||
ui_data = {'css_choices': {'class': 'Use CSS classes',
|
||||
'inline': 'Use the style attribute',
|
||||
'tag': 'Use HTML tags wherever possible'},
|
||||
'sheet_choices': {'external': 'Use an external CSS file',
|
||||
'inline': 'Use a <style> tag in the HTML '
|
||||
'file'}}
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='htmlz_css_type', recommended_value='class',
|
||||
level=OptionRecommendation.LOW,
|
||||
choices=list(ui_data['css_choices']),
|
||||
help=_('Specify the handling of CSS. Default is class.\n'
|
||||
help='Specify the handling of CSS. Default is class.\n'
|
||||
'class: {class}\n'
|
||||
'inline: {inline}\n'
|
||||
'tag: {tag}'
|
||||
).format(**ui_data['css_choices'])),
|
||||
'tag: {tag}'.format(**ui_data['css_choices'])),
|
||||
OptionRecommendation(name='htmlz_class_style', recommended_value='external',
|
||||
level=OptionRecommendation.LOW,
|
||||
choices=list(ui_data['sheet_choices']),
|
||||
help=_('How to handle the CSS when using css-type = \'class\'.\n'
|
||||
help='How to handle the CSS when using css-type = \'class\'.\n'
|
||||
'Default is external.\n'
|
||||
'external: {external}\n'
|
||||
'inline: {inline}'
|
||||
).format(**ui_data['sheet_choices'])),
|
||||
'inline: {inline}'.format(**ui_data['sheet_choices'])),
|
||||
OptionRecommendation(name='htmlz_title_filename',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('If set this option causes the file name of the HTML file'
|
||||
' inside the HTMLZ archive to be based on the book title.')
|
||||
),
|
||||
help='If set this option causes the file name of the HTML file '
|
||||
'inside the HTMLZ archive to be based on the book title.'
|
||||
)
|
||||
}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
|
||||
@@ -24,7 +24,7 @@ class LRFOptions(object):
|
||||
if val < 0:
|
||||
setattr(opts, attr, 0)
|
||||
self.title = None
|
||||
self.author = self.publisher = _('Unknown')
|
||||
self.author = self.publisher = 'Unknown'
|
||||
self.title_sort = self.author_sort = ''
|
||||
for x in m.creator:
|
||||
if x.role == 'aut':
|
||||
@@ -91,43 +91,44 @@ class LRFOutput(OutputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='enable_autorotation', recommended_value=False,
|
||||
help=_('Enable auto-rotation of images that are wider than the screen width.')
|
||||
help='Enable auto-rotation of images that are wider than the '
|
||||
'screen width.'
|
||||
),
|
||||
OptionRecommendation(name='wordspace',
|
||||
recommended_value=2.5, level=OptionRecommendation.LOW,
|
||||
help=_('Set the space between words in pts. Default is %default')
|
||||
help='Set the space between words in pts. Default is %default'
|
||||
),
|
||||
OptionRecommendation(name='header', recommended_value=False,
|
||||
help=_('Add a header to all the pages with title and author.')
|
||||
help='Add a header to all the pages with title and author.'
|
||||
),
|
||||
OptionRecommendation(name='header_format', recommended_value="%t by %a",
|
||||
help=_('Set the format of the header. %a is replaced by the author '
|
||||
'and %t by the title. Default is %default')
|
||||
help='Set the format of the header. %a is replaced by the author '
|
||||
'and %t by the title. Default is %default'
|
||||
),
|
||||
OptionRecommendation(name='header_separation', recommended_value=0,
|
||||
help=_('Add extra spacing below the header. Default is %default pt.')
|
||||
help='Add extra spacing below the header. Default is %default pt.'
|
||||
),
|
||||
OptionRecommendation(name='minimum_indent', recommended_value=0,
|
||||
help=_('Minimum paragraph indent (the indent of the first line '
|
||||
'of a paragraph) in pts. Default: %default')
|
||||
help='Minimum paragraph indent (the indent of the first line '
|
||||
'of a paragraph) in pts. Default: %default'
|
||||
),
|
||||
OptionRecommendation(name='render_tables_as_images',
|
||||
recommended_value=False,
|
||||
help=_('This option has no effect')
|
||||
help='This option has no effect'
|
||||
),
|
||||
OptionRecommendation(name='text_size_multiplier_for_rendered_tables',
|
||||
recommended_value=1.0,
|
||||
help=_('Multiply the size of text in rendered tables by this '
|
||||
'factor. Default is %default')
|
||||
help='Multiply the size of text in rendered tables by this '
|
||||
'factor. Default is %default'
|
||||
),
|
||||
OptionRecommendation(name='serif_family', recommended_value=None,
|
||||
help=_('The serif family of fonts to embed')
|
||||
help='The serif family of fonts to embed'
|
||||
),
|
||||
OptionRecommendation(name='sans_family', recommended_value=None,
|
||||
help=_('The sans-serif family of fonts to embed')
|
||||
help='The sans-serif family of fonts to embed'
|
||||
),
|
||||
OptionRecommendation(name='mono_family', recommended_value=None,
|
||||
help=_('The monospace family of fonts to embed')
|
||||
help='The monospace family of fonts to embed'
|
||||
),
|
||||
|
||||
}
|
||||
@@ -151,7 +152,7 @@ class LRFOutput(OutputFormatPlugin):
|
||||
book = Book(title=opts.title, author=opts.author,
|
||||
bookid=uuid4().hex,
|
||||
publisher='%s %s'%(__appname__, __version__),
|
||||
category=_('Comic'), pagestyledefault=ps,
|
||||
category='Comic', pagestyledefault=ps,
|
||||
booksetting=BookSetting(screenwidth=width, screenheight=height))
|
||||
for page in pages:
|
||||
imageStream = ImageStream(page)
|
||||
|
||||
@@ -44,64 +44,64 @@ class MOBIOutput(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='prefer_author_sort',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('When present, use author sort field as author.')
|
||||
help='When present, use author sort field as author.'
|
||||
),
|
||||
OptionRecommendation(name='no_inline_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Don\'t add Table of Contents to the book. Useful if '
|
||||
'the book has its own table of contents.')),
|
||||
help='Don\'t add Table of Contents to the book. Useful if '
|
||||
'the book has its own table of contents.'),
|
||||
OptionRecommendation(name='toc_title', recommended_value=None,
|
||||
help=_('Title for any generated in-line table of contents.')
|
||||
help='Title for any generated in-line table of contents.'
|
||||
),
|
||||
OptionRecommendation(name='dont_compress',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Disable compression of the file contents.')
|
||||
help='Disable compression of the file contents.'
|
||||
),
|
||||
OptionRecommendation(name='personal_doc', recommended_value='[PDOC]',
|
||||
help=_('Tag for MOBI files to be marked as personal documents.'
|
||||
help='Tag for MOBI files to be marked as personal documents.'
|
||||
' This option has no effect on the conversion. It is used'
|
||||
' only when sending MOBI files to a device. If the file'
|
||||
' being sent has the specified tag, it will be marked as'
|
||||
' a personal document when sent to the Kindle.')
|
||||
' a personal document when sent to the Kindle.'
|
||||
),
|
||||
OptionRecommendation(name='mobi_ignore_margins',
|
||||
recommended_value=False,
|
||||
help=_('Ignore margins in the input document. If False, then '
|
||||
help='Ignore margins in the input document. If False, then '
|
||||
'the MOBI output plugin will try to convert margins specified'
|
||||
' in the input document, otherwise it will ignore them.')
|
||||
' in the input document, otherwise it will ignore them.'
|
||||
),
|
||||
OptionRecommendation(name='mobi_toc_at_start',
|
||||
recommended_value=False,
|
||||
help=_('When adding the Table of Contents to the book, add it at the start of the '
|
||||
'book instead of the end. Not recommended.')
|
||||
help='When adding the Table of Contents to the book, add it at the start of the '
|
||||
'book instead of the end. Not recommended.'
|
||||
),
|
||||
OptionRecommendation(name='extract_to',
|
||||
help=_('Extract the contents of the generated %s file to the '
|
||||
help='Extract the contents of the generated %s file to the '
|
||||
'specified directory. The contents of the directory are first '
|
||||
'deleted, so be careful.') % 'MOBI'
|
||||
'deleted, so be careful.' % 'MOBI'
|
||||
),
|
||||
OptionRecommendation(name='share_not_sync', recommended_value=False,
|
||||
help=_('Enable sharing of book content via Facebook etc. '
|
||||
help='Enable sharing of book content via Facebook etc. '
|
||||
' on the Kindle. WARNING: Using this feature means that '
|
||||
' the book will not auto sync its last read position '
|
||||
' on multiple devices. Complain to Amazon.')
|
||||
' on multiple devices. Complain to Amazon.'
|
||||
),
|
||||
OptionRecommendation(name='mobi_keep_original_images',
|
||||
recommended_value=False,
|
||||
help=_('By default calibre converts all images to JPEG format '
|
||||
help='By default calibre converts all images to JPEG format '
|
||||
'in the output MOBI file. This is for maximum compatibility '
|
||||
'as some older MOBI viewers have problems with other image '
|
||||
'formats. This option tells calibre not to do this. '
|
||||
'Useful if your document contains lots of GIF/PNG images that '
|
||||
'become very large when converted to JPEG.')),
|
||||
'become very large when converted to JPEG.'),
|
||||
OptionRecommendation(name='mobi_file_type', choices=ui_data['file_types'], recommended_value='old',
|
||||
help=_('By default calibre generates MOBI files that contain the '
|
||||
help='By default calibre generates MOBI files that contain the '
|
||||
'old MOBI 6 format. This format is compatible with all '
|
||||
'devices. However, by changing this setting, you can tell '
|
||||
'calibre to generate MOBI files that contain both MOBI 6 and '
|
||||
'the new KF8 format, or only the new KF8 format. KF8 has '
|
||||
'more features than MOBI 6, but only works with newer Kindles. '
|
||||
'Allowed values: {}').format('old, both, new')),
|
||||
'Allowed values: {}'.format('old, both, new'))
|
||||
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class MOBIOutput(OutputFormatPlugin):
|
||||
# single section periodical
|
||||
self.oeb.manifest.remove(one)
|
||||
self.oeb.manifest.remove(two)
|
||||
sections = [TOC(klass='section', title=_('All articles'),
|
||||
sections = [TOC(klass='section', title='All articles',
|
||||
href=self.oeb.spine[0].href)]
|
||||
for x in toc:
|
||||
sections[0].nodes.append(x)
|
||||
@@ -274,34 +274,34 @@ class AZW3Output(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='prefer_author_sort',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('When present, use author sort field as author.')
|
||||
help='When present, use author sort field as author.'
|
||||
),
|
||||
OptionRecommendation(name='no_inline_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Don\'t add Table of Contents to the book. Useful if '
|
||||
'the book has its own table of contents.')),
|
||||
help='Don\'t add Table of Contents to the book. Useful if '
|
||||
'the book has its own table of contents.'),
|
||||
OptionRecommendation(name='toc_title', recommended_value=None,
|
||||
help=_('Title for any generated in-line table of contents.')
|
||||
help='Title for any generated in-line table of contents.'
|
||||
),
|
||||
OptionRecommendation(name='dont_compress',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Disable compression of the file contents.')
|
||||
help='Disable compression of the file contents.'
|
||||
),
|
||||
OptionRecommendation(name='mobi_toc_at_start',
|
||||
recommended_value=False,
|
||||
help=_('When adding the Table of Contents to the book, add it at the start of the '
|
||||
'book instead of the end. Not recommended.')
|
||||
help='When adding the Table of Contents to the book, add it at the start of the '
|
||||
'book instead of the end. Not recommended.'
|
||||
),
|
||||
OptionRecommendation(name='extract_to',
|
||||
help=_('Extract the contents of the generated %s file to the '
|
||||
help='Extract the contents of the generated %s file to the '
|
||||
'specified directory. The contents of the directory are first '
|
||||
'deleted, so be careful.') % 'AZW3'),
|
||||
'deleted, so be careful.' % 'AZW3'),
|
||||
OptionRecommendation(name='share_not_sync', recommended_value=False,
|
||||
help=_('Enable sharing of book content via Facebook etc. '
|
||||
help='Enable sharing of book content via Facebook etc. '
|
||||
' on the Kindle. WARNING: Using this feature means that '
|
||||
' the book will not auto sync its last read position '
|
||||
' on multiple devices. Complain to Amazon.')
|
||||
),
|
||||
' on multiple devices. Complain to Amazon.'
|
||||
)
|
||||
}
|
||||
|
||||
def convert(self, oeb, output_path, input_plugin, opts, log):
|
||||
|
||||
@@ -25,8 +25,10 @@ class PDBInput(InputFormatPlugin):
|
||||
Reader = get_reader(header.ident)
|
||||
|
||||
if Reader is None:
|
||||
raise PDBError('No reader available for format within container.\n Identity is %s. Book type is %s' %
|
||||
(header.ident, IDENTITY_TO_NAME.get(header.ident, _('Unknown'))))
|
||||
raise PDBError('No reader available for format within container.'
|
||||
'\n Identity is %s. Book type is %s' %
|
||||
(header.ident,
|
||||
IDENTITY_TO_NAME.get(header.ident, 'Unknown')))
|
||||
|
||||
log.debug('Detected ebook format as: %s with identity: %s' % (IDENTITY_TO_NAME[header.ident], header.ident))
|
||||
|
||||
|
||||
@@ -22,15 +22,16 @@ class PDBOutput(OutputFormatPlugin):
|
||||
OptionRecommendation(name='format', recommended_value='doc',
|
||||
level=OptionRecommendation.LOW,
|
||||
short_switch='f', choices=list(ALL_FORMAT_WRITERS),
|
||||
help=(_('Format to use inside the pdb container. Choices are:') + ' %s' % sorted(ALL_FORMAT_WRITERS))),
|
||||
help='Format to use inside the pdb container. Choices are: %s' %
|
||||
sorted(ALL_FORMAT_WRITERS)),
|
||||
OptionRecommendation(name='pdb_output_encoding', recommended_value='cp1252',
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the output document. '
|
||||
'The default is cp1252. Note: This option is not honored by all '
|
||||
'formats.')),
|
||||
help='Specify the character encoding of the output document. '
|
||||
'The default is cp1252. Note: This option is not honored by '
|
||||
'all formats.'),
|
||||
OptionRecommendation(name='inline_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Add Table of Contents to beginning of the book.')),
|
||||
help='Add Table of Contents to beginning of the book.'),
|
||||
}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
|
||||
@@ -19,13 +19,13 @@ class PDFInput(InputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='no_images', recommended_value=False,
|
||||
help=_('Do not extract images from the document')),
|
||||
help='Do not extract images from the document'),
|
||||
OptionRecommendation(name='unwrap_factor', recommended_value=0.45,
|
||||
help=_('Scale used to determine the length at which a line should '
|
||||
help='Scale used to determine the length at which a line should '
|
||||
'be unwrapped. Valid values are a decimal between 0 and 1. The '
|
||||
'default is 0.45, just below the median line length.')),
|
||||
'default is 0.45, just below the median line length.'),
|
||||
OptionRecommendation(name='new_pdf_engine', recommended_value=False,
|
||||
help=_('Use the new PDF conversion engine. Currently not operational.'))
|
||||
help='Use the new PDF conversion engine. Currently not operational.')
|
||||
}
|
||||
|
||||
def convert_new(self, stream, accelerators):
|
||||
|
||||
@@ -29,106 +29,104 @@ class PDFOutput(OutputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='use_profile_size', recommended_value=False,
|
||||
help=_('Instead of using the paper size specified in the PDF Output options,'
|
||||
help='Instead of using the paper size specified in the PDF Output options,'
|
||||
' use a paper size corresponding to the current output profile.'
|
||||
' Useful if you want to generate a PDF for viewing on a specific device.')),
|
||||
' Useful if you want to generate a PDF for viewing on a specific device.'),
|
||||
OptionRecommendation(name='unit', recommended_value='inch',
|
||||
level=OptionRecommendation.LOW, short_switch='u', choices=UNITS,
|
||||
help=_('The unit of measure for page sizes. Default is inch. Choices '
|
||||
help='The unit of measure for page sizes. Default is inch. Choices '
|
||||
'are {} '
|
||||
'Note: This does not override the unit for margins!').format(', '.join(UNITS))),
|
||||
'Note: This does not override the unit for margins!'.format(', '.join(UNITS))),
|
||||
OptionRecommendation(name='paper_size', recommended_value='letter',
|
||||
level=OptionRecommendation.LOW, choices=PAPER_SIZES,
|
||||
help=_('The size of the paper. This size will be overridden when a '
|
||||
help='The size of the paper. This size will be overridden when a '
|
||||
'non default output profile is used. Default is letter. Choices '
|
||||
'are {}').format(', '.join(PAPER_SIZES))),
|
||||
'are {}'.format(', '.join(PAPER_SIZES))),
|
||||
OptionRecommendation(name='custom_size', recommended_value=None,
|
||||
help=_('Custom size of the document. Use the form widthxheight '
|
||||
help='Custom size of the document. Use the form widthxheight '
|
||||
'e.g. `123x321` to specify the width and height. '
|
||||
'This overrides any specified paper-size.')),
|
||||
'This overrides any specified paper-size.'),
|
||||
OptionRecommendation(name='preserve_cover_aspect_ratio',
|
||||
recommended_value=False,
|
||||
help=_('Preserve the aspect ratio of the cover, instead'
|
||||
help='Preserve the aspect ratio of the cover, instead'
|
||||
' of stretching it to fill the full first page of the'
|
||||
' generated pdf.')),
|
||||
' generated pdf.'),
|
||||
OptionRecommendation(name='pdf_serif_family',
|
||||
recommended_value='Times', help=_(
|
||||
'The font family used to render serif fonts. Will work only if the font is available system-wide.')),
|
||||
recommended_value='Times', help=
|
||||
'The font family used to render serif fonts. Will work only if the font is available system-wide.'),
|
||||
OptionRecommendation(name='pdf_sans_family',
|
||||
recommended_value='Helvetica', help=_(
|
||||
'The font family used to render sans-serif fonts. Will work only if the font is available system-wide.')),
|
||||
recommended_value='Helvetica', help=
|
||||
'The font family used to render sans-serif fonts. Will work only if the font is available system-wide.'),
|
||||
OptionRecommendation(name='pdf_mono_family',
|
||||
recommended_value='Courier', help=_(
|
||||
'The font family used to render monospace fonts. Will work only if the font is available system-wide.')),
|
||||
recommended_value='Courier', help=
|
||||
'The font family used to render monospace fonts. Will work only if the font is available system-wide.'),
|
||||
OptionRecommendation(name='pdf_standard_font', choices=ui_data['font_types'],
|
||||
recommended_value='serif', help=_(
|
||||
'The font family used to render monospace fonts')),
|
||||
recommended_value='serif', help=
|
||||
'The font family used to render monospace fonts'),
|
||||
OptionRecommendation(name='pdf_default_font_size',
|
||||
recommended_value=20, help=_(
|
||||
'The default font size')),
|
||||
OptionRecommendation(name='pdf_mono_font_size',
|
||||
recommended_value=16, help=_(
|
||||
'The default font size for monospaced text')),
|
||||
recommended_value=20, help='The default font size'),
|
||||
OptionRecommendation(name='pdf_mono_font_size', recommended_value=16,
|
||||
help='The default font size for monospaced text'),
|
||||
OptionRecommendation(name='pdf_hyphenate', recommended_value=False,
|
||||
help=_('Break long words at the end of lines. This can give the text at the right margin a more even appearance.')),
|
||||
help='Break long words at the end of lines. This can give the text at the right margin a more even appearance.'),
|
||||
OptionRecommendation(name='pdf_mark_links', recommended_value=False,
|
||||
help=_('Surround all links with a red box, useful for debugging.')),
|
||||
help='Surround all links with a red box, useful for debugging.'),
|
||||
OptionRecommendation(name='pdf_page_numbers', recommended_value=False,
|
||||
help=_('Add page numbers to the bottom of every page in the generated PDF file. If you '
|
||||
help='Add page numbers to the bottom of every page in the generated PDF file. If you '
|
||||
'specify a footer template, it will take precedence '
|
||||
'over this option.')),
|
||||
'over this option.'),
|
||||
OptionRecommendation(name='pdf_footer_template', recommended_value=None,
|
||||
help=_('An HTML template used to generate %s on every page.'
|
||||
' The strings _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_ will be replaced by their current values.')%_('footers')),
|
||||
help='An HTML template used to generate %s on every page.'
|
||||
' The strings _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_ will be replaced by their current values.' % 'footers'),
|
||||
OptionRecommendation(name='pdf_header_template', recommended_value=None,
|
||||
help=_('An HTML template used to generate %s on every page.'
|
||||
' The strings _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_ will be replaced by their current values.')%_('headers')),
|
||||
help='An HTML template used to generate %s on every page.'
|
||||
' The strings _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_ will be replaced by their current values.' % 'headers'),
|
||||
OptionRecommendation(name='pdf_add_toc', recommended_value=False,
|
||||
help=_('Add a Table of Contents at the end of the PDF that lists page numbers. '
|
||||
'Useful if you want to print out the PDF. If this PDF is intended for electronic use, use the PDF Outline instead.')),
|
||||
help='Add a Table of Contents at the end of the PDF that lists page numbers. '
|
||||
'Useful if you want to print out the PDF. If this PDF is intended for electronic use, use the PDF Outline instead.'),
|
||||
OptionRecommendation(name='toc_title', recommended_value=None,
|
||||
help=_('Title for generated table of contents.')
|
||||
help='Title for generated table of contents.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='pdf_page_margin_left', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the left page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common left page margin setting.')
|
||||
help='The size of the left page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common left page margin setting.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='pdf_page_margin_top', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the top page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common top page margin setting, unless set to zero.')
|
||||
help='The size of the top page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common top page margin setting, unless set to zero.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='pdf_page_margin_right', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the right page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common right page margin setting, unless set to zero.')
|
||||
help='The size of the right page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common right page margin setting, unless set to zero.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='pdf_page_margin_bottom', recommended_value=72.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('The size of the bottom page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common bottom page margin setting, unless set to zero.')
|
||||
help='The size of the bottom page margin, in pts. Default is 72pt.'
|
||||
' Overrides the common bottom page margin setting, unless set to zero.'
|
||||
),
|
||||
OptionRecommendation(name='pdf_use_document_margins', recommended_value=False,
|
||||
help=_('Use the page margins specified in the input document via @page CSS rules.'
|
||||
help='Use the page margins specified in the input document via @page CSS rules.'
|
||||
' This will cause the margins specified in the conversion settings to be ignored.'
|
||||
' If the document does not specify page margins, the conversion settings will be used as a fallback.')
|
||||
' If the document does not specify page margins, the conversion settings will be used as a fallback.'
|
||||
),
|
||||
OptionRecommendation(name='pdf_page_number_map', recommended_value=None,
|
||||
help=_('Adjust page numbers, as needed. Syntax is a JavaScript expression for the page number.'
|
||||
' For example, "if (n < 3) 0; else n - 3;", where n is current page number.')
|
||||
help='Adjust page numbers, as needed. Syntax is a JavaScript expression for the page number.'
|
||||
' For example, "if (n < 3) 0; else n - 3;", where n is current page number.'
|
||||
),
|
||||
OptionRecommendation(name='uncompressed_pdf',
|
||||
recommended_value=False, help=_(
|
||||
'Generate an uncompressed PDF, useful for debugging.')
|
||||
recommended_value=False, help=
|
||||
'Generate an uncompressed PDF, useful for debugging.'
|
||||
),
|
||||
OptionRecommendation(name='pdf_odd_even_offset', recommended_value=0.0,
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
help=
|
||||
'Shift the text horizontally by the specified offset (in pts).'
|
||||
' On odd numbered pages, it is shifted to the right and on even'
|
||||
' numbered pages to the left. Use negative numbers for the opposite'
|
||||
@@ -136,7 +134,6 @@ class PDFOutput(OutputFormatPlugin):
|
||||
' are smaller than the specified offset. Shifting is done by setting'
|
||||
' the PDF CropBox, not all software respects the CropBox.'
|
||||
)
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,17 @@ class PMLOutput(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='pml_output_encoding', recommended_value='cp1252',
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the output document. '
|
||||
'The default is cp1252.')),
|
||||
help='Specify the character encoding of the output document. '
|
||||
'The default is cp1252.'),
|
||||
OptionRecommendation(name='inline_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Add Table of Contents to beginning of the book.')),
|
||||
help='Add Table of Contents to beginning of the book.'),
|
||||
OptionRecommendation(name='full_image_depth',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Do not reduce the size or bit depth of images. Images '
|
||||
help='Do not reduce the size or bit depth of images. Images '
|
||||
'have their size and depth reduced by default to accommodate '
|
||||
'applications that can not convert images on their '
|
||||
'own such as Dropbook.')),
|
||||
'own such as Dropbook.'),
|
||||
}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
|
||||
@@ -18,7 +18,7 @@ class RBOutput(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='inline_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Add Table of Contents to beginning of the book.'))}
|
||||
help='Add Table of Contents to beginning of the book.')}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
from ebook_converter.ebooks.rb.writer import RBWriter
|
||||
|
||||
@@ -18,7 +18,7 @@ class RecipeInput(InputFormatPlugin):
|
||||
|
||||
name = 'Recipe Input'
|
||||
author = 'Kovid Goyal'
|
||||
description = _('Download periodical content from the internet')
|
||||
description = 'Download periodical content from the internet'
|
||||
file_types = {'recipe', 'downloaded_recipe'}
|
||||
commit_name = 'recipe_input'
|
||||
|
||||
@@ -34,20 +34,19 @@ class RecipeInput(InputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='test', recommended_value=False,
|
||||
help=_(
|
||||
'Useful for recipe development. Forces'
|
||||
' max_articles_per_feed to 2 and downloads at most 2 feeds.'
|
||||
' You can change the number of feeds and articles by supplying optional arguments.'
|
||||
' For example: --test 3 1 will download at most 3 feeds and only 1 article per feed.')),
|
||||
help='Useful for recipe development. Forces max_articles_per_feed '
|
||||
'to 2 and downloads at most 2 feeds. You can change the '
|
||||
'number of feeds and articles by supplying optional '
|
||||
'arguments. For example: --test 3 1 will download at most 3 '
|
||||
'feeds and only 1 article per feed.'),
|
||||
OptionRecommendation(name='username', recommended_value=None,
|
||||
help=_('Username for sites that require a login to access '
|
||||
'content.')),
|
||||
help='Username for sites that require a login to access content.'),
|
||||
OptionRecommendation(name='password', recommended_value=None,
|
||||
help=_('Password for sites that require a login to access '
|
||||
'content.')),
|
||||
help='Password for sites that require a login to access content.'),
|
||||
OptionRecommendation(name='dont_download_recipe',
|
||||
recommended_value=False,
|
||||
help=_('Do not download latest version of builtin recipes from the calibre server')),
|
||||
help='Do not download latest version of builtin recipes from the '
|
||||
'calibre server'),
|
||||
OptionRecommendation(name='lrf', recommended_value=False,
|
||||
help='Optimize fetching for subsequent conversion to LRF.'),
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ class RTFInput(InputFormatPlugin):
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='ignore_wmf', recommended_value=False,
|
||||
help=_('Ignore WMF images instead of replacing them with a placeholder image.')),
|
||||
help='Ignore WMF images instead of replacing them with a '
|
||||
'placeholder image.'),
|
||||
}
|
||||
|
||||
def generate_xml(self, stream):
|
||||
@@ -259,8 +260,9 @@ class RTFInput(InputFormatPlugin):
|
||||
xml = self.generate_xml(stream.name)
|
||||
except RtfInvalidCodeException as e:
|
||||
self.log.exception('Unable to parse RTF')
|
||||
raise ValueError(_('This RTF file has a feature calibre does not '
|
||||
'support. Convert it to HTML first and then try it.\n%s')%e)
|
||||
raise ValueError('This RTF file has a feature calibre does not '
|
||||
'support. Convert it to HTML first and then try '
|
||||
'it.\n%s' % e)
|
||||
|
||||
d = glob.glob(os.path.join('*_rtf_pict_dir', 'picts.rtf'))
|
||||
if d:
|
||||
@@ -303,9 +305,9 @@ class RTFInput(InputFormatPlugin):
|
||||
stream.seek(0)
|
||||
mi = get_metadata(stream, 'rtf')
|
||||
if not mi.title:
|
||||
mi.title = _('Unknown')
|
||||
mi.title = 'Unknown'
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
mi.authors = ['Unknown']
|
||||
opf = OPFCreator(os.getcwd(), mi)
|
||||
opf.create_manifest([(u'index.xhtml', None)])
|
||||
opf.create_spine([u'index.xhtml'])
|
||||
|
||||
@@ -20,30 +20,30 @@ class SNBOutput(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='snb_output_encoding', recommended_value='utf-8',
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the output document. '
|
||||
'The default is utf-8.')),
|
||||
help='Specify the character encoding of the output document. '
|
||||
'The default is utf-8.'),
|
||||
OptionRecommendation(name='snb_max_line_length',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
help=_('The maximum number of characters per line. This splits on '
|
||||
'the first space before the specified value. If no space is found '
|
||||
'the line will be broken at the space after and will exceed the '
|
||||
'specified value. Also, there is a minimum of 25 characters. '
|
||||
'Use 0 to disable line splitting.')),
|
||||
help='The maximum number of characters per line. This splits on '
|
||||
'the first space before the specified value. If no space is '
|
||||
'found the line will be broken at the space after and will '
|
||||
'exceed the specified value. Also, there is a minimum of 25 '
|
||||
'characters. Use 0 to disable line splitting.'),
|
||||
OptionRecommendation(name='snb_insert_empty_line',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Specify whether or not to insert an empty line between '
|
||||
'two paragraphs.')),
|
||||
help='Specify whether or not to insert an empty line between two '
|
||||
'paragraphs.'),
|
||||
OptionRecommendation(name='snb_dont_indent_first_line',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Specify whether or not to insert two space characters '
|
||||
'to indent the first line of each paragraph.')),
|
||||
help='Specify whether or not to insert two space characters to '
|
||||
'indent the first line of each paragraph.'),
|
||||
OptionRecommendation(name='snb_hide_chapter_name',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Specify whether or not to hide the chapter title for each '
|
||||
'chapter. Useful for image-only output (eg. comics).')),
|
||||
help='Specify whether or not to hide the chapter title for each '
|
||||
'chapter. Useful for image-only output (eg. comics).'),
|
||||
OptionRecommendation(name='snb_full_screen',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Resize all the images for full screen view. ')),
|
||||
help='Resize all the images for full screen view. '),
|
||||
}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
@@ -123,7 +123,7 @@ class SNBOutput(OutputFormatPlugin):
|
||||
log.warn('This SNB file has no Table of Contents. '
|
||||
'Creating a default TOC')
|
||||
first = next(iter(oeb_book.spine))
|
||||
oeb_book.toc.add(_('Start page'), first.href)
|
||||
oeb_book.toc.add('Start page', first.href)
|
||||
else:
|
||||
first = next(iter(oeb_book.spine))
|
||||
if oeb_book.toc[0].href != first.href:
|
||||
@@ -133,9 +133,9 @@ class SNBOutput(OutputFormatPlugin):
|
||||
# the tocInfoTree directly instead of modifying the toc
|
||||
ch = etree.SubElement(tocBody, "chapter")
|
||||
ch.set("src", ProcessFileName(first.href) + ".snbc")
|
||||
ch.text = _('Cover pages')
|
||||
ch.text = 'Cover pages'
|
||||
outputFiles[first.href] = []
|
||||
outputFiles[first.href].append(("", _("Cover pages")))
|
||||
outputFiles[first.href].append(("", "Cover pages"))
|
||||
|
||||
for tocitem in oeb_book.toc:
|
||||
if tocitem.href.find('#') != -1:
|
||||
@@ -148,10 +148,12 @@ class SNBOutput(OutputFormatPlugin):
|
||||
else:
|
||||
outputFiles[item[0]] = []
|
||||
if "" not in outputFiles[item[0]]:
|
||||
outputFiles[item[0]].append(("", tocitem.title + _(" (Preface)")))
|
||||
outputFiles[item[0]].append(("",
|
||||
tocitem.title +
|
||||
" (Preface)"))
|
||||
ch = etree.SubElement(tocBody, "chapter")
|
||||
ch.set("src", ProcessFileName(item[0]) + ".snbc")
|
||||
ch.text = tocitem.title + _(" (Preface)")
|
||||
ch.text = tocitem.title + " (Preface)"
|
||||
outputFiles[item[0]].append((item[1], tocitem.title))
|
||||
else:
|
||||
if tocitem.href in outputFiles:
|
||||
@@ -200,7 +202,8 @@ class SNBOutput(OutputFormatPlugin):
|
||||
f.write(etree.tostring(oldTree, pretty_print=True, encoding='utf-8'))
|
||||
else:
|
||||
log.debug('Merge %s with last TOC item...' % item.href)
|
||||
snbwriter.merge_content(oldTree, oeb_book, item, [('', _("Start"))], opts)
|
||||
snbwriter.merge_content(oldTree, oeb_book, item,
|
||||
[('', "Start")], opts)
|
||||
|
||||
# Output the last one if needed
|
||||
log.debug('Output the last modified chapter again: %s' % lastName)
|
||||
|
||||
@@ -19,8 +19,8 @@ class TCROutput(OutputFormatPlugin):
|
||||
options = {
|
||||
OptionRecommendation(name='tcr_output_encoding', recommended_value='utf-8',
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the output document. '
|
||||
'The default is utf-8.'))}
|
||||
help='Specify the character encoding of the output document. '
|
||||
'The default is utf-8.')}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
from ebook_converter.ebooks.txt.txtml import TXTMLizer
|
||||
|
||||
@@ -9,23 +9,23 @@ __copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
MD_EXTENSIONS = {
|
||||
'abbr': _('Abbreviations'),
|
||||
'admonition': _('Support admonitions'),
|
||||
'attr_list': _('Add attribute to HTML tags'),
|
||||
'codehilite': _('Add code highlighting via Pygments'),
|
||||
'def_list': _('Definition lists'),
|
||||
'extra': _('Enables various common extensions'),
|
||||
'fenced_code': _('Alternative code block syntax'),
|
||||
'footnotes': _('Footnotes'),
|
||||
'legacy_attrs': _('Use legacy element attributes'),
|
||||
'legacy_em': _('Use legacy underscore handling for connected words'),
|
||||
'meta': _('Metadata in the document'),
|
||||
'nl2br': _('Treat newlines as hard breaks'),
|
||||
'sane_lists': _('Do not allow mixing list types'),
|
||||
'smarty': _('Use markdown\'s internal smartypants parser'),
|
||||
'tables': _('Support tables'),
|
||||
'toc': _('Generate a table of contents'),
|
||||
'wikilinks': _('Wiki style links'),
|
||||
'abbr': 'Abbreviations',
|
||||
'admonition': 'Support admonitions',
|
||||
'attr_list': 'Add attribute to HTML tags',
|
||||
'codehilite': 'Add code highlighting via Pygments',
|
||||
'def_list': 'Definition lists',
|
||||
'extra': 'Enables various common extensions',
|
||||
'fenced_code': 'Alternative code block syntax',
|
||||
'footnotes': 'Footnotes',
|
||||
'legacy_attrs': 'Use legacy element attributes',
|
||||
'legacy_em': 'Use legacy underscore handling for connected words',
|
||||
'meta': 'Metadata in the document',
|
||||
'nl2br': 'Treat newlines as hard breaks',
|
||||
'sane_lists': 'Do not allow mixing list types',
|
||||
'smarty': 'Use markdown\'s internal smartypants parser',
|
||||
'tables': 'Support tables',
|
||||
'toc': 'Generate a table of contents',
|
||||
'wikilinks': 'Wiki style links',
|
||||
}
|
||||
|
||||
|
||||
@@ -39,57 +39,67 @@ class TXTInput(InputFormatPlugin):
|
||||
ui_data = {
|
||||
'md_extensions': MD_EXTENSIONS,
|
||||
'paragraph_types': {
|
||||
'auto': _('Try to auto detect paragraph type'),
|
||||
'block': _('Treat a blank line as a paragraph break'),
|
||||
'single': _('Assume every line is a paragraph'),
|
||||
'print': _('Assume every line starting with 2+ spaces or a tab starts a paragraph'),
|
||||
'unformatted': _('Most lines have hard line breaks, few/no blank lines or indents'),
|
||||
'off': _('Don\'t modify the paragraph structure'),
|
||||
'auto': 'Try to auto detect paragraph type',
|
||||
'block': 'Treat a blank line as a paragraph break',
|
||||
'single': 'Assume every line is a paragraph',
|
||||
'print': 'Assume every line starting with 2+ spaces or a tab '
|
||||
'starts a paragraph',
|
||||
'unformatted': 'Most lines have hard line breaks, few/no blank '
|
||||
'lines or indents',
|
||||
'off': 'Don\'t modify the paragraph structure',
|
||||
},
|
||||
'formatting_types': {
|
||||
'auto': _('Automatically decide which formatting processor to use'),
|
||||
'plain': _('No formatting'),
|
||||
'heuristic': _('Use heuristics to determine chapter headings, italics, etc.'),
|
||||
'textile': _('Use the TexTile markup language'),
|
||||
'markdown': _('Use the Markdown markup language')
|
||||
'auto': 'Automatically decide which formatting processor to use',
|
||||
'plain': 'No formatting',
|
||||
'heuristic': 'Use heuristics to determine chapter headings, '
|
||||
'italics, etc.',
|
||||
'textile': 'Use the TexTile markup language',
|
||||
'markdown': 'Use the Markdown markup language'
|
||||
},
|
||||
}
|
||||
|
||||
options = {
|
||||
OptionRecommendation(name='formatting_type', recommended_value='auto',
|
||||
choices=list(ui_data['formatting_types']),
|
||||
help=_('Formatting used within the document.\n'
|
||||
help='Formatting used within the document.\n'
|
||||
'* auto: {auto}\n'
|
||||
'* plain: {plain}\n'
|
||||
'* heuristic: {heuristic}\n'
|
||||
'* textile: {textile}\n'
|
||||
'* markdown: {markdown}\n'
|
||||
'To learn more about markdown see {url}').format(
|
||||
url='https://daringfireball.net/projects/markdown/', **ui_data['formatting_types'])
|
||||
'To learn more about markdown see '
|
||||
'{url}'.format(url='https://daringfireball.net/projects/'
|
||||
'markdown/',
|
||||
**ui_data['formatting_types'])
|
||||
),
|
||||
OptionRecommendation(name='paragraph_type', recommended_value='auto',
|
||||
choices=list(ui_data['paragraph_types']),
|
||||
help=_('Paragraph structure to assume. The value of "off" is useful for formatted documents such as Markdown or Textile. '
|
||||
help='Paragraph structure to assume. The value of "off" is useful '
|
||||
'for formatted documents such as Markdown or Textile. '
|
||||
'Choices are:\n'
|
||||
'* auto: {auto}\n'
|
||||
'* block: {block}\n'
|
||||
'* single: {single}\n'
|
||||
'* print: {print}\n'
|
||||
'* unformatted: {unformatted}\n'
|
||||
'* off: {off}').format(**ui_data['paragraph_types'])
|
||||
'* off: {off}'.format(**ui_data['paragraph_types'])
|
||||
),
|
||||
OptionRecommendation(name='preserve_spaces', recommended_value=False,
|
||||
help=_('Normally extra spaces are condensed into a single space. '
|
||||
'With this option all spaces will be displayed.')),
|
||||
help='Normally extra spaces are condensed into a single space. '
|
||||
'With this option all spaces will be displayed.'),
|
||||
OptionRecommendation(name='txt_in_remove_indents', recommended_value=False,
|
||||
help=_('Normally extra space at the beginning of lines is retained. '
|
||||
'With this option they will be removed.')),
|
||||
OptionRecommendation(name="markdown_extensions", recommended_value='footnotes, tables, toc',
|
||||
help=_('Enable extensions to markdown syntax. Extensions are formatting that is not part '
|
||||
'of the standard markdown format. The extensions enabled by default: %default.\n'
|
||||
'To learn more about markdown extensions, see {}\n'
|
||||
'This should be a comma separated list of extensions to enable:\n'
|
||||
).format('https://python-markdown.github.io/extensions/') + '\n'.join('* %s: %s' % (k, MD_EXTENSIONS[k]) for k in sorted(MD_EXTENSIONS))),
|
||||
help='Normally extra space at the beginning of lines is retained. '
|
||||
'With this option they will be removed.'),
|
||||
OptionRecommendation(name="markdown_extensions",
|
||||
recommended_value='footnotes, tables, toc',
|
||||
help='Enable extensions to markdown syntax. Extensions are '
|
||||
'formatting that is not part of the standard markdown '
|
||||
'format. The extensions enabled by default: %default.\nTo '
|
||||
'learn more about markdown extensions, see {}\nThis should '
|
||||
'be a comma separated list of extensions to enable:'
|
||||
'\n'.format('https://python-markdown.github.io/extensions/') +
|
||||
'\n'.join('* %s: %s' % (k, MD_EXTENSIONS[k])
|
||||
for k in sorted(MD_EXTENSIONS))),
|
||||
}
|
||||
|
||||
def shift_file(self, fname, data):
|
||||
@@ -301,5 +311,5 @@ class TXTInput(InputFormatPlugin):
|
||||
for item in oeb.spine:
|
||||
if hasattr(item.data, 'xpath'):
|
||||
for title in item.data.xpath('//*[local-name()="title"]'):
|
||||
if title.text == _('Unknown'):
|
||||
if title.text == 'Unknown':
|
||||
title.text = self.html_postprocess_title
|
||||
|
||||
@@ -22,9 +22,9 @@ class TXTOutput(OutputFormatPlugin):
|
||||
ui_data = {
|
||||
'newline_types': NEWLINE_TYPES,
|
||||
'formatting_types': {
|
||||
'plain': _('Plain text'),
|
||||
'markdown': _('Markdown formatted text'),
|
||||
'textile': _('TexTile formatted text')
|
||||
'plain': 'Plain text',
|
||||
'markdown': 'Markdown formatted text',
|
||||
'textile': 'TexTile formatted text'
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,52 +32,57 @@ class TXTOutput(OutputFormatPlugin):
|
||||
OptionRecommendation(name='newline', recommended_value='system',
|
||||
level=OptionRecommendation.LOW,
|
||||
short_switch='n', choices=NEWLINE_TYPES,
|
||||
help=_('Type of newline to use. Options are %s. Default is \'system\'. '
|
||||
help='Type of newline to use. Options are %s. Default is \'system\'. '
|
||||
'Use \'old_mac\' for compatibility with Mac OS 9 and earlier. '
|
||||
'For macOS use \'unix\'. \'system\' will default to the newline '
|
||||
'type used by this OS.') % sorted(NEWLINE_TYPES)),
|
||||
'type used by this OS.' % sorted(NEWLINE_TYPES)),
|
||||
OptionRecommendation(name='txt_output_encoding', recommended_value='utf-8',
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the output document. '
|
||||
'The default is utf-8.')),
|
||||
help='Specify the character encoding of the output document. '
|
||||
'The default is utf-8.'),
|
||||
OptionRecommendation(name='inline_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Add Table of Contents to beginning of the book.')),
|
||||
help='Add Table of Contents to beginning of the book.'),
|
||||
OptionRecommendation(name='max_line_length',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
help=_('The maximum number of characters per line. This splits on '
|
||||
'the first space before the specified value. If no space is found '
|
||||
'the line will be broken at the space after and will exceed the '
|
||||
'specified value. Also, there is a minimum of 25 characters. '
|
||||
'Use 0 to disable line splitting.')),
|
||||
help='The maximum number of characters per line. This splits on '
|
||||
'the first space before the specified value. If no space is '
|
||||
'found the line will be broken at the space after and will '
|
||||
'exceed the specified value. Also, there is a minimum of 25 '
|
||||
'characters. Use 0 to disable line splitting.'),
|
||||
OptionRecommendation(name='force_max_line_length',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Force splitting on the max-line-length value when no space '
|
||||
'is present. Also allows max-line-length to be below the minimum')),
|
||||
help='Force splitting on the max-line-length value when no space '
|
||||
'is present. Also allows max-line-length to be below the '
|
||||
'minimum'),
|
||||
OptionRecommendation(name='txt_output_formatting',
|
||||
recommended_value='plain',
|
||||
choices=list(ui_data['formatting_types']),
|
||||
help=_('Formatting used within the document.\n'
|
||||
help='Formatting used within the document.\n'
|
||||
'* plain: {plain}\n'
|
||||
'* markdown: {markdown}\n'
|
||||
'* textile: {textile}').format(**ui_data['formatting_types'])),
|
||||
'* textile: {textile}'
|
||||
''.format(**ui_data['formatting_types'])),
|
||||
OptionRecommendation(name='keep_links',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Do not remove links within the document. This is only '
|
||||
help='Do not remove links within the document. This is only '
|
||||
'useful when paired with a txt-output-formatting option that '
|
||||
'is not none because links are always removed with plain text output.')),
|
||||
'is not none because links are always removed with plain '
|
||||
'text output.'),
|
||||
OptionRecommendation(name='keep_image_references',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Do not remove image references within the document. This is only '
|
||||
'useful when paired with a txt-output-formatting option that '
|
||||
'is not none because links are always removed with plain text output.')),
|
||||
help='Do not remove image references within the document. This is '
|
||||
'only useful when paired with a txt-output-formatting option '
|
||||
'that is not none because links are always removed with '
|
||||
'plain text output.'),
|
||||
OptionRecommendation(name='keep_color',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Do not remove font color from output. This is only useful when '
|
||||
'txt-output-formatting is set to textile. Textile is the only '
|
||||
'formatting that supports setting font color. If this option is '
|
||||
'not specified font color will not be set and default to the '
|
||||
'color displayed by the reader (generally this is black).')),
|
||||
help='Do not remove font color from output. This is only useful '
|
||||
'when txt-output-formatting is set to textile. Textile is '
|
||||
'the only formatting that supports setting font color. If '
|
||||
'this option is not specified font color will not be set and '
|
||||
'default to the color displayed by the reader (generally '
|
||||
'this is black).')
|
||||
}
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
|
||||
@@ -110,74 +110,70 @@ class Plumber(object):
|
||||
OptionRecommendation(name='verbose',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
short_switch='v',
|
||||
help=_('Level of verbosity. Specify multiple times for greater '
|
||||
help='Level of verbosity. Specify multiple times for greater '
|
||||
'verbosity. Specifying it twice will result in full '
|
||||
'verbosity, once medium verbosity and zero times least verbosity.')
|
||||
'verbosity, once medium verbosity and zero times least verbosity.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='debug_pipeline',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
short_switch='d',
|
||||
help=_('Save the output from different stages of the conversion '
|
||||
help='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.')
|
||||
'of the conversion process a bug is occurring.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='input_profile',
|
||||
recommended_value='default', level=OptionRecommendation.LOW,
|
||||
choices=[x.short_name for x in input_profiles()],
|
||||
help=_('Specify the input profile. The input profile gives the '
|
||||
help='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:')+ ', '.join([
|
||||
'pixels). Choices are:'+ ', '.join([
|
||||
x.short_name for x in input_profiles()])
|
||||
),
|
||||
|
||||
OptionRecommendation(name='output_profile',
|
||||
recommended_value='default', level=OptionRecommendation.LOW,
|
||||
choices=[x.short_name for x in output_profiles()],
|
||||
help=_('Specify the output profile. The output profile '
|
||||
help='Specify the output profile. The output profile '
|
||||
'tells the conversion system how to optimize the '
|
||||
'created document for the specified device (such as by resizing images for the device screen size). In some cases, '
|
||||
'an output profile can be used to optimize the output for a particular device, but this is rarely necessary. '
|
||||
'Choices are:') + ', '.join([
|
||||
'Choices are:' + ', '.join([
|
||||
x.short_name for x in output_profiles()])
|
||||
),
|
||||
|
||||
OptionRecommendation(name='base_font_size',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
help=_('The base font size in pts. All font sizes in the produced book '
|
||||
help='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, when the value is zero, the base font size is chosen based on '
|
||||
'the output profile you chose.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='font_size_mapping',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Mapping from CSS font names to font sizes in pts. '
|
||||
help='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.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='disable_font_rescaling',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Disable all rescaling of font sizes.'
|
||||
)
|
||||
help='Disable all rescaling of font sizes.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='minimum_line_height',
|
||||
recommended_value=120.0, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'The minimum line height, as a percentage of the element\'s '
|
||||
help='The minimum line height, as a percentage of the element\'s '
|
||||
'calculated font size. calibre will ensure that every element '
|
||||
'has a line height of at least this setting, irrespective of '
|
||||
'what the input document specifies. Set to zero to disable. '
|
||||
@@ -185,134 +181,119 @@ OptionRecommendation(name='minimum_line_height',
|
||||
'the direct line height specification, unless you know what '
|
||||
'you are doing. For example, you can achieve "double spaced" '
|
||||
'text by setting this to 240.'
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
OptionRecommendation(name='line_height',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'The line height in pts. Controls spacing between consecutive '
|
||||
help='The line height in pts. Controls spacing between consecutive '
|
||||
'lines of text. Only applies to elements that do not define '
|
||||
'their own line height. In most cases, the minimum line height '
|
||||
'option is more useful. '
|
||||
'By default no line height manipulation is performed.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='embed_font_family',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'Embed the specified font family into the book. This specifies '
|
||||
help='Embed the specified font family into the book. This specifies '
|
||||
'the "base" font used for the book. If the input document '
|
||||
'specifies its own fonts, they may override this base font. '
|
||||
'You can use the filter style information option to remove fonts from the '
|
||||
'input document. Note that font embedding only works '
|
||||
'with some output formats, principally EPUB, AZW3 and DOCX.')
|
||||
'with some output formats, principally EPUB, AZW3 and DOCX.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='embed_all_fonts',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'Embed every font that is referenced in the input document '
|
||||
help='Embed every font that is referenced in the input document '
|
||||
'but not already embedded. This will search your system for the '
|
||||
'fonts, and if found, they will be embedded. Embedding will only work '
|
||||
'if the format you are converting to supports embedded fonts, such as '
|
||||
'EPUB, AZW3, DOCX or PDF. Please ensure that you have the proper license for embedding '
|
||||
'the fonts used in this document.'
|
||||
)),
|
||||
),
|
||||
|
||||
OptionRecommendation(name='subset_embedded_fonts',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'Subset all embedded fonts. Every embedded font is reduced '
|
||||
help='Subset all embedded fonts. Every embedded font is reduced '
|
||||
'to contain only the glyphs used in this document. This decreases '
|
||||
'the size of the font files. Useful if you are embedding a '
|
||||
'particularly large font with lots of unused glyphs.')
|
||||
'particularly large font with lots of unused glyphs.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='linearize_tables',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Some badly designed documents use tables to control the '
|
||||
help='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.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='level1_toc',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('XPath expression that specifies all tags that '
|
||||
help='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.'
|
||||
' See the XPath Tutorial in the calibre User Manual for examples.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='level2_toc',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('XPath expression that specifies all tags that should be '
|
||||
help='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.'
|
||||
' See the XPath Tutorial in the calibre User Manual for examples.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='level3_toc',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('XPath expression that specifies all tags that should be '
|
||||
help='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.'
|
||||
' See the XPath Tutorial in the calibre User Manual for examples.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='use_auto_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Normally, if the source file already has a Table of '
|
||||
help='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.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='no_chapters_in_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_("Don't add auto-detected chapters to the Table of "
|
||||
help="Don't add auto-detected chapters to the Table of "
|
||||
'Contents.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='toc_threshold',
|
||||
recommended_value=6, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'If fewer than this number of chapters is detected, then links '
|
||||
'are added to the Table of Contents. Default: %default')
|
||||
help='If fewer than this number of chapters is detected, then links '
|
||||
'are added to the Table of Contents. Default: %default'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='max_toc_links',
|
||||
recommended_value=50, level=OptionRecommendation.LOW,
|
||||
help=_('Maximum number of links to insert into the TOC. Set to 0 '
|
||||
help='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.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='toc_filter',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Remove entries from the Table of Contents whose titles '
|
||||
help='Remove entries from the Table of Contents whose titles '
|
||||
'match the specified regular expression. Matching entries and all '
|
||||
'their children are removed.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='duplicate_links_in_toc',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('When creating a TOC from links in the input document, '
|
||||
help='When creating a TOC from links in the input document, '
|
||||
'allow duplicate entries, i.e. allow more than one entry '
|
||||
'with the same text, provided that they point to a '
|
||||
'different location.')
|
||||
'different location.'
|
||||
),
|
||||
|
||||
|
||||
@@ -320,7 +301,7 @@ OptionRecommendation(name='chapter',
|
||||
recommended_value="//*[((name()='h1' or name()='h2') and "
|
||||
r"re:test(., '\s*((chapter|book|section|part)\s+)|((prolog|prologue|epilogue)(\s+|$))', 'i')) or @class "
|
||||
"= 'chapter']", level=OptionRecommendation.LOW,
|
||||
help=_('An XPath expression to detect chapter titles. The default '
|
||||
help='An XPath expression to detect chapter titles. The default '
|
||||
'is to consider <h1> or <h2> tags that contain the words '
|
||||
'"chapter", "book", "section", "prologue", "epilogue" or "part" as chapter titles as '
|
||||
'well as any tags that have class="chapter". The expression '
|
||||
@@ -328,390 +309,380 @@ OptionRecommendation(name='chapter',
|
||||
'detection, use the expression "/". See the XPath Tutorial '
|
||||
'in the calibre User Manual for further help on using this '
|
||||
'feature.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='chapter_mark',
|
||||
recommended_value='pagebreak', level=OptionRecommendation.LOW,
|
||||
choices=['pagebreak', 'rule', 'both', 'none'],
|
||||
help=_('Specify how to mark detected chapters. A value of '
|
||||
help='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.')
|
||||
'to mark chapters.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='start_reading_at',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('An XPath expression to detect the location in the document'
|
||||
help='An XPath expression to detect the location in the document'
|
||||
' at which to start reading. Some e-book reading programs'
|
||||
' (most prominently the Kindle) use this location as the'
|
||||
' position at which to open the book. See the XPath tutorial'
|
||||
' in the calibre User Manual for further help using this'
|
||||
' feature.')
|
||||
' feature.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='extra_css',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Either the path to a CSS stylesheet or raw CSS. '
|
||||
help='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.')
|
||||
'rules.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='transform_css_rules',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Rules for transforming the styles in this book. These'
|
||||
' rules are applied after all other CSS processing is done.')
|
||||
help='Rules for transforming the styles in this book. These'
|
||||
' rules are applied after all other CSS processing is done.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='filter_css',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('A comma separated list of CSS properties that '
|
||||
help='A comma separated list of CSS properties that '
|
||||
'will be removed from all CSS style rules. This is useful '
|
||||
'if the presence of some style information prevents it '
|
||||
'from being overridden on your device. '
|
||||
'For example: '
|
||||
'font-family,color,margin-left,margin-right')
|
||||
'font-family,color,margin-left,margin-right'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='expand_css',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'By default, calibre will use the shorthand form for various'
|
||||
help='By default, calibre will use the shorthand form for various'
|
||||
' CSS properties such as margin, padding, border, etc. This'
|
||||
' option will cause it to use the full expanded form instead.'
|
||||
' Note that CSS is always expanded when generating EPUB files'
|
||||
' with the output profile set to one of the Nook profiles'
|
||||
' as the Nook cannot handle shorthand CSS.')
|
||||
' as the Nook cannot handle shorthand CSS.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='page_breaks_before',
|
||||
recommended_value="//*[name()='h1' or name()='h2']",
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('An XPath expression. Page breaks are inserted '
|
||||
'before the specified elements. To disable use the expression: /')
|
||||
help='An XPath expression. Page breaks are inserted '
|
||||
'before the specified elements. To disable use the expression: /'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='remove_fake_margins',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Some documents specify page margins by '
|
||||
help='Some documents specify page margins by '
|
||||
'specifying a left and right margin on each individual '
|
||||
'paragraph. calibre will try to detect and remove these '
|
||||
'margins. Sometimes, this can cause the removal of '
|
||||
'margins that should not have been removed. In this '
|
||||
'case you can disable the removal.')
|
||||
'case you can disable the removal.'
|
||||
),
|
||||
|
||||
|
||||
OptionRecommendation(name='margin_top',
|
||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||
help=_('Set the top margin in pts. Default is %default. '
|
||||
help='Set the top margin in pts. Default is %default. '
|
||||
'Setting this to less than zero will cause no margin to be set '
|
||||
'(the margin setting in the original document will be preserved). '
|
||||
'Note: Page oriented formats such as PDF and DOCX have their own'
|
||||
' margin settings that take precedence.')),
|
||||
' margin settings that take precedence.'),
|
||||
|
||||
OptionRecommendation(name='margin_bottom',
|
||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||
help=_('Set the bottom margin in pts. Default is %default. '
|
||||
help='Set the bottom margin in pts. Default is %default. '
|
||||
'Setting this to less than zero will cause no margin to be set '
|
||||
'(the margin setting in the original document will be preserved). '
|
||||
'Note: Page oriented formats such as PDF and DOCX have their own'
|
||||
' margin settings that take precedence.')),
|
||||
' margin settings that take precedence.'),
|
||||
|
||||
OptionRecommendation(name='margin_left',
|
||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||
help=_('Set the left margin in pts. Default is %default. '
|
||||
help='Set the left margin in pts. Default is %default. '
|
||||
'Setting this to less than zero will cause no margin to be set '
|
||||
'(the margin setting in the original document will be preserved). '
|
||||
'Note: Page oriented formats such as PDF and DOCX have their own'
|
||||
' margin settings that take precedence.')),
|
||||
' margin settings that take precedence.'),
|
||||
|
||||
OptionRecommendation(name='margin_right',
|
||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||
help=_('Set the right margin in pts. Default is %default. '
|
||||
help='Set the right margin in pts. Default is %default. '
|
||||
'Setting this to less than zero will cause no margin to be set '
|
||||
'(the margin setting in the original document will be preserved). '
|
||||
'Note: Page oriented formats such as PDF and DOCX have their own'
|
||||
' margin settings that take precedence.')),
|
||||
' margin settings that take precedence.'),
|
||||
|
||||
OptionRecommendation(name='change_justification',
|
||||
recommended_value='original', level=OptionRecommendation.LOW,
|
||||
choices=['left','justify','original'],
|
||||
help=_('Change text justification. A value of "left" converts all'
|
||||
help='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.')),
|
||||
'justification.'),
|
||||
|
||||
OptionRecommendation(name='remove_paragraph_spacing',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Remove spacing between paragraphs. Also sets an indent on '
|
||||
help='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).')
|
||||
'if the source file does not use paragraphs (<p> or <div> tags).'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='remove_paragraph_spacing_indent_size',
|
||||
recommended_value=1.5, level=OptionRecommendation.LOW,
|
||||
help=_('When calibre removes blank lines between paragraphs, it automatically '
|
||||
help='When calibre removes blank lines between paragraphs, it automatically '
|
||||
'sets a paragraph indent, to ensure that paragraphs can be easily '
|
||||
'distinguished. This option controls the width of that indent (in em). '
|
||||
'If you set this value negative, then the indent specified in the input '
|
||||
'document is used, that is, calibre does not change the indentation.')
|
||||
'document is used, that is, calibre does not change the indentation.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='prefer_metadata_cover',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Use the cover detected from the source file in preference '
|
||||
'to the specified cover.')
|
||||
help='Use the cover detected from the source file in preference '
|
||||
'to the specified cover.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='insert_blank_line',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Insert a blank line between paragraphs. Will not work '
|
||||
help='Insert a blank line between paragraphs. Will not work '
|
||||
'if the source file does not use paragraphs (<p> or <div> tags).'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='insert_blank_line_size',
|
||||
recommended_value=0.5, level=OptionRecommendation.LOW,
|
||||
help=_('Set the height of the inserted blank lines (in em).'
|
||||
help='Set the height of the inserted blank lines (in em).'
|
||||
' The height of the lines between paragraphs will be twice the value'
|
||||
' set here.')
|
||||
' set here.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='remove_first_image',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Remove the first image from the input e-book. Useful if the '
|
||||
help='Remove the first image from the input e-book. Useful if the '
|
||||
'input document has a cover image that is not identified as a cover. '
|
||||
'In this case, if you set a cover in calibre, the output document will '
|
||||
'end up with two cover images if you do not specify this option.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='insert_metadata',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Insert the book metadata at the start of '
|
||||
help='Insert the book metadata at the start of '
|
||||
'the book. This is useful if your e-book reader does not support '
|
||||
'displaying/searching metadata directly.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='smarten_punctuation',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Convert plain quotes, dashes and ellipsis to their '
|
||||
help='Convert plain quotes, dashes and ellipsis to their '
|
||||
'typographically correct equivalents. For details, see '
|
||||
'https://daringfireball.net/projects/smartypants'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='unsmarten_punctuation',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Convert fancy quotes, dashes and ellipsis to their '
|
||||
help='Convert fancy quotes, dashes and ellipsis to their '
|
||||
'plain equivalents.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='read_metadata_from_opf',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
short_switch='m',
|
||||
help=_('Read metadata from the specified OPF file. Metadata read '
|
||||
help='Read metadata from the specified OPF file. Metadata read '
|
||||
'from this file will override any metadata in the source '
|
||||
'file.')
|
||||
'file.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='asciiize',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=(_('Transliterate unicode characters to an ASCII '
|
||||
help='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 based on the current calibre interface language will be '
|
||||
'used.')%
|
||||
'used.' %
|
||||
'\u041c\u0438\u0445\u0430\u0438\u043b '
|
||||
'\u0413\u043e\u0440\u0431\u0430\u0447\u0451\u0432'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='keep_ligatures',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Preserve ligatures present in the input document. '
|
||||
help='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.')
|
||||
'characters. This option will preserve them instead.'
|
||||
),
|
||||
|
||||
OptionRecommendation(name='title',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the title.')),
|
||||
help='Set the title.'),
|
||||
|
||||
OptionRecommendation(name='authors',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the authors. Multiple authors should be separated by '
|
||||
'ampersands.')),
|
||||
help='Set the authors. Multiple authors should be separated by '
|
||||
'ampersands.'),
|
||||
|
||||
OptionRecommendation(name='title_sort',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('The version of the title to be used for sorting. ')),
|
||||
help='The version of the title to be used for sorting. '),
|
||||
|
||||
OptionRecommendation(name='author_sort',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('String to be used when sorting by author. ')),
|
||||
help='String to be used when sorting by author. '),
|
||||
|
||||
OptionRecommendation(name='cover',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the cover to the specified file or URL')),
|
||||
help='Set the cover to the specified file or URL'),
|
||||
|
||||
OptionRecommendation(name='comments',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the e-book description.')),
|
||||
help='Set the e-book description.'),
|
||||
|
||||
OptionRecommendation(name='publisher',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the e-book publisher.')),
|
||||
help='Set the e-book publisher.'),
|
||||
|
||||
OptionRecommendation(name='series',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the series this e-book belongs to.')),
|
||||
help='Set the series this e-book belongs to.'),
|
||||
|
||||
OptionRecommendation(name='series_index',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the index of the book in this series.')),
|
||||
help='Set the index of the book in this series.'),
|
||||
|
||||
OptionRecommendation(name='rating',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the rating. Should be a number between 1 and 5.')),
|
||||
help='Set the rating. Should be a number between 1 and 5.'),
|
||||
|
||||
OptionRecommendation(name='isbn',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the ISBN of the book.')),
|
||||
help='Set the ISBN of the book.'),
|
||||
|
||||
OptionRecommendation(name='tags',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the tags for the book. Should be a comma separated list.')),
|
||||
help='Set the tags for the book. Should be a comma separated list.'),
|
||||
|
||||
OptionRecommendation(name='book_producer',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the book producer.')),
|
||||
help='Set the book producer.'),
|
||||
|
||||
OptionRecommendation(name='language',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the language.')),
|
||||
help='Set the language.'),
|
||||
|
||||
OptionRecommendation(name='pubdate',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the publication date (assumed to be in the local timezone, unless the timezone is explicitly specified)')),
|
||||
help='Set the publication date (assumed to be in the local timezone, unless the timezone is explicitly specified)'),
|
||||
|
||||
OptionRecommendation(name='timestamp',
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help=_('Set the book timestamp (no longer used anywhere)')),
|
||||
help='Set the book timestamp (no longer used anywhere)'),
|
||||
|
||||
OptionRecommendation(name='enable_heuristics',
|
||||
recommended_value=False, level=OptionRecommendation.LOW,
|
||||
help=_('Enable heuristic processing. This option must be set for any '
|
||||
'heuristic processing to take place.')),
|
||||
help='Enable heuristic processing. This option must be set for any '
|
||||
'heuristic processing to take place.'),
|
||||
|
||||
OptionRecommendation(name='markup_chapter_headings',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Detect unformatted chapter headings and sub headings. Change '
|
||||
help='Detect unformatted chapter headings and sub headings. Change '
|
||||
'them to h2 and h3 tags. This setting will not create a TOC, '
|
||||
'but can be used in conjunction with structure detection to create '
|
||||
'one.')),
|
||||
'one.'),
|
||||
|
||||
OptionRecommendation(name='italicize_common_cases',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Look for common words and patterns that denote '
|
||||
'italics and italicize them.')),
|
||||
help='Look for common words and patterns that denote '
|
||||
'italics and italicize them.'),
|
||||
|
||||
OptionRecommendation(name='fix_indents',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Turn indentation created from multiple non-breaking space entities '
|
||||
'into CSS indents.')),
|
||||
help='Turn indentation created from multiple non-breaking space entities '
|
||||
'into CSS indents.'),
|
||||
|
||||
OptionRecommendation(name='html_unwrap_factor',
|
||||
recommended_value=0.40, level=OptionRecommendation.LOW,
|
||||
help=_('Scale used to determine the length at which a line should '
|
||||
help='Scale used to determine the length at which a line should '
|
||||
'be unwrapped. Valid values are a decimal between 0 and 1. The '
|
||||
'default is 0.4, just below the median line length. If only a '
|
||||
'few lines in the document require unwrapping this value should '
|
||||
'be reduced')),
|
||||
'be reduced'),
|
||||
|
||||
OptionRecommendation(name='unwrap_lines',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Unwrap lines using punctuation and other formatting clues.')),
|
||||
help='Unwrap lines using punctuation and other formatting clues.'),
|
||||
|
||||
OptionRecommendation(name='delete_blank_paragraphs',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Remove empty paragraphs from the document when they exist between '
|
||||
'every other paragraph')),
|
||||
help='Remove empty paragraphs from the document when they exist between '
|
||||
'every other paragraph'),
|
||||
|
||||
OptionRecommendation(name='format_scene_breaks',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Left aligned scene break markers are center aligned. '
|
||||
'Replace soft scene breaks that use multiple blank lines with '
|
||||
'horizontal rules.')),
|
||||
help='Left aligned scene break markers are center aligned. Replace soft '
|
||||
'scene breaks that use multiple blank lines with horizontal rules.'),
|
||||
|
||||
OptionRecommendation(name='replace_scene_breaks',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Replace scene breaks with the specified text. By default, the '
|
||||
'text from the input document is used.')),
|
||||
help='Replace scene breaks with the specified text. By default, the text '
|
||||
'from the input document is used.'),
|
||||
|
||||
OptionRecommendation(name='dehyphenate',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Analyze hyphenated words throughout the document. The '
|
||||
'document itself is used as a dictionary to determine whether hyphens '
|
||||
'should be retained or removed.')),
|
||||
help='Analyze hyphenated words throughout the document. The document '
|
||||
'itself is used as a dictionary to determine whether hyphens should '
|
||||
'be retained or removed.'),
|
||||
|
||||
OptionRecommendation(name='renumber_headings',
|
||||
recommended_value=True, level=OptionRecommendation.LOW,
|
||||
help=_('Looks for occurrences of sequential <h1> or <h2> tags. '
|
||||
'The tags are renumbered to prevent splitting in the middle '
|
||||
'of chapter headings.')),
|
||||
help='Looks for occurrences of sequential <h1> or <h2> tags. The tags are '
|
||||
'renumbered to prevent splitting in the middle of chapter headings.'),
|
||||
|
||||
OptionRecommendation(name='sr1_search',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Search pattern (regular expression) to be replaced with '
|
||||
'sr1-replace.')),
|
||||
help='Search pattern (regular expression) to be replaced with '
|
||||
'sr1-replace.'),
|
||||
|
||||
OptionRecommendation(name='sr1_replace',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Replacement to replace the text found with sr1-search.')),
|
||||
help='Replacement to replace the text found with sr1-search.'),
|
||||
|
||||
OptionRecommendation(name='sr2_search',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Search pattern (regular expression) to be replaced with '
|
||||
'sr2-replace.')),
|
||||
help='Search pattern (regular expression) to be replaced with '
|
||||
'sr2-replace.'),
|
||||
|
||||
OptionRecommendation(name='sr2_replace',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Replacement to replace the text found with sr2-search.')),
|
||||
help='Replacement to replace the text found with sr2-search.'),
|
||||
|
||||
OptionRecommendation(name='sr3_search',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Search pattern (regular expression) to be replaced with '
|
||||
'sr3-replace.')),
|
||||
help='Search pattern (regular expression) to be replaced with '
|
||||
'sr3-replace.'),
|
||||
|
||||
OptionRecommendation(name='sr3_replace',
|
||||
recommended_value='', level=OptionRecommendation.LOW,
|
||||
help=_('Replacement to replace the text found with sr3-search.')),
|
||||
help='Replacement to replace the text found with sr3-search.'),
|
||||
|
||||
OptionRecommendation(name='search_replace',
|
||||
recommended_value=None, level=OptionRecommendation.LOW, help=_(
|
||||
'Path to a file containing search and replace regular expressions. '
|
||||
recommended_value=None, level=OptionRecommendation.LOW,
|
||||
help='Path to a file containing search and replace regular expressions. '
|
||||
'The file must contain alternating lines of regular expression '
|
||||
'followed by replacement pattern (which can be an empty line). '
|
||||
'The regular expression must be in the Python regex syntax and '
|
||||
'the file must be UTF-8 encoded.')),
|
||||
'the file must be UTF-8 encoded.'),
|
||||
]
|
||||
# }}}
|
||||
|
||||
@@ -818,7 +789,7 @@ OptionRecommendation(name='search_replace',
|
||||
html_pat = re.compile(r'\.(x){0,1}htm(l){0,1}$', re.IGNORECASE)
|
||||
html_files = [f for f in files if html_pat.search(f) is not None]
|
||||
if not html_files:
|
||||
raise ValueError(_('Could not find an e-book inside the archive'))
|
||||
raise ValueError('Could not find an e-book inside the archive')
|
||||
html_files = [(f, os.stat(f).st_size) for f in html_files]
|
||||
html_files.sort(key=lambda x: x[1])
|
||||
html_files = [f[0] for f in html_files]
|
||||
@@ -908,14 +879,14 @@ OptionRecommendation(name='search_replace',
|
||||
try:
|
||||
val = float(val)
|
||||
except ValueError:
|
||||
self.log.warn(_('Values of series index and rating must'
|
||||
' be numbers. Ignoring'), val)
|
||||
self.log.warn('Values of series index and rating must'
|
||||
' be numbers. Ignoring', val)
|
||||
continue
|
||||
elif x in ('timestamp', 'pubdate'):
|
||||
try:
|
||||
val = parse_date(val, assume_utc=x=='timestamp')
|
||||
except:
|
||||
self.log.exception(_('Failed to parse date/time') + ' ' + str(val))
|
||||
self.log.exception('Failed to parse date/time %s', val)
|
||||
continue
|
||||
setattr(mi, x, val)
|
||||
|
||||
@@ -1095,7 +1066,7 @@ OptionRecommendation(name='search_replace',
|
||||
self.flush()
|
||||
return
|
||||
|
||||
self.ui_reporter(0.01, _('Converting input to HTML...'))
|
||||
self.ui_reporter(0.01, 'Converting input to HTML...')
|
||||
ir = CompositeProgressReporter(0.01, 0.34, self.ui_reporter)
|
||||
self.input_plugin.report_progress = ir
|
||||
if self.for_regex_wizard:
|
||||
@@ -1129,7 +1100,7 @@ OptionRecommendation(name='search_replace',
|
||||
self.input_plugin.specialize(self.oeb, self.opts, self.log,
|
||||
self.output_fmt)
|
||||
|
||||
pr(0., _('Running transforms on e-book...'))
|
||||
pr(0., 'Running transforms on e-book...')
|
||||
|
||||
self.oeb.plumber_output_format = self.output_fmt or ''
|
||||
|
||||
@@ -1266,7 +1237,7 @@ OptionRecommendation(name='search_replace',
|
||||
self.log.info('Creating %s...'%self.output_plugin.name)
|
||||
our = CompositeProgressReporter(0.67, 1., self.ui_reporter)
|
||||
self.output_plugin.report_progress = our
|
||||
our(0., _('Running %s plugin')%self.output_plugin.name)
|
||||
our(0., 'Running %s plugin' % self.output_plugin.name)
|
||||
with self.output_plugin:
|
||||
self.output_plugin.convert(self.oeb, self.output, self.input_plugin,
|
||||
self.opts, self.log)
|
||||
|
||||
@@ -261,9 +261,8 @@ def format_fields(mi, prefs):
|
||||
f = formatter()
|
||||
|
||||
def safe_format(field):
|
||||
return f.safe_format(
|
||||
getattr(prefs, field), mi, _('Template error'), mi, template_cache=_template_cache
|
||||
)
|
||||
return f.safe_format(getattr(prefs, field), mi, 'Template error', mi,
|
||||
template_cache=_template_cache)
|
||||
return map(safe_format, ('title_template', 'subtitle_template', 'footer_template'))
|
||||
|
||||
|
||||
@@ -285,7 +284,7 @@ def preserve_fields(obj, fields):
|
||||
|
||||
def format_text(mi, prefs):
|
||||
with preserve_fields(mi, 'authors formatted_series_index'):
|
||||
mi.authors = [a for a in mi.authors if a != _('Unknown')]
|
||||
mi.authors = [a for a in mi.authors if a != 'Unknown']
|
||||
mi.formatted_series_index = fmt_sidx(mi.series_index or 0, use_roman=get_use_roman())
|
||||
return tuple(format_fields(mi, prefs))
|
||||
# }}}
|
||||
@@ -358,7 +357,6 @@ class Style(object):
|
||||
class Cross(Style):
|
||||
|
||||
NAME = 'The Cross'
|
||||
GUI_NAME = _('The Cross')
|
||||
|
||||
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
|
||||
painter.fillRect(rect, self.color1)
|
||||
@@ -379,7 +377,6 @@ class Cross(Style):
|
||||
class Half(Style):
|
||||
|
||||
NAME = 'Half and Half'
|
||||
GUI_NAME = _('Half and half')
|
||||
|
||||
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
|
||||
g = QLinearGradient(QPointF(0, 0), QPointF(0, rect.height()))
|
||||
@@ -404,7 +401,6 @@ def draw_curved_line(painter_path, dx, dy, c1_frac, c1_amp, c2_frac, c2_amp):
|
||||
class Banner(Style):
|
||||
|
||||
NAME = 'Banner'
|
||||
GUI_NAME = _('Banner')
|
||||
GRADE = 0.07
|
||||
|
||||
def calculate_margins(self, prefs):
|
||||
@@ -474,7 +470,6 @@ class Banner(Style):
|
||||
class Ornamental(Style):
|
||||
|
||||
NAME = 'Ornamental'
|
||||
GUI_NAME = _('Ornamental')
|
||||
|
||||
# SVG vectors {{{
|
||||
CORNER_VECTOR = "m 67.791903,64.260958 c -4.308097,-2.07925 -4.086719,-8.29575 0.334943,-9.40552 4.119758,-1.03399 8.732363,5.05239 5.393055,7.1162 -0.55,0.33992 -1,1.04147 -1,1.55902 0,1.59332 2.597425,1.04548 5.365141,-1.1316 1.999416,-1.57274 2.634859,-2.96609 2.634859,-5.7775 0,-9.55787 -9.827495,-13.42961 -24.43221,-9.62556 -3.218823,0.83839 -5.905663,1.40089 -5.970755,1.25 -0.06509,-0.1509 -0.887601,-1.19493 -1.827799,-2.32007 -1.672708,-2.00174 -1.636693,-2.03722 1.675668,-1.65052 1.861815,0.21736 6.685863,-0.35719 10.720107,-1.27678 12.280767,-2.79934 20.195487,-0.0248 22.846932,8.0092 3.187273,9.65753 -6.423297,17.7497 -15.739941,13.25313 z m 49.881417,-20.53932 c -3.19204,-2.701 -3.72967,-6.67376 -1.24009,-9.16334 2.48236,-2.48236 5.35141,-2.67905 7.51523,-0.51523 1.85966,1.85966 2.07045,6.52954 0.37143,8.22857 -2.04025,2.04024 3.28436,1.44595 6.92316,-0.77272 9.66959,-5.89579 0.88581,-18.22422 -13.0777,-18.35516 -5.28594,-0.0496 -10.31098,1.88721 -14.26764,5.4991 -1.98835,1.81509 -2.16454,1.82692 -2.7936,0.18763 -0.40973,-1.06774 0.12141,-2.82197 1.3628,-4.50104 2.46349,-3.33205 1.67564,-4.01299 -2.891784,-2.49938 -2.85998,0.94777 -3.81038,2.05378 -5.59837,6.51495 -1.184469,2.95536 -3.346819,6.86882 -4.805219,8.69657 -1.4584,1.82776 -2.65164,4.02223 -2.65164,4.87662 0,3.24694 -4.442667,0.59094 -5.872557,-3.51085 -1.361274,-3.90495 0.408198,-8.63869 4.404043,-11.78183 5.155844,-4.05558 1.612374,-3.42079 -9.235926,1.65457 -12.882907,6.02725 -16.864953,7.18038 -24.795556,7.18038 -8.471637,0 -13.38802,-1.64157 -17.634617,-5.88816 -2.832233,-2.83224 -3.849773,-4.81378 -4.418121,-8.6038 -1.946289,-12.9787795 8.03227,-20.91713135 19.767685,-15.7259993 5.547225,2.4538018 6.993631,6.1265383 3.999564,10.1557393 -5.468513,7.35914 -15.917883,-0.19431 -10.657807,-7.7041155 1.486298,-2.1219878 1.441784,-2.2225068 -0.984223,-2.2225068 -1.397511,0 -4.010527,1.3130878 -5.806704,2.9179718 -2.773359,2.4779995 -3.265777,3.5977995 -3.265777,7.4266705 0,5.10943 2.254112,8.84197 7.492986,12.40748 8.921325,6.07175 19.286666,5.61396 37.12088,-1.63946 15.35037,-6.24321 21.294999,-7.42408 34.886123,-6.92999 11.77046,0.4279 19.35803,3.05537 24.34054,8.42878 4.97758,5.3681 2.53939,13.58271 -4.86733,16.39873 -4.17361,1.58681 -11.00702,1.19681 -13.31978,-0.76018 z m 26.50156,-0.0787 c -2.26347,-2.50111 -2.07852,-7.36311 0.39995,-10.51398 2.68134,-3.40877 10.49035,-5.69409 18.87656,-5.52426 l 6.5685,0.13301 -7.84029,0.82767 c -8.47925,0.89511 -12.76997,2.82233 -16.03465,7.20213 -1.92294,2.57976 -1.96722,3.00481 -0.57298,5.5 1.00296,1.79495 2.50427,2.81821 4.46514,3.04333 2.92852,0.33623 2.93789,0.32121 1.08045,-1.73124 -1.53602,-1.69728 -1.64654,-2.34411 -0.61324,-3.58916 2.84565,-3.4288 7.14497,-0.49759 5.03976,3.43603 -1.86726,3.48903 -8.65528,4.21532 -11.3692,1.21647 z m -4.17462,-14.20302 c -0.38836,-0.62838 -0.23556,-1.61305 0.33954,-2.18816 1.3439,-1.34389 4.47714,-0.17168 3.93038,1.47045 -0.5566,1.67168 -3.38637,2.14732 -4.26992,0.71771 z m -8.48037,-9.1829 c -12.462,-4.1101 -12.53952,-4.12156 -25.49998,-3.7694 -24.020921,0.65269 -32.338219,0.31756 -37.082166,-1.49417 -5.113999,-1.95305 -8.192504,-6.3647405 -6.485463,-9.2940713 0.566827,-0.972691 1.020091,-1.181447 1.037211,-0.477701 0.01685,0.692606 1.268676,1.2499998 2.807321,1.2499998 1.685814,0 4.868609,1.571672 8.10041,4.0000015 4.221481,3.171961 6.182506,3.999221 9.473089,3.996261 l 4.149585,-0.004 -3.249996,-1.98156 c -3.056252,-1.863441 -4.051566,-3.8760635 -2.623216,-5.3044145 0.794,-0.794 6.188222,1.901516 9.064482,4.5295635 1.858669,1.698271 3.461409,1.980521 10.559493,1.859621 11.30984,-0.19266 20.89052,1.29095 31.97905,4.95208 7.63881,2.52213 11.51931,3.16471 22.05074,3.65141 7.02931,0.32486 13.01836,0.97543 13.30902,1.44571 0.29065,0.47029 -5.2356,0.83436 -12.28056,0.80906 -12.25942,-0.044 -13.34537,-0.2229 -25.30902,-4.16865 z" # noqa
|
||||
@@ -541,7 +536,6 @@ class Ornamental(Style):
|
||||
class Blocks(Style):
|
||||
|
||||
NAME = 'Blocks'
|
||||
GUI_NAME = _('Blocks')
|
||||
FOOTER_ALIGN = Qt.AlignRight | Qt.AlignTop
|
||||
|
||||
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
|
||||
|
||||
@@ -222,7 +222,7 @@ class DOCX(object):
|
||||
|
||||
@property
|
||||
def metadata(self):
|
||||
mi = Metadata(_('Unknown'))
|
||||
mi = Metadata('Unknown')
|
||||
dp_name, ap_name = self.get_document_properties_names()
|
||||
if dp_name:
|
||||
try:
|
||||
|
||||
@@ -61,7 +61,7 @@ class Convert(object):
|
||||
self.ws_pat = re.compile(r'[\n\r\t]')
|
||||
self.log = self.docx.log
|
||||
self.detect_cover = detect_cover
|
||||
self.notes_text = notes_text or _('Notes')
|
||||
self.notes_text = notes_text or 'Notes'
|
||||
self.notes_nopb = notes_nopb
|
||||
self.nosupsub = nosupsub
|
||||
self.dest_dir = dest_dir or os.getcwd()
|
||||
@@ -77,7 +77,7 @@ class Convert(object):
|
||||
self.html = HTML(
|
||||
HEAD(
|
||||
META(charset='utf-8'),
|
||||
TITLE(self.mi.title or _('Unknown')),
|
||||
TITLE(self.mi.title or 'Unknown'),
|
||||
LINK(rel='stylesheet', type='text/css', href='docx.css'),
|
||||
),
|
||||
self.body
|
||||
@@ -390,8 +390,9 @@ class Convert(object):
|
||||
|
||||
def process_guide(E, guide):
|
||||
if self.toc_anchor is not None:
|
||||
guide.append(E.reference(
|
||||
href='index.html#' + self.toc_anchor, title=_('Table of Contents'), type='toc'))
|
||||
guide.append(E.reference(href='index.html#' + self.toc_anchor,
|
||||
title='Table of Contents',
|
||||
type='toc'))
|
||||
toc_file = os.path.join(self.dest_dir, 'toc.ncx')
|
||||
with open(os.path.join(self.dest_dir, 'metadata.opf'), 'wb') as of, open(toc_file, 'wb') as ncx:
|
||||
opf.render(of, ncx, 'toc.ncx', process_guide=process_guide)
|
||||
|
||||
@@ -202,7 +202,8 @@ class ImagesManager(object):
|
||||
makeelement(parent, 'wp:extent', cx=str(width), cy=str(height))
|
||||
makeelement(parent, 'wp:effectExtent', l='0', r='0', t='0', b='0')
|
||||
makeelement(parent, 'wp:wrapTopAndBottom')
|
||||
self.create_docx_image_markup(parent, 'cover.jpg', _('Cover'), img.rid, width, height)
|
||||
self.create_docx_image_markup(parent, 'cover.jpg', 'Cover', img.rid,
|
||||
width, height)
|
||||
return ans
|
||||
|
||||
def write_cover_block(self, body, cover_image):
|
||||
|
||||
@@ -161,7 +161,7 @@ class LinksManager(object):
|
||||
pbb.set('{%s}val' % self.namespace.namespaces['w'], 'on')
|
||||
for block in reversed(self.toc):
|
||||
block.serialize(body, self.namespace.makeelement)
|
||||
title = __('Table of Contents')
|
||||
title = 'Table of Contents'
|
||||
makeelement = self.namespace.makeelement
|
||||
p = makeelement(body, 'w:p', append=False)
|
||||
ppr = makeelement(p, 'w:pPr')
|
||||
|
||||
@@ -12,11 +12,11 @@ __docformat__ = 'restructuredtext en'
|
||||
class HTML2ZIP(FileTypePlugin):
|
||||
name = 'HTML to ZIP'
|
||||
author = 'Kovid Goyal'
|
||||
description = textwrap.dedent(_('''\
|
||||
Follow all local links in an HTML file and create a ZIP \
|
||||
file containing all linked files. This plugin is run \
|
||||
every time you add an HTML file to the library.\
|
||||
'''))
|
||||
description = textwrap.dedent('''\
|
||||
Follow all local links in an HTML file and create a ZIP \
|
||||
file containing all linked files. This plugin is run \
|
||||
every time you add an HTML file to the library.\
|
||||
''')
|
||||
version = numeric_version
|
||||
file_types = {'html', 'htm', 'xhtml', 'xhtm', 'shtm', 'shtml'}
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
@@ -60,8 +60,8 @@ every time you add an HTML file to the library.\
|
||||
return of.name
|
||||
|
||||
def customization_help(self, gui=False):
|
||||
return _('Character encoding for the input HTML files. Common choices '
|
||||
'include: cp1252, cp1251, latin1 and utf-8.')
|
||||
return 'Character encoding for the input HTML files. Common choices '
|
||||
'include: cp1252, cp1251, latin1 and utf-8.'
|
||||
|
||||
def do_user_config(self, parent=None):
|
||||
'''
|
||||
@@ -81,7 +81,7 @@ every time you add an HTML file to the library.\
|
||||
|
||||
button_box.accepted.connect(config_dialog.accept)
|
||||
button_box.rejected.connect(config_dialog.reject)
|
||||
config_dialog.setWindowTitle(_('Customize') + ' ' + self.name)
|
||||
config_dialog.setWindowTitle('Customize' + ' ' + self.name)
|
||||
from ebook_converter.customize.ui import (plugin_customization,
|
||||
customize_plugin)
|
||||
help_text = self.customization_help(gui=True)
|
||||
@@ -90,11 +90,12 @@ every time you add an HTML file to the library.\
|
||||
help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard)
|
||||
help_text.setOpenExternalLinks(True)
|
||||
v.addWidget(help_text)
|
||||
bf = QCheckBox(_('Add linked files in breadth first order'))
|
||||
bf.setToolTip(_('Normally, when following links in HTML files'
|
||||
' calibre does it depth first, i.e. if file A links to B and '
|
||||
' C, but B links to D, the files are added in the order A, B, D, C. '
|
||||
' With this option, they will instead be added as A, B, C, D'))
|
||||
bf = QCheckBox('Add linked files in breadth first order')
|
||||
bf.setToolTip('Normally, when following links in HTML files calibre '
|
||||
'does it depth first, i.e. if file A links to B and C, '
|
||||
'but B links to D, the files are added in the order A, '
|
||||
'B, D, C. With this option, they will instead be added '
|
||||
'as A, B, C, D')
|
||||
sc = plugin_customization(self)
|
||||
if not sc:
|
||||
sc = ''
|
||||
|
||||
@@ -45,7 +45,7 @@ class OEB2HTML(object):
|
||||
try:
|
||||
self.book_title = str(oeb_book.metadata.title[0])
|
||||
except Exception:
|
||||
self.book_title = _('Unknown')
|
||||
self.book_title = 'Unknown'
|
||||
self.links = {}
|
||||
self.images = {}
|
||||
self.base_hrefs = [item.href for item in oeb_book.spine]
|
||||
|
||||
@@ -322,9 +322,9 @@ class HTMLConverter(object):
|
||||
|
||||
if not self.book_designer and self.is_book_designer(raw):
|
||||
self.book_designer = True
|
||||
self.log.info(_('\tBook Designer file detected.'))
|
||||
self.log.info('\tBook Designer file detected.')
|
||||
|
||||
self.log.info(_('\tParsing HTML...'))
|
||||
self.log.info('\tParsing HTML...')
|
||||
|
||||
if self.baen:
|
||||
nmassage.extend(HTMLConverter.BAEN)
|
||||
@@ -340,7 +340,7 @@ class HTMLConverter(object):
|
||||
soup = html5_parser(raw)
|
||||
if not self.baen and self.is_baen(soup):
|
||||
self.baen = True
|
||||
self.log.info(_('\tBaen file detected. Re-parsing...'))
|
||||
self.log.info('\tBaen file detected. Re-parsing...')
|
||||
return self.preprocess(raw)
|
||||
if self.book_designer:
|
||||
t = soup.find(id='BookTitle')
|
||||
@@ -356,7 +356,7 @@ class HTMLConverter(object):
|
||||
try:
|
||||
with open(os.path.join(tdir, 'html2lrf-verbose.html'), 'wb') as f:
|
||||
f.write(str(soup).encode('utf-8'))
|
||||
self.log.info(_('Written preprocessed HTML to ')+f.name)
|
||||
self.log.info('Written preprocessed HTML to '+f.name)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -372,7 +372,8 @@ class HTMLConverter(object):
|
||||
self.css[selector] = self.override_css[selector]
|
||||
|
||||
self.file_name = os.path.basename(path)
|
||||
self.log.info(_('Processing %s')%(path if self.verbose else self.file_name))
|
||||
self.log.info('Processing %s' % (path if self.verbose else
|
||||
self.file_name))
|
||||
|
||||
if not os.path.exists(path):
|
||||
path = path.replace('&', '%26') # convertlit replaces & with %26 in file names
|
||||
@@ -385,7 +386,7 @@ class HTMLConverter(object):
|
||||
else:
|
||||
raw = xml_to_unicode(raw, self.verbose)[0]
|
||||
soup = self.preprocess(raw)
|
||||
self.log.info(_('\tConverting to BBeB...'))
|
||||
self.log.info('\tConverting to BBeB...')
|
||||
self.current_style = {}
|
||||
self.page_break_found = False
|
||||
if not isinstance(path, str):
|
||||
@@ -533,12 +534,13 @@ class HTMLConverter(object):
|
||||
for c in self.current_page.contents:
|
||||
if isinstance(c, (TextBlock, ImageBlock)):
|
||||
return c
|
||||
raise ConversionError(_('Could not parse file: %s')%self.file_name)
|
||||
raise ConversionError('Could not parse file: %s' %
|
||||
self.file_name)
|
||||
else:
|
||||
try:
|
||||
index = self.book.pages().index(opage)
|
||||
except ValueError:
|
||||
self.log.warning(_('%s is an empty file')%self.file_name)
|
||||
self.log.warning('%s is an empty file' % self.file_name)
|
||||
tb = self.book.create_text_block()
|
||||
self.current_page.append(tb)
|
||||
return tb
|
||||
@@ -546,7 +548,8 @@ class HTMLConverter(object):
|
||||
for c in page.contents:
|
||||
if isinstance(c, (TextBlock, ImageBlock, Canvas)):
|
||||
return c
|
||||
raise ConversionError(_('Could not parse file: %s')%self.file_name)
|
||||
raise ConversionError('Could not parse file: %s' %
|
||||
self.file_name)
|
||||
|
||||
return top
|
||||
|
||||
@@ -557,9 +560,8 @@ class HTMLConverter(object):
|
||||
para = children[i]
|
||||
break
|
||||
if para is None:
|
||||
raise ConversionError(
|
||||
_('Failed to parse link %(tag)s %(children)s')%dict(
|
||||
tag=tag, children=children))
|
||||
raise ConversionError('Failed to parse link %(tag)s %(children)s' %
|
||||
dict(tag=tag, children=children))
|
||||
text = self.get_text(tag, 1000)
|
||||
if not text:
|
||||
text = 'Link'
|
||||
@@ -941,9 +943,8 @@ class HTMLConverter(object):
|
||||
self.scaled_images[path] = pt
|
||||
return pt.name
|
||||
except (IOError, SystemError) as err: # PIL chokes on interlaced PNG images as well a some GIF images
|
||||
self.log.warning(
|
||||
_('Unable to process image %(path)s. Error: %(err)s')%dict(
|
||||
path=path, err=err))
|
||||
self.log.warning('Unable to process image %(path)s. Error: '
|
||||
'%(err)s' % dict(path=path, err=err))
|
||||
|
||||
if width is None or height is None:
|
||||
width, height = im.size
|
||||
@@ -988,7 +989,8 @@ class HTMLConverter(object):
|
||||
self.rotated_images[path] = pt
|
||||
width, height = im.size
|
||||
except IOError: # PIL chokes on interlaced PNG files and since auto-rotation is not critical we ignore the error
|
||||
self.log.debug(_('Unable to process interlaced PNG %s')% original_path)
|
||||
self.log.debug('Unable to process interlaced PNG %s' %
|
||||
original_path)
|
||||
finally:
|
||||
pt.close()
|
||||
|
||||
@@ -1725,9 +1727,11 @@ class HTMLConverter(object):
|
||||
try:
|
||||
self.process_table(tag, tag_css)
|
||||
except Exception as err:
|
||||
self.log.warning(_('An error occurred while processing a table: %s. Ignoring table markup.')%repr(err))
|
||||
self.log.warning('An error occurred while processing a '
|
||||
'table: %s. Ignoring table markup.' %
|
||||
repr(err))
|
||||
self.log.exception('')
|
||||
self.log.debug(_('Bad table:\n%s')%str(tag)[:300])
|
||||
self.log.debug('Bad table:\n%s' % str(tag)[:300])
|
||||
self.in_table = False
|
||||
self.process_children(tag, tag_css, tag_pseudo_css)
|
||||
finally:
|
||||
@@ -1749,7 +1753,7 @@ class HTMLConverter(object):
|
||||
for block, xpos, ypos, delta, targets in table.blocks(int(ps['textwidth']), int(ps['textheight'])):
|
||||
if not block:
|
||||
if ypos > int(ps['textheight']):
|
||||
raise Exception(_('Table has cell that is too large'))
|
||||
raise Exception('Table has cell that is too large')
|
||||
canvases.append(Canvas(int(self.current_page.pageStyle.attrs['textwidth']), ypos+rowpad,
|
||||
blockrule='block-fixed'))
|
||||
for name in targets:
|
||||
@@ -1813,10 +1817,10 @@ def process_file(path, options, logger):
|
||||
tim.save(tf.name)
|
||||
tpath = tf.name
|
||||
except IOError as err: # PIL sometimes fails, for example on interlaced PNG files
|
||||
logger.warn(_('Could not read cover image: %s'), err)
|
||||
logger.warn('Could not read cover image: %s', err)
|
||||
options.cover = None
|
||||
else:
|
||||
raise ConversionError(_('Cannot read from: %s')% (options.cover,))
|
||||
raise ConversionError('Cannot read from: %s'% (options.cover,))
|
||||
|
||||
if not options.title:
|
||||
options.title = default_title
|
||||
@@ -1844,9 +1848,9 @@ def process_file(path, options, logger):
|
||||
header = Paragraph()
|
||||
fheader = options.headerformat
|
||||
if not options.title:
|
||||
options.title = _('Unknown')
|
||||
options.title = 'Unknown'
|
||||
if not options.author:
|
||||
options.author = _('Unknown')
|
||||
options.author = 'Unknown'
|
||||
if not fheader:
|
||||
fheader = "%t by %a"
|
||||
fheader = re.sub(r'(?<!%)%t', options.title, fheader)
|
||||
@@ -1946,4 +1950,4 @@ def try_opf(path, options, logger):
|
||||
if not getattr(options, 'toc', None):
|
||||
options.toc = opf.toc
|
||||
except Exception:
|
||||
logger.exception(_('Failed to process OPF file'))
|
||||
logger.exception('Failed to process OPF file')
|
||||
|
||||
@@ -344,9 +344,9 @@ class ResourceCollection(object):
|
||||
res.set_basedir(path)
|
||||
|
||||
|
||||
def MetaInformation(title, authors=(_('Unknown'),)):
|
||||
def MetaInformation(title, authors=('Unknown',)):
|
||||
''' Convenient encapsulation of book metadata, needed for compatibility
|
||||
@param title: title or ``_('Unknown')`` or a MetaInformation object
|
||||
@param title: title or ``'Unknown'`` or a MetaInformation object
|
||||
@param authors: List of strings or []
|
||||
'''
|
||||
from ebook_converter.ebooks.metadata.book.base import Metadata
|
||||
|
||||
@@ -40,8 +40,9 @@ class KPFExtract(FileTypePlugin):
|
||||
|
||||
name = 'KPF Extract'
|
||||
author = 'Kovid Goyal'
|
||||
description = _('Extract the source DOCX file from Amazon Kindle Create KPF files.'
|
||||
' Note this will not contain any edits made in the Kindle Create program itself.')
|
||||
description = ('Extract the source DOCX file from Amazon Kindle Create '
|
||||
'KPF files. Note this will not contain any edits made in '
|
||||
'the Kindle Create program itself.')
|
||||
file_types = {'kpf'}
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
on_import = True
|
||||
@@ -62,9 +63,9 @@ class KPFExtract(FileTypePlugin):
|
||||
class ArchiveExtract(FileTypePlugin):
|
||||
name = 'Archive Extract'
|
||||
author = 'Kovid Goyal'
|
||||
description = _('Extract common e-book formats from archive files '
|
||||
'(ZIP/RAR). Also try to autodetect if they are actually '
|
||||
'CBZ/CBR files.')
|
||||
description = ('Extract common e-book formats from archive files (ZIP/'
|
||||
'RAR). Also try to autodetect if they are actually CBZ/CBR '
|
||||
'files.')
|
||||
file_types = {'zip', 'rar'}
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
on_import = True
|
||||
|
||||
@@ -21,11 +21,11 @@ TOP_LEVEL_IDENTIFIERS = frozenset((
|
||||
))
|
||||
|
||||
PUBLICATION_METADATA_FIELDS = frozenset((
|
||||
'title', # title must never be None. Should be _('Unknown')
|
||||
'title', # title must never be None. Should be 'Unknown'
|
||||
# Pseudo field that can be set, but if not set is auto generated
|
||||
# from title and languages
|
||||
'title_sort',
|
||||
'authors', # Ordered list. Must never be None, can be [_('Unknown')]
|
||||
'authors', # Ordered list. Must never be None, can be ['Unknown']
|
||||
'author_sort_map', # Map of sort strings for each author
|
||||
# Pseudo field that can be set, but if not set is auto generated
|
||||
# from authors and languages
|
||||
|
||||
@@ -24,21 +24,19 @@ def human_readable(size, precision=2):
|
||||
return ('%.'+str(precision)+'f'+ 'MB') % (size/(1024*1024),)
|
||||
|
||||
|
||||
NULL_VALUES = {
|
||||
'user_metadata': {},
|
||||
'cover_data' : (None, None),
|
||||
'tags' : [],
|
||||
'identifiers' : {},
|
||||
'languages' : [],
|
||||
NULL_VALUES = {'user_metadata': {},
|
||||
'cover_data': (None, None),
|
||||
'tags': [],
|
||||
'identifiers': {},
|
||||
'languages': [],
|
||||
'device_collections': [],
|
||||
'author_sort_map': {},
|
||||
'authors' : [_('Unknown')],
|
||||
'author_sort' : _('Unknown'),
|
||||
'title' : _('Unknown'),
|
||||
'user_categories' : {},
|
||||
'author_link_map' : {},
|
||||
'language' : 'und'
|
||||
}
|
||||
'authors': ['Unknown'],
|
||||
'author_sort': 'Unknown',
|
||||
'title': 'Unknown',
|
||||
'user_categories': {},
|
||||
'author_link_map': {},
|
||||
'language': 'und'}
|
||||
|
||||
field_metadata = FieldMetadata()
|
||||
|
||||
@@ -74,10 +72,10 @@ class Metadata(object):
|
||||
'''
|
||||
__calibre_serializable__ = True
|
||||
|
||||
def __init__(self, title, authors=(_('Unknown'),), other=None, template_cache=None,
|
||||
formatter=None):
|
||||
def __init__(self, title, authors=('Unknown',), other=None,
|
||||
template_cache=None, formatter=None):
|
||||
'''
|
||||
@param title: title or ``_('Unknown')``
|
||||
@param title: title or ``'Unknown'``
|
||||
@param authors: List of strings or []
|
||||
@param other: None or a metadata object
|
||||
'''
|
||||
@@ -101,7 +99,7 @@ class Metadata(object):
|
||||
'''
|
||||
Return True if the value of field is null in this object.
|
||||
'null' means it is unknown or evaluates to False. So a title of
|
||||
_('Unknown') is null or a language of 'und' is null.
|
||||
'Unknown' is null or a language of 'und' is null.
|
||||
|
||||
Be careful with numeric fields since this will return True for zero as
|
||||
well as None.
|
||||
@@ -142,9 +140,7 @@ class Metadata(object):
|
||||
if val is None:
|
||||
d['#value#'] = 'RECURSIVE_COMPOSITE FIELD (Metadata) ' + field
|
||||
val = d['#value#'] = self.formatter.safe_format(
|
||||
d['display']['composite_template'],
|
||||
self,
|
||||
_('TEMPLATE ERROR'),
|
||||
d['display']['composite_template'], self, 'TEMPLATE ERROR',
|
||||
self, column_name=field,
|
||||
template_cache=self.template_cache).strip()
|
||||
return val
|
||||
@@ -474,7 +470,7 @@ class Metadata(object):
|
||||
if v not in (None, NULL_VALUES.get(attr, None)):
|
||||
setattr(dest, attr, copy.deepcopy(v))
|
||||
|
||||
unknown = _('Unknown')
|
||||
unknown = 'Unknown'
|
||||
if other.title and other.title != unknown:
|
||||
self.title = other.title
|
||||
if hasattr(other, 'title_sort'):
|
||||
@@ -658,7 +654,7 @@ class Metadata(object):
|
||||
elif datatype == 'datetime':
|
||||
res = format_date(res, cmeta['display'].get('date_format','dd MMM yyyy'))
|
||||
elif datatype == 'bool':
|
||||
res = _('Yes') if res else _('No')
|
||||
res = 'Yes' if res else 'No'
|
||||
elif datatype == 'rating':
|
||||
res = '%.2g'%(res/2)
|
||||
elif datatype in ['int', 'float']:
|
||||
@@ -725,7 +721,7 @@ class Metadata(object):
|
||||
if self.authors:
|
||||
fmt('Author(s)', authors_to_string(self.authors) +
|
||||
((' [' + self.author_sort + ']')
|
||||
if self.author_sort and self.author_sort != _('Unknown') else ''))
|
||||
if self.author_sort and self.author_sort != 'Unknown' else ''))
|
||||
if self.publisher:
|
||||
fmt('Publisher', self.publisher)
|
||||
if getattr(self, 'book_producer', False):
|
||||
@@ -764,22 +760,26 @@ class Metadata(object):
|
||||
'''
|
||||
from ebook_converter.ebooks.metadata import authors_to_string
|
||||
from ebook_converter.utils.date import isoformat
|
||||
ans = [(_('Title'), str(self.title))]
|
||||
ans += [(_('Author(s)'), (authors_to_string(self.authors) if self.authors else _('Unknown')))]
|
||||
ans += [(_('Publisher'), str(self.publisher))]
|
||||
ans += [(_('Producer'), str(self.book_producer))]
|
||||
ans += [(_('Comments'), str(self.comments))]
|
||||
ans = [('Title', str(self.title))]
|
||||
ans += [('Author(s)', (authors_to_string(self.authors)
|
||||
if self.authors else 'Unknown'))]
|
||||
ans += [('Publisher', str(self.publisher))]
|
||||
ans += [('Producer', str(self.book_producer))]
|
||||
ans += [('Comments', str(self.comments))]
|
||||
ans += [('ISBN', str(self.isbn))]
|
||||
ans += [(_('Tags'), ', '.join([str(t) for t in self.tags]))]
|
||||
ans += [('Tags', ', '.join([str(t) for t in self.tags]))]
|
||||
if self.series:
|
||||
ans += [(_('Series'), str(self.series) + ' #%s'%self.format_series_index())]
|
||||
ans += [(_('Languages'), ', '.join(self.languages))]
|
||||
ans += [('Series', str(self.series) +
|
||||
' #%s' % self.format_series_index())]
|
||||
ans += [('Languages', ', '.join(self.languages))]
|
||||
if self.timestamp is not None:
|
||||
ans += [(_('Timestamp'), str(isoformat(self.timestamp, as_utc=False, sep=' ')))]
|
||||
ans += [('Timestamp', str(isoformat(self.timestamp, as_utc=False,
|
||||
sep=' ')))]
|
||||
if self.pubdate is not None:
|
||||
ans += [(_('Published'), str(isoformat(self.pubdate, as_utc=False, sep=' ')))]
|
||||
ans += [('Published', str(isoformat(self.pubdate, as_utc=False,
|
||||
sep=' ')))]
|
||||
if self.rights is not None:
|
||||
ans += [(_('Rights'), str(self.rights))]
|
||||
ans += [('Rights', str(self.rights))]
|
||||
for key in self.custom_field_keys():
|
||||
val = self.get(key, None)
|
||||
if val:
|
||||
|
||||
@@ -25,7 +25,7 @@ class SafeFormat(TemplateFormatter):
|
||||
if hasattr(self.book, orig_key):
|
||||
key = orig_key
|
||||
else:
|
||||
raise ValueError(_('Value: unknown field ') + orig_key)
|
||||
raise ValueError('Value: unknown field ' + orig_key)
|
||||
try:
|
||||
b = self.book.get_user_metadata(key, False)
|
||||
except:
|
||||
|
||||
@@ -110,7 +110,7 @@ def get_metadata(stream):
|
||||
root = _get_fbroot(get_fb2_data(stream)[0])
|
||||
ctx = Context(root)
|
||||
book_title = _parse_book_title(root, ctx)
|
||||
authors = _parse_authors(root, ctx) or [_('Unknown')]
|
||||
authors = _parse_authors(root, ctx) or ['Unknown']
|
||||
|
||||
# fallback for book_title
|
||||
if book_title:
|
||||
@@ -118,7 +118,7 @@ def get_metadata(stream):
|
||||
else:
|
||||
book_title = force_unicode(os.path.splitext(
|
||||
os.path.basename(getattr(stream, 'name',
|
||||
_('Unknown'))))[0])
|
||||
'Unknown')))[0])
|
||||
mi = MetaInformation(book_title, authors)
|
||||
|
||||
try:
|
||||
@@ -173,7 +173,7 @@ def _parse_authors(root, ctx):
|
||||
|
||||
# if no author so far
|
||||
if not authors:
|
||||
authors.append(_('Unknown'))
|
||||
authors.append('Unknown')
|
||||
|
||||
return authors
|
||||
|
||||
|
||||
@@ -151,10 +151,10 @@ def get_metadata_(src, encoding=None):
|
||||
return ans
|
||||
|
||||
# Title
|
||||
title = get('title') or title_tag.strip() or _('Unknown')
|
||||
title = get('title') or title_tag.strip() or 'Unknown'
|
||||
|
||||
# Author
|
||||
authors = authors_to_string(get_all('authors')) or _('Unknown')
|
||||
authors = authors_to_string(get_all('authors')) or 'Unknown'
|
||||
|
||||
# Create MetaInformation with Title and Author
|
||||
mi = Metadata(title, string_to_authors(authors))
|
||||
@@ -340,7 +340,7 @@ class MetadataHtmlTest(unittest.TestCase):
|
||||
|
||||
def test_input_title(self):
|
||||
stream_meta = get_metadata(self.get_stream('title'))
|
||||
canon_meta = Metadata('A Title Tag & Title Ⓒ', [_('Unknown')])
|
||||
canon_meta = Metadata('A Title Tag & Title Ⓒ', ['Unknown'])
|
||||
self.compare_metadata(stream_meta, canon_meta)
|
||||
|
||||
def test_input_meta_single(self):
|
||||
|
||||
@@ -33,7 +33,7 @@ def metadata_from_formats(formats, force_read_metadata=False, pattern=None):
|
||||
except:
|
||||
mi = metadata_from_filename(list(iter(formats))[0], pat=pattern)
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
mi.authors = ['Unknown']
|
||||
return mi
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@ def _metadata_from_formats(formats, force_read_metadata=False, pattern=None):
|
||||
return mi
|
||||
|
||||
if not mi.title:
|
||||
mi.title = _('Unknown')
|
||||
mi.title = 'Unknown'
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
mi.authors = ['Unknown']
|
||||
|
||||
return mi
|
||||
|
||||
@@ -106,9 +106,9 @@ def _get_metadata(stream, stream_type, use_libprs_metadata,
|
||||
base = metadata_from_filename(name, pat=pattern, fallback_pat=re.compile(
|
||||
r'^(?P<title>.+) - (?P<author>[^-]+)$'))
|
||||
if not base.authors:
|
||||
base.authors = [_('Unknown')]
|
||||
base.authors = ['Unknown']
|
||||
if not base.title:
|
||||
base.title = _('Unknown')
|
||||
base.title = 'Unknown'
|
||||
mi = MetaInformation(None, None)
|
||||
if force_read_metadata or prefs['read_file_metadata']:
|
||||
mi = get_file_type_metadata(stream, stream_type)
|
||||
|
||||
@@ -1360,7 +1360,7 @@ class OPFCreator(Metadata):
|
||||
if not isinstance(self.toc, TOC):
|
||||
self.toc = None
|
||||
if not self.authors:
|
||||
self.authors = [_('Unknown')]
|
||||
self.authors = ['Unknown']
|
||||
if self.guide is None:
|
||||
self.guide = Guide()
|
||||
if self.cover:
|
||||
@@ -1470,7 +1470,7 @@ class OPFCreator(Metadata):
|
||||
metadata = M.metadata()
|
||||
a = metadata.append
|
||||
role = {}
|
||||
a(DC_ELEM('title', self.title if self.title else _('Unknown'),
|
||||
a(DC_ELEM('title', self.title if self.title else 'Unknown',
|
||||
opf_attrs=role))
|
||||
for i, author in enumerate(self.authors):
|
||||
fa = {'role':'aut'}
|
||||
@@ -1679,7 +1679,7 @@ def metadata_to_opf(mi, as_string=True, default_lang=None):
|
||||
mi.cover = mi.cover.decode(filesystem_encoding)
|
||||
guide.text = '\n'+(' '*8)
|
||||
r = guide.makeelement(OPF('reference'),
|
||||
attrib={'type':'cover', 'title':_('Cover'), 'href':mi.cover})
|
||||
attrib={'type': 'cover', 'title': 'Cover', 'href': mi.cover})
|
||||
r.tail = '\n' +(' '*4)
|
||||
guide.append(r)
|
||||
if pretty_print_opf:
|
||||
|
||||
@@ -960,7 +960,7 @@ def set_last_modified_in_opf(root):
|
||||
|
||||
|
||||
def read_metadata(root, ver=None, return_extra_data=False):
|
||||
ans = Metadata(_('Unknown'), [_('Unknown')])
|
||||
ans = Metadata('Unknown', ['Unknown'])
|
||||
prefixes, refines = read_prefixes(root), read_refines(root)
|
||||
identifiers = read_identifiers(root, prefixes, refines)
|
||||
ids = {}
|
||||
|
||||
@@ -122,10 +122,10 @@ def get_metadata(stream, cover=True):
|
||||
with open(covpath, 'rb') as f:
|
||||
cdata = f.read()
|
||||
|
||||
title = info.get('Title', None) or _('Unknown')
|
||||
title = info.get('Title', None) or 'Unknown'
|
||||
au = info.get('Author', None)
|
||||
if au is None:
|
||||
au = [_('Unknown')]
|
||||
au = ['Unknown']
|
||||
else:
|
||||
au = string_to_authors(au)
|
||||
mi = MetaInformation(title, au)
|
||||
|
||||
@@ -110,10 +110,10 @@ def get_metadata(stream):
|
||||
"""
|
||||
stream.seek(0)
|
||||
if stream.read(5) != br'{\rtf':
|
||||
return MetaInformation(_('Unknown'))
|
||||
return MetaInformation('Unknown')
|
||||
block = get_document_info(stream)[0]
|
||||
if not block:
|
||||
return MetaInformation(_('Unknown'))
|
||||
return MetaInformation('Unknown')
|
||||
|
||||
stream.seek(0)
|
||||
cpg = detect_codepage(stream)
|
||||
@@ -123,7 +123,7 @@ def get_metadata(stream):
|
||||
if title_match is not None:
|
||||
title = decode(title_match.group(1).strip(), cpg)
|
||||
else:
|
||||
title = _('Unknown')
|
||||
title = 'Unknown'
|
||||
author_match = author_pat.search(block)
|
||||
if author_match is not None:
|
||||
author = decode(author_match.group(1).strip(), cpg)
|
||||
|
||||
@@ -17,7 +17,7 @@ def get_metadata(stream, extract_cover=True):
|
||||
name = getattr(stream, 'name', '').rpartition('.')[0]
|
||||
if name:
|
||||
name = os.path.basename(name)
|
||||
mi = MetaInformation(name or _('Unknown'), [_('Unknown')])
|
||||
mi = MetaInformation(name or 'Unknown', ['Unknown'])
|
||||
stream.seek(0)
|
||||
|
||||
mdata = ''
|
||||
|
||||
@@ -235,7 +235,7 @@ def more_recent(one, two):
|
||||
|
||||
def metadata_from_xmp_packet(raw_bytes):
|
||||
root = parse_xmp_packet(raw_bytes)
|
||||
mi = Metadata(_('Unknown'))
|
||||
mi = Metadata('Unknown')
|
||||
title = first_alt('//dc:title', root)
|
||||
if title:
|
||||
if title.startswith(r'\376\377'):
|
||||
@@ -346,7 +346,9 @@ def consolidate_metadata(info_mi, info):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return info_mi
|
||||
info_title, info_authors, info_tags = info_mi.title or _('Unknown'), list(info_mi.authors or ()), list(info_mi.tags or ())
|
||||
info_title = info_mi.title or 'Unknown'
|
||||
info_authors = list(info_mi.authors or ())
|
||||
info_tags = list(info_mi.tags or ())
|
||||
info_mi.smart_update(xmp_mi, replace_metadata=True)
|
||||
prefer_info = False
|
||||
if 'ModDate' in info and hasattr(xmp_mi, 'metadata_date'):
|
||||
|
||||
@@ -32,7 +32,7 @@ class EXTHHeader(object): # {{{
|
||||
self.length, self.num_items = struct.unpack('>LL', raw[4:12])
|
||||
raw = raw[12:]
|
||||
pos = 0
|
||||
self.mi = MetaInformation(_('Unknown'), [_('Unknown')])
|
||||
self.mi = MetaInformation('Unknown', ['Unknown'])
|
||||
self.has_fake_cover = True
|
||||
self.start_offset = None
|
||||
left = self.num_items
|
||||
@@ -67,7 +67,7 @@ class EXTHHeader(object): # {{{
|
||||
if content == b'EBSP':
|
||||
if not self.mi.tags:
|
||||
self.mi.tags = []
|
||||
self.mi.tags.append(_('Sample Book'))
|
||||
self.mi.tags.append('Sample Book')
|
||||
elif idx == 502:
|
||||
# last update time
|
||||
pass
|
||||
@@ -127,7 +127,7 @@ class EXTHHeader(object): # {{{
|
||||
self.mi.authors.append(au)
|
||||
elif idx == 101:
|
||||
self.mi.publisher = clean_xml_chars(self.decode(content).strip())
|
||||
if self.mi.publisher in {'Unknown', _('Unknown')}:
|
||||
if self.mi.publisher in {'Unknown', 'Unknown'}:
|
||||
self.mi.publisher = None
|
||||
elif idx == 103:
|
||||
self.mi.comments = clean_xml_chars(self.decode(content).strip())
|
||||
@@ -194,7 +194,7 @@ class BookHeader(object):
|
||||
if len(raw) <= 16:
|
||||
self.codec = 'cp1252'
|
||||
self.extra_flags = 0
|
||||
self.title = _('Unknown')
|
||||
self.title = 'Unknown'
|
||||
self.language = 'ENGLISH'
|
||||
self.sublanguage = 'NEUTRAL'
|
||||
self.exth_flag, self.exth = 0, None
|
||||
@@ -233,7 +233,7 @@ class BookHeader(object):
|
||||
|
||||
toff, tlen = struct.unpack('>II', raw[0x54:0x5c])
|
||||
tend = toff + tlen
|
||||
self.title = raw[toff:tend] if tend < len(raw) else _('Unknown')
|
||||
self.title = raw[toff:tend] if tend < len(raw) else 'Unknown'
|
||||
langcode = struct.unpack('!L', raw[0x5C:0x60])[0]
|
||||
langid = langcode & 0xFF
|
||||
sublangid = (langcode >> 10) & 0xFF
|
||||
|
||||
@@ -30,10 +30,10 @@ class TopazError(ValueError):
|
||||
class KFXError(ValueError):
|
||||
|
||||
def __init__(self):
|
||||
ValueError.__init__(self, _(
|
||||
'This is an Amazon KFX book. It cannot be processed.'
|
||||
' See {} for information on how to handle KFX books.'
|
||||
).format('https://www.mobileread.com/forums/showthread.php?t=283371'))
|
||||
ValueError.__init__(self, 'This is an Amazon KFX book. It cannot be '
|
||||
'processed. See https://www.mobileread.com/forums/'
|
||||
'showthread.php?t=283371 for information on how '
|
||||
'to handle KFX books.')
|
||||
|
||||
|
||||
class MobiReader(object):
|
||||
@@ -77,7 +77,8 @@ class MobiReader(object):
|
||||
|
||||
raw = stream.read()
|
||||
if raw.startswith(b'TPZ'):
|
||||
raise TopazError(_('This is an Amazon Topaz book. It cannot be processed.'))
|
||||
raise TopazError('This is an Amazon Topaz book. It cannot be '
|
||||
'processed.')
|
||||
if raw.startswith(b'\xeaDRMION\xee'):
|
||||
raise KFXError()
|
||||
|
||||
@@ -642,7 +643,7 @@ class MobiReader(object):
|
||||
def create_opf(self, htmlfile, guide=None, root=None):
|
||||
mi = getattr(self.book_header.exth, 'mi', self.embedded_mi)
|
||||
if mi is None:
|
||||
mi = MetaInformation(self.book_header.title, [_('Unknown')])
|
||||
mi = MetaInformation(self.book_header.title, ['Unknown'])
|
||||
opf = OPFCreator(os.path.dirname(htmlfile), mi)
|
||||
if hasattr(self.book_header.exth, 'cover_offset'):
|
||||
opf.cover = 'images/%05d.jpg' % (self.book_header.exth.cover_offset + 1)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os, glob
|
||||
import glob
|
||||
import os
|
||||
|
||||
from ebook_converter import CurrentDir
|
||||
from ebook_converter.ebooks.mobi import MobiError
|
||||
@@ -8,8 +9,8 @@ from ebook_converter.utils.logging import default_log
|
||||
from ebook_converter.ebooks import DRMError
|
||||
from ebook_converter.ebooks.mobi.reader.mobi8 import Mobi8Reader
|
||||
from ebook_converter.ebooks.conversion.plumber import Plumber, create_oebbook
|
||||
from ebook_converter.customize.ui import (plugin_for_input_format,
|
||||
plugin_for_output_format)
|
||||
from ebook_converter.customize.ui import plugin_for_input_format
|
||||
from ebook_converter.customize.ui import plugin_for_output_format
|
||||
from ebook_converter.utils.ipc.simple_worker import fork_job
|
||||
|
||||
|
||||
@@ -31,44 +32,46 @@ def do_explode(path, dest):
|
||||
opf = os.path.abspath(mr())
|
||||
try:
|
||||
os.remove('debug-raw.html')
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return opf
|
||||
|
||||
|
||||
def explode(path, dest, question=lambda x:True):
|
||||
def explode(path, dest, question=lambda x: True):
|
||||
with open(path, 'rb') as stream:
|
||||
raw = stream.read(3)
|
||||
stream.seek(0)
|
||||
if raw == b'TPZ':
|
||||
raise BadFormat(_('This is not a MOBI file. It is a Topaz file.'))
|
||||
raise BadFormat('This is not a MOBI file. It is a Topaz file.')
|
||||
|
||||
try:
|
||||
header = MetadataHeader(stream, default_log)
|
||||
except MobiError:
|
||||
raise BadFormat(_('This is not a MOBI file.'))
|
||||
raise BadFormat('This is not a MOBI file.')
|
||||
|
||||
if header.encryption_type != 0:
|
||||
raise DRMError(_('This file is locked with DRM. It cannot be tweaked.'))
|
||||
raise DRMError('This file is locked with DRM. It cannot be '
|
||||
'tweaked.')
|
||||
|
||||
kf8_type = header.kf8_type
|
||||
|
||||
if kf8_type is None:
|
||||
raise BadFormat(_('This MOBI file does not contain a KF8 format '
|
||||
'book. KF8 is the new format from Amazon. calibre can '
|
||||
'only tweak MOBI files that contain KF8 books. Older '
|
||||
'MOBI files without KF8 are not tweakable.'))
|
||||
raise BadFormat('This MOBI file does not contain a KF8 format '
|
||||
'book. KF8 is the new format from Amazon. calibre '
|
||||
'can only tweak MOBI files that contain KF8 '
|
||||
'books. Older MOBI files without KF8 are not '
|
||||
'tweakable.')
|
||||
|
||||
if kf8_type == 'joint':
|
||||
if not question(_('This MOBI file contains both KF8 and '
|
||||
'older Mobi6 data. Tweaking it will remove the Mobi6 data, which '
|
||||
'means the file will not be usable on older Kindles. Are you '
|
||||
'sure?')):
|
||||
if not question('This MOBI file contains both KF8 and older Mobi6 '
|
||||
'data. Tweaking it will remove the Mobi6 data, '
|
||||
'which means the file will not be usable on older '
|
||||
'Kindles. Are you sure?'):
|
||||
return None
|
||||
|
||||
return fork_job('ebook_converter.ebooks.mobi.tweak', 'do_explode', args=(path,
|
||||
dest), no_output=True)['result']
|
||||
return fork_job('ebook_converter.ebooks.mobi.tweak', 'do_explode',
|
||||
args=(path, dest), no_output=True)['result']
|
||||
|
||||
|
||||
def set_cover(oeb):
|
||||
@@ -96,11 +99,10 @@ def do_rebuild(opf, dest_path):
|
||||
def rebuild(src_dir, dest_path):
|
||||
opf = glob.glob(os.path.join(src_dir, '*.opf'))
|
||||
if not opf:
|
||||
raise ValueError('No OPF file found in %s'%src_dir)
|
||||
raise ValueError('No OPF file found in %s' % src_dir)
|
||||
opf = opf[0]
|
||||
# For debugging, uncomment the following two lines
|
||||
# def fork_job(a, b, args=None, no_output=True):
|
||||
# do_rebuild(*args)
|
||||
fork_job('ebook_converter.ebooks.mobi.tweak', 'do_rebuild', args=(opf, dest_path),
|
||||
no_output=True)
|
||||
|
||||
fork_job('ebook_converter.ebooks.mobi.tweak', 'do_rebuild',
|
||||
args=(opf, dest_path), no_output=True)
|
||||
|
||||
@@ -336,7 +336,7 @@ def utf8_text(text):
|
||||
text = text.decode('utf-8', 'replace')
|
||||
text = normalize(text).encode('utf-8')
|
||||
else:
|
||||
text = _('Unknown').encode('utf-8')
|
||||
text = 'Unknown'.encode('utf-8')
|
||||
return text
|
||||
|
||||
|
||||
|
||||
@@ -461,9 +461,9 @@ class Indexer(object): # {{{
|
||||
if node.klass == 'article':
|
||||
aut, desc = node.author, node.description
|
||||
if not aut:
|
||||
aut = _('Unknown')
|
||||
aut = 'Unknown'
|
||||
if not desc:
|
||||
desc = _('No details available')
|
||||
desc = 'No details available'
|
||||
node.author, node.description = aut, desc
|
||||
|
||||
self.cncx = CNCX(oeb.toc, self.is_periodical)
|
||||
|
||||
@@ -276,9 +276,9 @@ class Extract(ODF2XHTML):
|
||||
stream.seek(0)
|
||||
mi = get_metadata(stream, 'odt')
|
||||
if not mi.title:
|
||||
mi.title = _('Unknown')
|
||||
mi.title = 'Unknown'
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
mi.authors = ['Unknown']
|
||||
self.filter_load(stream, mi, log)
|
||||
|
||||
# NOTE(gryf): Here is a workaround for ODF2XHTML.xhtml() method,
|
||||
|
||||
@@ -967,7 +967,7 @@ class Manifest(object):
|
||||
if title:
|
||||
title = str(title[0])
|
||||
else:
|
||||
title = _('Unknown')
|
||||
title = 'Unknown'
|
||||
|
||||
return self._parse_xhtml(convert_markdown(data, title=title))
|
||||
|
||||
@@ -1368,23 +1368,23 @@ class Guide(object):
|
||||
:attr:`href`: Book-internal URL of the referenced section. May include
|
||||
a fragment identifier.
|
||||
"""
|
||||
_TYPES_TITLES = [('cover', __('Cover')),
|
||||
('title-page', __('Title page')),
|
||||
('toc', __('Table of Contents')),
|
||||
('index', __('Index')),
|
||||
('glossary', __('Glossary')),
|
||||
('acknowledgements', __('Acknowledgements')),
|
||||
('bibliography', __('Bibliography')),
|
||||
('colophon', __('Colophon')),
|
||||
('copyright-page', __('Copyright')),
|
||||
('dedication', __('Dedication')),
|
||||
('epigraph', __('Epigraph')),
|
||||
('foreword', __('Foreword')),
|
||||
('loi', __('List of illustrations')),
|
||||
('lot', __('List of tables')),
|
||||
('notes', __('Notes')),
|
||||
('preface', __('Preface')),
|
||||
('text', __('Main text'))]
|
||||
_TYPES_TITLES = [('cover', 'Cover'),
|
||||
('title-page', 'Title page'),
|
||||
('toc', 'Table of Contents'),
|
||||
('index', 'Index'),
|
||||
('glossary', 'Glossary'),
|
||||
('acknowledgements', 'Acknowledgements'),
|
||||
('bibliography', 'Bibliography'),
|
||||
('colophon', 'Colophon'),
|
||||
('copyright-page', 'Copyright'),
|
||||
('dedication', 'Dedication'),
|
||||
('epigraph', 'Epigraph'),
|
||||
('foreword', 'Foreword'),
|
||||
('loi', 'List of illustrations'),
|
||||
('lot', 'List of tables'),
|
||||
('notes', 'Notes'),
|
||||
('preface', 'Preface'),
|
||||
('text', 'Main text')]
|
||||
TITLES = dict(_TYPES_TITLES)
|
||||
TYPES = frozenset(TITLES)
|
||||
ORDER = {t: i for i, (t, _) in enumerate(_TYPES_TITLES)}
|
||||
|
||||
@@ -312,14 +312,14 @@ def parse_html(data, log=None, decoder=None, preprocessor=None,
|
||||
head = etree.Element(XHTML('head'))
|
||||
data.insert(0, head)
|
||||
title = etree.SubElement(head, XHTML('title'))
|
||||
title.text = _('Unknown')
|
||||
title.text = 'Unknown'
|
||||
elif not xpath(data, '/h:html/h:head/h:title'):
|
||||
title = etree.SubElement(head, XHTML('title'))
|
||||
title.text = _('Unknown')
|
||||
title.text = 'Unknown'
|
||||
# Ensure <title> is not empty
|
||||
title = xpath(data, '/h:html/h:head/h:title')[0]
|
||||
if not title.text or not title.text.strip():
|
||||
title.text = _('Unknown')
|
||||
title.text = 'Unknown'
|
||||
# Remove any encoding-specifying <meta/> elements
|
||||
for meta in META_XP(data):
|
||||
meta.getparent().remove(meta)
|
||||
|
||||
@@ -1458,12 +1458,13 @@ class AZW3Container(Container):
|
||||
with open(pathtoazw3, 'rb') as stream:
|
||||
raw = stream.read(3)
|
||||
if raw == b'TPZ':
|
||||
raise InvalidMobi(_('This is not a MOBI file. It is a Topaz file.'))
|
||||
raise InvalidMobi('This is not a MOBI file. It is a Topaz '
|
||||
'file.')
|
||||
|
||||
try:
|
||||
header = MetadataHeader(stream, default_log)
|
||||
except MobiError:
|
||||
raise InvalidMobi(_('This is not a MOBI file.'))
|
||||
raise InvalidMobi('This is not a MOBI file.')
|
||||
|
||||
if header.encryption_type != 0:
|
||||
raise DRMError()
|
||||
@@ -1471,15 +1472,16 @@ class AZW3Container(Container):
|
||||
kf8_type = header.kf8_type
|
||||
|
||||
if kf8_type is None:
|
||||
raise InvalidMobi(_('This MOBI file does not contain a KF8 format '
|
||||
'book. KF8 is the new format from Amazon. calibre can '
|
||||
'only edit MOBI files that contain KF8 books. Older '
|
||||
'MOBI files without KF8 are not editable.'))
|
||||
raise InvalidMobi('This MOBI file does not contain a KF8 '
|
||||
'format book. KF8 is the new format from '
|
||||
'Amazon. calibre can only edit MOBI files '
|
||||
'that contain KF8 books. Older MOBI files '
|
||||
'without KF8 are not editable.')
|
||||
|
||||
if kf8_type == 'joint':
|
||||
raise InvalidMobi(_('This MOBI file contains both KF8 and '
|
||||
'older Mobi6 data. calibre can only edit MOBI files '
|
||||
'that contain only KF8 data.'))
|
||||
raise InvalidMobi('This MOBI file contains both KF8 and older '
|
||||
'Mobi6 data. calibre can only edit MOBI '
|
||||
'files that contain only KF8 data.')
|
||||
|
||||
try:
|
||||
opf_path, obfuscated_fonts = fork_job(
|
||||
|
||||
@@ -167,20 +167,19 @@ def remove_unused_css(container, report=None, remove_unused_classes=False, merge
|
||||
num_changes = num_of_removed_rules + num_merged + num_of_removed_classes
|
||||
if num_changes > 0:
|
||||
if num_of_removed_rules > 0:
|
||||
report(ngettext('Removed one unused CSS style rule', 'Removed {} unused CSS style rules',
|
||||
num_of_removed_rules).format(num_of_removed_rules))
|
||||
report('Removed {} unused CSS style '
|
||||
'rules'.format(num_of_removed_rules))
|
||||
if num_of_removed_classes > 0:
|
||||
report(ngettext('Removed one unused class from the HTML', 'Removed {} unused classes from the HTML',
|
||||
num_of_removed_classes).format(num_of_removed_classes))
|
||||
report('Removed {} unused classes from the HTML'
|
||||
.format(num_of_removed_classes))
|
||||
if num_merged > 0:
|
||||
report(ngettext('Merged one CSS style rule', 'Merged {} CSS style rules',
|
||||
num_merged).format(num_merged))
|
||||
report('Merged {} CSS style rules'.format(num_merged))
|
||||
if num_of_removed_rules == 0:
|
||||
report(_('No unused CSS style rules found'))
|
||||
report('No unused CSS style rules found')
|
||||
if remove_unused_classes and num_of_removed_classes == 0:
|
||||
report(_('No unused class attributes found'))
|
||||
report('No unused class attributes found')
|
||||
if merge_rules and num_merged == 0:
|
||||
report(_('No style rules that could be merged found'))
|
||||
report('No style rules that could be merged found')
|
||||
return num_changes > 0
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ class InvalidBook(ValueError):
|
||||
class DRMError(_DRMError):
|
||||
|
||||
def __init__(self):
|
||||
super(DRMError, self).__init__(_('This file is locked with DRM. It cannot be edited.'))
|
||||
super(DRMError, self).__init__('This file is locked with DRM. It '
|
||||
'cannot be edited.')
|
||||
|
||||
|
||||
class MalformedMarkup(ValueError):
|
||||
|
||||
@@ -157,7 +157,7 @@ def smarten_punctuation(container, report):
|
||||
newhtml = smarten_punctuation(html, container.log)
|
||||
if newhtml != html:
|
||||
changed = True
|
||||
report(_('Smartened punctuation in: %s')%name)
|
||||
report('Smartened punctuation in: %s' % name)
|
||||
newhtml = strip_encoding_declarations(newhtml)
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
@@ -171,7 +171,7 @@ def smarten_punctuation(container, report):
|
||||
container.dirty(name)
|
||||
smartened = True
|
||||
if not smartened:
|
||||
report(_('No punctuation that could be smartened found'))
|
||||
report('No punctuation that could be smartened found')
|
||||
return smartened
|
||||
|
||||
|
||||
|
||||
@@ -194,8 +194,9 @@ def split(container, name, loc_or_xpath, before=True, totals=None):
|
||||
try:
|
||||
split_point = node_from_loc(root, loc_or_xpath, totals=totals)
|
||||
except MalformedMarkup:
|
||||
raise MalformedMarkup(_('The file %s has malformed markup. Try running the Fix HTML tool'
|
||||
' before splitting') % name)
|
||||
raise MalformedMarkup('The file %s has malformed markup. Try '
|
||||
'running the Fix HTML tool before '
|
||||
'splitting' % name)
|
||||
container.replace(name, root)
|
||||
if in_table(split_point):
|
||||
raise AbortError('Cannot split inside tables')
|
||||
@@ -269,7 +270,7 @@ def multisplit(container, name, xpath, before=True):
|
||||
root = container.parsed(name)
|
||||
nodes = root.xpath(xpath, namespaces=XPNSMAP)
|
||||
if not nodes:
|
||||
raise AbortError(_('The expression %s did not match any nodes') % xpath)
|
||||
raise AbortError('The expression %s did not match any nodes' % xpath)
|
||||
for split_point in nodes:
|
||||
if in_table(split_point):
|
||||
raise AbortError('Cannot split inside tables')
|
||||
|
||||
@@ -240,17 +240,17 @@ def verify_toc_destinations(container, toc):
|
||||
name = item.dest
|
||||
if not name:
|
||||
item.dest_exists = False
|
||||
item.dest_error = _('No file named %s exists')%name
|
||||
item.dest_error = 'No file named %s exists' % name
|
||||
continue
|
||||
try:
|
||||
root = container.parsed(name)
|
||||
except KeyError:
|
||||
item.dest_exists = False
|
||||
item.dest_error = _('No file named %s exists')%name
|
||||
item.dest_error = 'No file named %s exists' % name
|
||||
continue
|
||||
if not hasattr(root, 'xpath'):
|
||||
item.dest_exists = False
|
||||
item.dest_error = _('No HTML file named %s exists')%name
|
||||
item.dest_error = 'No HTML file named %s exists' % name
|
||||
continue
|
||||
if not item.frag:
|
||||
item.dest_exists = True
|
||||
@@ -259,9 +259,8 @@ def verify_toc_destinations(container, toc):
|
||||
anchor_map[name] = frozenset(anchor_xpath(root))
|
||||
item.dest_exists = item.frag in anchor_map[name]
|
||||
if not item.dest_exists:
|
||||
item.dest_error = _(
|
||||
'The anchor %(a)s does not exist in file %(f)s')%dict(
|
||||
a=item.frag, f=name)
|
||||
item.dest_error = ('The anchor %(a)s does not exist in file '
|
||||
'%(f)s' % dict(a=item.frag, f=name))
|
||||
|
||||
|
||||
def find_existing_ncx_toc(container):
|
||||
@@ -370,7 +369,7 @@ def elem_to_toc_text(elem):
|
||||
text = re.sub(r'\s+', ' ', text.strip())
|
||||
text = text[:1000].strip()
|
||||
if not text:
|
||||
text = _('(Untitled)')
|
||||
text = '(Untitled)'
|
||||
return text
|
||||
|
||||
|
||||
@@ -533,8 +532,9 @@ def from_files(container):
|
||||
text = find_text(body[0])
|
||||
if not text:
|
||||
text = name.rpartition('/')[-1]
|
||||
if i == 0 and text.rpartition('.')[0].lower() in {'titlepage', 'cover'}:
|
||||
text = _('Cover')
|
||||
if i == 0 and text.rpartition('.')[0].lower() in {'titlepage',
|
||||
'cover'}:
|
||||
text = 'Cover'
|
||||
toc.add(text, name)
|
||||
return toc
|
||||
|
||||
@@ -563,8 +563,9 @@ def add_id(container, name, loc, totals=None):
|
||||
try:
|
||||
node = node_from_loc(root, loc, totals=totals)
|
||||
except MalformedMarkup:
|
||||
raise MalformedMarkup(_('The file %s has malformed markup. Try running the Fix HTML tool'
|
||||
' before editing.') % name)
|
||||
raise MalformedMarkup('The file %s has malformed markup. Try '
|
||||
'running the Fix HTML tool before '
|
||||
'editing.' % name)
|
||||
container.replace(name, root)
|
||||
|
||||
if not node.get('id'):
|
||||
@@ -641,7 +642,7 @@ def commit_ncx_toc(container, toc, lang=None, uid=None):
|
||||
if m:
|
||||
uid = xml2text(m[0])
|
||||
|
||||
title = _('Table of Contents')
|
||||
title = 'Table of Contents'
|
||||
m = container.opf_xpath('//dc:title')
|
||||
if m:
|
||||
x = xml2text(m[0]).strip()
|
||||
|
||||
@@ -146,14 +146,14 @@ class OEBReader(object):
|
||||
m.add('identifier', str(uuid.uuid4()), id='uuid_id', scheme='uuid')
|
||||
self.oeb.uid = self.oeb.metadata.identifier[-1]
|
||||
if not m.title:
|
||||
m.add('title', self.oeb.translate(__('Unknown')))
|
||||
m.add('title', self.oeb.translate('Unknown'))
|
||||
has_aut = False
|
||||
for x in m.creator:
|
||||
if getattr(x, 'role', '').lower() in ('', 'aut'):
|
||||
has_aut = True
|
||||
break
|
||||
if not has_aut:
|
||||
m.add('creator', self.oeb.translate(__('Unknown')), role='aut')
|
||||
m.add('creator', self.oeb.translate('Unknown'), role='aut')
|
||||
|
||||
def _manifest_prune_invalid(self):
|
||||
'''
|
||||
|
||||
@@ -10,7 +10,7 @@ __all__ = ['HTMLTOCAdder']
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
||||
|
||||
DEFAULT_TITLE = __('Table of Contents')
|
||||
DEFAULT_TITLE = 'Table of Contents'
|
||||
|
||||
STYLE_CSS = {
|
||||
'nested': """
|
||||
@@ -52,9 +52,9 @@ class HTMLTOCAdder(object):
|
||||
|
||||
@classmethod
|
||||
def config(cls, cfg):
|
||||
group = cfg.add_group('htmltoc', _('HTML TOC generation options.'))
|
||||
group = cfg.add_group('htmltoc', 'HTML TOC generation options.')
|
||||
group('toc_title', ['--toc-title'], default=None,
|
||||
help=_('Title for any generated in-line table of contents.'))
|
||||
help='Title for any generated in-line table of contents.')
|
||||
return cfg
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -110,12 +110,12 @@ class Jacket(Base):
|
||||
try:
|
||||
title = str(self.oeb.metadata.title[0])
|
||||
except:
|
||||
title = _('Unknown')
|
||||
title = 'Unknown'
|
||||
|
||||
try:
|
||||
authors = list(map(str, self.oeb.metadata.creator))
|
||||
except:
|
||||
authors = [_('Unknown')]
|
||||
authors = ['Unknown']
|
||||
|
||||
root = render_jacket(mi, self.opts.output_profile,
|
||||
alt_title=title, alt_tags=tags, alt_authors=authors,
|
||||
@@ -174,10 +174,11 @@ class Series(str):
|
||||
|
||||
def __new__(self, series, series_index):
|
||||
if series and series_index is not None:
|
||||
roman = _('{1} of <em>{0}</em>').format(
|
||||
roman = '{1} of <em>{0}</em>'.format(
|
||||
escape(series), escape(fmt_sidx(series_index, use_roman=True)))
|
||||
combined = _('{1} of <em>{0}</em>').format(
|
||||
escape(series), escape(fmt_sidx(series_index, use_roman=False)))
|
||||
combined = '{1} of <em>{0}</em>'.format(
|
||||
escape(series), escape(fmt_sidx(series_index,
|
||||
use_roman=False)))
|
||||
else:
|
||||
combined = roman = escape(series or u'')
|
||||
s = str.__new__(self, combined)
|
||||
@@ -227,7 +228,7 @@ def postprocess_jacket(root, output_profile, has_data):
|
||||
|
||||
|
||||
def render_jacket(mi, output_profile,
|
||||
alt_title=_('Unknown'), alt_tags=[], alt_comments='',
|
||||
alt_title='Unknown', alt_tags=[], alt_comments='',
|
||||
alt_publisher='', rescale_fonts=False, alt_authors=None):
|
||||
with open(pkg_resources.resource_filename('ebook_converter',
|
||||
'data/jacket/stylesheet.css'),
|
||||
@@ -244,7 +245,7 @@ def render_jacket(mi, output_profile,
|
||||
try:
|
||||
title_str = alt_title if mi.is_null('title') else mi.title
|
||||
except:
|
||||
title_str = _('Unknown')
|
||||
title_str = 'Unknown'
|
||||
title_str = escape(title_str)
|
||||
title = '<span class="title">%s</span>' % title_str
|
||||
|
||||
@@ -275,7 +276,7 @@ def render_jacket(mi, output_profile,
|
||||
|
||||
orig = mi.authors
|
||||
if mi.is_null('authors'):
|
||||
mi.authors = list(alt_authors or (_('Unknown'),))
|
||||
mi.authors = list(alt_authors or ('Unknown',))
|
||||
try:
|
||||
author = mi.format_authors()
|
||||
except:
|
||||
@@ -285,20 +286,25 @@ def render_jacket(mi, output_profile,
|
||||
has_data = {}
|
||||
|
||||
def generate_html(comments):
|
||||
args = dict(xmlns=XHTML_NS,
|
||||
title_str=title_str,
|
||||
css=css,
|
||||
title=title,
|
||||
author=author,
|
||||
publisher=publisher,
|
||||
pubdate_label=_('Published'), pubdate=pubdate,
|
||||
series_label=_('Series'), series=series,
|
||||
rating_label=_('Rating'), rating=rating,
|
||||
tags_label=_('Tags'), tags=tags,
|
||||
comments=comments,
|
||||
footer='',
|
||||
searchable_tags=' '.join(escape(t)+'ttt' for t in tags.tags_list),
|
||||
)
|
||||
args = {'author': author,
|
||||
'comments': comments,
|
||||
'css': css,
|
||||
'footer': '',
|
||||
'pubdate': pubdate,
|
||||
'pubdate_label': 'Published',
|
||||
'publisher': publisher,
|
||||
'rating': rating,
|
||||
'rating_label': 'Rating',
|
||||
'searchable_tags': ' '.join(escape(t) + 'ttt'
|
||||
for t in tags.tags_list),
|
||||
'series': series,
|
||||
'series_label': 'Series',
|
||||
'tags': tags,
|
||||
'tags_label': 'Tags',
|
||||
'title': title,
|
||||
'title_str': title_str,
|
||||
'xmlns': XHTML_NS}
|
||||
|
||||
for key in mi.custom_field_keys():
|
||||
m = mi.get_user_metadata(key, False) or {}
|
||||
try:
|
||||
|
||||
@@ -35,10 +35,9 @@ class SplitError(ValueError):
|
||||
|
||||
def __init__(self, path, root):
|
||||
size = len(tostring(root))/1024.
|
||||
ValueError.__init__(self,
|
||||
_('Could not find reasonable point at which to split: '
|
||||
'%(path)s Sub-tree size: %(size)d KB')%dict(
|
||||
path=path, size=size))
|
||||
ValueError.__init__(self, 'Could not find reasonable point at which '
|
||||
'to split: %(path)s Sub-tree size: %(size)d KB' %
|
||||
{'path': path, 'size': size})
|
||||
|
||||
|
||||
class Split(object):
|
||||
|
||||
@@ -100,7 +100,7 @@ class DetectStructure(object):
|
||||
|
||||
for node in self.oeb.toc.iter():
|
||||
if not node.title or not node.title.strip():
|
||||
node.title = _('Unnamed')
|
||||
node.title = 'Unnamed'
|
||||
|
||||
if self.opts.start_reading_at:
|
||||
self.detect_start_reading()
|
||||
@@ -279,7 +279,7 @@ class DetectStructure(object):
|
||||
node = self.oeb.toc.add(text, _href,
|
||||
play_order=self.oeb.toc.next_play_order())
|
||||
added[elem] = node
|
||||
# node.add(_('Top'), _href)
|
||||
# node.add('Top', _href)
|
||||
|
||||
if self.opts.level2_toc is not None and added:
|
||||
level2_toc, level2_title = self.get_toc_parts_for_xpath(self.opts.level2_toc)
|
||||
|
||||
@@ -29,13 +29,13 @@ class OEBWriter(object):
|
||||
"""Add any book-writing options to the :class:`Config` object
|
||||
:param:`cfg`.
|
||||
"""
|
||||
oeb = cfg.add_group('oeb', _('OPF/NCX/etc. generation options.'))
|
||||
oeb = cfg.add_group('oeb', 'OPF/NCX/etc. generation options.')
|
||||
versions = ['1.2', '2.0']
|
||||
oeb('opf_version', ['--opf-version'], default='2.0', choices=versions,
|
||||
help=_('OPF version to generate. Default is %default.'))
|
||||
help='OPF version to generate. Default is %default.')
|
||||
oeb('adobe_page_map', ['--adobe-page-map'], default=False,
|
||||
help=_('Generate an Adobe "page-map" file if pagination '
|
||||
'information is available.'))
|
||||
help='Generate an Adobe "page-map" file if pagination '
|
||||
'information is available.')
|
||||
return cfg
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -124,7 +124,7 @@ class Reader132(FormatReader):
|
||||
toc = hizer.get_toc()
|
||||
|
||||
if self.header_record.footnote_count > 0:
|
||||
html += '<br /><h1>%s</h1>' % _('Footnotes')
|
||||
html += '<br /><h1>%s</h1>' % 'Footnotes'
|
||||
footnoteids = re.findall(
|
||||
'\\w+(?=\x00)', self.section_data(self.header_record.footnote_offset).decode('cp1252' if self.encoding is None else self.encoding))
|
||||
for fid, i in enumerate(range(self.header_record.footnote_offset + 1, self.header_record.footnote_offset + self.header_record.footnote_count)):
|
||||
@@ -136,7 +136,7 @@ class Reader132(FormatReader):
|
||||
html += footnote_to_html(fid, self.decompress_text(i))
|
||||
|
||||
if self.header_record.sidebar_count > 0:
|
||||
html += '<br /><h1>%s</h1>' % _('Sidebar')
|
||||
html += '<br /><h1>%s</h1>' % 'Sidebar'
|
||||
sidebarids = re.findall(
|
||||
'\\w+(?=\x00)', self.section_data(self.header_record.sidebar_offset).decode('cp1252' if self.encoding is None else self.encoding))
|
||||
for sid, i in enumerate(range(self.header_record.sidebar_offset + 1, self.header_record.sidebar_offset + self.header_record.sidebar_count)):
|
||||
|
||||
@@ -70,8 +70,8 @@ def pdftohtml(output_dir, pdf_path, no_images, as_xml=False):
|
||||
stdin=subprocess.PIPE)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
raise ConversionError(
|
||||
_('Could not find pdftohtml, check it is in your PATH'))
|
||||
raise ConversionError('Could not find pdftohtml, check it is '
|
||||
'in your PATH')
|
||||
else:
|
||||
raise
|
||||
ret = eintr_retry_call(p.wait)
|
||||
|
||||
@@ -142,7 +142,7 @@ def convert_markdown_with_metadata(txt, title='', extensions=DEFAULT_MD_EXTENSIO
|
||||
extensions.append('meta')
|
||||
md = create_markdown_object(extensions)
|
||||
html = md.convert(txt)
|
||||
mi = Metadata(title or _('Unknown'))
|
||||
mi = Metadata(title or 'Unknown')
|
||||
m = md.Meta
|
||||
for k, v in {'date':'pubdate', 'summary':'comments'}.items():
|
||||
if v not in m and k in m:
|
||||
|
||||
@@ -96,7 +96,7 @@ class TXTMLizer(object):
|
||||
toc = ['']
|
||||
if getattr(self.opts, 'inline_toc', None):
|
||||
self.log.debug('Generating table of contents...')
|
||||
toc.append('%s\n\n' % _('Table of Contents:'))
|
||||
toc.append('%s\n\n' % 'Table of Contents:')
|
||||
for item in self.toc_titles:
|
||||
toc.append('* %s\n\n' % item)
|
||||
return ''.join(toc)
|
||||
|
||||
@@ -30,78 +30,79 @@ class BIBTEX(CatalogPlugin):
|
||||
default='all',
|
||||
dest='fields',
|
||||
action=None,
|
||||
help=_('The fields to output when cataloging books in the '
|
||||
help='The fields to output when cataloging books in the '
|
||||
'database. Should be a comma-separated list of fields.\n'
|
||||
'Available fields: %(fields)s.\n'
|
||||
'plus user-created custom fields.\n'
|
||||
'Example: %(opt)s=title,authors,tags\n'
|
||||
"Default: '%%default'\n"
|
||||
"Applies to: BIBTEX output format")%dict(
|
||||
"Applies to: BIBTEX output format" % dict(
|
||||
fields=', '.join(FIELDS), opt='--fields')),
|
||||
|
||||
Option('--sort-by',
|
||||
default='id',
|
||||
dest='sort_by',
|
||||
action=None,
|
||||
help=_('Output field to sort on.\n'
|
||||
help='Output field to sort on.\n'
|
||||
'Available fields: author_sort, id, rating, size, timestamp, title.\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: BIBTEX output format")),
|
||||
"Applies to: BIBTEX output format"),
|
||||
|
||||
Option('--create-citation',
|
||||
default='True',
|
||||
dest='impcit',
|
||||
action=None,
|
||||
help=_('Create a citation for BibTeX entries.\n'
|
||||
help='Create a citation for BibTeX entries.\n'
|
||||
'Boolean value: True, False\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: BIBTEX output format")),
|
||||
"Applies to: BIBTEX output format"),
|
||||
|
||||
Option('--add-files-path',
|
||||
default='True',
|
||||
dest='addfiles',
|
||||
action=None,
|
||||
help=_('Create a file entry if formats is selected for BibTeX entries.\n'
|
||||
help='Create a file entry if formats is selected for BibTeX entries.\n'
|
||||
'Boolean value: True, False\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: BIBTEX output format")),
|
||||
"Applies to: BIBTEX output format"),
|
||||
|
||||
Option('--citation-template',
|
||||
default='{authors}{id}',
|
||||
dest='bib_cit',
|
||||
action=None,
|
||||
help=_('The template for citation creation from database fields.\n'
|
||||
help='The template for citation creation from database fields.\n'
|
||||
'Should be a template with {} enclosed fields.\n'
|
||||
'Available fields: %s.\n'
|
||||
"Default: '%%default'\n"
|
||||
"Applies to: BIBTEX output format")%', '.join(TEMPLATE_ALLOWED_FIELDS)),
|
||||
"Applies to: BIBTEX output format" %
|
||||
', '.join(TEMPLATE_ALLOWED_FIELDS)),
|
||||
|
||||
Option('--choose-encoding',
|
||||
default='utf8',
|
||||
dest='bibfile_enc',
|
||||
action=None,
|
||||
help=_('BibTeX file encoding output.\n'
|
||||
help='BibTeX file encoding output.\n'
|
||||
'Available types: utf8, cp1252, ascii.\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: BIBTEX output format")),
|
||||
"Applies to: BIBTEX output format"),
|
||||
|
||||
Option('--choose-encoding-configuration',
|
||||
default='strict',
|
||||
dest='bibfile_enctag',
|
||||
action=None,
|
||||
help=_('BibTeX file encoding flag.\n'
|
||||
help='BibTeX file encoding flag.\n'
|
||||
'Available types: strict, replace, ignore, backslashreplace.\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: BIBTEX output format")),
|
||||
"Applies to: BIBTEX output format"),
|
||||
|
||||
Option('--entry-type',
|
||||
default='book',
|
||||
dest='bib_entry',
|
||||
action=None,
|
||||
help=_('Entry type for BibTeX catalog.\n'
|
||||
help='Entry type for BibTeX catalog.\n'
|
||||
'Available types: book, misc, mixed.\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: BIBTEX output format"))]
|
||||
"Applies to: BIBTEX output format")]
|
||||
|
||||
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
||||
from ebook_converter.utils.date import isoformat
|
||||
|
||||
@@ -29,23 +29,23 @@ class CSV_XML(CatalogPlugin):
|
||||
default='all',
|
||||
dest='fields',
|
||||
action=None,
|
||||
help=_('The fields to output when cataloging books in the '
|
||||
help='The fields to output when cataloging books in the '
|
||||
'database. Should be a comma-separated list of fields.\n'
|
||||
'Available fields: %(fields)s,\n'
|
||||
'plus user-created custom fields.\n'
|
||||
'Example: %(opt)s=title,authors,tags\n'
|
||||
"Default: '%%default'\n"
|
||||
"Applies to: CSV, XML output formats") % dict(
|
||||
"Applies to: CSV, XML output formats" % dict(
|
||||
fields=', '.join(FIELDS), opt='--fields')),
|
||||
|
||||
Option('--sort-by',
|
||||
default='id',
|
||||
dest='sort_by',
|
||||
action=None,
|
||||
help=_('Output field to sort on.\n'
|
||||
help='Output field to sort on.\n'
|
||||
'Available fields: author_sort, id, rating, size, timestamp, title_sort\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: CSV, XML output formats"))]
|
||||
"Applies to: CSV, XML output formats")]
|
||||
|
||||
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
||||
from ebook_converter.library import current_library_name
|
||||
|
||||
@@ -36,154 +36,178 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
default='My Books',
|
||||
dest='catalog_title',
|
||||
action=None,
|
||||
help=_('Title of generated catalog used as title in metadata.\n'
|
||||
help='Title of generated catalog used as title in '
|
||||
'metadata.\n'
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--cross-reference-authors',
|
||||
default=False,
|
||||
dest='cross_reference_authors',
|
||||
action='store_true',
|
||||
help=_("Create cross-references in Authors section for books with multiple authors.\n"
|
||||
help="Create cross-references in Authors section "
|
||||
"for books with multiple authors.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--debug-pipeline',
|
||||
default=None,
|
||||
dest='debug_pipeline',
|
||||
action=None,
|
||||
help=_("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.\n"
|
||||
help="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.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--exclude-genre',
|
||||
default=r'\[.+\]|^\+$',
|
||||
dest='exclude_genre',
|
||||
action=None,
|
||||
help=_("Regex describing tags to exclude as genres.\n"
|
||||
"Default: '%default' excludes bracketed tags, e.g. '[Project Gutenberg]', and '+', the default tag for read books.\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
help="Regex describing tags to exclude as genres.\n"
|
||||
"Default: '%default' excludes bracketed tags, e.g. "
|
||||
"'[Project Gutenberg]', and '+', the default tag "
|
||||
"for read books.\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--exclusion-rules',
|
||||
default="(('Catalogs','Tags','Catalog'),)",
|
||||
dest='exclusion_rules',
|
||||
action=None,
|
||||
help=_("Specifies the rules used to exclude books from the generated catalog.\n"
|
||||
"The model for an exclusion rule is either\n('<rule name>','Tags','<comma-separated list of tags>') or\n"
|
||||
help="Specifies the rules used to exclude books "
|
||||
"from the generated catalog.\n"
|
||||
"The model for an exclusion rule is either\n"
|
||||
"('<rule name>','Tags','<comma-separated list of "
|
||||
"tags>') or\n"
|
||||
"('<rule name>','<custom column>','<pattern>').\n"
|
||||
"For example:\n"
|
||||
"(('Archived books','#status','Archived'),)\n"
|
||||
"will exclude a book with a value of 'Archived' in the custom column 'status'.\n"
|
||||
"When multiple rules are defined, all rules will be applied.\n"
|
||||
"Default: \n" + '"' + '%default' + '"' + "\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"will exclude a book with a value of 'Archived' in "
|
||||
"the custom column 'status'.\n"
|
||||
"When multiple rules are defined, all rules will be "
|
||||
"applied.\n"
|
||||
"Default: \n\"%default\"\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--generate-authors',
|
||||
default=False,
|
||||
dest='generate_authors',
|
||||
action='store_true',
|
||||
help=_("Include 'Authors' section in catalog.\n"
|
||||
help="Include 'Authors' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--generate-descriptions',
|
||||
default=False,
|
||||
dest='generate_descriptions',
|
||||
action='store_true',
|
||||
help=_("Include 'Descriptions' section in catalog.\n"
|
||||
help="Include 'Descriptions' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--generate-genres',
|
||||
default=False,
|
||||
dest='generate_genres',
|
||||
action='store_true',
|
||||
help=_("Include 'Genres' section in catalog.\n"
|
||||
help="Include 'Genres' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--generate-titles',
|
||||
default=False,
|
||||
dest='generate_titles',
|
||||
action='store_true',
|
||||
help=_("Include 'Titles' section in catalog.\n"
|
||||
help="Include 'Titles' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--generate-series',
|
||||
default=False,
|
||||
dest='generate_series',
|
||||
action='store_true',
|
||||
help=_("Include 'Series' section in catalog.\n"
|
||||
help="Include 'Series' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--generate-recently-added',
|
||||
default=False,
|
||||
dest='generate_recently_added',
|
||||
action='store_true',
|
||||
help=_("Include 'Recently Added' section in catalog.\n"
|
||||
help="Include 'Recently Added' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--genre-source-field',
|
||||
default=_('Tags'),
|
||||
default='Tags',
|
||||
dest='genre_source_field',
|
||||
action=None,
|
||||
help=_("Source field for 'Genres' section.\n"
|
||||
help="Source field for 'Genres' section.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--header-note-source-field',
|
||||
default='',
|
||||
dest='header_note_source_field',
|
||||
action=None,
|
||||
help=_("Custom field containing note text to insert in Description header.\n"
|
||||
help="Custom field containing note text to insert "
|
||||
"in Description header.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--merge-comments-rule',
|
||||
default='::',
|
||||
dest='merge_comments_rule',
|
||||
action=None,
|
||||
help=_("#<custom field>:[before|after]:[True|False] specifying:\n"
|
||||
" <custom field> Custom field containing notes to merge with Comments\n"
|
||||
" [before|after] Placement of notes with respect to Comments\n"
|
||||
" [True|False] - A horizontal rule is inserted between notes and Comments\n"
|
||||
help="#<custom field>:[before|after]:[True|False] "
|
||||
"specifying:\n"
|
||||
" <custom field> Custom field containing notes to "
|
||||
"merge with Comments\n"
|
||||
" [before|after] Placement of notes with respect "
|
||||
"to Comments\n"
|
||||
" [True|False] - A horizontal rule is inserted "
|
||||
"between notes and Comments\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--output-profile',
|
||||
default=None,
|
||||
dest='output_profile',
|
||||
action=None,
|
||||
help=_("Specifies the output profile. In some cases, an output profile is required to optimize"
|
||||
" the catalog for the device. For example, 'kindle' or 'kindle_dx' creates a structured"
|
||||
" Table of Contents with Sections and Articles.\n"
|
||||
help="Specifies the output profile. In some cases, "
|
||||
"an output profile is required to optimize the "
|
||||
"catalog for the device. For example, 'kindle' or "
|
||||
"'kindle_dx' creates a structured Table of Contents "
|
||||
"with Sections and Articles.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--prefix-rules',
|
||||
default="(('Read books','tags','+','\u2713'),('Wishlist item','tags','Wishlist','\u00d7'))",
|
||||
default="(('Read books','tags','+','\u2713'),"
|
||||
"('Wishlist item','tags','Wishlist','\u00d7'))",
|
||||
dest='prefix_rules',
|
||||
action=None,
|
||||
help=_("Specifies the rules used to include prefixes indicating read books, wishlist items and other user-specified prefixes.\n"
|
||||
"The model for a prefix rule is ('<rule name>','<source field>','<pattern>','<prefix>').\n"
|
||||
"When multiple rules are defined, the first matching rule will be used.\n"
|
||||
help="Specifies the rules used to include prefixes "
|
||||
"indicating read books, wishlist items and other "
|
||||
"user-specified prefixes.\n"
|
||||
"The model for a prefix rule is ('<rule name>',"
|
||||
"'<source field>','<pattern>','<prefix>').\n"
|
||||
"When multiple rules are defined, the first "
|
||||
"matching rule will be used.\n"
|
||||
"Default:\n" + '"' + '%default' + '"' + "\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--preset',
|
||||
default=None,
|
||||
dest='preset',
|
||||
action=None,
|
||||
help=_("Use a named preset created with the GUI catalog builder.\n"
|
||||
"A preset specifies all settings for building a catalog.\n"
|
||||
help="Use a named preset created with the GUI "
|
||||
"catalog builder.\n"
|
||||
"A preset specifies all settings for building a "
|
||||
"catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--use-existing-cover',
|
||||
default=False,
|
||||
dest='use_existing_cover',
|
||||
action='store_true',
|
||||
help=_("Replace existing cover when generating the catalog.\n"
|
||||
help="Replace existing cover when generating the "
|
||||
"catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
"Applies to: AZW3, EPUB, MOBI output formats"),
|
||||
Option('--thumb-width',
|
||||
default='1.0',
|
||||
dest='thumb_width',
|
||||
action=None,
|
||||
help=_("Size hint (in inches) for book covers in catalog.\n"
|
||||
help="Size hint (in inches) for book covers in "
|
||||
"catalog.\n"
|
||||
"Range: 1.0 - 2.0\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")),
|
||||
]
|
||||
"Applies to: AZW3, EPUB, MOBI output formats")]
|
||||
# }}}
|
||||
|
||||
def run(self, path_to_output, opts, db, notification=DummyReporter()):
|
||||
@@ -196,10 +220,12 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
available_presets = JSONConfig("catalog_presets")
|
||||
if opts.preset not in available_presets:
|
||||
if available_presets:
|
||||
print(_('Error: Preset "%s" not found.' % opts.preset))
|
||||
print(_('Stored presets: %s' % ', '.join([p for p in sorted(available_presets.keys())])))
|
||||
print('Error: Preset "%s" not found.' % opts.preset)
|
||||
print('Stored presets: %s' %
|
||||
', '.join([p for p in
|
||||
sorted(available_presets.keys())]))
|
||||
else:
|
||||
print(_('Error: No stored presets.'))
|
||||
print('Error: No stored presets.')
|
||||
return 1
|
||||
|
||||
# Copy the relevant preset values to the opts object
|
||||
@@ -329,7 +355,8 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
opts.log.warn('\n*** No enabled Sections, terminating catalog generation ***')
|
||||
return ["No Included Sections", "No enabled Sections.\nCheck E-book options tab\n'Included sections'\n"]
|
||||
if opts.fmt == 'mobi' and sections_list == ['Descriptions']:
|
||||
warning = _("\n*** Adding 'By authors' section required for MOBI output ***")
|
||||
warning = ("\n*** Adding 'By authors' section required for MOBI "
|
||||
"output ***")
|
||||
opts.log.warn(warning)
|
||||
sections_list.insert(0, 'Authors')
|
||||
opts.generate_authors = True
|
||||
|
||||
@@ -41,7 +41,7 @@ def _builtin_field_metadata():
|
||||
'ui_to_list': '&',
|
||||
'list_to_ui': ' & '},
|
||||
'kind':'field',
|
||||
'name':_('Authors'),
|
||||
'name':'Authors',
|
||||
'search_terms':['authors', 'author'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -55,7 +55,7 @@ def _builtin_field_metadata():
|
||||
'ui_to_list': ',',
|
||||
'list_to_ui': ', '},
|
||||
'kind':'field',
|
||||
'name':_('Languages'),
|
||||
'name':'Languages',
|
||||
'search_terms':['languages', 'language'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -68,7 +68,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'series',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':ngettext('Series', 'Series', 1),
|
||||
'name': 'Series',
|
||||
'search_terms':['series'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -80,7 +80,7 @@ def _builtin_field_metadata():
|
||||
'ui_to_list': ',',
|
||||
'list_to_ui': ', '},
|
||||
'kind':'field',
|
||||
'name':_('Formats'),
|
||||
'name':'Formats',
|
||||
'search_terms':['formats', 'format'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -92,7 +92,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Publisher'),
|
||||
'name':'Publisher',
|
||||
'search_terms':['publisher'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -104,7 +104,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'rating',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Rating'),
|
||||
'name':'Rating',
|
||||
'search_terms':['rating'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -115,7 +115,7 @@ def _builtin_field_metadata():
|
||||
'datatype':None,
|
||||
'is_multiple':{},
|
||||
'kind':'category',
|
||||
'name':_('News'),
|
||||
'name':'News',
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -129,7 +129,7 @@ def _builtin_field_metadata():
|
||||
'ui_to_list': ',',
|
||||
'list_to_ui': ', '},
|
||||
'kind':'field',
|
||||
'name':_('Tags'),
|
||||
'name':'Tags',
|
||||
'search_terms':['tags', 'tag'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -141,7 +141,7 @@ def _builtin_field_metadata():
|
||||
'ui_to_list': ',',
|
||||
'list_to_ui': ', '},
|
||||
'kind':'field',
|
||||
'name':_('Identifiers'),
|
||||
'name':'Identifiers',
|
||||
'search_terms':['identifiers', 'identifier', 'isbn'],
|
||||
'is_custom':False,
|
||||
'is_category':True,
|
||||
@@ -151,7 +151,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Author sort'),
|
||||
'name':'Author sort',
|
||||
'search_terms':['author_sort'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -173,7 +173,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Comments'),
|
||||
'name':'Comments',
|
||||
'search_terms':['comments', 'comment'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -183,7 +183,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'int',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Cover'),
|
||||
'name':'Cover',
|
||||
'search_terms':['cover'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -203,7 +203,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'datetime',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Modified'),
|
||||
'name':'Modified',
|
||||
'search_terms':['last_modified'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -213,7 +213,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('On device'),
|
||||
'name':'On device',
|
||||
'search_terms':['ondevice'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -223,7 +223,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Path'),
|
||||
'name':'Path',
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -233,7 +233,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'datetime',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Published'),
|
||||
'name':'Published',
|
||||
'search_terms':['pubdate'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -263,7 +263,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Series sort'),
|
||||
'name':'Series sort',
|
||||
'search_terms':['series_sort'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -273,7 +273,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Title sort'),
|
||||
'name':'Title sort',
|
||||
'search_terms':['title_sort'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -283,7 +283,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'float',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Size'),
|
||||
'name':'Size',
|
||||
'search_terms':['size'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -293,7 +293,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'datetime',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Date'),
|
||||
'name':'Date',
|
||||
'search_terms':['date'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -303,7 +303,7 @@ def _builtin_field_metadata():
|
||||
'datatype':'text',
|
||||
'is_multiple':{},
|
||||
'kind':'field',
|
||||
'name':_('Title'),
|
||||
'name':'Title',
|
||||
'search_terms':['title'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@@ -452,7 +452,7 @@ class FieldMetadata(object):
|
||||
'series_index', 'path', 'formats', 'identifiers', 'uuid',
|
||||
'comments',
|
||||
} if self._tb_cats[k]['name']}
|
||||
ans['cover'] = _('Has cover')
|
||||
ans['cover'] = 'Has cover'
|
||||
return ans
|
||||
|
||||
def displayable_field_keys(self):
|
||||
|
||||
@@ -12,13 +12,6 @@ import sys
|
||||
|
||||
from ebook_converter import constants
|
||||
|
||||
# Default translation is NOOP
|
||||
builtins.__dict__['_'] = lambda s: s
|
||||
|
||||
# For strings which belong in the translation tables, but which shouldn't be
|
||||
# immediately translated to the environment language
|
||||
builtins.__dict__['__'] = lambda s: s
|
||||
|
||||
# For backwards compat with some third party plugins
|
||||
builtins.__dict__['dynamic_property'] = lambda func: func(None)
|
||||
|
||||
@@ -93,12 +86,6 @@ if not _run_once:
|
||||
import ebook_converter.utils.resources as resources
|
||||
resources
|
||||
|
||||
#
|
||||
# Setup translations
|
||||
from ebook_converter.utils.localization import set_translators
|
||||
|
||||
set_translators()
|
||||
|
||||
#
|
||||
# Initialize locale
|
||||
# Import string as we do not want locale specific
|
||||
|
||||
@@ -16,10 +16,6 @@ from ebook_converter.utils.config_base import (
|
||||
from ebook_converter.utils.lock import ExclusiveFile
|
||||
|
||||
|
||||
# optparse uses gettext.gettext instead of _ from builtins, so we
|
||||
# monkey patch it.
|
||||
optparse._ = _
|
||||
|
||||
if False:
|
||||
# Make pyflakes happy
|
||||
Config, ConfigProxy, Option, OptionValues, StringConfig, OptionSet,
|
||||
@@ -38,7 +34,7 @@ class CustomHelpFormatter(optparse.IndentedHelpFormatter):
|
||||
if parts:
|
||||
parts[0] = colored(parts[0], fg='yellow', bold=True)
|
||||
usage = ' '.join(parts)
|
||||
return colored(_('Usage'), fg='blue', bold=True) + ': ' + usage
|
||||
return colored('Usage', fg='blue', bold=True) + ': ' + usage
|
||||
|
||||
def format_heading(self, heading):
|
||||
from ebook_converter.utils.terminal import colored
|
||||
@@ -89,21 +85,18 @@ class OptionParser(optparse.OptionParser):
|
||||
|
||||
usage = textwrap.dedent(usage)
|
||||
if epilog is None:
|
||||
epilog = _('Created by ')+colored(__author__, fg='cyan')
|
||||
usage += '\n\n'+_('''Whenever you pass arguments to %prog that have spaces in them, '''
|
||||
'''enclose the arguments in quotation marks. For example: "{}"''').format(
|
||||
"C:\\some path with spaces" if iswindows else '/some path/with spaces') +'\n'
|
||||
epilog = 'Created by ' + colored(__author__, fg='cyan')
|
||||
usage += ('\n\nWhenever you pass arguments to %prog that have spaces '
|
||||
'in them, enclose the arguments in quotation marks. For '
|
||||
'example: "{}"\n\n').format("C:\\some path with spaces"
|
||||
if iswindows
|
||||
else '/some path/with spaces')
|
||||
if version is None:
|
||||
version = '%%prog (%s %s)'%(__appname__, get_version())
|
||||
optparse.OptionParser.__init__(self, usage=usage, version=version, epilog=epilog,
|
||||
formatter=CustomHelpFormatter(),
|
||||
conflict_handler=conflict_handler, **kwds)
|
||||
self.gui_mode = gui_mode
|
||||
if False:
|
||||
# Translatable string from optparse
|
||||
_("Options")
|
||||
_("show this help message and exit")
|
||||
_("show program's version number and exit")
|
||||
|
||||
def print_usage(self, file=None):
|
||||
from ebook_converter.utils.terminal import ANSIStream
|
||||
|
||||
@@ -473,72 +473,70 @@ def create_global_prefs(conf_obj=None):
|
||||
c = Config('global', 'calibre wide preferences') if conf_obj is None else conf_obj
|
||||
c.add_opt('database_path',
|
||||
default=os.path.expanduser('~/library1.db'),
|
||||
help=_('Path to the database in which books are stored'))
|
||||
help='Path to the database in which books are stored')
|
||||
c.add_opt('filename_pattern', default=u'(?P<title>.+) - (?P<author>[^_]+)',
|
||||
help=_('Pattern to guess metadata from filenames'))
|
||||
help='Pattern to guess metadata from filenames')
|
||||
c.add_opt('isbndb_com_key', default='',
|
||||
help=_('Access key for isbndb.com'))
|
||||
help='Access key for isbndb.com')
|
||||
c.add_opt('network_timeout', default=5,
|
||||
help=_('Default timeout for network operations (seconds)'))
|
||||
help='Default timeout for network operations (seconds)')
|
||||
c.add_opt('library_path', default=None,
|
||||
help=_('Path to directory in which your library of books is stored'))
|
||||
help='Path to directory in which your library of books is stored')
|
||||
c.add_opt('language', default=None,
|
||||
help=_('The language in which to display the user interface'))
|
||||
help='The language in which to display the user interface')
|
||||
c.add_opt('output_format', default='EPUB',
|
||||
help=_('The default output format for e-book conversions. When auto-converting'
|
||||
help='The default output format for e-book conversions. When auto-converting'
|
||||
' to send to a device this can be overridden by individual device preferences.'
|
||||
' These can be changed by right clicking the device icon in calibre and'
|
||||
' choosing "Configure".'))
|
||||
' choosing "Configure".')
|
||||
c.add_opt('input_format_order', default=['EPUB', 'AZW3', 'MOBI', 'LIT', 'PRC',
|
||||
'FB2', 'HTML', 'HTM', 'XHTM', 'SHTML', 'XHTML', 'ZIP', 'DOCX', 'ODT', 'RTF', 'PDF',
|
||||
'TXT'],
|
||||
help=_('Ordered list of formats to prefer for input.'))
|
||||
help='Ordered list of formats to prefer for input.')
|
||||
c.add_opt('read_file_metadata', default=True,
|
||||
help=_('Read metadata from files'))
|
||||
help='Read metadata from files')
|
||||
c.add_opt('worker_process_priority', default='normal',
|
||||
help=_('The priority of worker processes. A higher priority '
|
||||
help='The priority of worker processes. A higher priority '
|
||||
'means they run faster and consume more resources. '
|
||||
'Most tasks like conversion/news download/adding books/etc. '
|
||||
'are affected by this setting.'))
|
||||
'are affected by this setting.')
|
||||
c.add_opt('swap_author_names', default=False,
|
||||
help=_('Swap author first and last names when reading metadata'))
|
||||
help='Swap author first and last names when reading metadata')
|
||||
c.add_opt('add_formats_to_existing', default=False,
|
||||
help=_('Add new formats to existing book records'))
|
||||
help='Add new formats to existing book records')
|
||||
c.add_opt('check_for_dupes_on_ctl', default=False,
|
||||
help=_('Check for duplicates when copying to another library'))
|
||||
help='Check for duplicates when copying to another library')
|
||||
c.add_opt('installation_uuid', default=None, help='Installation UUID')
|
||||
c.add_opt('new_book_tags', default=[], help=_('Tags to apply to books added to the library'))
|
||||
c.add_opt('mark_new_books', default=False, help=_(
|
||||
'Mark newly added books. The mark is a temporary mark that is automatically removed when calibre is restarted.'))
|
||||
c.add_opt('new_book_tags', default=[], help='Tags to apply to books added to the library')
|
||||
c.add_opt('mark_new_books', default=False, help='Mark newly added books. The mark is a temporary mark that is automatically removed when calibre is restarted.')
|
||||
|
||||
# these are here instead of the gui preferences because calibredb and
|
||||
# calibre server can execute searches
|
||||
c.add_opt('saved_searches', default={}, help=_('List of named saved searches'))
|
||||
c.add_opt('user_categories', default={}, help=_('User-created Tag browser categories'))
|
||||
c.add_opt('saved_searches', default={}, help='List of named saved searches')
|
||||
c.add_opt('user_categories', default={}, help='User-created Tag browser categories')
|
||||
c.add_opt('manage_device_metadata', default='manual',
|
||||
help=_('How and when calibre updates metadata on the device.'))
|
||||
help='How and when calibre updates metadata on the device.')
|
||||
c.add_opt('limit_search_columns', default=False,
|
||||
help=_('When searching for text without using lookup '
|
||||
help='When searching for text without using lookup '
|
||||
'prefixes, as for example, Red instead of title:Red, '
|
||||
'limit the columns searched to those named below.'))
|
||||
'limit the columns searched to those named below.')
|
||||
c.add_opt('limit_search_columns_to',
|
||||
default=['title', 'authors', 'tags', 'series', 'publisher'],
|
||||
help=_('Choose columns to be searched when not using prefixes, '
|
||||
help='Choose columns to be searched when not using prefixes, '
|
||||
'as for example, when searching for Red instead of '
|
||||
'title:Red. Enter a list of search/lookup names '
|
||||
'separated by commas. Only takes effect if you set the option '
|
||||
'to limit search columns above.'))
|
||||
'to limit search columns above.')
|
||||
c.add_opt('use_primary_find_in_search', default=True,
|
||||
help=_(u'Characters typed in the search box will match their '
|
||||
help=u'Characters typed in the search box will match their '
|
||||
'accented versions, based on the language you have chosen '
|
||||
'for the calibre interface. For example, in '
|
||||
u'English, searching for n will match both {} and n, but if '
|
||||
'your language is Spanish it will only match n. Note that '
|
||||
'this is much slower than a simple search on very large '
|
||||
'libraries. Also, this option will have no effect if you turn '
|
||||
'on case-sensitive searching'))
|
||||
c.add_opt('case_sensitive', default=False, help=_(
|
||||
'Make searches case-sensitive'))
|
||||
'on case-sensitive searching')
|
||||
c.add_opt('case_sensitive', default=False, help='Make searches case-sensitive')
|
||||
|
||||
c.add_opt('migrated', default=False, help='For Internal use. Don\'t modify.')
|
||||
return c
|
||||
|
||||
@@ -402,7 +402,7 @@ class WindowsAtomicFolderMove(object):
|
||||
self.close_handles()
|
||||
if getattr(e, 'winerror', 0) == winerror.ERROR_SHARING_VIOLATION:
|
||||
err = IOError(errno.EACCES,
|
||||
_('File is open in another process'))
|
||||
'File is open in another process')
|
||||
err.filename = f
|
||||
raise err
|
||||
prints('CreateFile failed for: %r' % f)
|
||||
|
||||
@@ -30,7 +30,8 @@ class _Parser(object):
|
||||
self.prog = prog[0]
|
||||
self.prog_len = len(self.prog)
|
||||
if prog[1] != '':
|
||||
self.error(_('failed to scan program. Invalid input {0}').format(prog[1]))
|
||||
self.error('failed to scan program. Invalid input '
|
||||
'{0}'.format(prog[1]))
|
||||
self.parent = parent
|
||||
self.parent_kwargs = parent.kwargs
|
||||
self.parent_book = parent.book
|
||||
@@ -38,13 +39,13 @@ class _Parser(object):
|
||||
self.funcs = funcs
|
||||
|
||||
def error(self, message):
|
||||
m = 'Formatter: ' + message + _(' near ')
|
||||
m = 'Formatter: ' + message + ' near '
|
||||
if self.lex_pos > 0:
|
||||
m = '{0} {1}'.format(m, self.prog[self.lex_pos-1][1])
|
||||
elif self.lex_pos < self.prog_len:
|
||||
m = '{0} {1}'.format(m, self.prog[self.lex_pos+1][1])
|
||||
else:
|
||||
m = '{0} {1}'.format(m, _('end of program'))
|
||||
m = '{0} {1}'.format(m, 'end of program')
|
||||
raise ValueError(m)
|
||||
|
||||
def token(self):
|
||||
@@ -106,7 +107,7 @@ class _Parser(object):
|
||||
def program(self):
|
||||
val = self.statement()
|
||||
if not self.token_is_eof():
|
||||
self.error(_('syntax error - program ends before EOF'))
|
||||
self.error('syntax error - program ends before EOF')
|
||||
return val
|
||||
|
||||
def statement(self):
|
||||
@@ -133,14 +134,14 @@ class _Parser(object):
|
||||
self.parent_book, self.locals, id, self.expr())
|
||||
val = self.locals.get(id, None)
|
||||
if val is None:
|
||||
self.error(_('Unknown identifier ') + id)
|
||||
self.error('Unknown identifier ' + id)
|
||||
return val
|
||||
# We have a function.
|
||||
# Check if it is a known one. We do this here so error reporting is
|
||||
# better, as it can identify the tokens near the problem.
|
||||
id = id.strip()
|
||||
if id not in self.funcs:
|
||||
self.error(_('unknown function {0}').format(id))
|
||||
self.error('unknown function {0}'.format(id))
|
||||
|
||||
# Eat the paren
|
||||
self.consume()
|
||||
@@ -160,7 +161,7 @@ class _Parser(object):
|
||||
break
|
||||
self.consume()
|
||||
if self.token() != ')':
|
||||
self.error(_('missing closing parenthesis'))
|
||||
self.error('missing closing parenthesis')
|
||||
|
||||
# Evaluate the function
|
||||
cls = self.funcs[id]
|
||||
@@ -172,7 +173,7 @@ class _Parser(object):
|
||||
# String or number
|
||||
return self.token()
|
||||
else:
|
||||
self.error(_('expression is not function or constant'))
|
||||
self.error('expression is not function or constant')
|
||||
|
||||
|
||||
class TemplateFormatter(string.Formatter):
|
||||
@@ -206,14 +207,14 @@ class TemplateFormatter(string.Formatter):
|
||||
try:
|
||||
val = int(val)
|
||||
except Exception:
|
||||
raise ValueError(
|
||||
_('format: type {0} requires an integer value, got {1}').format(typ, val))
|
||||
raise ValueError('format: type {0} requires an integer value, '
|
||||
'got {1}'.format(typ, val))
|
||||
elif 'eEfFgGn%'.find(typ) >= 0:
|
||||
try:
|
||||
val = float(val)
|
||||
except:
|
||||
raise ValueError(
|
||||
_('format: type {0} requires a decimal (float) value, got {1}').format(typ, val))
|
||||
raise ValueError('format: type {0} requires a decimal (float) '
|
||||
'value, got {1}'.format(typ, val))
|
||||
return str(('{0:'+fmt+'}').format(val))
|
||||
|
||||
def _explode_format_string(self, fmt):
|
||||
@@ -329,7 +330,7 @@ class TemplateFormatter(string.Formatter):
|
||||
if self.strip_results:
|
||||
val = val.strip()
|
||||
else:
|
||||
return _('%s: unknown function')%fname
|
||||
return '%s: unknown function' % fname
|
||||
if val:
|
||||
val = self._do_format(val, dispfmt)
|
||||
if not val:
|
||||
@@ -408,7 +409,7 @@ class EvalFormatter(TemplateFormatter):
|
||||
if key == '':
|
||||
return ''
|
||||
key = key.lower()
|
||||
return kwargs.get(key, _('No such variable ') + key)
|
||||
return kwargs.get(key, 'No such variable ' + key)
|
||||
|
||||
|
||||
# DEPRECATED. This is not thread safe. Do not use.
|
||||
|
||||
@@ -23,10 +23,10 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
class FormatterFunctions(object):
|
||||
|
||||
error_function_body = ('def evaluate(self, formatter, kwargs, mi, locals):\n'
|
||||
'\treturn "' +
|
||||
_('Duplicate user function name {0}. '
|
||||
'Change the name or ensure that the functions are identical') + '"')
|
||||
error_function_body = ('def evaluate(self, formatter, kwargs, mi, '
|
||||
'locals):\n\treturn "Duplicate user function name '
|
||||
'{0}. Change the name or ensure that the functions '
|
||||
'are identical"')
|
||||
|
||||
def __init__(self):
|
||||
self._builtins = {}
|
||||
@@ -39,7 +39,7 @@ class FormatterFunctions(object):
|
||||
func_class.__class__.__name__))
|
||||
name = func_class.name
|
||||
if name in self._functions:
|
||||
raise ValueError('Name %s already used'%name)
|
||||
raise ValueError('Name %s already used' % name)
|
||||
self._builtins[name] = func_class
|
||||
self._functions[name] = func_class
|
||||
for a in func_class.aliases:
|
||||
@@ -51,7 +51,7 @@ class FormatterFunctions(object):
|
||||
func_class.__class__.__name__))
|
||||
name = func_class.name
|
||||
if not replace and name in self._functions:
|
||||
raise ValueError('Name %s already used'%name)
|
||||
raise ValueError('Name %s already used' % name)
|
||||
self._functions[name] = func_class
|
||||
|
||||
def register_functions(self, library_uuid, funcs):
|
||||
@@ -116,7 +116,7 @@ def formatter_functions():
|
||||
|
||||
class FormatterFunction(object):
|
||||
|
||||
doc = _('No documentation provided')
|
||||
doc = 'No documentation provided'
|
||||
name = 'no name provided'
|
||||
category = 'Unknown'
|
||||
arg_count = 0
|
||||
@@ -152,9 +152,9 @@ class BuiltinStrcmp(BuiltinFormatterFunction):
|
||||
name = 'strcmp'
|
||||
arg_count = 5
|
||||
category = 'Relational'
|
||||
__doc__ = doc = _('strcmp(x, y, lt, eq, gt) -- does a case-insensitive comparison of x '
|
||||
'and y as strings. Returns lt if x < y. Returns eq if x == y. '
|
||||
'Otherwise returns gt.')
|
||||
__doc__ = doc = ('strcmp(x, y, lt, eq, gt) -- does a case-insensitive '
|
||||
'comparison of x and y as strings. Returns lt if x < y. '
|
||||
'Returns eq if x == y. Otherwise returns gt.')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):
|
||||
v = strcmp(x, y)
|
||||
@@ -169,8 +169,9 @@ class BuiltinCmp(BuiltinFormatterFunction):
|
||||
name = 'cmp'
|
||||
category = 'Relational'
|
||||
arg_count = 5
|
||||
__doc__ = doc = _('cmp(x, y, lt, eq, gt) -- compares x and y after converting both to '
|
||||
'numbers. Returns lt if x < y. Returns eq if x == y. Otherwise returns gt.')
|
||||
__doc__ = doc = ('cmp(x, y, lt, eq, gt) -- compares x and y after '
|
||||
'converting both to numbers. Returns lt if x < y. '
|
||||
'Returns eq if x == y. Otherwise returns gt.')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):
|
||||
x = float(x if x and x != 'None' else 0)
|
||||
@@ -186,16 +187,18 @@ class BuiltinFirstMatchingCmp(BuiltinFormatterFunction):
|
||||
name = 'first_matching_cmp'
|
||||
category = 'Relational'
|
||||
arg_count = -1
|
||||
__doc__ = doc = _('first_matching_cmp(val, cmp1, result1, cmp2, r2, ..., else_result) -- '
|
||||
'compares "val < cmpN" in sequence, returning resultN for '
|
||||
'the first comparison that succeeds. Returns else_result '
|
||||
'if no comparison succeeds. Example: '
|
||||
'first_matching_cmp(10,5,"small",10,"middle",15,"large","giant") '
|
||||
'returns "large". The same example with a first value of 16 returns "giant".')
|
||||
__doc__ = doc = ('first_matching_cmp(val, cmp1, result1, cmp2, r2, ..., '
|
||||
'else_result) -- compares "val < cmpN" in sequence, '
|
||||
'returning resultN for the first comparison that '
|
||||
'succeeds. Returns else_result if no comparison '
|
||||
'succeeds. Example: first_matching_cmp(10,5,"small",10,'
|
||||
'"middle",15,"large","giant") returns "large". The same '
|
||||
'example with a first value of 16 returns "giant".')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||
if (len(args) % 2) != 0:
|
||||
raise ValueError(_('first_matching_cmp requires an even number of arguments'))
|
||||
raise ValueError('first_matching_cmp requires an even number of '
|
||||
'arguments')
|
||||
val = float(args[0] if args[0] and args[0] != 'None' else 0)
|
||||
for i in range(1, len(args) - 1, 2):
|
||||
c = float(args[i] if args[i] and args[i] != 'None' else 0)
|
||||
@@ -208,7 +211,7 @@ class BuiltinStrcat(BuiltinFormatterFunction):
|
||||
name = 'strcat'
|
||||
arg_count = -1
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('strcat(a, b, ...) -- can take any number of arguments. Returns a '
|
||||
__doc__ = doc = ('strcat(a, b, ...) -- can take any number of arguments. Returns a '
|
||||
'string formed by concatenating all the arguments')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||
@@ -223,7 +226,7 @@ class BuiltinStrlen(BuiltinFormatterFunction):
|
||||
name = 'strlen'
|
||||
arg_count = 1
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('strlen(a) -- Returns the length of the string passed as '
|
||||
__doc__ = doc = ('strlen(a) -- Returns the length of the string passed as '
|
||||
'the argument')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, a):
|
||||
@@ -237,7 +240,7 @@ class BuiltinAdd(BuiltinFormatterFunction):
|
||||
name = 'add'
|
||||
arg_count = 2
|
||||
category = 'Arithmetic'
|
||||
__doc__ = doc = _('add(x, y) -- returns x + y. Throws an exception if either x or y are not numbers.')
|
||||
__doc__ = doc = 'add(x, y) -- returns x + y. Throws an exception if either x or y are not numbers.'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, x, y):
|
||||
x = float(x if x and x != 'None' else 0)
|
||||
@@ -249,7 +252,7 @@ class BuiltinSubtract(BuiltinFormatterFunction):
|
||||
name = 'subtract'
|
||||
arg_count = 2
|
||||
category = 'Arithmetic'
|
||||
__doc__ = doc = _('subtract(x, y) -- returns x - y. Throws an exception if either x or y are not numbers.')
|
||||
__doc__ = doc = 'subtract(x, y) -- returns x - y. Throws an exception if either x or y are not numbers.'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, x, y):
|
||||
x = float(x if x and x != 'None' else 0)
|
||||
@@ -261,7 +264,7 @@ class BuiltinMultiply(BuiltinFormatterFunction):
|
||||
name = 'multiply'
|
||||
arg_count = 2
|
||||
category = 'Arithmetic'
|
||||
__doc__ = doc = _('multiply(x, y) -- returns x * y. Throws an exception if either x or y are not numbers.')
|
||||
__doc__ = doc = 'multiply(x, y) -- returns x * y. Throws an exception if either x or y are not numbers.'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, x, y):
|
||||
x = float(x if x and x != 'None' else 0)
|
||||
@@ -273,7 +276,7 @@ class BuiltinDivide(BuiltinFormatterFunction):
|
||||
name = 'divide'
|
||||
arg_count = 2
|
||||
category = 'Arithmetic'
|
||||
__doc__ = doc = _('divide(x, y) -- returns x / y. Throws an exception if either x or y are not numbers.')
|
||||
__doc__ = doc = 'divide(x, y) -- returns x / y. Throws an exception if either x or y are not numbers.'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, x, y):
|
||||
x = float(x if x and x != 'None' else 0)
|
||||
@@ -286,7 +289,7 @@ class BuiltinTemplate(BuiltinFormatterFunction):
|
||||
arg_count = 1
|
||||
category = 'Recursion'
|
||||
|
||||
__doc__ = doc = _('template(x) -- evaluates x as a template. The evaluation is done '
|
||||
__doc__ = doc = ('template(x) -- evaluates x as a template. The evaluation is done '
|
||||
'in its own context, meaning that variables are not shared between '
|
||||
'the caller and the template evaluation. Because the { and } '
|
||||
'characters are special, you must use [[ for the { character and '
|
||||
@@ -305,7 +308,7 @@ class BuiltinEval(BuiltinFormatterFunction):
|
||||
name = 'eval'
|
||||
arg_count = 1
|
||||
category = 'Recursion'
|
||||
__doc__ = doc = _('eval(template) -- evaluates the template, passing the local '
|
||||
__doc__ = doc = ('eval(template) -- evaluates the template, passing the local '
|
||||
'variables (those \'assign\'ed to) instead of the book metadata. '
|
||||
' This permits using the template processor to construct complex '
|
||||
'results from local variables. Because the { and } '
|
||||
@@ -325,7 +328,7 @@ class BuiltinAssign(BuiltinFormatterFunction):
|
||||
name = 'assign'
|
||||
arg_count = 2
|
||||
category = 'Other'
|
||||
__doc__ = doc = _('assign(id, val) -- assigns val to id, then returns val. '
|
||||
__doc__ = doc = ('assign(id, val) -- assigns val to id, then returns val. '
|
||||
'id must be an identifier, not an expression')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, target, value):
|
||||
@@ -337,7 +340,7 @@ class BuiltinPrint(BuiltinFormatterFunction):
|
||||
name = 'print'
|
||||
arg_count = -1
|
||||
category = 'Other'
|
||||
__doc__ = doc = _('print(a, b, ...) -- prints the arguments to standard output. '
|
||||
__doc__ = doc = ('print(a, b, ...) -- prints the arguments to standard output. '
|
||||
'Unless you start calibre from the command line (calibre-debug -g), '
|
||||
'the output will go to a black hole.')
|
||||
|
||||
@@ -350,7 +353,7 @@ class BuiltinField(BuiltinFormatterFunction):
|
||||
name = 'field'
|
||||
arg_count = 1
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('field(name) -- returns the metadata field named by name')
|
||||
__doc__ = doc = ('field(name) -- returns the metadata field named by name')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, name):
|
||||
return formatter.get_value(name, [], kwargs)
|
||||
@@ -360,7 +363,7 @@ class BuiltinRawField(BuiltinFormatterFunction):
|
||||
name = 'raw_field'
|
||||
arg_count = 1
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('raw_field(name) -- returns the metadata field named by name '
|
||||
__doc__ = doc = ('raw_field(name) -- returns the metadata field named by name '
|
||||
'without applying any formatting.')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, name):
|
||||
@@ -377,7 +380,7 @@ class BuiltinRawList(BuiltinFormatterFunction):
|
||||
name = 'raw_list'
|
||||
arg_count = 2
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('raw_list(name, separator) -- returns the metadata list '
|
||||
__doc__ = doc = ('raw_list(name, separator) -- returns the metadata list '
|
||||
'named by name without applying any formatting or sorting and '
|
||||
'with items separated by separator.')
|
||||
|
||||
@@ -392,7 +395,7 @@ class BuiltinSubstr(BuiltinFormatterFunction):
|
||||
name = 'substr'
|
||||
arg_count = 3
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('substr(str, start, end) -- returns the start\'th through the end\'th '
|
||||
__doc__ = doc = ('substr(str, start, end) -- returns the start\'th through the end\'th '
|
||||
'characters of str. The first character in str is the zero\'th '
|
||||
'character. If end is negative, then it indicates that many '
|
||||
'characters counting from the right. If end is zero, then it '
|
||||
@@ -407,7 +410,7 @@ class BuiltinLookup(BuiltinFormatterFunction):
|
||||
name = 'lookup'
|
||||
arg_count = -1
|
||||
category = 'Iterating over values'
|
||||
__doc__ = doc = _('lookup(val, pattern, field, pattern, field, ..., else_field) -- '
|
||||
__doc__ = doc = ('lookup(val, pattern, field, pattern, field, ..., else_field) -- '
|
||||
'like switch, except the arguments are field (metadata) names, not '
|
||||
'text. The value of the appropriate field will be fetched and used. '
|
||||
'Note that because composite columns are fields, you can use this '
|
||||
@@ -422,7 +425,7 @@ class BuiltinLookup(BuiltinFormatterFunction):
|
||||
else:
|
||||
return formatter.vformat('{'+args[1].strip()+'}', [], kwargs)
|
||||
if (len(args) % 2) != 1:
|
||||
raise ValueError(_('lookup requires either 2 or an odd number of arguments'))
|
||||
raise ValueError('lookup requires either 2 or an odd number of arguments')
|
||||
i = 0
|
||||
while i < len(args):
|
||||
if i + 1 >= len(args):
|
||||
@@ -436,7 +439,7 @@ class BuiltinTest(BuiltinFormatterFunction):
|
||||
name = 'test'
|
||||
arg_count = 3
|
||||
category = 'If-then-else'
|
||||
__doc__ = doc = _('test(val, text if not empty, text if empty) -- return `text if not '
|
||||
__doc__ = doc = ('test(val, text if not empty, text if empty) -- return `text if not '
|
||||
'empty` if val is not empty, otherwise return `text if empty`')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, value_if_set, value_not_set):
|
||||
@@ -450,7 +453,7 @@ class BuiltinContains(BuiltinFormatterFunction):
|
||||
name = 'contains'
|
||||
arg_count = 4
|
||||
category = 'If-then-else'
|
||||
__doc__ = doc = _('contains(val, pattern, text if match, text if not match) -- checks '
|
||||
__doc__ = doc = ('contains(val, pattern, text if match, text if not match) -- checks '
|
||||
'if val contains matches for the regular expression `pattern`. '
|
||||
'Returns `text if match` if matches are found, otherwise it returns '
|
||||
'`text if no match`')
|
||||
@@ -467,7 +470,7 @@ class BuiltinSwitch(BuiltinFormatterFunction):
|
||||
name = 'switch'
|
||||
arg_count = -1
|
||||
category = 'Iterating over values'
|
||||
__doc__ = doc = _('switch(val, pattern, value, pattern, value, ..., else_value) -- '
|
||||
__doc__ = doc = ('switch(val, pattern, value, pattern, value, ..., else_value) -- '
|
||||
'for each `pattern, value` pair, checks if `val` matches '
|
||||
'the regular expression `pattern` and if so, returns that '
|
||||
'`value`. If no pattern matches, then `else_value` is returned. '
|
||||
@@ -475,7 +478,7 @@ class BuiltinSwitch(BuiltinFormatterFunction):
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, *args):
|
||||
if (len(args) % 2) != 1:
|
||||
raise ValueError(_('switch requires an odd number of arguments'))
|
||||
raise ValueError('switch requires an odd number of arguments')
|
||||
i = 0
|
||||
while i < len(args):
|
||||
if i + 1 >= len(args):
|
||||
@@ -489,7 +492,7 @@ class BuiltinStrcatMax(BuiltinFormatterFunction):
|
||||
name = 'strcat_max'
|
||||
arg_count = -1
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('strcat_max(max, string1, prefix2, string2, ...) -- '
|
||||
__doc__ = doc = ('strcat_max(max, string1, prefix2, string2, ...) -- '
|
||||
'Returns a string formed by concatenating the arguments. The '
|
||||
'returned value is initialized to string1. `Prefix, string` '
|
||||
'pairs are added to the end of the value as long as the '
|
||||
@@ -499,13 +502,13 @@ class BuiltinStrcatMax(BuiltinFormatterFunction):
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||
if len(args) < 2:
|
||||
raise ValueError(_('strcat_max requires 2 or more arguments'))
|
||||
raise ValueError('strcat_max requires 2 or more arguments')
|
||||
if (len(args) % 2) != 0:
|
||||
raise ValueError(_('strcat_max requires an even number of arguments'))
|
||||
raise ValueError('strcat_max requires an even number of arguments')
|
||||
try:
|
||||
max = int(args[0])
|
||||
except:
|
||||
raise ValueError(_('first argument to strcat_max must be an integer'))
|
||||
raise ValueError('first argument to strcat_max must be an integer')
|
||||
|
||||
i = 2
|
||||
result = args[1]
|
||||
@@ -524,7 +527,7 @@ class BuiltinInList(BuiltinFormatterFunction):
|
||||
name = 'in_list'
|
||||
arg_count = -1
|
||||
category = 'List lookup'
|
||||
__doc__ = doc = _('in_list(val, separator, pattern, found_val, ..., not_found_val) -- '
|
||||
__doc__ = doc = ('in_list(val, separator, pattern, found_val, ..., not_found_val) -- '
|
||||
'treat val as a list of items separated by separator, '
|
||||
'evaluating the pattern against each value in the list. If the '
|
||||
'pattern matches a value, return found_val, otherwise return '
|
||||
@@ -535,7 +538,7 @@ class BuiltinInList(BuiltinFormatterFunction):
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):
|
||||
if (len(args) % 2) != 1:
|
||||
raise ValueError(_('in_list requires an odd number of arguments'))
|
||||
raise ValueError('in_list requires an odd number of arguments')
|
||||
l = [v.strip() for v in val.split(sep) if v.strip()]
|
||||
i = 0
|
||||
while i < len(args):
|
||||
@@ -554,7 +557,7 @@ class BuiltinStrInList(BuiltinFormatterFunction):
|
||||
name = 'str_in_list'
|
||||
arg_count = -1
|
||||
category = 'List lookup'
|
||||
__doc__ = doc = _('str_in_list(val, separator, string, found_val, ..., not_found_val) -- '
|
||||
__doc__ = doc = ('str_in_list(val, separator, string, found_val, ..., not_found_val) -- '
|
||||
'treat val as a list of items separated by separator, '
|
||||
'comparing the string against each value in the list. If the '
|
||||
'string matches a value (ignoring case) then return found_val, otherwise return '
|
||||
@@ -566,7 +569,7 @@ class BuiltinStrInList(BuiltinFormatterFunction):
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):
|
||||
if (len(args) % 2) != 1:
|
||||
raise ValueError(_('str_in_list requires an odd number of arguments'))
|
||||
raise ValueError('str_in_list requires an odd number of arguments')
|
||||
l = [v.strip() for v in val.split(sep) if v.strip()]
|
||||
i = 0
|
||||
while i < len(args):
|
||||
@@ -587,7 +590,7 @@ class BuiltinIdentifierInList(BuiltinFormatterFunction):
|
||||
name = 'identifier_in_list'
|
||||
arg_count = 4
|
||||
category = 'List lookup'
|
||||
__doc__ = doc = _('identifier_in_list(val, id, found_val, not_found_val) -- '
|
||||
__doc__ = doc = ('identifier_in_list(val, id, found_val, not_found_val) -- '
|
||||
'treat val as a list of identifiers separated by commas, '
|
||||
'comparing the string against each value in the list. An identifier '
|
||||
'has the format "identifier:value". The id parameter should be '
|
||||
@@ -614,7 +617,7 @@ class BuiltinRe(BuiltinFormatterFunction):
|
||||
name = 're'
|
||||
arg_count = 3
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('re(val, pattern, replacement) -- return val after applying '
|
||||
__doc__ = doc = ('re(val, pattern, replacement) -- return val after applying '
|
||||
'the regular expression. All instances of `pattern` are replaced '
|
||||
'with `replacement`. As in all of calibre, these are '
|
||||
'Python-compatible regular expressions')
|
||||
@@ -627,7 +630,7 @@ class BuiltinReGroup(BuiltinFormatterFunction):
|
||||
name = 're_group'
|
||||
arg_count = -1
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('re_group(val, pattern, template_for_group_1, for_group_2, ...) -- '
|
||||
__doc__ = doc = ('re_group(val, pattern, template_for_group_1, for_group_2, ...) -- '
|
||||
'return a string made by applying the regular expression pattern '
|
||||
'to the val and replacing each matched instance with the string '
|
||||
'computed by replacing each matched group by the value returned '
|
||||
@@ -662,7 +665,7 @@ class BuiltinSwapAroundComma(BuiltinFormatterFunction):
|
||||
name = 'swap_around_comma'
|
||||
arg_count = 1
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('swap_around_comma(val) -- given a value of the form '
|
||||
__doc__ = doc = ('swap_around_comma(val) -- given a value of the form '
|
||||
'"B, A", return "A B". This is most useful for converting names '
|
||||
'in LN, FN format to FN LN. If there is no comma, the function '
|
||||
'returns val unchanged')
|
||||
@@ -675,7 +678,7 @@ class BuiltinIfempty(BuiltinFormatterFunction):
|
||||
name = 'ifempty'
|
||||
arg_count = 2
|
||||
category = 'If-then-else'
|
||||
__doc__ = doc = _('ifempty(val, text if empty) -- return val if val is not empty, '
|
||||
__doc__ = doc = ('ifempty(val, text if empty) -- return val if val is not empty, '
|
||||
'otherwise return `text if empty`')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, value_if_empty):
|
||||
@@ -689,7 +692,7 @@ class BuiltinShorten(BuiltinFormatterFunction):
|
||||
name = 'shorten'
|
||||
arg_count = 4
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('shorten(val, left chars, middle text, right chars) -- Return a '
|
||||
__doc__ = doc = ('shorten(val, left chars, middle text, right chars) -- Return a '
|
||||
'shortened version of val, consisting of `left chars` '
|
||||
'characters from the beginning of val, followed by '
|
||||
'`middle text`, followed by `right chars` characters from '
|
||||
@@ -716,7 +719,7 @@ class BuiltinCount(BuiltinFormatterFunction):
|
||||
name = 'count'
|
||||
arg_count = 2
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('count(val, separator) -- interprets the value as a list of items '
|
||||
__doc__ = doc = ('count(val, separator) -- interprets the value as a list of items '
|
||||
'separated by `separator`, returning the number of items in the '
|
||||
'list. Most lists use a comma as the separator, but authors '
|
||||
'uses an ampersand. Examples: {tags:count(,)}, {authors:count(&)}')
|
||||
@@ -729,7 +732,7 @@ class BuiltinListitem(BuiltinFormatterFunction):
|
||||
name = 'list_item'
|
||||
arg_count = 3
|
||||
category = 'List lookup'
|
||||
__doc__ = doc = _('list_item(val, index, separator) -- interpret the value as a list of '
|
||||
__doc__ = doc = ('list_item(val, index, separator) -- interpret the value as a list of '
|
||||
'items separated by `separator`, returning the `index`th item. '
|
||||
'The first item is number zero. The last item can be returned '
|
||||
'using `list_item(-1,separator)`. If the item is not in the list, '
|
||||
@@ -751,7 +754,7 @@ class BuiltinSelect(BuiltinFormatterFunction):
|
||||
name = 'select'
|
||||
arg_count = 2
|
||||
category = 'List lookup'
|
||||
__doc__ = doc = _('select(val, key) -- interpret the value as a comma-separated list '
|
||||
__doc__ = doc = ('select(val, key) -- interpret the value as a comma-separated list '
|
||||
'of items, with the items being "id:value". Find the pair with the '
|
||||
'id equal to key, and return the corresponding value.'
|
||||
)
|
||||
@@ -770,7 +773,7 @@ class BuiltinApproximateFormats(BuiltinFormatterFunction):
|
||||
name = 'approximate_formats'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('approximate_formats() -- return a comma-separated '
|
||||
__doc__ = doc = ('approximate_formats() -- return a comma-separated '
|
||||
'list of formats that at one point were associated with the '
|
||||
'book. There is no guarantee that this list is correct, '
|
||||
'although it probably is. '
|
||||
@@ -791,14 +794,14 @@ class BuiltinApproximateFormats(BuiltinFormatterFunction):
|
||||
return ''
|
||||
data = sorted(fmt_data)
|
||||
return ','.join(v.upper() for v in data)
|
||||
return _('This function can be used only in the GUI')
|
||||
return 'This function can be used only in the GUI'
|
||||
|
||||
|
||||
class BuiltinFormatsModtimes(BuiltinFormatterFunction):
|
||||
name = 'formats_modtimes'
|
||||
arg_count = 1
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('formats_modtimes(date_format) -- return a comma-separated '
|
||||
__doc__ = doc = ('formats_modtimes(date_format) -- return a comma-separated '
|
||||
'list of colon-separated items representing modification times '
|
||||
'for the formats of a book. The date_format parameter '
|
||||
'specifies how the date is to be formatted. See the '
|
||||
@@ -822,7 +825,7 @@ class BuiltinFormatsSizes(BuiltinFormatterFunction):
|
||||
name = 'formats_sizes'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('formats_sizes() -- return a comma-separated list of '
|
||||
__doc__ = doc = ('formats_sizes() -- return a comma-separated list of '
|
||||
'colon-separated items representing sizes in bytes '
|
||||
'of the formats of a book. You can use the select '
|
||||
'function to get the size for a specific '
|
||||
@@ -842,7 +845,7 @@ class BuiltinFormatsPaths(BuiltinFormatterFunction):
|
||||
name = 'formats_paths'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('formats_paths() -- return a comma-separated list of '
|
||||
__doc__ = doc = ('formats_paths() -- return a comma-separated list of '
|
||||
'colon-separated items representing full path to '
|
||||
'the formats of a book. You can use the select '
|
||||
'function to get the path for a specific '
|
||||
@@ -861,7 +864,7 @@ class BuiltinHumanReadable(BuiltinFormatterFunction):
|
||||
name = 'human_readable'
|
||||
arg_count = 1
|
||||
category = 'Formatting values'
|
||||
__doc__ = doc = _('human_readable(v) -- return a string '
|
||||
__doc__ = doc = ('human_readable(v) -- return a string '
|
||||
'representing the number v in KB, MB, GB, etc.'
|
||||
)
|
||||
|
||||
@@ -876,7 +879,7 @@ class BuiltinFormatNumber(BuiltinFormatterFunction):
|
||||
name = 'format_number'
|
||||
arg_count = 2
|
||||
category = 'Formatting values'
|
||||
__doc__ = doc = _('format_number(v, template) -- format the number v using '
|
||||
__doc__ = doc = ('format_number(v, template) -- format the number v using '
|
||||
'a Python formatting template such as "{0:5.2f}" or '
|
||||
'"{0:,d}" or "${0:5,.2f}". The field_name part of the '
|
||||
'template must be a 0 (zero) (the "{0:" in the above examples). '
|
||||
@@ -912,7 +915,7 @@ class BuiltinSublist(BuiltinFormatterFunction):
|
||||
name = 'sublist'
|
||||
arg_count = 4
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('sublist(val, start_index, end_index, separator) -- interpret the '
|
||||
__doc__ = doc = ('sublist(val, start_index, end_index, separator) -- interpret the '
|
||||
'value as a list of items separated by `separator`, returning a '
|
||||
'new list made from the `start_index` to the `end_index` item. '
|
||||
'The first item is number zero. If an index is negative, then it '
|
||||
@@ -948,7 +951,7 @@ class BuiltinSubitems(BuiltinFormatterFunction):
|
||||
name = 'subitems'
|
||||
arg_count = 3
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('subitems(val, start_index, end_index) -- This function is used to '
|
||||
__doc__ = doc = ('subitems(val, start_index, end_index) -- This function is used to '
|
||||
'break apart lists of items such as genres. It interprets the value '
|
||||
'as a comma-separated list of items, where each item is a period-'
|
||||
'separated list. Returns a new list made by first finding all the '
|
||||
@@ -993,7 +996,7 @@ class BuiltinFormatDate(BuiltinFormatterFunction):
|
||||
name = 'format_date'
|
||||
arg_count = 2
|
||||
category = 'Formatting values'
|
||||
__doc__ = doc = _('format_date(val, format_string) -- format the value, '
|
||||
__doc__ = doc = ('format_date(val, format_string) -- format the value, '
|
||||
'which must be a date, using the format_string, returning a string. '
|
||||
'The formatting codes are: '
|
||||
'd : the day as number without a leading zero (1 to 31) '
|
||||
@@ -1031,7 +1034,7 @@ class BuiltinUppercase(BuiltinFormatterFunction):
|
||||
name = 'uppercase'
|
||||
arg_count = 1
|
||||
category = 'String case changes'
|
||||
__doc__ = doc = _('uppercase(val) -- return val in upper case')
|
||||
__doc__ = doc = 'uppercase(val) -- return val in upper case'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val):
|
||||
return val.upper()
|
||||
@@ -1041,7 +1044,7 @@ class BuiltinLowercase(BuiltinFormatterFunction):
|
||||
name = 'lowercase'
|
||||
arg_count = 1
|
||||
category = 'String case changes'
|
||||
__doc__ = doc = _('lowercase(val) -- return val in lower case')
|
||||
__doc__ = doc = 'lowercase(val) -- return val in lower case'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val):
|
||||
return val.lower()
|
||||
@@ -1051,7 +1054,7 @@ class BuiltinTitlecase(BuiltinFormatterFunction):
|
||||
name = 'titlecase'
|
||||
arg_count = 1
|
||||
category = 'String case changes'
|
||||
__doc__ = doc = _('titlecase(val) -- return val in title case')
|
||||
__doc__ = doc = 'titlecase(val) -- return val in title case'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val):
|
||||
return titlecase(val)
|
||||
@@ -1061,7 +1064,7 @@ class BuiltinCapitalize(BuiltinFormatterFunction):
|
||||
name = 'capitalize'
|
||||
arg_count = 1
|
||||
category = 'String case changes'
|
||||
__doc__ = doc = _('capitalize(val) -- return val capitalized')
|
||||
__doc__ = doc = 'capitalize(val) -- return val capitalized'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val):
|
||||
return capitalize(val)
|
||||
@@ -1071,7 +1074,7 @@ class BuiltinBooksize(BuiltinFormatterFunction):
|
||||
name = 'booksize'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('booksize() -- return value of the size field. '
|
||||
__doc__ = doc = ('booksize() -- return value of the size field. '
|
||||
'This function works only in the GUI. If you want to use this value '
|
||||
'in save-to-disk or send-to-device templates then you '
|
||||
'must make a custom "Column built from other columns", use '
|
||||
@@ -1088,14 +1091,14 @@ class BuiltinBooksize(BuiltinFormatterFunction):
|
||||
except:
|
||||
pass
|
||||
return ''
|
||||
return _('This function can be used only in the GUI')
|
||||
return 'This function can be used only in the GUI'
|
||||
|
||||
|
||||
class BuiltinOndevice(BuiltinFormatterFunction):
|
||||
name = 'ondevice'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('ondevice() -- return Yes if ondevice is set, otherwise return '
|
||||
__doc__ = doc = ('ondevice() -- return Yes if ondevice is set, otherwise return '
|
||||
'the empty string. This function works only in the GUI. If you want to '
|
||||
'use this value in save-to-disk or send-to-device templates then you '
|
||||
'must make a custom "Column built from other columns", use '
|
||||
@@ -1105,16 +1108,16 @@ class BuiltinOndevice(BuiltinFormatterFunction):
|
||||
def evaluate(self, formatter, kwargs, mi, locals):
|
||||
if hasattr(mi, '_proxy_metadata'):
|
||||
if mi._proxy_metadata.ondevice_col:
|
||||
return _('Yes')
|
||||
return 'Yes'
|
||||
return ''
|
||||
return _('This function can be used only in the GUI')
|
||||
return 'This function can be used only in the GUI'
|
||||
|
||||
|
||||
class BuiltinSeriesSort(BuiltinFormatterFunction):
|
||||
name = 'series_sort'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('series_sort() -- return the series sort value')
|
||||
__doc__ = doc = 'series_sort() -- return the series sort value'
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals):
|
||||
if mi.series:
|
||||
@@ -1126,12 +1129,12 @@ class BuiltinHasCover(BuiltinFormatterFunction):
|
||||
name = 'has_cover'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('has_cover() -- return Yes if the book has a cover, '
|
||||
__doc__ = doc = ('has_cover() -- return Yes if the book has a cover, '
|
||||
'otherwise return the empty string')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals):
|
||||
if mi.has_cover:
|
||||
return _('Yes')
|
||||
return 'Yes'
|
||||
return ''
|
||||
|
||||
|
||||
@@ -1139,7 +1142,7 @@ class BuiltinFirstNonEmpty(BuiltinFormatterFunction):
|
||||
name = 'first_non_empty'
|
||||
arg_count = -1
|
||||
category = 'Iterating over values'
|
||||
__doc__ = doc = _('first_non_empty(value, value, ...) -- '
|
||||
__doc__ = doc = ('first_non_empty(value, value, ...) -- '
|
||||
'returns the first value that is not empty. If all values are '
|
||||
'empty, then the empty value is returned. '
|
||||
'You can have as many values as you want.')
|
||||
@@ -1157,7 +1160,7 @@ class BuiltinAnd(BuiltinFormatterFunction):
|
||||
name = 'and'
|
||||
arg_count = -1
|
||||
category = 'Boolean'
|
||||
__doc__ = doc = _('and(value, value, ...) -- '
|
||||
__doc__ = doc = ('and(value, value, ...) -- '
|
||||
'returns the string "1" if all values are not empty, otherwise '
|
||||
'returns the empty string. This function works well with test or '
|
||||
'first_non_empty. You can have as many values as you want. ')
|
||||
@@ -1175,7 +1178,7 @@ class BuiltinOr(BuiltinFormatterFunction):
|
||||
name = 'or'
|
||||
arg_count = -1
|
||||
category = 'Boolean'
|
||||
__doc__ = doc = _('or(value, value, ...) -- '
|
||||
__doc__ = doc = ('or(value, value, ...) -- '
|
||||
'returns the string "1" if any value is not empty, otherwise '
|
||||
'returns the empty string. This function works well with test or '
|
||||
'first_non_empty. You can have as many values as you want.')
|
||||
@@ -1193,7 +1196,7 @@ class BuiltinNot(BuiltinFormatterFunction):
|
||||
name = 'not'
|
||||
arg_count = 1
|
||||
category = 'Boolean'
|
||||
__doc__ = doc = _('not(value) -- '
|
||||
__doc__ = doc = ('not(value) -- '
|
||||
'returns the string "1" if the value is empty, otherwise '
|
||||
'returns the empty string. This function works well with test or '
|
||||
'first_non_empty.')
|
||||
@@ -1206,7 +1209,7 @@ class BuiltinListUnion(BuiltinFormatterFunction):
|
||||
name = 'list_union'
|
||||
arg_count = 3
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_union(list1, list2, separator) -- '
|
||||
__doc__ = doc = ('list_union(list1, list2, separator) -- '
|
||||
'return a list made by merging the items in list1 and list2, '
|
||||
'removing duplicate items using a case-insensitive comparison. If '
|
||||
'items differ in case, the one in list1 is used. '
|
||||
@@ -1231,7 +1234,7 @@ class BuiltinListDifference(BuiltinFormatterFunction):
|
||||
name = 'list_difference'
|
||||
arg_count = 3
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_difference(list1, list2, separator) -- '
|
||||
__doc__ = doc = ('list_difference(list1, list2, separator) -- '
|
||||
'return a list made by removing from list1 any item found in list2, '
|
||||
'using a case-insensitive comparison. The items in list1 and list2 '
|
||||
'are separated by separator, as are the items in the returned list.')
|
||||
@@ -1253,7 +1256,7 @@ class BuiltinListIntersection(BuiltinFormatterFunction):
|
||||
name = 'list_intersection'
|
||||
arg_count = 3
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_intersection(list1, list2, separator) -- '
|
||||
__doc__ = doc = ('list_intersection(list1, list2, separator) -- '
|
||||
'return a list made by removing from list1 any item not found in list2, '
|
||||
'using a case-insensitive comparison. The items in list1 and list2 '
|
||||
'are separated by separator, as are the items in the returned list.')
|
||||
@@ -1275,7 +1278,7 @@ class BuiltinListSort(BuiltinFormatterFunction):
|
||||
name = 'list_sort'
|
||||
arg_count = 3
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_sort(list, direction, separator) -- '
|
||||
__doc__ = doc = ('list_sort(list, direction, separator) -- '
|
||||
'return list sorted using a case-insensitive sort. If direction is '
|
||||
'zero, the list is sorted ascending, otherwise descending. The list items '
|
||||
'are separated by separator, as are the items in the returned list.')
|
||||
@@ -1291,7 +1294,7 @@ class BuiltinListEquals(BuiltinFormatterFunction):
|
||||
name = 'list_equals'
|
||||
arg_count = 6
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_equals(list1, sep1, list2, sep2, yes_val, no_val) -- '
|
||||
__doc__ = doc = ('list_equals(list1, sep1, list2, sep2, yes_val, no_val) -- '
|
||||
'return yes_val if list1 and list2 contain the same items, '
|
||||
'otherwise return no_val. The items are determined by splitting '
|
||||
'each list using the appropriate separator character (sep1 or '
|
||||
@@ -1310,7 +1313,7 @@ class BuiltinListRe(BuiltinFormatterFunction):
|
||||
name = 'list_re'
|
||||
arg_count = 4
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_re(src_list, separator, include_re, opt_replace) -- '
|
||||
__doc__ = doc = ('list_re(src_list, separator, include_re, opt_replace) -- '
|
||||
'Construct a list by first separating src_list into items using '
|
||||
'the separator character. For each item in the list, check if it '
|
||||
'matches include_re. If it does, then add it to the list to be '
|
||||
@@ -1336,7 +1339,7 @@ class BuiltinListReGroup(BuiltinFormatterFunction):
|
||||
name = 'list_re_group'
|
||||
arg_count = -1
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _('list_re_group(src_list, separator, include_re, search_re, group_1_template, ...) -- '
|
||||
__doc__ = doc = ('list_re_group(src_list, separator, include_re, search_re, group_1_template, ...) -- '
|
||||
'Like list_re except replacements are not optional. It '
|
||||
'uses re_group(list_item, search_re, group_1_template, ...) when '
|
||||
'doing the replacements on the resulting list.')
|
||||
@@ -1376,7 +1379,7 @@ class BuiltinToday(BuiltinFormatterFunction):
|
||||
name = 'today'
|
||||
arg_count = 0
|
||||
category = 'Date functions'
|
||||
__doc__ = doc = _('today() -- '
|
||||
__doc__ = doc = ('today() -- '
|
||||
'return a date string for today. This value is designed for use in '
|
||||
'format_date or days_between, but can be manipulated like any '
|
||||
'other string. The date is in ISO format.')
|
||||
@@ -1389,7 +1392,7 @@ class BuiltinDaysBetween(BuiltinFormatterFunction):
|
||||
name = 'days_between'
|
||||
arg_count = 2
|
||||
category = 'Date functions'
|
||||
__doc__ = doc = _('days_between(date1, date2) -- '
|
||||
__doc__ = doc = ('days_between(date1, date2) -- '
|
||||
'return the number of days between date1 and date2. The number is '
|
||||
'positive if date1 is greater than date2, otherwise negative. If '
|
||||
'either date1 or date2 are not dates, the function returns the '
|
||||
@@ -1413,7 +1416,7 @@ class BuiltinLanguageStrings(BuiltinFormatterFunction):
|
||||
name = 'language_strings'
|
||||
arg_count = 2
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('language_strings(lang_codes, localize) -- '
|
||||
__doc__ = doc = ('language_strings(lang_codes, localize) -- '
|
||||
'return the strings for the language codes passed in lang_codes. '
|
||||
'If localize is zero, return the strings in English. If '
|
||||
'localize is not zero, return the strings in the language of '
|
||||
@@ -1435,7 +1438,7 @@ class BuiltinLanguageCodes(BuiltinFormatterFunction):
|
||||
name = 'language_codes'
|
||||
arg_count = 1
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('language_codes(lang_strings) -- '
|
||||
__doc__ = doc = ('language_codes(lang_strings) -- '
|
||||
'return the language codes for the strings passed in lang_strings. '
|
||||
'The strings must be in the language of the current locale. '
|
||||
'Lang_strings is a comma-separated list.')
|
||||
@@ -1456,7 +1459,7 @@ class BuiltinCurrentLibraryName(BuiltinFormatterFunction):
|
||||
name = 'current_library_name'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('current_library_name() -- '
|
||||
__doc__ = doc = ('current_library_name() -- '
|
||||
'return the last name on the path to the current calibre library. '
|
||||
'This function can be called in template program mode using the '
|
||||
'template "{:\'current_library_name()\'}".')
|
||||
@@ -1470,7 +1473,7 @@ class BuiltinCurrentLibraryPath(BuiltinFormatterFunction):
|
||||
name = 'current_library_path'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('current_library_path() -- '
|
||||
__doc__ = doc = ('current_library_path() -- '
|
||||
'return the path to the current calibre library. This function can '
|
||||
'be called in template program mode using the template '
|
||||
'"{:\'current_library_path()\'}".')
|
||||
@@ -1484,7 +1487,7 @@ class BuiltinFinishFormatting(BuiltinFormatterFunction):
|
||||
name = 'finish_formatting'
|
||||
arg_count = 4
|
||||
category = 'Formatting values'
|
||||
__doc__ = doc = _('finish_formatting(val, fmt, prefix, suffix) -- apply the '
|
||||
__doc__ = doc = ('finish_formatting(val, fmt, prefix, suffix) -- apply the '
|
||||
'format, prefix, and suffix to a value in the same way as '
|
||||
'done in a template like `{series_index:05.2f| - |- }`. For '
|
||||
'example, the following program produces the same output '
|
||||
@@ -1501,7 +1504,7 @@ class BuiltinVirtualLibraries(BuiltinFormatterFunction):
|
||||
name = 'virtual_libraries'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('virtual_libraries() -- return a comma-separated list of '
|
||||
__doc__ = doc = ('virtual_libraries() -- return a comma-separated list of '
|
||||
'virtual libraries that contain this book. This function '
|
||||
'works only in the GUI. If you want to use these values '
|
||||
'in save-to-disk or send-to-device templates then you '
|
||||
@@ -1512,14 +1515,14 @@ class BuiltinVirtualLibraries(BuiltinFormatterFunction):
|
||||
def evaluate(self, formatter, kwargs, mi, locals_):
|
||||
if hasattr(mi, '_proxy_metadata'):
|
||||
return mi._proxy_metadata.virtual_libraries
|
||||
return _('This function can be used only in the GUI')
|
||||
return 'This function can be used only in the GUI'
|
||||
|
||||
|
||||
class BuiltinUserCategories(BuiltinFormatterFunction):
|
||||
name = 'user_categories'
|
||||
arg_count = 0
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('user_categories() -- return a comma-separated list of '
|
||||
__doc__ = doc = ('user_categories() -- return a comma-separated list of '
|
||||
'the user categories that contain this book. This function '
|
||||
'works only in the GUI. If you want to use these values '
|
||||
'in save-to-disk or send-to-device templates then you '
|
||||
@@ -1532,14 +1535,14 @@ class BuiltinUserCategories(BuiltinFormatterFunction):
|
||||
cats = set(k for k, v in mi._proxy_metadata.user_categories.items() if v)
|
||||
cats = sorted(cats, key=sort_key)
|
||||
return ', '.join(cats)
|
||||
return _('This function can be used only in the GUI')
|
||||
return 'This function can be used only in the GUI'
|
||||
|
||||
|
||||
class BuiltinTransliterate(BuiltinFormatterFunction):
|
||||
name = 'transliterate'
|
||||
arg_count = 1
|
||||
category = 'String manipulation'
|
||||
__doc__ = doc = _('transliterate(a) -- Returns a string in a latin alphabet '
|
||||
__doc__ = doc = ('transliterate(a) -- Returns a string in a latin alphabet '
|
||||
'formed by approximating the sound of the words in the '
|
||||
'source string. For example, if the source is "{0}"'
|
||||
' the function returns "{1}".').format(
|
||||
@@ -1554,7 +1557,7 @@ class BuiltinAuthorLinks(BuiltinFormatterFunction):
|
||||
name = 'author_links'
|
||||
arg_count = 2
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('author_links(val_separator, pair_separator) -- returns '
|
||||
__doc__ = doc = ('author_links(val_separator, pair_separator) -- returns '
|
||||
'a string containing a list of authors and that author\'s '
|
||||
'link values in the '
|
||||
'form author1 val_separator author1link pair_separator '
|
||||
@@ -1573,14 +1576,14 @@ class BuiltinAuthorLinks(BuiltinFormatterFunction):
|
||||
return ''
|
||||
names = sorted(link_data.keys(), key=sort_key)
|
||||
return pair_sep.join(n + val_sep + link_data[n] for n in names)
|
||||
return _('This function can be used only in the GUI')
|
||||
return 'This function can be used only in the GUI'
|
||||
|
||||
|
||||
class BuiltinAuthorSorts(BuiltinFormatterFunction):
|
||||
name = 'author_sorts'
|
||||
arg_count = 1
|
||||
category = 'Get values from metadata'
|
||||
__doc__ = doc = _('author_sorts(val_separator) -- returns a string '
|
||||
__doc__ = doc = ('author_sorts(val_separator) -- returns a string '
|
||||
'containing a list of author\'s sort values for the '
|
||||
'authors of the book. The sort is the one in the author '
|
||||
'metadata (different from the author_sort in books). The '
|
||||
|
||||
@@ -9,7 +9,7 @@ def html2text(html):
|
||||
r'<\s*(?P<solidus>/?)\s*[uU]\b(?P<rest>[^>]*)>',
|
||||
r'<\g<solidus>span\g<rest>>', html)
|
||||
h2t = HTML2Text()
|
||||
h2t.default_image_alt = _('Unnamed image')
|
||||
h2t.default_image_alt = 'Unnamed image'
|
||||
h2t.body_width = 0
|
||||
h2t.single_line_break = True
|
||||
h2t.emphasis_mark = '*'
|
||||
|
||||
@@ -2,9 +2,10 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import re, io, sys
|
||||
import re
|
||||
import io
|
||||
import sys
|
||||
import json
|
||||
from gettext import GNUTranslations, NullTranslations
|
||||
import pkg_resources
|
||||
|
||||
_available_translations = None
|
||||
@@ -62,101 +63,92 @@ def load_po(path):
|
||||
return buf
|
||||
|
||||
|
||||
def set_translators():
|
||||
t = NullTranslations()
|
||||
set_translators.lang = t.info().get('language')
|
||||
t.install(names=('ngettext',))
|
||||
|
||||
|
||||
set_translators.lang = None
|
||||
|
||||
|
||||
_iso639 = None
|
||||
_extra_lang_codes = {
|
||||
'pt_BR' : _('Brazilian Portuguese'),
|
||||
'en_GB' : _('English (UK)'),
|
||||
'zh_CN' : _('Simplified Chinese'),
|
||||
'zh_TW' : _('Traditional Chinese'),
|
||||
'en' : _('English'),
|
||||
'en_US' : _('English (United States)'),
|
||||
'en_AR' : _('English (Argentina)'),
|
||||
'en_AU' : _('English (Australia)'),
|
||||
'en_JP' : _('English (Japan)'),
|
||||
'en_DE' : _('English (Germany)'),
|
||||
'en_BG' : _('English (Bulgaria)'),
|
||||
'en_EG' : _('English (Egypt)'),
|
||||
'en_NZ' : _('English (New Zealand)'),
|
||||
'en_CA' : _('English (Canada)'),
|
||||
'en_GR' : _('English (Greece)'),
|
||||
'en_IN' : _('English (India)'),
|
||||
'en_NP' : _('English (Nepal)'),
|
||||
'en_TH' : _('English (Thailand)'),
|
||||
'en_TR' : _('English (Turkey)'),
|
||||
'en_CY' : _('English (Cyprus)'),
|
||||
'en_CZ' : _('English (Czech Republic)'),
|
||||
'en_PH' : _('English (Philippines)'),
|
||||
'en_PK' : _('English (Pakistan)'),
|
||||
'en_PL' : _('English (Poland)'),
|
||||
'en_HR' : _('English (Croatia)'),
|
||||
'en_HU' : _('English (Hungary)'),
|
||||
'en_ID' : _('English (Indonesia)'),
|
||||
'en_IL' : _('English (Israel)'),
|
||||
'en_RU' : _('English (Russia)'),
|
||||
'en_SG' : _('English (Singapore)'),
|
||||
'en_YE' : _('English (Yemen)'),
|
||||
'en_IE' : _('English (Ireland)'),
|
||||
'en_CN' : _('English (China)'),
|
||||
'en_TW' : _('English (Taiwan)'),
|
||||
'en_ZA' : _('English (South Africa)'),
|
||||
'es_PY' : _('Spanish (Paraguay)'),
|
||||
'es_UY' : _('Spanish (Uruguay)'),
|
||||
'es_AR' : _('Spanish (Argentina)'),
|
||||
'es_CR' : _('Spanish (Costa Rica)'),
|
||||
'es_MX' : _('Spanish (Mexico)'),
|
||||
'es_CU' : _('Spanish (Cuba)'),
|
||||
'es_CL' : _('Spanish (Chile)'),
|
||||
'es_EC' : _('Spanish (Ecuador)'),
|
||||
'es_HN' : _('Spanish (Honduras)'),
|
||||
'es_VE' : _('Spanish (Venezuela)'),
|
||||
'es_BO' : _('Spanish (Bolivia)'),
|
||||
'es_NI' : _('Spanish (Nicaragua)'),
|
||||
'es_CO' : _('Spanish (Colombia)'),
|
||||
'de_AT' : _('German (AT)'),
|
||||
'fr_BE' : _('French (BE)'),
|
||||
'nl' : _('Dutch (NL)'),
|
||||
'nl_BE' : _('Dutch (BE)'),
|
||||
'und' : _('Unknown')
|
||||
'pt_BR' : 'Brazilian Portuguese',
|
||||
'en_GB' : 'English (UK)',
|
||||
'zh_CN' : 'Simplified Chinese',
|
||||
'zh_TW' : 'Traditional Chinese',
|
||||
'en' : 'English',
|
||||
'en_US' : 'English (United States)',
|
||||
'en_AR' : 'English (Argentina)',
|
||||
'en_AU' : 'English (Australia)',
|
||||
'en_JP' : 'English (Japan)',
|
||||
'en_DE' : 'English (Germany)',
|
||||
'en_BG' : 'English (Bulgaria)',
|
||||
'en_EG' : 'English (Egypt)',
|
||||
'en_NZ' : 'English (New Zealand)',
|
||||
'en_CA' : 'English (Canada)',
|
||||
'en_GR' : 'English (Greece)',
|
||||
'en_IN' : 'English (India)',
|
||||
'en_NP' : 'English (Nepal)',
|
||||
'en_TH' : 'English (Thailand)',
|
||||
'en_TR' : 'English (Turkey)',
|
||||
'en_CY' : 'English (Cyprus)',
|
||||
'en_CZ' : 'English (Czech Republic)',
|
||||
'en_PH' : 'English (Philippines)',
|
||||
'en_PK' : 'English (Pakistan)',
|
||||
'en_PL' : 'English (Poland)',
|
||||
'en_HR' : 'English (Croatia)',
|
||||
'en_HU' : 'English (Hungary)',
|
||||
'en_ID' : 'English (Indonesia)',
|
||||
'en_IL' : 'English (Israel)',
|
||||
'en_RU' : 'English (Russia)',
|
||||
'en_SG' : 'English (Singapore)',
|
||||
'en_YE' : 'English (Yemen)',
|
||||
'en_IE' : 'English (Ireland)',
|
||||
'en_CN' : 'English (China)',
|
||||
'en_TW' : 'English (Taiwan)',
|
||||
'en_ZA' : 'English (South Africa)',
|
||||
'es_PY' : 'Spanish (Paraguay)',
|
||||
'es_UY' : 'Spanish (Uruguay)',
|
||||
'es_AR' : 'Spanish (Argentina)',
|
||||
'es_CR' : 'Spanish (Costa Rica)',
|
||||
'es_MX' : 'Spanish (Mexico)',
|
||||
'es_CU' : 'Spanish (Cuba)',
|
||||
'es_CL' : 'Spanish (Chile)',
|
||||
'es_EC' : 'Spanish (Ecuador)',
|
||||
'es_HN' : 'Spanish (Honduras)',
|
||||
'es_VE' : 'Spanish (Venezuela)',
|
||||
'es_BO' : 'Spanish (Bolivia)',
|
||||
'es_NI' : 'Spanish (Nicaragua)',
|
||||
'es_CO' : 'Spanish (Colombia)',
|
||||
'de_AT' : 'German (AT)',
|
||||
'fr_BE' : 'French (BE)',
|
||||
'nl' : 'Dutch (NL)',
|
||||
'nl_BE' : 'Dutch (BE)',
|
||||
'und' : 'Unknown'
|
||||
}
|
||||
|
||||
if False:
|
||||
# Extra strings needed for Qt
|
||||
|
||||
# NOTE: Ante Meridian (i.e. like 10:00 AM)
|
||||
_('AM')
|
||||
'AM'
|
||||
# NOTE: Post Meridian (i.e. like 10:00 PM)
|
||||
_('PM')
|
||||
'PM'
|
||||
# NOTE: Ante Meridian (i.e. like 10:00 am)
|
||||
_('am')
|
||||
'am'
|
||||
# NOTE: Post Meridian (i.e. like 10:00 pm)
|
||||
_('pm')
|
||||
_('&Copy')
|
||||
_('Select All')
|
||||
_('Copy Link')
|
||||
_('&Select All')
|
||||
_('Copy &Link Location')
|
||||
_('&Undo')
|
||||
_('&Redo')
|
||||
_('Cu&t')
|
||||
_('&Paste')
|
||||
_('Paste and Match Style')
|
||||
_('Directions')
|
||||
_('Left to Right')
|
||||
_('Right to Left')
|
||||
_('Fonts')
|
||||
_('&Step up')
|
||||
_('Step &down')
|
||||
_('Close without Saving')
|
||||
_('Close Tab')
|
||||
'pm'
|
||||
'&Copy'
|
||||
'Select All'
|
||||
'Copy Link'
|
||||
'&Select All'
|
||||
'Copy &Link Location'
|
||||
'&Undo'
|
||||
'&Redo'
|
||||
'Cu&t'
|
||||
'&Paste'
|
||||
'Paste and Match Style'
|
||||
'Directions'
|
||||
'Left to Right'
|
||||
'Right to Left'
|
||||
'Fonts'
|
||||
'&Step up'
|
||||
'Step &down'
|
||||
'Close without Saving'
|
||||
'Close Tab'
|
||||
|
||||
_lcase_map = {}
|
||||
for k in _extra_lang_codes:
|
||||
@@ -227,15 +219,6 @@ def get_iso_language(lang_trans, lang):
|
||||
return lang_trans(ans)
|
||||
|
||||
|
||||
def get_language(lang):
|
||||
translate = _
|
||||
lang = _lcase_map.get(lang, lang)
|
||||
if lang in _extra_lang_codes:
|
||||
# The translator was not active when _extra_lang_codes was defined, so
|
||||
# re-translate
|
||||
return translate(_extra_lang_codes[lang])
|
||||
attr = 'gettext' if sys.version_info.major > 2 else 'ugettext'
|
||||
return get_iso_language(getattr(_lang_trans, attr, translate), lang)
|
||||
|
||||
|
||||
def calibre_langcode_to_name(lc, localize=True):
|
||||
|
||||
Reference in New Issue
Block a user