diff --git a/resources/catalog/stylesheet.css b/resources/catalog/stylesheet.css index 40b0d0eb4e..f14b1aaa29 100644 --- a/resources/catalog/stylesheet.css +++ b/resources/catalog/stylesheet.css @@ -83,7 +83,7 @@ p.author_index { font-size:large; font-weight:bold; text-align:left; - margin-top:0px; + margin-top:0.25px; margin-bottom:-2px; text-indent: 0em; } diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.py b/src/calibre/gui2/catalog/catalog_epub_mobi.py index 0e8dd27e3f..42143eb506 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.py +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.py @@ -545,9 +545,9 @@ class GenericRulesTable(QTableWidget): first = rows[0].row() + 1 last = rows[-1].row() + 1 - message = '

Are you sure you want to delete rule %d?' % first + message = _('Are you sure you want to delete rule %d?') % first 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 %d-%d?') % (first, last) if not question_dialog(self, _('Are you sure?'), message, show_copy_button=False): return first_sel_row = self.currentRow() @@ -652,9 +652,9 @@ class GenericRulesTable(QTableWidget): class ExclusionRules(GenericRulesTable): COLUMNS = { 'ENABLED':{'ordinal': 0, 'name': ''}, - 'NAME': {'ordinal': 1, 'name': 'Name'}, - 'FIELD': {'ordinal': 2, 'name': 'Field'}, - 'PATTERN': {'ordinal': 3, 'name': 'Value'},} + 'NAME': {'ordinal': 1, 'name': _('Name')}, + 'FIELD': {'ordinal': 2, 'name': _('Field')}, + 'PATTERN': {'ordinal': 3, 'name': _('Value')},} def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db): super(ExclusionRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db) @@ -760,15 +760,15 @@ class ExclusionRules(GenericRulesTable): elif source_field == 'Tags': values = sorted(self.db.all_tags(), key=sort_key) else: - if self.eligible_custom_fields[source_field]['datatype'] in ['enumeration', 'text']: + if self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['enumeration', 'text']: values = self.db.all_custom(self.db.field_metadata.key_to_label( - self.eligible_custom_fields[source_field]['field'])) + self.eligible_custom_fields[unicode(source_field)]['field'])) values = sorted(values, key=sort_key) - elif self.eligible_custom_fields[source_field]['datatype'] in ['bool']: + elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['bool']: values = ['True','False','unspecified'] - elif self.eligible_custom_fields[source_field]['datatype'] in ['composite']: + elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['composite']: values = ['any value','unspecified'] - elif self.eligible_custom_fields[source_field]['datatype'] in ['datetime']: + elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['datetime']: values = ['any date','unspecified'] values_combo = ComboBox(self, values, pattern) @@ -777,10 +777,10 @@ class ExclusionRules(GenericRulesTable): class PrefixRules(GenericRulesTable): COLUMNS = { 'ENABLED':{'ordinal': 0, 'name': ''}, - 'NAME': {'ordinal': 1, 'name': 'Name'}, - 'PREFIX': {'ordinal': 2, 'name': 'Prefix'}, - 'FIELD': {'ordinal': 3, 'name': 'Field'}, - 'PATTERN':{'ordinal': 4, 'name': 'Value'},} + 'NAME': {'ordinal': 1, 'name': _('Name')}, + 'PREFIX': {'ordinal': 2, 'name': _('Prefix')}, + 'FIELD': {'ordinal': 3, 'name': _('Field')}, + 'PATTERN':{'ordinal': 4, 'name': _('Value')},} def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db): super(PrefixRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db) @@ -1035,15 +1035,15 @@ class PrefixRules(GenericRulesTable): elif source_field == 'Tags': values = sorted(self.db.all_tags(), key=sort_key) else: - if self.eligible_custom_fields[source_field]['datatype'] in ['enumeration', 'text']: + if self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['enumeration', 'text']: values = self.db.all_custom(self.db.field_metadata.key_to_label( - self.eligible_custom_fields[source_field]['field'])) + self.eligible_custom_fields[unicode(source_field)]['field'])) values = sorted(values, key=sort_key) - elif self.eligible_custom_fields[source_field]['datatype'] in ['bool']: + elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['bool']: values = ['True','False','unspecified'] - elif self.eligible_custom_fields[source_field]['datatype'] in ['composite']: + elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['composite']: values = ['any value','unspecified'] - elif self.eligible_custom_fields[source_field]['datatype'] in ['datetime']: + elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['datetime']: values = ['any date','unspecified'] values_combo = ComboBox(self, values, pattern) diff --git a/src/calibre/library/catalogs/epub_mobi.py b/src/calibre/library/catalogs/epub_mobi.py index d3276719f9..28d77c66a5 100644 --- a/src/calibre/library/catalogs/epub_mobi.py +++ b/src/calibre/library/catalogs/epub_mobi.py @@ -174,14 +174,14 @@ class EPUB_MOBI(CatalogPlugin): if op is None: op = 'default' - if opts.connected_device['name'] and \ - opts.connected_device['short_name'] in ['kindle','kindle dx']: + if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower(): opts.connected_kindle = True if opts.connected_device['serial'] and \ opts.connected_device['serial'][:4] in ['B004','B005']: op = "kindle_dx" else: op = "kindle" + opts.descriptionClip = 380 if op.endswith('dx') or 'kindle' not in op else 100 opts.authorClip = 100 if op.endswith('dx') or 'kindle' not in op else 60 opts.output_profile = op @@ -385,9 +385,6 @@ class EPUB_MOBI(CatalogPlugin): new_cover_path.close() recommendations.append(('cover', new_cover_path.name, OptionRecommendation.HIGH)) - if opts.verbose: - log.info("Invoking Plumber with recommendations:\n %s" % recommendations) - # Run ebook-convert from calibre.ebooks.conversion.plumber import Plumber plumber = Plumber(os.path.join(catalog.catalogPath, diff --git a/src/calibre/library/catalogs/epub_mobi_builder.py b/src/calibre/library/catalogs/epub_mobi_builder.py index a81409ffc7..c196db3ca5 100644 --- a/src/calibre/library/catalogs/epub_mobi_builder.py +++ b/src/calibre/library/catalogs/epub_mobi_builder.py @@ -15,7 +15,7 @@ from calibre.ptempfile import PersistentTemporaryDirectory from calibre.utils.config import config_dir from calibre.utils.date import format_date, is_date_undefined, now as nowf from calibre.utils.filenames import ascii_text -from calibre.utils.icu import capitalize, sort_key +from calibre.utils.icu import capitalize, collation_order, sort_key from calibre.utils.magick.draw import thumbnail from calibre.utils.zipfile import ZipFile @@ -517,19 +517,19 @@ class CatalogBuilder(object): self.generateOPF() self.generateNCXHeader() if self.opts.generate_authors: - self.generateNCXByAuthor("Authors") + self.generateNCXByAuthor(_("Authors")) if self.opts.generate_titles: - self.generateNCXByTitle("Titles") + self.generateNCXByTitle(_("Titles")) if self.opts.generate_series: - self.generateNCXBySeries("Series") + self.generateNCXBySeries(_("Series")) if self.opts.generate_genres: - self.generateNCXByGenre("Genres") + self.generateNCXByGenre(_("Genres")) if self.opts.generate_recently_added: - self.generateNCXByDateAdded("Recently Added") + self.generateNCXByDateAdded(_("Recently Added")) if self.generateRecentlyRead: - self.generateNCXByDateRead("Recently Read") + self.generateNCXByDateRead(_("Recently Read")) if self.opts.generate_descriptions: - self.generateNCXDescriptions("Descriptions") + self.generateNCXDescriptions(_("Descriptions")) self.writeNCX() return True @@ -673,7 +673,8 @@ Author '{0}': for record in data: matched = list(set(record['tags']) & set(exclude_tags)) if matched : - self.opts.log.info(" - %s (Exclusion rule Tags: '%s')" % (record['title'], str(matched[0]))) + self.opts.log.info(" - %s by %s (Exclusion rule Tags: '%s')" % + (record['title'], record['authors'][0], str(matched[0]))) search_phrase = '' if exclude_tags: @@ -960,7 +961,7 @@ Author '{0}': aTag['id'] = "bytitle" pTag.insert(ptc,aTag) ptc += 1 - pTag.insert(ptc,NavigableString('Titles')) + pTag.insert(ptc,NavigableString(_('Titles'))) body.insert(btc,pTag) btc += 1 @@ -976,6 +977,9 @@ Author '{0}': nspt = sorted(nspt, key=lambda x: sort_key(x['title_sort'].upper())) self.booksByTitle_noSeriesPrefix = nspt + # Establish initial letter equivalencies + sort_equivalents = self.establish_equivalencies(self.booksByTitle, key='title_sort') + # Loop through the books by title # Generate one divRunningTag per initial letter for the purposes of # minimizing widows and orphans on readers that can handle large @@ -985,8 +989,8 @@ Author '{0}': title_list = self.booksByTitle_noSeriesPrefix drtc = 0 divRunningTag = None - for book in title_list: - if self.letter_or_symbol(book['title_sort'][0]) != current_letter : + for idx, book in enumerate(title_list): + if self.letter_or_symbol(sort_equivalents[idx]) != current_letter: # Start a new letter if drtc and divRunningTag is not None: divTag.insert(dtc, divRunningTag) @@ -998,13 +1002,15 @@ Author '{0}': pIndexTag = Tag(soup, "p") pIndexTag['class'] = "author_title_letter_index" aTag = Tag(soup, "a") - current_letter = self.letter_or_symbol(book['title_sort'][0]) + current_letter = self.letter_or_symbol(sort_equivalents[idx]) if current_letter == self.SYMBOLS: - aTag['id'] = self.SYMBOLS + aTag['id'] = self.SYMBOLS + "_titles" + pIndexTag.insert(0,aTag) + pIndexTag.insert(1,NavigableString(self.SYMBOLS)) else: - aTag['id'] = "%s" % self.generateUnicodeName(current_letter) - pIndexTag.insert(0,aTag) - pIndexTag.insert(1,NavigableString(self.letter_or_symbol(book['title_sort'][0]))) + aTag['id'] = self.generateUnicodeName(current_letter) + "_titles" + pIndexTag.insert(0,aTag) + pIndexTag.insert(1,NavigableString(sort_equivalents[idx])) divRunningTag.insert(dtc,pIndexTag) drtc += 1 @@ -1079,7 +1085,7 @@ Author '{0}': ''' self.updateProgressFullStep("'Authors'") - friendly_name = "Authors" + friendly_name = _("Authors") soup = self.generateHTMLEmptyHeader(friendly_name) body = soup.find('body') @@ -1100,11 +1106,14 @@ Author '{0}': current_author = '' current_letter = '' current_series = None - #for book in sorted(self.booksByAuthor, key = self.booksByAuthorSorter_author_sort): - for book in self.booksByAuthor: + # Establish initial letter equivalencies + sort_equivalents = self.establish_equivalencies(self.booksByAuthor,key='author_sort') + #for book in sorted(self.booksByAuthor, key = self.booksByAuthorSorter_author_sort): + #for book in self.booksByAuthor: + for idx, book in enumerate(self.booksByAuthor): book_count += 1 - if self.letter_or_symbol(book['author_sort'][0].upper()) != current_letter : + if self.letter_or_symbol(sort_equivalents[idx]) != current_letter : # Start a new letter with Index letter if divOpeningTag is not None: divTag.insert(dtc, divOpeningTag) @@ -1124,13 +1133,16 @@ Author '{0}': pIndexTag = Tag(soup, "p") pIndexTag['class'] = "author_title_letter_index" aTag = Tag(soup, "a") - current_letter = self.letter_or_symbol(book['author_sort'][0].upper()) + #current_letter = self.letter_or_symbol(book['author_sort'][0].upper()) + current_letter = self.letter_or_symbol(sort_equivalents[idx]) if current_letter == self.SYMBOLS: aTag['id'] = self.SYMBOLS + '_authors' + pIndexTag.insert(0,aTag) + pIndexTag.insert(1,NavigableString(self.SYMBOLS)) else: - aTag['id'] = "%s_authors" % self.generateUnicodeName(current_letter) - pIndexTag.insert(0,aTag) - pIndexTag.insert(1,NavigableString(self.letter_or_symbol(book['author_sort'][0].upper()))) + aTag['id'] = self.generateUnicodeName(current_letter) + '_authors' + pIndexTag.insert(0,aTag) + pIndexTag.insert(1,NavigableString(sort_equivalents[idx])) divOpeningTag.insert(dotc,pIndexTag) dotc += 1 @@ -1180,7 +1192,7 @@ Author '{0}': if self.opts.generate_series: aTag = Tag(soup,'a') aTag['href'] = "%s.html#%s_series" % ('BySeries', - re.sub('\W','',book['series']).lower()) + re.sub('\s','',book['series']).lower()) aTag.insert(0, book['series']) pSeriesTag.insert(0, aTag) else: @@ -1282,7 +1294,7 @@ Author '{0}': def add_books_to_HTML_by_month(this_months_list, dtc): if len(this_months_list): - #this_months_list = sorted(this_months_list, key=self.booksByAuthorSorter_author_sort) + this_months_list = sorted(this_months_list, key=self.booksByAuthorSorter_author_sort) # Create a new month anchor date_string = strftime(u'%B %Y', current_date.timetuple()) @@ -1307,7 +1319,7 @@ Author '{0}': pAuthorTag['class'] = "author_index" aTag = Tag(soup, "a") if self.opts.generate_authors: - aTag['id'] = "%s" % self.generateAuthorAnchor(current_author) + aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(current_author)) aTag.insert(0,NavigableString(current_author)) pAuthorTag.insert(0,aTag) divTag.insert(dtc,pAuthorTag) @@ -1425,7 +1437,7 @@ Author '{0}': dtc += 1 return dtc - friendly_name = "Recently Added" + friendly_name = _("Recently Added") soup = self.generateHTMLEmptyHeader(friendly_name) body = soup.find('body') @@ -1518,7 +1530,7 @@ Author '{0}': ''' Write books by active bookmarks ''' - friendly_name = 'Recently Read' + friendly_name = _('Recently Read') self.updateProgressFullStep("'%s'" % friendly_name) if not self.bookmarked_books: return @@ -1710,6 +1722,8 @@ Author '{0}': # Fetch the database as a dictionary data = self.plugin.search_sort_db(self.db, self.opts) + + # Remove exclusions self.booksBySeries = self.processExclusions(data) if not self.booksBySeries: @@ -1717,24 +1731,25 @@ Author '{0}': self.opts.log(" no series found in selected books, cancelling series generation") return - friendly_name = "Series" + # Generate series_sort + for book in self.booksBySeries: + book['series_sort'] = self.generateSortTitle(book['series']) + + friendly_name = _("Series") soup = self.generateHTMLEmptyHeader(friendly_name) body = soup.find('body') btc = 0 - # Insert section tag + pTag = Tag(soup, "p") + pTag['style'] = 'display:none' + ptc = 0 aTag = Tag(soup,'a') - aTag['name'] = 'section_start' - body.insert(btc, aTag) - btc += 1 - - # Insert the anchor - aTag = Tag(soup, "a") - anchor_name = friendly_name.lower() - aTag['name'] = anchor_name.replace(" ","") - body.insert(btc, aTag) + aTag['id'] = 'section_start' + pTag.insert(ptc, aTag) + ptc += 1 + body.insert(btc, pTag) btc += 1 divTag = Tag(soup, "div") @@ -1742,23 +1757,29 @@ Author '{0}': current_letter = "" current_series = None + # Establish initial letter equivalencies + sort_equivalents = self.establish_equivalencies(self.booksBySeries, key='series_sort') + # Loop through booksBySeries series_count = 0 - for book in self.booksBySeries: + for idx, book in enumerate(self.booksBySeries): # Check for initial letter change - sort_title = self.generateSortTitle(book['series']) - if self.letter_or_symbol(sort_title[0].upper()) != current_letter : + if self.letter_or_symbol(sort_equivalents[idx]) != current_letter : # Start a new letter with Index letter - current_letter = self.letter_or_symbol(sort_title[0].upper()) + current_letter = self.letter_or_symbol(sort_equivalents[idx]) pIndexTag = Tag(soup, "p") pIndexTag['class'] = "series_letter_index" aTag = Tag(soup, "a") - aTag['name'] = "%s_series" % self.letter_or_symbol(current_letter) - pIndexTag.insert(0,aTag) - pIndexTag.insert(1,NavigableString(self.letter_or_symbol(sort_title[0].upper()))) + if current_letter == self.SYMBOLS: + aTag['id'] = self.SYMBOLS + "_series" + pIndexTag.insert(0,aTag) + pIndexTag.insert(1,NavigableString(self.SYMBOLS)) + else: + aTag['id'] = self.generateUnicodeName(current_letter) + "_series" + pIndexTag.insert(0,aTag) + pIndexTag.insert(1,NavigableString(sort_equivalents[idx])) divTag.insert(dtc,pIndexTag) dtc += 1 - # Check for series change if book['series'] != current_series: # Start a new series @@ -1767,7 +1788,10 @@ Author '{0}': pSeriesTag = Tag(soup,'p') pSeriesTag['class'] = "series" aTag = Tag(soup, 'a') - aTag['name'] = "%s_series" % re.sub('\W','',book['series']).lower() + if self.letter_or_symbol(book['series']): + aTag['id'] = "symbol_%s_series" % re.sub('\W','',book['series']).lower() + else: + aTag['id'] = "%s_series" % re.sub('\W','',book['series']).lower() pSeriesTag.insert(0,aTag) pSeriesTag.insert(1,NavigableString('%s' % book['series'])) divTag.insert(dtc,pSeriesTag) @@ -1830,7 +1854,7 @@ Author '{0}': pTag['class'] = 'title' aTag = Tag(soup, "a") anchor_name = friendly_name.lower() - aTag['name'] = anchor_name.replace(" ","") + aTag['id'] = anchor_name.replace(" ","") pTag.insert(0,aTag) #h2Tag.insert(1,NavigableString('%s (%d)' % (friendly_name, series_count))) pTag.insert(1,NavigableString('%s' % friendly_name)) @@ -1984,7 +2008,7 @@ Author '{0}': thumb_generated = False if not thumb_generated: - self.opts.log.warn(" using default cover for '%s' (%d)" % (title['title'], title['id'])) + self.opts.log.warn(" using default cover for '%s' (%d)" % (title['title'], title['id'])) # Confirm thumb exists, default is current default_thumb_fp = os.path.join(image_dir,"thumbnail_default.jpg") cover = os.path.join(self.catalogPath, "DefaultCover.png") @@ -2376,22 +2400,30 @@ Author '{0}': nptc += 1 series_by_letter = [] + # Establish initial letter equivalencies + sort_equivalents = self.establish_equivalencies(self.booksBySeries, key='series_sort') # Loop over the series titles, find start of each letter, add description_preview_count books # Special switch for using different title list + title_list = self.booksBySeries - current_letter = self.letter_or_symbol(self.generateSortTitle(title_list[0]['series'])[0]) + + # Prime the pump + current_letter = self.letter_or_symbol(sort_equivalents[0]) + title_letters = [current_letter] current_series_list = [] current_series = "" - for book in title_list: + for idx, book in enumerate(title_list): sort_title = self.generateSortTitle(book['series']) - if self.letter_or_symbol(sort_title[0]) != current_letter: + sort_title_equivalent = self.establish_equivalencies([sort_title])[0] + if self.letter_or_symbol(sort_equivalents[idx]) != current_letter: + # Save the old list add_to_series_by_letter(current_series_list) # Start the new list - current_letter = self.letter_or_symbol(sort_title[0]) + current_letter = self.letter_or_symbol(sort_equivalents[idx]) title_letters.append(current_letter) current_series = book['series'] current_series_list = [book['series']] @@ -2413,12 +2445,17 @@ Author '{0}': self.playOrder += 1 navLabelTag = Tag(soup, 'navLabel') textTag = Tag(soup, 'text') - textTag.insert(0, NavigableString(u"Series beginning with %s" % \ + textTag.insert(0, NavigableString(_(u"Series beginning with %s") % \ (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') - contentTag['src'] = "content/%s.html#%s_series" % (output, title_letters[i]) + #contentTag['src'] = "content/%s.html#%s_series" % (output, title_letters[i]) + if title_letters[i] == self.SYMBOLS: + contentTag['src'] = "content/%s.html#%s_series" % (output, self.SYMBOLS) + else: + contentTag['src'] = "content/%s.html#%s_series" % (output, self.generateUnicodeName(title_letters[i])) + navPointByLetterTag.insert(1,contentTag) if self.generateForKindle: @@ -2469,23 +2506,31 @@ Author '{0}': books_by_letter = [] + # Establish initial letter equivalencies + sort_equivalents = self.establish_equivalencies(self.booksByTitle, key='title_sort') + # Loop over the titles, find start of each letter, add description_preview_count books # Special switch for using different title list if self.useSeriesPrefixInTitlesSection: title_list = self.booksByTitle else: title_list = self.booksByTitle_noSeriesPrefix - current_letter = self.letter_or_symbol(title_list[0]['title_sort'][0]) + + # Prime the list + current_letter = self.letter_or_symbol(sort_equivalents[0]) title_letters = [current_letter] current_book_list = [] current_book = "" - for book in title_list: - if self.letter_or_symbol(book['title_sort'][0]) != current_letter: + for idx, book in enumerate(title_list): + #if self.letter_or_symbol(book['title_sort'][0]) != current_letter: + if self.letter_or_symbol(sort_equivalents[idx]) != current_letter: + # Save the old list add_to_books_by_letter(current_book_list) # Start the new list - current_letter = self.letter_or_symbol(book['title_sort'][0]) + #current_letter = self.letter_or_symbol(book['title_sort'][0]) + current_letter = self.letter_or_symbol(sort_equivalents[idx]) title_letters.append(current_letter) current_book = book['title'] current_book_list = [book['title']] @@ -2507,15 +2552,15 @@ Author '{0}': self.playOrder += 1 navLabelTag = Tag(soup, 'navLabel') textTag = Tag(soup, 'text') - textTag.insert(0, NavigableString(u"Titles beginning with %s" % \ + textTag.insert(0, NavigableString(_(u"Titles beginning with %s") % \ (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') if title_letters[i] == self.SYMBOLS: - contentTag['src'] = "content/%s.html#%s" % (output, title_letters[i]) + contentTag['src'] = "content/%s.html#%s_titles" % (output, self.SYMBOLS) else: - contentTag['src'] = "content/%s.html#%s" % (output, self.generateUnicodeName(title_letters[i])) + contentTag['src'] = "content/%s.html#%s_titles" % (output, self.generateUnicodeName(title_letters[i])) navPointByLetterTag.insert(1,contentTag) if self.generateForKindle: @@ -2570,17 +2615,22 @@ Author '{0}': # Loop over the sorted_authors list, find start of each letter, # add description_preview_count artists # self.authors[0]:friendly [1]:author_sort [2]:book_count + # (, author_sort, book_count) + + # Need to extract a list of author_sort, generate sort_equivalents from that + sort_equivalents = self.establish_equivalencies([x[1] for x in self.authors]) + master_author_list = [] - # self.authors[0][1][0] = Initial letter of author_sort[0] - current_letter = self.letter_or_symbol(self.authors[0][1][0]) + # Prime the pump + current_letter = self.letter_or_symbol(sort_equivalents[0]) current_author_list = [] - for author in self.authors: - if self.letter_or_symbol(author[1][0]) != current_letter: + for idx, author in enumerate(self.authors): + if self.letter_or_symbol(sort_equivalents[idx]) != current_letter: # Save the old list add_to_author_list(current_author_list, current_letter) # Start the new list - current_letter = self.letter_or_symbol(author[1][0]) + current_letter = self.letter_or_symbol(sort_equivalents[idx]) current_author_list = [author[0]] else: if len(current_author_list) < self.descriptionClip: @@ -2599,7 +2649,7 @@ Author '{0}': self.playOrder += 1 navLabelTag = Tag(soup, 'navLabel') textTag = Tag(soup, 'text') - textTag.insert(0, NavigableString("Authors beginning with '%s'" % (authors_by_letter[1]))) + textTag.insert(0, NavigableString(_("Authors beginning with '%s'") % (authors_by_letter[1]))) navLabelTag.insert(0, textTag) navPointByLetterTag.insert(0,navLabelTag) contentTag = Tag(soup, 'content') @@ -3177,6 +3227,46 @@ Author '{0}': return None + def establish_equivalencies(self, item_list, key=None): + # Filter for leading letter equivalencies + + # Hack to force the cataloged leading letter to be + # an unadorned character if the accented version sorts before the unaccented + exceptions = { + u'Ä':u'A', + u'Ö':u'O', + u'Ü':u'U' + } + + if key is not None: + sort_field = key + + cl_list = [None] * len(item_list) + last_ordnum = 0 + + for idx, item in enumerate(item_list): + if key: + c = item[sort_field] + else: + c = item + + ordnum, ordlen = collation_order(c) + if last_ordnum != ordnum: + last_c = icu_upper(c[0:ordlen]) + if last_c in exceptions.keys(): + last_c = exceptions[unicode(last_c)] + last_ordnum = ordnum + cl_list[idx] = last_c + + if False: + if key: + for idx, item in enumerate(item_list): + print("%s %s" % (cl_list[idx],item[sort_field])) + else: + print("%s %s" % (cl_list[0], item)) + + return cl_list + def filterDbTags(self, tags): # Remove the special marker tags from the database's tag list, # return sorted list of normalized genre tags @@ -3458,11 +3548,11 @@ Author '{0}': author = book['author'] if book['prefix']: - author_prefix = book['prefix'] + " by " + author_prefix = book['prefix'] + ' ' + _("by ") elif self.opts.connected_kindle and book['id'] in self.bookmarked_books: - author_prefix = self.READING_SYMBOL + " by " + author_prefix = self.READING_SYMBOL + ' ' + _("by ") else: - author_prefix = "by " + author_prefix = _("by ") # Genres genres = '' @@ -3551,8 +3641,12 @@ Author '{0}': if aTag: if book['series']: if self.opts.generate_series: - aTag['href'] = "%s.html#%s_series" % ('BySeries', + if self.letter_or_symbol(book['series']): + aTag['href'] = "%s.html#symbol_%s_series" % ('BySeries', re.sub('\W','',book['series']).lower()) + else: + aTag['href'] = "%s.html#%s_series" % ('BySeries', + re.sub('\s','',book['series']).lower()) else: aTag.extract() @@ -4045,7 +4139,7 @@ Author '{0}': re.IGNORECASE) is not None: if self.opts.verbose: field_md = self.db.metadata_for_field(field) - self.opts.log.info(" - %s (Exclusion rule '%s': %s:%s)" % + self.opts.log.info(" - %s (Exclusion rule '%s': %s:%s)" % (record['title'], field_md['name'], field,pat)) exclusion_set.append(record) if record in filtered_data_set: