diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.py b/src/calibre/gui2/catalog/catalog_epub_mobi.py index e0dfffbb35..ac51dd08bb 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.py +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.py @@ -87,7 +87,7 @@ class PluginWidget(QWidget,Ui_Form): option_fields += zip(['exclusion_rules_tw'], [{'ordinal':0, 'enabled':True, - 'name':'Catalogs', + 'name':_('Catalogs'), 'field':'Tags', 'pattern':'Catalog'},], ['table_widget']) @@ -96,13 +96,13 @@ class PluginWidget(QWidget,Ui_Form): option_fields += zip(['prefix_rules_tw','prefix_rules_tw'], [{'ordinal':0, 'enabled':True, - 'name':'Read book', + 'name':_('Read book'), 'field':'Tags', 'pattern':'+', 'prefix':u'\u2713'}, {'ordinal':1, 'enabled':True, - 'name':'Wishlist item', + 'name':_('Wishlist item'), 'field':'Tags', 'pattern':'Wishlist', 'prefix':u'\u00d7'},], @@ -612,7 +612,7 @@ class GenericRulesTable(QTableWidget): first_rule_name = unicode(self.cellWidget(first-1,self.COLUMNS['NAME']['ordinal']).text()).strip() message = _("Are you sure you want to delete '%s'?") % (first_rule_name) if len(rows) > 1: - message = _('Are you sure you want to delete rules #%d-%d?') % (first, last) + message = _('Are you sure you want to delete rules #%(first)d-%(last)d?') % dict(first=first, last=last) if not question_dialog(self, _('Delete Rule'), message, show_copy_button=False): return first_sel_row = self.currentRow() diff --git a/src/calibre/library/catalogs/epub_mobi.py b/src/calibre/library/catalogs/epub_mobi.py index f0a4d1cb78..9db05d5076 100644 --- a/src/calibre/library/catalogs/epub_mobi.py +++ b/src/calibre/library/catalogs/epub_mobi.py @@ -59,7 +59,7 @@ class EPUB_MOBI(CatalogPlugin): "Applies to: AZW3, ePub, MOBI output formats")), Option('--exclusion-rules', - default="(('Excluded tags','Tags','Catalog'),)", + default="(('Catalogs','Tags','Catalog'),)", dest='exclusion_rules', action=None, help=_("Specifies the rules used to exclude books from the generated catalog.\n" @@ -139,7 +139,7 @@ class EPUB_MOBI(CatalogPlugin): "Default: '%default'\n" "Applies to: AZW3, ePub, MOBI output formats")), Option('--prefix-rules', - default="(('Read books','tags','+','\u2713'),('Wishlist items','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" @@ -412,10 +412,15 @@ class EPUB_MOBI(CatalogPlugin): pass if GENERATE_DEBUG_EPUB: + from calibre.ebooks.epub import initialize_container from calibre.ebooks.tweak import zip_rebuilder + from calibre.utils.zipfile import ZipFile input_path = os.path.join(catalog_debug_path,'input') - shutil.copy(P('catalog/mimetype'),input_path) - shutil.copytree(P('catalog/META-INF'),os.path.join(input_path,'META-INF')) + epub_shell = os.path.join(catalog_debug_path,'epub_shell.zip') + initialize_container(epub_shell, opf_name='content.opf') + with ZipFile(epub_shell, 'r') as zf: + zf.extractall(path=input_path) + os.remove(epub_shell) zip_rebuilder(input_path, os.path.join(catalog_debug_path,'input.epub')) # returns to gui2.actions.catalog:catalog_generated() diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py index a2a22d2c74..3fc0df58b2 100644 --- a/src/calibre/library/catalogs/epub_mobi_builder.py +++ b/src/calibre/library/catalogs/epub_mobi_builder.py @@ -5,6 +5,7 @@ __copyright__ = '2010, Greg Riker' import datetime, htmlentitydefs, os, re, shutil, unicodedata, zlib from copy import deepcopy +from operator import itemgetter from xml.sax.saxutils import escape from calibre import (prepare_string_for_xml, strftime, force_unicode) @@ -54,214 +55,95 @@ class CatalogBuilder(object): # title dc:title in OPF metadata, NCX periodical # verbosity level of diagnostic printout - """ property decorators for attributes """ - if True: + ''' device-specific symbol (default empty star) ''' + @property + def SYMBOL_EMPTY_RATING(self): + return self.output_profile.empty_ratings_char + ''' device-specific symbol (default filled star) ''' + @property + def SYMBOL_FULL_RATING(self): + return self.output_profile.ratings_char + ''' device-specific symbol for reading progress ''' + @property + def SYMBOL_PROGRESS_READ(self): + psr = '+' + if self.generate_for_kindle: + psr = '▪' + return psr + ''' device-specific symbol for reading progress ''' + @property + def SYMBOL_PROGRESS_UNREAD(self): + psu = '-' + if self.generate_for_kindle: + psu = '▫' + return psu + ''' device-specific symbol for reading progress ''' + @property + def SYMBOL_READING(self): + if self.generate_for_kindle: + return self.format_prefix('▷') + else: + return self.format_prefix(' ') - - - - ''' directory to store cached thumbs ''' - @property - def cache_dir(self): - return self.__cache_dir - - ''' temp dir to store generated catalog ''' - @property - def catalog_path(self): - return self.__catalog_path - - ''' content dir in generated catalog ''' - @property - def content_dir(self): - return self.__content_dir - - - ''' active database ''' - @property - def db(self): - return self.__db - - - ''' tags to exclude as genres ''' - @property - def excluded_tags(self): - return self.__excluded_tags - - ''' True if generating for Kindle in MOBI format ''' - @property - def generate_for_kindle(self): - return self.__generate_for_kindle - - ''' True if connected Kindle and generating for Kindle ''' - @property - def generate_recently_read(self): - return self.__generate_recently_read - - - - - - ''' additional field to include before/after comments ''' - @property - def merge_comments_rule(self): - return self.__merge_comments_rule - - - ''' opts passed from gui2.catalog.catalog_epub_mobi.py ''' - @property - def opts(self): - return self.__opts - - ''' output_profile declares special symbols ''' - @property - def output_profile(self): - return self.__output_profile - - - ''' catalog??? device??? ''' - @property - def plugin(self): - return self.__plugin - - - - - ''' Progress Reporter for Jobs ''' - @property - def reporter(self): - return self.__reporter - - ''' stylesheet to include with catalog ''' - @property - def stylesheet(self): - return self.__stylesheet - - ''' device-specific symbol (default empty star) ''' - @property - def SYMBOL_EMPTY_RATING(self): - return self.output_profile.empty_ratings_char - - ''' device-specific symbol (default filled star) ''' - @property - def SYMBOL_FULL_RATING(self): - return self.output_profile.ratings_char - - ''' device-specific symbol for reading progress ''' - @property - def SYMBOL_PROGRESS_READ(self): - psr = '+' - if self.generate_for_kindle: - psr = '▪' - return psr - - ''' device-specific symbol for reading progress ''' - @property - def SYMBOL_PROGRESS_UNREAD(self): - psu = '-' - if self.generate_for_kindle: - psu = '▫' - return psu - - ''' device-specific symbol for reading progress ''' - @property - def SYMBOL_READING(self): - if self.generate_for_kindle: - return self.format_prefix('▷') - else: - return self.format_prefix(' ') - - - ''' full path to thumbs archive ''' - @property - def thumbs_path(self): - return self.__thumbs_path - - - ''' switch controlling format of series books in Titles section ''' - @property - def use_series_prefix_in_titles_section(self): - return self.__use_series_prefix_in_titles_section - def __init__(self, db, _opts, plugin, report_progress=DummyReporter(), stylesheet="content/stylesheet.css", init_resources=True): - self.__db = db - self.__opts = _opts - self.__plugin = plugin - self.__reporter = report_progress - self.__stylesheet = stylesheet - self.__cache_dir = os.path.join(config_dir, 'caches', 'catalog') - self.__catalog_path = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='') - self.__generate_for_kindle = True if (_opts.fmt == 'mobi' and + self.db = db + self.opts = _opts + self.plugin = plugin + self.reporter = report_progress + self.stylesheet = stylesheet + self.cache_dir = os.path.join(config_dir, 'caches', 'catalog') + self.catalog_path = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='') + self.excluded_tags = self.get_excluded_tags() + self.generate_for_kindle = True if (_opts.fmt == 'mobi' and _opts.output_profile and _opts.output_profile.startswith("kindle")) else False - ''' list of unique authors ''' self.authors = None - ''' dict of bookmarked books ''' self.bookmarked_books = None - ''' list of bookmarked books, sorted by date read ''' self.bookmarked_books_by_date_read = None - ''' list of books, sorted by author ''' self.books_by_author = None - ''' list of books, grouped by date range (30 days) ''' self.books_by_date_range = None - ''' list of books, by date added reverse (most recent first) ''' self.books_by_month = None - ''' list of books in series ''' self.books_by_series = None - ''' list of books, sorted by title ''' self.books_by_title = None - ''' list of books in series, without series prefix ''' self.books_by_title_no_series_prefix = None - self.__content_dir = os.path.join(self.catalog_path, "content") - ''' track Job progress ''' + self.books_to_catalog = None + self.content_dir = os.path.join(self.catalog_path, "content") self.current_step = 0.0 - ''' cumulative error messages to report at conclusion ''' self.error = [] - self.__excluded_tags = self.get_excluded_tags() - self.__generate_recently_read = True if (_opts.generate_recently_added and - _opts.connected_kindle and - self.generate_for_kindle) else False - ''' list of dicts with books by genre ''' + self.generate_recently_read = True if (_opts.generate_recently_added and + _opts.connected_kindle and + self.generate_for_kindle) else False self.genres = [] - ''' dict of enabled genre tags ''' self.genre_tags_dict = None - ''' Author, Title, Series sections ''' self.html_filelist_1 = [] - ''' Date Added, Date Read ''' self.html_filelist_2 = [] - self.__merge_comments_rule = dict(zip(['field','position','hr'],_opts.merge_comments_rule.split(':'))) - ''' cumulative HTML for NCX file ''' + self.merge_comments_rule = dict(zip(['field','position','hr'], + _opts.merge_comments_rule.split(':'))) self.ncx_soup = None - self.__output_profile = None - self.__output_profile = self.get_output_profile(_opts) - ''' playOrder value for building NCX ''' + self.output_profile = None + self.output_profile = self.get_output_profile(_opts) self.play_order = 1 - ''' dict of prefix rules ''' self.prefix_rules = self.get_prefix_rules() - ''' used with ProgressReporter() ''' self.progress_int = 0.0 - ''' used with ProgressReporter() ''' self.progress_string = '' - - self.__thumb_height = 0 - - self.__thumb_width = 0 - ''' list of generated thumbs ''' + self.thumb_height = 0 + self.thumb_width = 0 self.thumbs = None - self.__thumbs_path = os.path.join(self.cache_dir, "thumbs.zip") - ''' used with ProgressReporter() ''' + self.thumbs_path = os.path.join(self.cache_dir, "thumbs.zip") self.total_steps = 6.0 - self.__use_series_prefix_in_titles_section = False + self.use_series_prefix_in_titles_section = False + self.books_to_catalog = self.fetch_books_to_catalog() self.compute_total_steps() self.calculate_thumbnail_dimensions() self.confirm_thumbs_archive() @@ -343,6 +225,15 @@ class CatalogBuilder(object): series_index) return key + def _kf_books_by_series_sorter(self, book): + index = book['series_index'] + integer = int(index) + fraction = index-integer + series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0')) + key = '%s %s' % (self.generate_sort_title(book['series']), + series_index) + return key + """ Methods """ def build_sources(self): @@ -614,7 +505,7 @@ class CatalogBuilder(object): annoyance for EPUB. Inputs: - self.books_by_title (list): list of books to catalog + self.books_to_catalog (list): list of books to catalog Output: self.books_by_author (list): sorted by author @@ -623,7 +514,7 @@ class CatalogBuilder(object): AuthorSortMismatchException: author_sort mismatch detected """ - self.books_by_author = sorted(list(self.books_by_title), key=self._kf_books_by_author_sorter_author) + self.books_by_author = sorted(list(self.books_to_catalog), key=self._kf_books_by_author_sorter_author) authors = [(record['author'], record['author_sort']) for record in self.books_by_author] current_author = authors[0] for (i,author) in enumerate(authors): @@ -671,7 +562,7 @@ class CatalogBuilder(object): None: no match """ def _log_prefix_rule_match_info(rule, record): - self.opts.log.info(" %s '%s' by %s (Prefix rule '%s')" % + self.opts.log.info(" %s '%s' by %s (Prefix rule '%s')" % (rule['prefix'],record['title'], record['authors'][0], rule['name'])) @@ -770,7 +661,7 @@ class CatalogBuilder(object): to self.authors. Inputs: - self.books_by_title (list): database, sorted by title + self.books_to_catalog (list): database, sorted by title Outputs: books_by_author: database, sorted by author @@ -790,7 +681,7 @@ class CatalogBuilder(object): # Determine the longest author_sort length before sorting asl = [i['author_sort'] for i in self.books_by_author] las = max(asl, key=len) - self.books_by_author = sorted(self.books_by_author, + self.books_by_author = sorted(self.books_to_catalog, key=lambda x: sort_key(self._kf_books_by_author_sorter_author_sort(x, len(las)))) if self.DEBUG and self.opts.verbose: @@ -843,9 +734,42 @@ class CatalogBuilder(object): return True def fetch_books_by_title(self): - """ Populate self.books_by_title from database + """ Generate a list of books sorted by title. - Create self.books_by_title from filtered database. + Sort the database by title. + + Inputs: + self.books_to_catalog (list): database + + Outputs: + books_by_title: database, sorted by title + + Return: + True: no errors + False: author_sort mismatch detected while building MOBI + """ + self.update_progress_full_step(_("Sorting titles")) + # Re-sort based on title_sort + if len(self.books_to_catalog): + self.books_by_title = sorted(self.books_to_catalog, key=lambda x: sort_key(x['title_sort'].upper())) + + if self.DEBUG and self.opts.verbose: + self.opts.log.info("fetch_books_by_title(): %d books" % len(self.books_by_title)) + self.opts.log.info(" %-40s %-40s" % ('title', 'title_sort')) + for title in self.books_by_title: + self.opts.log.info((u" %-40s %-40s" % (title['title'][0:40], + title['title_sort'][0:40])).encode('utf-8')) + else: + error_msg = _("No books to catalog.\nCheck 'Excluded books' rules in E-book options.\n") + self.opts.log.error('*** ' + error_msg + ' ***') + self.error.append(_('No books available to include in catalog')) + self.error.append(error_msg) + raise EmptyCatalogException, error_msg + + def fetch_books_to_catalog(self): + """ Populate self.books_to_catalog from database + + Create self.books_to_catalog from filtered database. Keys: authors massaged author_sort record['author_sort'] or computed @@ -871,7 +795,7 @@ class CatalogBuilder(object): data (list): filtered list of book metadata dicts Outputs: - (list) books_by_title + (list) books_to_catalog Returns: True: Successful @@ -953,9 +877,11 @@ class CatalogBuilder(object): this_title['prefix'] = self.discover_prefix(record) + this_title['tags'] = [] if record['tags']: this_title['tags'] = self.filter_excluded_genres(record['tags'], self.opts.exclude_genre) + if record['formats']: formats = [] for format in record['formats']: @@ -980,7 +906,6 @@ class CatalogBuilder(object): return this_title # Entry point - self.update_progress_full_step(_("Fetching database")) self.opts.sort_by = 'title' search_phrase = '' @@ -1003,28 +928,15 @@ class CatalogBuilder(object): data = self.plugin.search_sort_db(self.db, self.opts) data = self.process_exclusions(data) + if self.opts.verbose and self.prefix_rules: + self.opts.log.info(" Added prefixes:") + # Populate this_title{} from data[{},{}] titles = [] for record in data: this_title = _populate_title(record) titles.append(this_title) - - # Re-sort based on title_sort - if len(titles): - self.books_by_title = sorted(titles, key=lambda x: sort_key(x['title_sort'].upper())) - - if self.DEBUG and self.opts.verbose: - self.opts.log.info("fetch_books_by_title(): %d books" % len(self.books_by_title)) - self.opts.log.info(" %-40s %-40s" % ('title', 'title_sort')) - for title in self.books_by_title: - self.opts.log.info((u" %-40s %-40s" % (title['title'][0:40], - title['title_sort'][0:40])).encode('utf-8')) - else: - error_msg = _("No books to catalog.\nCheck 'Excluded books' rules in E-book options.\n") - self.opts.log.error('*** ' + error_msg + ' ***') - self.error.append(_('No books available to include in catalog')) - self.error.append(error_msg) - raise EmptyCatalogException, error_msg + return titles def fetch_bookmarks(self): """ Interrogate connected Kindle for bookmarks. @@ -1104,7 +1016,7 @@ class CatalogBuilder(object): d.initialize(self.opts.connected_device['save_template']) bookmarks = {} - for book in self.books_by_title: + for book in self.books_to_catalog: if 'formats' in book: path_map = {} id = book['id'] @@ -1148,7 +1060,7 @@ class CatalogBuilder(object): genre_tags_dict (dict): dict of filtered, normalized tags in data set """ - def _format_tag_list(tags, indent=5, line_break=70, header='Tag list'): + def _format_tag_list(tags, indent=2, line_break=70, header='Tag list'): def _next_tag(sorted_tags): for (i, tag) in enumerate(sorted_tags): if i < len(tags) - 1: @@ -1541,7 +1453,7 @@ class CatalogBuilder(object): def generate_html_by_date_added(self): """ Generate content/ByDateAdded.html. - Loop through self.books_by_title sorted by reverse date, generate HTML. + Loop through self.books_to_catalog sorted by reverse date, generate HTML. Input: books_by_title (list): books, sorted by title @@ -1735,10 +1647,10 @@ class CatalogBuilder(object): # >>> Books by date range <<< if self.use_series_prefix_in_titles_section: - self.books_by_date_range = sorted(self.books_by_title, + self.books_by_date_range = sorted(self.books_to_catalog, key=lambda x:(x['timestamp'], x['timestamp']),reverse=True) else: - nspt = deepcopy(self.books_by_title) + nspt = deepcopy(self.books_to_catalog) self.books_by_date_range = sorted(nspt, key=lambda x:(x['timestamp'], x['timestamp']),reverse=True) date_range_list = [] @@ -1763,7 +1675,7 @@ class CatalogBuilder(object): # >>>> Books by month <<<< # Sort titles case-insensitive for by month using series prefix - self.books_by_month = sorted(self.books_by_title, + self.books_by_month = sorted(self.books_to_catalog, key=lambda x:(x['timestamp'], x['timestamp']),reverse=True) # Loop through books by date @@ -2026,12 +1938,12 @@ class CatalogBuilder(object): if self.opts.verbose: if len(genre_list): - self.opts.log.info(" Genre summary: %d active genre tags used in generating catalog with %d titles" % - (len(genre_list), len(self.books_by_title))) + self.opts.log.info(" Genre summary: %d active genre tags used in generating catalog with %d titles" % + (len(genre_list), len(self.books_to_catalog))) for genre in genre_list: for key in genre: - self.opts.log.info(" %s: %d %s" % (self.get_friendly_genre_tag(key), + self.opts.log.info(" %s: %d %s" % (self.get_friendly_genre_tag(key), len(genre[key]), 'titles' if len(genre[key]) > 1 else 'title')) @@ -2226,48 +2138,28 @@ class CatalogBuilder(object): Output: content/BySeries.html (file) - To do: - self.books_by_series = [i for i in self.books_by_title if i['series']] """ friendly_name = _("Series") self.update_progress_full_step("%s HTML" % friendly_name) self.opts.sort_by = 'series' - # Merge self.excluded_tags with opts.search_text - # Updated to use exact match syntax - - search_phrase = 'series:true ' - if self.excluded_tags: - search_terms = [] - for tag in self.excluded_tags: - search_terms.append("tag:=%s" % tag) - search_phrase += "not (%s)" % " or ".join(search_terms) - - # If a list of ids are provided, don't use search_text - if self.opts.ids: - self.opts.search_text = search_phrase - else: - if self.opts.search_text: - self.opts.search_text += " " + search_phrase - else: - self.opts.search_text = search_phrase - - # Fetch the database as a dictionary - data = self.plugin.search_sort_db(self.db, self.opts) - - # Remove exclusions - self.books_by_series = self.process_exclusions(data, log_exclusion=False) + # *** Convert the existing database, resort by series/index *** + self.books_by_series = [i for i in self.books_to_catalog if i['series']] + self.books_by_series = sorted(self.books_by_series, key=lambda x: sort_key(self._kf_books_by_series_sorter(x))) if not self.books_by_series: self.opts.generate_series = False - self.opts.log(" no series found in selected books, cancelling series generation") + self.opts.log(" no series found in selected books, skipping Series section") return # Generate series_sort for book in self.books_by_series: book['series_sort'] = self.generate_sort_title(book['series']) + # Establish initial letter equivalencies + sort_equivalents = self.establish_equivalencies(self.books_by_series, key='series_sort') + soup = self.generate_html_empty_header(friendly_name) body = soup.find('body') @@ -2277,9 +2169,6 @@ class CatalogBuilder(object): current_letter = "" current_series = None - # Establish initial letter equivalencies - sort_equivalents = self.establish_equivalencies(self.books_by_series, key='series_sort') - # Loop through books_by_series series_count = 0 for idx, book in enumerate(self.books_by_series): @@ -2335,11 +2224,6 @@ class CatalogBuilder(object): # Use series, series index if avail else just title #aTag.insert(0,'%d. %s · %s' % (book['series_index'],escape(book['title']), ' & '.join(book['authors']))) - if is_date_undefined(book['pubdate']): - book['date'] = None - else: - book['date'] = strftime(u'%B %Y', book['pubdate'].timetuple()) - args = self.generate_format_args(book) formatted_title = self.by_series_title_template.format(**args).rstrip() aTag.insert(0,NavigableString(escape(formatted_title))) @@ -2438,7 +2322,7 @@ class CatalogBuilder(object): # Re-sort title list without leading series/series_index # Incoming title : if not self.use_series_prefix_in_titles_section: - nspt = deepcopy(self.books_by_title) + nspt = deepcopy(self.books_to_catalog) nspt = sorted(nspt, key=lambda x: sort_key(x['title_sort'].upper())) self.books_by_title_no_series_prefix = nspt @@ -3153,8 +3037,12 @@ class CatalogBuilder(object): self.play_order += 1 navLabelTag = Tag(soup, 'navLabel') textTag = Tag(soup, 'text') - textTag.insert(0, NavigableString(_(u"Series beginning with %s") % \ - (title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'"))) + if len(title_letters[i])>1: + fmt_string = _(u"Series beginning with %s") + else: + fmt_string = _(u"Series beginning with '%s'") + textTag.insert(0, NavigableString(fmt_string % + (title_letters[i] if len(title_letters[i])>1 else title_letters[i]))) navLabelTag.insert(0, textTag) navPointByLetterTag.insert(0,navLabelTag) contentTag = Tag(soup, 'content') @@ -3274,8 +3162,12 @@ class CatalogBuilder(object): self.play_order += 1 navLabelTag = Tag(soup, 'navLabel') textTag = Tag(soup, 'text') - textTag.insert(0, NavigableString(_(u"Titles beginning with %s") % \ - (title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'"))) + if len(title_letters[i])>1: + fmt_string = _(u"Titles beginning with %s") + else: + fmt_string = _(u"Titles beginning with '%s'") + textTag.insert(0, NavigableString(fmt_string % + (title_letters[i] if len(title_letters[i])>1 else title_letters[i]))) navLabelTag.insert(0, textTag) navPointByLetterTag.insert(0,navLabelTag) contentTag = Tag(soup, 'content') @@ -3385,7 +3277,11 @@ class CatalogBuilder(object): self.play_order += 1 navLabelTag = Tag(soup, 'navLabel') textTag = Tag(soup, 'text') - textTag.insert(0, NavigableString(_("Authors beginning with '%s'") % (authors_by_letter[1]))) + if len(authors_by_letter[1])>1: + fmt_string = _(u"Authors beginning with %s") + else: + fmt_string = _(u"Authors beginning with '%s'") + textTag.insert(0, NavigableString(fmt_string % (authors_by_letter[1]))) navLabelTag.insert(0, textTag) navPointByLetterTag.insert(0,navLabelTag) contentTag = Tag(soup, 'content') @@ -4339,7 +4235,7 @@ class CatalogBuilder(object): # Report excluded books if self.opts.verbose and excluded_tags: - self.opts.log.info(" Excluded books by Tags:") + self.opts.log.info(" Excluded books:") data = self.db.get_data_as_dict(ids=self.opts.ids) for record in data: matched = list(set(record['tags']) & set(excluded_tags)) @@ -4632,7 +4528,7 @@ class CatalogBuilder(object): normalized += c return normalized - def process_exclusions(self, data_set, log_exclusion=True): + def process_exclusions(self, data_set): """ Filter data_set based on exclusion_rules. Compare each book in data_set to each exclusion_rule. Remove @@ -4666,16 +4562,18 @@ class CatalogBuilder(object): matched = re.search(pat, unicode(field_contents), re.IGNORECASE) if matched is not None: - if self.opts.verbose and log_exclusion: + if self.opts.verbose: field_md = self.db.metadata_for_field(field) for rule in self.opts.exclusion_rules: if rule[1] == '#%s' % field_md['label']: - self.opts.log.info(" - '%s' by %s (Exclusion rule '%s')" % + self.opts.log.info(" - '%s' by %s (Exclusion rule '%s')" % (record['title'], record['authors'][0], rule[0])) exclusion_set.append(record) if record in filtered_data_set: filtered_data_set.remove(record) break + else: + filtered_data_set.append(record) else: if (record not in filtered_data_set and record not in exclusion_set): diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 631e78aa95..c2f5e1b38c 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.8.68\n" -"POT-Creation-Date: 2012-09-07 08:49+IST\n" -"PO-Revision-Date: 2012-09-07 08:49+IST\n" +"POT-Creation-Date: 2012-09-08 17:09+IST\n" +"PO-Revision-Date: 2012-09-08 17:09+IST\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -131,8 +131,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/pdb/ztxt/writer.py:27 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:108 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:109 -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:426 -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:434 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:439 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:447 #: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:166 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:397 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:400 @@ -143,8 +143,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:124 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:143 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:145 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1366 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1369 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1367 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1370 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_empty_book.py:55 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_empty_book.py:60 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:128 @@ -173,12 +173,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:585 #: /home/kovid/work/calibre/src/calibre/library/database2.py:593 #: /home/kovid/work/calibre/src/calibre/library/database2.py:604 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2189 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2343 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2768 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3415 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3417 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3554 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2192 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2346 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2771 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3418 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3420 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3557 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:250 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:251 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:247 @@ -1034,14 +1034,14 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1199 #: /home/kovid/work/calibre/src/calibre/library/database2.py:370 #: /home/kovid/work/calibre/src/calibre/library/database2.py:383 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3272 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3275 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:187 msgid "News" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2770 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3228 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3246 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3231 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3249 msgid "Catalog" msgstr "" @@ -3352,8 +3352,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:70 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:163 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:401 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2232 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:292 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2142 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:140 msgid "Series" msgid_plural "Series" @@ -3880,7 +3880,17 @@ msgstr "" msgid "Show this confirmation again" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:546 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:134 +msgid "Restart needed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:334 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:741 +msgid "Restart calibre now" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:559 msgid "Choose Files" msgstr "" @@ -4112,7 +4122,7 @@ msgid "Merging user annotations into database" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/annotate.py:63 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:744 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:745 msgid "Fetch annotations (experimental)" msgstr "" @@ -4357,7 +4367,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:403 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:197 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:933 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:934 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:1004 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:114 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:128 @@ -4590,14 +4600,14 @@ msgid "Main memory" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:239 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:669 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:678 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:670 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:679 msgid "Storage Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:240 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:671 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:680 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:672 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:681 msgid "Storage Card B" msgstr "" @@ -5373,7 +5383,7 @@ msgid "The specified directory could not be processed." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:274 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1087 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1088 msgid "No books" msgstr "" @@ -5794,6 +5804,18 @@ msgstr "" msgid "E-book options" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:90 +msgid "Catalogs" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:99 +msgid "Read book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:105 +msgid "Wishlist item" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:133 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:769 msgid "any date" @@ -5831,7 +5853,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:615 #, python-format -msgid "Are you sure you want to delete rules #%d-%d?" +msgid "Are you sure you want to delete rules #%(first)d-%(last)d?" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:616 @@ -7685,226 +7707,222 @@ msgstr "" msgid "tags to remove" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:51 #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:148 msgid "No details available." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:202 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:203 msgid "Device no longer connected." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:413 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:414 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:27 msgid "Debug device detection" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:429 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:430 msgid "Get device information" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:444 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:445 msgid "Get list of books on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:451 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:452 msgid "Prepare files for transfer from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:462 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:463 msgid "Get annotations from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:474 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:475 msgid "Send metadata to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:479 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:480 msgid "Send collections to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:529 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:530 #, python-format msgid "Upload %d books to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:545 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:546 msgid "Delete books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:563 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:564 msgid "Download books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:573 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:574 msgid "View book on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:652 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:653 msgid "Set default send to device action" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:658 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:659 msgid "Send to main memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:660 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:661 msgid "Send to storage card A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:662 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:663 msgid "Send to storage card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:667 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:676 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:668 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:677 msgid "Main Memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:688 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:689 msgid "Send specific format to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:689 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:690 msgid "Send and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:732 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:733 msgid "Eject device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:813 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:814 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc.py:71 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:332 #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:58 msgid "Error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:814 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:815 msgid "Error communicating with device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:843 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1416 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:844 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1417 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:260 msgid "No suitable formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:859 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:860 msgid "Select folder to open as device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:877 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:878 msgid "Running jobs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:878 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:879 msgid "Cannot configure the device while there are running device jobs." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:883 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:884 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:168 #, python-format msgid "Configure %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:898 -msgid "Disconnect device" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/device.py:899 #, python-format -msgid "Disconnect and re-connect the %s for your changes to be applied." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:939 -msgid "Error talking to device" +msgid "Restart calibre for the changes to %s to be applied." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device.py:940 +msgid "Error talking to device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:941 msgid "There was a temporary error talking to the device. Please unplug and reconnect the device or reboot." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:984 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:985 msgid "Device: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:986 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:987 msgid " detected." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1088 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1089 msgid "selected to send" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1095 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1125 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1096 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1126 msgid "No device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1096 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1097 msgid "No device connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1112 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1113 #, python-format msgid "%(num)i of %(total)i Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1116 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1117 #, python-format msgid "0 of %i Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1118 msgid "Choose format to send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1126 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1127 msgid "Cannot send: No device is connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1129 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1133 -msgid "No card" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1130 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1134 +msgid "No card" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1131 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1135 msgid "Cannot send: Device has no storage card" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1195 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1278 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1410 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1196 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1279 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1411 msgid "Auto convert the following books before uploading to the device?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1224 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1225 msgid "Sending catalogs to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1323 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1324 msgid "Sending news to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1377 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1378 msgid "Sending books to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1417 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1418 msgid "Could not upload the following books to the device, as no suitable formats were found. Convert the book(s) to a format supported by your device first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1490 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1491 msgid "No space on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1491 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1492 msgid "<p>Cannot upload books to device there is no more free space available " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1496 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1497 msgid "Incorrect destination" msgstr "" @@ -9471,11 +9489,6 @@ msgstr "" msgid "Plugin <b>{0}</b> successfully installed under <b> {1} plugins</b>. You may have to restart calibre for the plugin to take effect." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:741 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:352 -msgid "Restart calibre now" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:760 msgid "A problem occurred while installing this plugin. This plugin will now be uninstalled. Please post the error message in details below into the forum thread for this plugin and restart Calibre." msgstr "" @@ -9529,8 +9542,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/quickview.py:87 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:156 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:397 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1342 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:288 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1254 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:113 msgid "Authors" msgstr "" @@ -13072,11 +13085,6 @@ msgstr "" msgid "The changes you have made require calibre be restarted immediately. You will not be allowed to set any more preferences, until you restart." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:350 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:134 -msgid "Restart needed" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:48 msgid "Source" msgstr "" @@ -14986,7 +14994,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/update.py:78 #, python-format -msgid "%(app)s has been updated to version <b>%(ver)s</b>. See the <a href=\"http://calibre-ebook.com/whats-new\">new features</a>." +msgid "New version <b>%(ver)s</b> of %(app)s is available for download. See the <a href=\"http://calibre-ebook.com/whats-new\">new features</a>." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/update.py:84 @@ -16370,153 +16378,168 @@ msgid "" "*** Adding 'By Authors' Section required for MOBI output ***" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:46 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:47 msgid "Symbols" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:382 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:273 msgid "No genres to catalog.\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:384 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:275 msgid "Check 'Excluded genres' regex in E-book options.\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:386 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:277 msgid "No books available to catalog" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:399 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2429 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:290 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2313 msgid "Titles" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:403 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:294 msgid "Genres" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:405 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1703 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:296 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1615 msgid "Recently Added" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:407 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1902 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:298 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1814 msgid "Recently Read" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:409 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:300 msgid "Descriptions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:634 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:525 msgid "<p>Inconsistent Author Sort values for Author<br/>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:651 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:542 msgid "Warning: Inconsistent Author Sort values for Author '{!s}':\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:785 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:676 msgid "Sorting database" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:983 -msgid "Fetching database" +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:751 +msgid "Sorting titles" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1023 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:763 msgid "" "No books to catalog.\n" "Check 'Excluded books' rules in E-book options.\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1025 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:765 msgid "No books available to include in catalog" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1983 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:1895 msgid "Genres HTML" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2409 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2293 msgid "Titles HTML" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2604 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2606 -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2608 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2488 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2490 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2492 msgid "by " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2745 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2629 msgid "Descriptions HTML" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2749 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2633 msgid "Description HTML" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2884 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2768 msgid "NCX header" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2959 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2843 msgid "NCX for Descriptions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3080 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:2964 msgid "NCX for Series" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3156 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3041 #, python-format msgid "Series beginning with %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3199 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3043 +#, python-format +msgid "Series beginning with '%s'" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3087 msgid "NCX for Titles" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3277 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3166 #, python-format msgid "Titles beginning with %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3318 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3168 +#, python-format +msgid "Titles beginning with '%s'" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3210 msgid "NCX for Authors" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3388 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3281 +#, python-format +msgid "Authors beginning with %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3283 #, python-format msgid "Authors beginning with '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3428 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3324 msgid "NCX for Recently Added" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3615 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3511 msgid "NCX for Recently Read" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3752 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3648 msgid "NCX for Genres" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3870 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:3766 msgid "Generating OPF" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4242 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4138 msgid "Thumbnails" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4248 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4144 msgid "Thumbnail" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4743 +#: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:4641 msgid "Saving NCX" msgstr "" @@ -17107,17 +17130,17 @@ msgstr "" msgid "creating custom column " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3580 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3583 #, python-format msgid "<p>Migrating old database to ebook library in %s<br><center>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3609 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3612 #, python-format msgid "Copying <b>%s</b>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3626 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3629 msgid "Compacting database" msgstr ""