From d533be245e9aa0a9123131906f1e3f397ffa6e40 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Aug 2011 10:52:11 -0600 Subject: [PATCH 01/10] IGN:Tag release --- src/calibre/translations/calibre.pot | 931 ++++++++++++++------------- 1 file changed, 491 insertions(+), 440 deletions(-) diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 9f08bd0bab..17adb883f0 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: calibre 0.8.12\n" -"POT-Creation-Date: 2011-07-29 10:47+MDT\n" -"PO-Revision-Date: 2011-07-29 10:47+MDT\n" +"Project-Id-Version: calibre 0.8.13\n" +"POT-Creation-Date: 2011-08-05 09:47+MDT\n" +"PO-Revision-Date: 2011-08-05 09:47+MDT\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -29,7 +29,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/jetbook/driver.py:74 #: /home/kovid/work/calibre/src/calibre/devices/kindle/driver.py:77 #: /home/kovid/work/calibre/src/calibre/devices/kobo/books.py:24 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:557 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:563 #: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:70 #: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:71 #: /home/kovid/work/calibre/src/calibre/devices/prs500/books.py:267 @@ -92,10 +92,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:125 #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:159 #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:713 -#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:964 -#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:966 -#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:968 -#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/utils.py:292 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:967 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:969 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:971 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/utils.py:299 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer2/indexer.py:489 #: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:99 #: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:101 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1001 @@ -132,12 +133,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:315 #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:376 #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:384 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:156 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:155 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:376 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:379 #: /home/kovid/work/calibre/src/calibre/gui2/add.py:161 #: /home/kovid/work/calibre/src/calibre/gui2/add.py:168 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:550 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:555 #: /home/kovid/work/calibre/src/calibre/gui2/convert/__init__.py:42 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:122 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:151 @@ -173,21 +174,21 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:535 #: /home/kovid/work/calibre/src/calibre/library/database2.py:543 #: /home/kovid/work/calibre/src/calibre/library/database2.py:554 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2005 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2152 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3169 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3171 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3304 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2006 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2153 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3170 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3172 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3305 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:225 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:226 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:243 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:156 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:159 #: /home/kovid/work/calibre/src/calibre/library/server/xml.py:79 -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:147 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:148 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:46 -#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:64 -#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:78 +#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:66 +#: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:88 #: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/collection.py:46 #: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/collection.py:54 msgid "Unknown" @@ -230,7 +231,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:557 #: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:18 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:22 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:25 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:197 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:287 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:309 @@ -406,199 +407,203 @@ msgstr "" msgid "Find the next or previous match when searching in your calibre library in highlight mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:850 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:849 +msgid "Choose a random book from your calibre library" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:856 msgid "Search for books from different book sellers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:866 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:872 msgid "Get new calibre plugins or update your existing ones" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:885 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:891 msgid "Look and Feel" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:887 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:899 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:910 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:921 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:933 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:893 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:905 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:916 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:927 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:939 msgid "Interface" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:891 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:897 msgid "Adjust the look and feel of the calibre interface to suit your tastes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:897 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:903 msgid "Behavior" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:903 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:909 msgid "Change the way calibre behaves" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:908 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:914 #: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:232 msgid "Add your own columns" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:914 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:920 msgid "Add/remove your own columns to the calibre book list" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:919 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:925 msgid "Toolbar" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:925 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:931 msgid "Customize the toolbars and context menus, changing which actions are available in each" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:931 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:937 msgid "Searching" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:937 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:943 msgid "Customize the way searching for books works in calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:942 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:948 msgid "Input Options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:944 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:955 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:966 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:950 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:961 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:972 msgid "Conversion" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:948 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:954 msgid "Set conversion options specific to each input format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:953 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:959 msgid "Common Options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:959 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:965 msgid "Set conversion options common to all formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:964 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:970 msgid "Output Options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:970 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:976 msgid "Set conversion options specific to each output format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:975 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:981 msgid "Adding books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:977 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:989 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1001 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1013 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:983 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:995 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1007 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1019 msgid "Import/Export" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:981 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:987 msgid "Control how calibre reads metadata from files when adding books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:987 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:993 msgid "Saving books to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:993 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:999 msgid "Control how calibre exports files from its database to disk when using Save to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:999 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1005 msgid "Sending books to devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1005 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1011 msgid "Control how calibre transfers files to your ebook reader" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1011 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1017 msgid "Metadata plugboards" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1017 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1023 msgid "Change metadata fields before saving/sending" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1022 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1028 msgid "Template Functions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1024 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1071 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1083 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1094 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1030 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1077 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1089 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1100 msgid "Advanced" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1028 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1034 msgid "Create your own template functions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1033 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1039 msgid "Sharing books by email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1035 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1047 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1060 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1041 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1053 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1066 msgid "Sharing" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1039 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1045 msgid "Setup sharing of books via email. Can be used for automatic sending of downloaded news to your devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1045 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1051 msgid "Sharing over the net" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1051 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1057 msgid "Setup the calibre Content Server which will give you access to your calibre library from anywhere, on any device, over the internet" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1058 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1064 msgid "Metadata download" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1064 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1070 msgid "Control how calibre downloads ebook metadata from the net" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1069 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1075 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:275 msgid "Plugins" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1075 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1081 msgid "Add/remove/customize various bits of calibre functionality" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1081 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1087 msgid "Tweaks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1087 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1093 msgid "Fine tune how calibre behaves in various contexts" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1092 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1098 msgid "Miscellaneous" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1098 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1104 msgid "Miscellaneous advanced configuration" msgstr "" @@ -815,7 +820,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/db/backend.py:270 #: /home/kovid/work/calibre/src/calibre/db/backend.py:279 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:236 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:230 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:71 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:667 #: /home/kovid/work/calibre/src/calibre/library/database2.py:130 @@ -829,8 +834,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:66 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:564 #: /home/kovid/work/calibre/src/calibre/library/database2.py:972 -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:754 -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:766 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:758 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:770 msgid "Yes" msgstr "" @@ -859,11 +864,11 @@ msgstr "" msgid "Communicate with Android phones." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:113 +#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:114 msgid "Comma separated list of directories to send e-books to on the device. The first one that exists will be used" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:166 +#: /home/kovid/work/calibre/src/calibre/devices/android/driver.py:167 msgid "Communicate with S60 phones." msgstr "" @@ -964,11 +969,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:1114 #: /home/kovid/work/calibre/src/calibre/gui2/actions/fetch_news.py:73 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:452 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1132 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1134 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1139 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1141 #: /home/kovid/work/calibre/src/calibre/library/database2.py:330 #: /home/kovid/work/calibre/src/calibre/library/database2.py:343 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3030 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3031 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:171 msgid "News" msgstr "" @@ -976,8 +981,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2685 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:65 #: /home/kovid/work/calibre/src/calibre/library/catalog.py:652 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2990 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3008 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2991 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3009 msgid "Catalog" msgstr "" @@ -1040,8 +1045,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/bambook/driver.py:285 #: /home/kovid/work/calibre/src/calibre/devices/bambook/driver.py:299 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:415 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:450 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:421 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:456 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:297 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:328 msgid "Adding books to device metadata listing..." @@ -1051,8 +1056,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/bambook/driver.py:309 #: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:114 #: /home/kovid/work/calibre/src/calibre/devices/hanvon/driver.py:125 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:367 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:399 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:373 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:405 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:334 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:352 msgid "Removing books from device..." @@ -1060,8 +1065,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/bambook/driver.py:324 #: /home/kovid/work/calibre/src/calibre/devices/bambook/driver.py:329 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:403 -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:410 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:409 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:416 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:359 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:364 msgid "Removing books from device metadata listing..." @@ -1284,12 +1289,12 @@ msgstr "" msgid "Create tags for automatic management" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:537 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:388 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:543 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:387 msgid "Not Implemented" msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:538 +#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:544 msgid "\".kobo\" files do not exist on the device as books instead, they are rows in the sqlite database. Currently they cannot be exported or viewed." msgstr "" @@ -2075,7 +2080,7 @@ msgid "Remove empty paragraphs from the document when they exist between every o msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:559 -msgid "Left aligned scene break markers are center aligned. Replace soft scene breaks that use multiple blank lines withhorizontal rules." +msgid "Left aligned scene break markers are center aligned. Replace soft scene breaks that use multiple blank lines with horizontal rules." msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plumber.py:565 @@ -2886,7 +2891,11 @@ msgstr "" msgid "When adding the Table of Contents to the book, add it at the start of the book instead of the end. Not recommended." msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/output.py:105 +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/output.py:54 +msgid "Extract the contents of the MOBI file to the specified directory. If the directory already exists, it will be deleted." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/output.py:110 msgid "All articles" msgstr "" @@ -2894,6 +2903,10 @@ msgstr "" msgid "This is an Amazon Topaz book. It cannot be processed." msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer2/indexer.py:490 +msgid "No details available" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1499 msgid "Title Page" msgstr "" @@ -3559,7 +3572,7 @@ msgstr "" msgid "A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:55 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:52 msgid "Add books from a single directory" msgstr "" @@ -3591,78 +3604,78 @@ msgstr "" msgid "Shift+A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:89 msgid "Are you sure" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:91 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:90 #, python-format msgid "Are you sure you want to add the same files to all %d books? If the formatalready exists for a book, it will be replaced." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:97 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:96 msgid "Select book files" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:168 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:167 msgid "Adding" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:169 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:168 msgid "Creating book records from ISBNs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:268 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:317 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:267 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:316 msgid "Uploading books to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:288 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:287 msgid "Supported books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:291 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:290 msgid "Select books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:329 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:328 msgid "Merged some books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:330 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:329 msgid "The following duplicate books were found and incoming book formats were processed and merged into your Calibre database according to your automerge settings:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:349 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:348 msgid "Failed to read metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:350 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:349 msgid "Failed to read metadata from the following" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:371 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:376 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:395 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:370 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:394 msgid "Add to library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:376 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:130 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:83 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:102 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:111 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:84 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:103 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:112 #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:140 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:186 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:185 msgid "No book selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:389 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:388 msgid "The following books are virtual and cannot be added to the calibre library:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:395 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:394 msgid "No book files found" msgstr "" @@ -3705,7 +3718,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:157 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:221 #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:258 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:91 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:90 msgid "No books selected" msgstr "" @@ -3743,7 +3756,7 @@ msgid "Location %(dl)d • %(typ)s
" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:20 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:34 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:35 msgid "Create a catalog of the books in your calibre library" msgstr "" @@ -3781,125 +3794,126 @@ msgstr "" msgid "Choose calibre library to work with" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:95 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:86 msgid "Switch/create library..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:106 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:103 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:87 msgid "Quick switch" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:108 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:105 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:88 msgid "Rename library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:110 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:107 msgid "Remove library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:113 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:110 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/random.py:17 msgid "Pick a random book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:130 msgid "Library Maintenance" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:131 msgid "Library metadata backup status" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:135 msgid "Start backing up metadata of all books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:142 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:139 msgid "Check library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:146 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:143 msgid "Restore database" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:221 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:215 msgid "Rename" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:222 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:216 #, python-format msgid "Choose a new name for the library %s. " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:223 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:217 msgid "Note that the actual library folder will be renamed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:230 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:224 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:726 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:201 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:291 msgid "Already exists" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:231 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:225 #, python-format msgid "The folder %s already exists. Delete it first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:235 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:289 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:229 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:283 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:70 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:666 msgid "Too long" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:243 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:237 msgid "Rename failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:244 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:238 #, python-format msgid "Failed to rename the library at %s. The most common cause for this is if one of the files in the library is open in another program." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:258 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:252 msgid "Library removed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:259 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:253 #, python-format msgid "The library %s has been removed from calibre. The files remain on your computer, if you want to delete them, you will have to do so manually." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:272 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:266 msgid "none" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:273 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:267 msgid "Backup status" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:274 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:268 #, python-format msgid "Book metadata files remaining to be written: %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:280 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:274 msgid "Backup metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:281 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:275 msgid "Metadata will be backed up while calibre is running, at the rate of approximately 1 book every three seconds." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:290 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:284 #, python-format msgid "Path to library too long. Must be less than %d characters. Move your library to a location with a shorter path using Windows Explorer, then point calibre to the new location and try again." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:325 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:319 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:733 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:106 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:111 @@ -3908,11 +3922,11 @@ msgstr "" msgid "Success" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:326 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:320 msgid "Found no errors in your calibre library database. Do you want calibre to check if the files in your library match the information in the database?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:331 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:325 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:160 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:741 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:956 @@ -3922,40 +3936,40 @@ msgstr "" msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:326 msgid "Database integrity check failed, click Show details for details." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:337 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:331 msgid "No problems found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:338 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:332 msgid "The files in your library match the information in the database." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:347 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:341 msgid "No library found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:348 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:342 #, python-format msgid "No existing calibre library was found at %s. It will be removed from the list of known libraries." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:414 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:419 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:408 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:413 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:178 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:100 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:99 #: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:886 msgid "Not allowed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:415 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:409 msgid "You cannot change libraries while using the environment variable CALIBRE_OVERRIDE_DATABASE_PATH." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:420 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:414 msgid "You cannot change libraries while jobs are running." msgstr "" @@ -3967,11 +3981,11 @@ msgstr "" msgid "Convert books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:29 msgid "Convert individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:30 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:31 msgid "Bulk convert" msgstr "" @@ -4034,8 +4048,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:30 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:53 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:112 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:674 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:78 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:209 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:370 #: /home/kovid/work/calibre/src/calibre/gui2/jobs.py:469 #: /home/kovid/work/calibre/src/calibre/gui2/jobs.py:477 @@ -4067,96 +4083,96 @@ msgstr "" msgid "Failed to delete some books, click the Show Details button for details." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:84 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:85 msgid "Remove books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:88 msgid "Remove selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:94 msgid "Remove files of a specific format from selected books.." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:95 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:97 msgid "Remove all formats from selected books, except..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:98 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:100 msgid "Remove all formats from selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:101 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:103 msgid "Remove covers from selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:104 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:106 msgid "Remove matching books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:129 msgid "Cannot delete" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:140 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:142 msgid "Choose formats to be deleted" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:158 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:160 msgid "Choose formats not to be deleted.

Note that this will never remove all formats from a book." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:186 msgid "All formats for the selected books will be deleted from your library.
The book metadata will be kept. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:204 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:206 msgid "Cannot delete books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:205 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:207 msgid "No device is connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:215 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:217 msgid "Main memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:216 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:218 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:516 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:525 msgid "Storage Card A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:219 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:518 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:527 msgid "Storage Card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:222 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:224 msgid "No books to delete" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:223 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:225 msgid "None of the selected books are on the device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:240 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:331 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:242 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:333 msgid "Deleting books from device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:286 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:288 msgid "Some of the selected books are on the attached device. Where do you want the selected files deleted from?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:298 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:300 msgid "The selected books will be permanently deleted and the files removed from your calibre library. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:323 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:325 msgid "The selected books will be permanently deleted from your device. Are you sure?" msgstr "" @@ -4236,35 +4252,35 @@ msgstr "" msgid "Edit metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:29 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:30 msgid "Merge book records" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:30 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:31 msgid "M" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:33 msgid "Edit metadata individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:35 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:36 msgid "Edit metadata in bulk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:38 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:39 msgid "Download metadata and covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:43 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:44 msgid "Merge into first selected book - delete others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:47 msgid "Merge into first selected book - keep others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:51 msgid "Merge only formats into first selected book - delete others" msgstr "" @@ -4441,20 +4457,20 @@ msgstr "" msgid "Ctrl+P" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:24 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:20 msgid "Change calibre behavior" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:25 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:26 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:208 msgid "Run welcome wizard" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:29 msgid "Get plugins to enhance calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:31 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:32 msgid "Restart in debug mode" msgstr "" @@ -4484,7 +4500,6 @@ msgid "S" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:39 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:45 msgid "Save to disk" msgstr "" @@ -4493,43 +4508,43 @@ msgid "Save to disk in a single directory" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:49 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:67 #, python-format msgid "Save only %s format to disk" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:53 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:71 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:70 #, python-format msgid "Save only %s format to disk in a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:89 msgid "Cannot save to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:93 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:92 msgid "Choose destination directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:101 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:100 msgid "You are trying to save files into the calibre library. This can cause corruption of your library. Save to disk is meant to export files from your calibre library elsewhere." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:134 msgid "Error while saving" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:136 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:135 msgid "There was an error while saving." msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:142 #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:143 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:144 msgid "Could not save some books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:145 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:144 msgid "Click the show details button to see which ones." msgstr "" @@ -4570,93 +4585,97 @@ msgstr "" msgid "Similar books..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:24 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:25 msgid "Alt+A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:24 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:25 msgid "Books by same author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:25 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:26 msgid "Books in this series" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:26 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:27 msgid "Alt+Shift+S" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:28 msgid "Alt+P" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:28 msgid "Books by this publisher" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:29 msgid "Alt+T" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/similar_books.py:29 msgid "Books with the same tags" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:20 +msgid "G" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:20 msgid "Get books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:29 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:22 msgid "Search for ebooks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:30 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:32 msgid "Search for this author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:31 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:33 msgid "Search for this title" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:34 msgid "Search for this book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:34 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:36 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/search_ui.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/store/search_ui.py:110 msgid "Stores" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:43 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:45 #: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/chooser_dialog.py:18 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/search.py:285 msgid "Choose stores" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:83 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:102 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:111 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:84 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:103 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:112 msgid "Cannot search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:130 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:131 msgid "Calibre helps you find the ebooks you want by searching the websites of various commercial and public domain book sources for you." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:135 msgid "Using the integrated search you can easily find which store has the book you are looking for, at the best price. You also get DRM status and other useful information." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:139 msgid "All transactions (paid or otherwise) are handled between you and the book seller. Calibre is not part of this process and any issues related to a purchase should be directed to the website you are buying from. Be sure to double check that any books you get will work with your e-book reader, especially if the book you are buying has DRM." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:148 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:149 msgid "Show this message again" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:149 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:150 msgid "About Get Books" msgstr "" @@ -4690,61 +4709,61 @@ msgstr "" msgid "View" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:43 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:46 msgid "View specific format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:51 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:50 msgid "Read a random book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:55 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:54 msgid "Clear recently viewed list" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:140 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:220 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:227 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:219 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:226 msgid "Cannot view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:153 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:167 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:152 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:166 msgid "Format unavailable" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:154 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:153 msgid "Selected books have no formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:156 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:155 #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:128 msgid "Choose the format to view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:168 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:167 #, python-format msgid "Not all the selected books were available in the %s format. You should convert them first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:175 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:174 msgid "Multiple Books Selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:176 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:175 #, python-format msgid "You are attempting to open %d books. Opening too many books at once can be slow and have a negative effect on the responsiveness of your computer. Once started the process cannot be stopped until complete. Do you wish to continue?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:185 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:184 msgid "Cannot open folder" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:221 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:220 msgid "This book no longer exists in your library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:228 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:227 #, python-format msgid "%s has no available formats." msgstr "" @@ -4901,6 +4920,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:79 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:80 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:86 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:80 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:82 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:560 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:565 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:98 @@ -4915,8 +4936,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:133 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:136 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:140 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:80 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:82 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:72 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:74 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:277 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:279 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:280 @@ -4964,45 +4985,45 @@ msgstr "" msgid "Donate" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:116 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:117 msgid "Click to open" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:132 msgid "Ids" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:163 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:164 #, python-format msgid "Book %(sidx)s of %(series)s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:179 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1020 msgid "Collections" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:276 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:281 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:247 msgid "Paste Cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:277 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:282 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:248 msgid "Copy Cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:543 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:548 msgid "Double-click to open Book Details window" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:544 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:549 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:279 msgid "Path" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:545 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:550 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:109 #, python-format msgid "Cover size: %(width)d x %(height)d" @@ -5021,7 +5042,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/convert/htmlz_output.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:20 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:20 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:18 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_input.py:13 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output.py:16 @@ -5041,7 +5062,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/convert/htmlz_output.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output.py:20 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:20 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:18 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output.py:16 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pml_output.py:15 @@ -5066,7 +5087,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:145 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:120 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:158 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:77 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:71 #: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup_ui.py:120 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_input_ui.py:36 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output_ui.py:47 @@ -6056,52 +6077,43 @@ msgstr "" msgid "Book " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:19 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:17 msgid "MOBI Output" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:44 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:64 -msgid "Default" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:78 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:72 msgid "&Title for Table of Contents:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:79 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:73 msgid "Rescale images for &Palm devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:80 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:74 msgid "Use author &sort for author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:81 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:75 msgid "Disable compression of the file contents" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:82 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:76 msgid "Do not add Table of Contents to book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:83 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:77 msgid "Kindle options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:84 -msgid "Periodical masthead font:" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:78 msgid "Personal Doc tag:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:86 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:79 msgid "Put generated Table of Contents at &start of book instead of end" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:80 msgid "Ignore &margins" msgstr "" @@ -7366,6 +7378,74 @@ msgstr "" msgid "Delete from device" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:21 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:22 +#, python-format +msgid "%(curr)s (was %(initial)s)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:86 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:183 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:882 +msgid "Item is blank" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:883 +msgid "An item cannot be set to nothing. Delete it instead." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:100 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:197 +msgid "No item selected" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:101 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:198 +msgid "You must select one item from the list of Available items." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:108 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:205 +msgid "No items selected" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:109 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:206 +msgid "You must select at least one item from the list." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor.py:113 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:210 +msgid "Are you sure you want to delete the following items?" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:77 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:70 +msgid "Category Editor" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:78 +msgid "Items in use" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:79 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:71 +msgid "Delete item from database. This will unapply the item from all books and then remove it from the database." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:81 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:73 +msgid "Rename the item in every book where it is used." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/device_category_editor_ui.py:83 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:75 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:112 +msgid "Ctrl+S" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/drm_error_ui.py:54 msgid "This book is DRMed" msgstr "" @@ -7435,12 +7515,12 @@ msgid "Copy to author" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:313 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:925 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:932 msgid "Invalid author name" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:314 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:926 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:933 msgid "Author names cannot contain & characters." msgstr "" @@ -7455,7 +7535,7 @@ msgid "&Search for:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog_ui.py:90 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:321 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:316 msgid "F&ind" msgstr "" @@ -8919,7 +8999,6 @@ msgid "Unapply (remove) tag from current tag category" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor.py:70 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:112 msgid "Are your sure?" msgstr "" @@ -8963,60 +9042,12 @@ msgstr "" msgid "Add tag to available tags and apply it to current book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:21 -#, python-format -msgid "%(curr)s (was %(initial)s)" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:86 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:875 -msgid "Item is blank" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:87 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:876 -msgid "An item cannot be set to nothing. Delete it instead." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:100 -msgid "No item selected" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:101 -msgid "You must select one item from the list of Available items." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:108 -msgid "No items selected" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:109 -msgid "You must select at least one items from the list." +msgid "Tag" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:113 -msgid "Are you certain you want to delete the following items?" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:77 -msgid "Category Editor" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:78 -msgid "Items in use" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:79 -msgid "Delete item from database. This will unapply the item from all books and then remove it from the database." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:81 -msgid "Rename the item in every book where it is used." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:83 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:112 -msgid "Ctrl+S" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:112 +msgid "Count" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:257 @@ -9031,19 +9062,19 @@ msgstr "" msgid "EXCEPTION: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:302 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:301 msgid "No column chosen" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:303 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:302 msgid "You must specify a column to be colored" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:306 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:305 msgid "No template provided" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:307 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:306 msgid "The template box cannot be empty" msgstr "" @@ -10547,6 +10578,10 @@ msgstr "" msgid "Compact Metadata" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:64 +msgid "Default" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:65 msgid "All on 1 tab" msgstr "" @@ -12882,40 +12917,40 @@ msgstr "" msgid "The grouped search term name is \"{0}\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:724 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:731 msgid "Changing the authors for several books can take a while. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:729 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:736 msgid "Changing the metadata for that many books can take a while. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:816 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:823 #: /home/kovid/work/calibre/src/calibre/library/database2.py:449 msgid "Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:881 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:901 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:910 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:888 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:908 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:917 msgid "Rename user category" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:882 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:889 msgid "You cannot use periods in the name when renaming user categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:902 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:911 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:909 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:918 #, python-format msgid "The name %s is already used" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:930 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:937 msgid "Duplicate search name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:931 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:938 #, python-format msgid "The saved search name %s is already used." msgstr "" @@ -12992,11 +13027,11 @@ msgstr "" msgid "A user category %s does not exist" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:305 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:300 msgid "Find item in tag browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:309 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:304 msgid "" "Search for items. This is a \"contains\" search; items containing the\n" "text anywhere in the name will be found. You can limit the search\n" @@ -13006,55 +13041,55 @@ msgid "" "containing the text \"foo\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:317 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:312 msgid "ALT+f" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:322 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:317 msgid "Find the first/next matching item" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:327 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:322 msgid "Collapse all categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:351 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:346 msgid "No More Matches.

Click Find again to go to first match" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:364 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:359 msgid "Sort by name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:364 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:359 msgid "Sort by popularity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:365 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:360 msgid "Sort by average rating" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:368 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:363 msgid "Set the sort order for entries in the Tag Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:370 msgid "Match all" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:370 msgid "Match any" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:380 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:375 msgid "When selecting multiple entries in the Tag Browser match any or all of them" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:387 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:382 msgid "Manage authors, tags, etc" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:388 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/ui.py:383 msgid "All of these category_managers are available by right-clicking on items in the tag browser above" msgstr "" @@ -14945,17 +14980,17 @@ msgstr "" msgid "%(tt)sAverage rating is %(rating)3.1f" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3330 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3331 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3359 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3360 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3376 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3377 msgid "Compacting database" msgstr "" @@ -15468,211 +15503,223 @@ msgstr "" msgid "No such variable " msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:59 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:64 msgid "No documentation provided" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:93 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:97 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:109 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:113 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:125 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:129 msgid "strcat(a, b, ...) -- can take any number of arguments. Returns a string formed by concatenating all the arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:139 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:143 msgid "add(x, y) -- returns x + y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:150 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:154 msgid "subtract(x, y) -- returns x - y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:161 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:165 msgid "multiply(x, y) -- returns x * y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:172 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:176 msgid "divide(x, y) -- returns x / y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:184 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:188 msgid "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 ]] for the } character; they are converted automatically. For example, template('[[title_sort]]') will evaluate the template {title_sort} and return its value." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:200 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:204 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:214 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:218 msgid "assign(id, val) -- assigns val to id, then returns val. id must be an identifier, not an expression" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:225 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:229 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:237 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:241 msgid "field(name) -- returns the metadata field named by name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:246 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:250 msgid "raw_field(name) -- returns the metadata field named by name without applying any formatting." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:256 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:260 msgid "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 indicates the last character. For example, substr('12345', 1, 0) returns '2345', and substr('12345', 1, -1) returns '234'." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:270 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:274 msgid "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 function in one composite field to use the value of some other composite field. This is extremely useful when constructing variable save paths" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:285 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:289 msgid "lookup requires either 2 or an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:298 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:302 msgid "test(val, text if not empty, text if empty) -- return `text if not empty` if the field is not empty, otherwise return `text if empty`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:311 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:315 msgid "contains(val, pattern, text if match, text if not match) -- checks if field contains matches for the regular expression `pattern`. Returns `text if match` if matches are found, otherwise it returns `text if no match`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:327 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:331 msgid "switch(val, pattern, value, pattern, value, ..., else_value) -- for each `pattern, value` pair, checks if the field matches the regular expression `pattern` and if so, returns that `value`. If no pattern matches, then else_value is returned. You can have as many `pattern, value` pairs as you want" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:335 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:339 msgid "switch requires an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:348 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:352 msgid "in_list(val, separator, pattern, found_val, not_found_val) -- treat val as a list of items separated by separator, comparing the pattern against each value in the list. If the pattern matches a value, return found_val, otherwise return not_found_val." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:366 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:370 msgid "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, return found_val, otherwise return not_found_val. If the string contains separators, then it is also treated as a list and each value is checked." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:387 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:391 msgid "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 either \"id\" or \"id:regexp\". The first case matches if there is any identifier with that id. The second case matches if the regexp matches the identifier's value. If there is a match, return found_val, otherwise return not_found_val." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:413 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:417 msgid "re(val, pattern, replacement) -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of calibre, these are python-compatible regular expressions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:425 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:429 msgid "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" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:437 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:441 msgid "ifempty(val, text if empty) -- return val if val is not empty, otherwise return `text if empty`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:450 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:454 msgid "shorten(val, left chars, middle text, right chars) -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use {title:shorten(9,-,5)}, the result will be `Ancient E-nhoe`. If the field's length is less than left chars + right chars + the length of `middle text`, then the field will be used intact. For example, the title `The Dome` would not be changed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:476 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:480 msgid "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(&)}" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:488 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:492 msgid "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, then the empty value is returned. The separator has the same meaning as in the count function." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:509 -msgid "select(val, key) -- interpret the value as a comma-separated list of items, with the items being \"id:value\". Find the pair with theid equal to key, and return the corresponding value." +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:513 +msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:527 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:531 msgid "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 date_format function for details. You can use the select function to get the mod time for a specific format. Note that format names are always uppercase, as in EPUB." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:546 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:550 msgid "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 format. Note that format names are always uppercase, as in EPUB." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:562 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:566 msgid "human_readable(v) -- return a string representing the number v in KB, MB, GB, etc." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:576 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:580 msgid "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). See the template language and python documentation for more examples. Returns the empty string if formatting fails." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:601 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:605 msgid "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 counts from the end of the list. As a special case, an end_index of zero is assumed to be the length of the list. Examples using basic template mode and assuming that the tags column (which is comma-separated) contains \"A, B, C\": {tags:sublist(0,1,\\,)} returns \"A\". {tags:sublist(-1,0,\\,)} returns \"C\". {tags:sublist(0,-1,\\,)} returns \"A, B\"." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:632 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:636 msgid "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 period-separated items, then for each such item extracting the start_index` to the `end_index` components, then combining the results back together. The first component in a period-separated list has an index of zero. If an index is negative, then it counts from the end of the list. As a special case, an end_index of zero is assumed to be the length of the list. Example using basic template mode and assuming a #genre value of \"A.B.C\": {#genre:subitems(0,1)} returns \"A\". {#genre:subitems(0,2)} returns \"A.B\". {#genre:subitems(1,0)} returns \"B.C\". Assuming a #genre value of \"A.B.C, D.E.F\", {#genre:subitems(0,1)} returns \"A, D\". {#genre:subitems(0,2)} returns \"A.B, D.E\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:670 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:674 msgid "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) dd : the day as number with a leading zero (01 to 31) ddd : the abbreviated localized day name (e.g. \"Mon\" to \"Sun\"). dddd : the long localized day name (e.g. \"Monday\" to \"Sunday\"). M : the month as number without a leading zero (1 to 12). MM : the month as number with a leading zero (01 to 12) MMM : the abbreviated localized month name (e.g. \"Jan\" to \"Dec\"). MMMM : the long localized month name (e.g. \"January\" to \"December\"). yy : the year as two digit number (00 to 99). yyyy : the year as four digit number. iso : the date with time and timezone. Must be the only format present" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:699 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:703 msgid "uppercase(val) -- return value of the field in upper case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:708 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:712 msgid "lowercase(val) -- return value of the field in lower case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:717 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:721 msgid "titlecase(val) -- return value of the field in title case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:726 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:730 msgid "capitalize(val) -- return value of the field capitalized" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:735 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:739 msgid "booksize() -- return value of the size field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:749 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:753 msgid "ondevice() -- return Yes if ondevice is set, otherwise return the empty string" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:761 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:765 msgid "has_cover() -- return Yes if the book has a cover, otherwise return the empty string" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:773 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:777 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:790 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:794 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:807 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:811 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:824 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:828 msgid "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. You can have as many values as you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:836 -msgid "merge_lists(list1, list2, separator) -- return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive compare. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list." +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:840 +msgid "list_union(list1, list2, separator) -- return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive compare. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:860 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:865 +msgid "list_difference(list1, list2, separator) -- return a list made by removing from list1 any item found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:884 +msgid "list_intersection(list1, list2, separator) -- return a list made by removing from list1 any item not found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:903 +msgid "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." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:916 msgid "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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:871 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:927 msgid "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 empty string." msgstr "" @@ -15833,38 +15880,42 @@ msgid "Spanish (Nicaragua)" msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/localization.py:143 -msgid "German (AT)" +msgid "Spanish (Colombia)" msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/localization.py:144 -msgid "French (BE)" +msgid "German (AT)" msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/localization.py:145 -msgid "Dutch (NL)" +msgid "French (BE)" msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/localization.py:146 +msgid "Dutch (NL)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:147 msgid "Dutch (BE)" msgstr "" #. NOTE: Ante Meridian (i.e. like 10:00 AM) -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:154 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:155 msgid "AM" msgstr "" #. NOTE: Post Meridian (i.e. like 10:00 PM) -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:156 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:157 msgid "PM" msgstr "" #. NOTE: Ante Meridian (i.e. like 10:00 am) -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:158 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:159 msgid "am" msgstr "" #. NOTE: Post Meridian (i.e. like 10:00 pm) -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:160 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:161 msgid "pm" msgstr "" @@ -16043,29 +16094,29 @@ msgstr "" msgid "Masthead image downloaded" msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1216 +#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1185 msgid "Untitled Article" msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1287 +#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1256 #, python-format msgid "Article downloaded: %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1298 +#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1267 #, python-format msgid "Article download failed: %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1315 +#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1284 msgid "Fetching feed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1462 +#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1431 msgid "Failed to log in, check your username and password for the calibre Periodicals service." msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1477 +#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:1446 msgid "You do not have permission to download this issue. Either your subscription has expired or you have exceeded the maximum allowed downloads for today." msgstr "" From 99fec62ddc38e19dc15eb840fa19cde6183ce867 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Aug 2011 14:08:25 -0600 Subject: [PATCH 02/10] ... --- recipes/economist_free.recipe | 156 ++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/recipes/economist_free.recipe b/recipes/economist_free.recipe index 71c323d6a3..73fb7b8891 100644 --- a/recipes/economist_free.recipe +++ b/recipes/economist_free.recipe @@ -1,3 +1,157 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2008, Kovid Goyal ' +''' +economist.com +''' +from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import Tag, NavigableString +from collections import OrderedDict + +import time, re + +class Economist(BasicNewsRecipe): + + title = 'The Economist' + language = 'en' + + __author__ = "Kovid Goyal" + INDEX = 'http://www.economist.com/printedition' + description = ('Global news and current affairs from a European' + ' perspective. Best downloaded on Friday mornings (GMT)') + extra_css = '.headline {font-size: x-large;} \n h2 { font-size: small; } \n h1 { font-size: medium; }' + oldest_article = 7.0 + cover_url = 'http://media.economist.com/sites/default/files/imagecache/print-cover-thumbnail/print-covers/currentcoverus_large.jpg' + #cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg' + remove_tags = [ + dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']), + dict(attrs={'class':['dblClkTrk', 'ec-article-info', + 'share_inline_header', 'related-items']}), + {'class': lambda x: x and 'share-links-header' in x}, + ] + keep_only_tags = [dict(id='ec-article-body')] + needs_subscription = False + no_stylesheets = True + preprocess_regexps = [(re.compile('.*', re.DOTALL), + lambda x:'')] + + ''' + def get_browser(self): + br = BasicNewsRecipe.get_browser() + br.open('http://www.economist.com') + req = mechanize.Request( + 'http://www.economist.com/members/members.cfm?act=exec_login', + headers = { + 'Referer':'http://www.economist.com/', + }, + data=urllib.urlencode({ + 'logging_in' : 'Y', + 'returnURL' : '/', + 'email_address': self.username, + 'fakepword' : 'Password', + 'pword' : self.password, + 'x' : '0', + 'y' : '0', + })) + br.open(req).read() + return br + ''' + + def parse_index(self): + try: + return self.economist_parse_index() + except: + raise + self.log.warn( + 'Initial attempt to parse index failed, retrying in 30 seconds') + time.sleep(30) + return self.economist_parse_index() + + def economist_parse_index(self): + soup = self.index_to_soup(self.INDEX) + div = soup.find('div', attrs={'class':'issue-image'}) + if div is not None: + img = div.find('img', src=True) + if img is not None: + self.cover_url = img['src'] + feeds = OrderedDict() + for section in soup.findAll(attrs={'class':lambda x: x and 'section' in + x}): + h4 = section.find('h4') + if h4 is None: + continue + section_title = self.tag_to_string(h4).strip() + if not section_title: + continue + self.log('Found section: %s'%section_title) + articles = [] + for h5 in section.findAll('h5'): + article_title = self.tag_to_string(h5).strip() + if not article_title: + continue + data = h5.findNextSibling(attrs={'class':'article'}) + if data is None: continue + a = data.find('a', href=True) + if a is None: continue + url = a['href'] + if url.startswith('/'): url = 'http://www.economist.com'+url + url += '/print' + article_title += ': %s'%self.tag_to_string(a).strip() + articles.append({'title':article_title, 'url':url, + 'description':'', 'date':''}) + if not articles: + # We have last or first section + for art in section.findAll(attrs={'class':'article'}): + a = art.find('a', href=True) + if a is not None: + url = a['href'] + if url.startswith('/'): url = 'http://www.economist.com'+url + url += '/print' + title = self.tag_to_string(a) + if title: + articles.append({'title':title, 'url':url, + 'description':'', 'date':''}) + + if articles: + if section_title not in feeds: + feeds[section_title] = [] + feeds[section_title] += articles + + ans = [(key, val) for key, val in feeds.iteritems()] + if not ans: + raise Exception('Could not find any articles, either the ' + 'economist.com server is having trouble and you should ' + 'try later or the website format has changed and the ' + 'recipe needs to be updated.') + return ans + + def eco_find_image_tables(self, soup): + for x in soup.findAll('table', align=['right', 'center']): + if len(x.findAll('font')) in (1,2) and len(x.findAll('img')) == 1: + yield x + + def postprocess_html(self, soup, first): + body = soup.find('body') + for name, val in body.attrs: + del body[name] + + for table in list(self.eco_find_image_tables(soup)): + caption = table.find('font') + img = table.find('img') + div = Tag(soup, 'div') + div['style'] = 'text-align:left;font-size:70%' + ns = NavigableString(self.tag_to_string(caption)) + div.insert(0, ns) + div.insert(1, Tag(soup, 'br')) + del img['width'] + del img['height'] + img.extract() + div.insert(2, img) + table.replaceWith(div) + return soup + +''' from calibre.web.feeds.news import BasicNewsRecipe from calibre.utils.threadpool import ThreadPool, makeRequests from calibre.ebooks.BeautifulSoup import Tag, NavigableString @@ -145,3 +299,5 @@ class Economist(BasicNewsRecipe): div.insert(2, img) table.replaceWith(div) return soup +''' + From 902a50c7114623e4581e1ff920aaac2c44cdb69f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Aug 2011 14:35:58 -0600 Subject: [PATCH 03/10] Fix #821635 (rtf to mobi coversion regression in 0.8.13) --- src/calibre/ebooks/mobi/writer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/calibre/ebooks/mobi/writer.py b/src/calibre/ebooks/mobi/writer.py index 90747d0a73..40e9eeedd0 100644 --- a/src/calibre/ebooks/mobi/writer.py +++ b/src/calibre/ebooks/mobi/writer.py @@ -1710,7 +1710,6 @@ class MobiWriter(object): ''' from calibre.ebooks.oeb.base import TOC items = list(self._oeb.toc.iterdescendants()) - items = [i for i in items if i.depth == 1] offsets = {i:self._id_offsets.get(i.href, -1) for i in items if i.href} items = [i for i in items if offsets[i] > -1] items.sort(key=lambda i:offsets[i]) From 292cca050718f53a955eb84a064d24323ca40e11 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Aug 2011 21:33:02 -0600 Subject: [PATCH 04/10] Centralize management of keyboard shortcuts --- src/calibre/gui2/actions/__init__.py | 49 +++++++++++++--- src/calibre/gui2/actions/add.py | 23 ++++---- src/calibre/gui2/actions/convert.py | 22 +++---- src/calibre/gui2/actions/delete.py | 22 +++---- src/calibre/gui2/actions/device.py | 9 +++ src/calibre/gui2/actions/edit_metadata.py | 41 ++++++------- src/calibre/gui2/actions/preferences.py | 17 +++--- src/calibre/gui2/actions/save_to_disk.py | 13 +++-- src/calibre/gui2/actions/store.py | 23 ++++---- src/calibre/gui2/actions/view.py | 36 ++++++------ src/calibre/gui2/init.py | 2 +- src/calibre/gui2/keyboard.py | 71 +++++++++++++++++++++++ src/calibre/gui2/layout.py | 9 ++- src/calibre/gui2/search_box.py | 9 ++- src/calibre/gui2/ui.py | 13 ++++- src/calibre/gui2/widgets.py | 9 ++- src/calibre/manual/gui.rst | 2 + 17 files changed, 260 insertions(+), 110 deletions(-) create mode 100644 src/calibre/gui2/keyboard.py diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 83748766b2..dbeaa61ea1 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -106,6 +106,10 @@ class InterfaceAction(QObject): self.gui.addAction(self.menuless_qaction) self.genesis() + @property + def unique_name(self): + return u'%s(%s)'%(self.__class__.__name__, self.name) + def create_action(self, spec=None, attr='qaction'): if spec is None: spec = self.action_spec @@ -125,13 +129,20 @@ class InterfaceAction(QObject): a.setToolTip(text) a.setStatusTip(text) a.setWhatsThis(text) - if shortcut: - a = ma if attr == 'qaction' else action - if isinstance(shortcut, list): - a.setShortcuts(shortcut) - else: - a.setShortcut(shortcut) - setattr(self, attr, action) + keys = () + shortcut_action = action + desc = tooltip if tooltip else None + if attr == 'qaction': + shortcut_action = ma + if shortcut is not None: + keys = ((shortcut,) if isinstance(shortcut, basestring) else + tuple(shortcut)) + + self.gui.keyboard.register_shortcut(self.unique_name + ' - ' + attr, + unicode(shortcut_action.text()), default_keys=keys, + action=shortcut_action, description=desc) + if attr is not None: + setattr(self, attr, action) if attr == 'qaction' and self.action_add_menu: menu = QMenu() action.setMenu(menu) @@ -139,6 +150,30 @@ class InterfaceAction(QObject): menu.addAction(self.menuless_qaction) return action + def create_menu_action(self, menu, unique_name, text, icon=None, shortcut=None, + description=None, triggered=None): + ac = menu.addAction(text) + if icon is not None: + if not isinstance(icon, QIcon): + icon = QIcon(I(icon)) + ac.setIcon(icon) + keys = () + if shortcut is not None and shortcut is not False: + keys = ((shortcut,) if isinstance(shortcut, basestring) else + tuple(shortcut)) + unique_name = '%s : menu action : %s'%(self.unique_name, unique_name) + if description is not None: + ac.setToolTip(description) + ac.setStatusTip(description) + ac.setWhatsThis(description) + if shortcut is not False: + self.gui.keyboard.register_shortcut(unique_name, + unicode(text), default_keys=keys, + action=ac, description=description) + if triggered is not None: + ac.triggered.connect(triggered) + return ac + def load_resources(self, names): ''' If this plugin comes in a ZIP file (user added plugin), this method diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 7f7bf72be9..379e72822d 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -54,20 +54,22 @@ class AddAction(InterfaceAction): def genesis(self): self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book) self.add_menu = self.qaction.menu() - self.add_menu.addAction(_('Add books from directories, including ' + ma = partial(self.create_menu_action, self.add_menu) + ma('recursive-single', _('Add books from directories, including ' 'sub-directories (One book per directory, assumes every ebook ' - 'file is the same book in a different format)'), + 'file is the same book in a different format)')).triggered.connect( self.add_recursive_single) - self.add_menu.addAction(_('Add books from directories, including ' + ma('recursive-multiple', _('Add books from directories, including ' 'sub directories (Multiple books per directory, assumes every ' - 'ebook file is a different book)'), self.add_recursive_multiple) + 'ebook file is a different book)')).triggered.connect( + self.add_recursive_multiple) self.add_menu.addSeparator() - self.add_menu.addAction(_('Add Empty book. (Book entry with no ' - 'formats)'), self.add_empty, _('Shift+Ctrl+E')) - self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn) + ma('add-empty', _('Add Empty book. (Book entry with no formats)'), + shortcut=_('Shift+Ctrl+E')).triggered.connect(self.add_empty) + ma('add-isbn', _('Add from ISBN')).triggered.connect(self.add_from_isbn) self.add_menu.addSeparator() - self.add_menu.addAction(_('Add files to selected book records'), - self.add_formats, _('Shift+A')) + ma('add-formats', _('Add files to selected book records'), + triggered=self.add_formats, shortcut=_('Shift+A')) self.qaction.triggered.connect(self.add_books) @@ -82,7 +84,8 @@ class AddAction(InterfaceAction): view = self.gui.library_view rows = view.selectionModel().selectedRows() if not rows: - return + return error_dialog(self.gui, _('No books selected'), + _('Cannot add files as no books are selected'), show=True) ids = [view.model().id(r) for r in rows] if len(ids) > 1 and not question_dialog(self.gui, diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index b51d59aa19..0dbbdaf1f3 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import os from functools import partial -from PyQt4.Qt import QModelIndex, QIcon +from PyQt4.Qt import QModelIndex from calibre.gui2 import error_dialog, Dispatcher from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook @@ -25,17 +25,19 @@ class ConvertAction(InterfaceAction): action_add_menu = True def genesis(self): - cm = self.qaction.menu() - cm.addAction(self.qaction.icon(), _('Convert individually'), partial(self.convert_ebook, + m = self.convert_menu = self.qaction.menu() + cm = partial(self.create_menu_action, self.convert_menu) + cm('convert-individual', _('Convert individually'), + icon=self.qaction.icon(), triggered=partial(self.convert_ebook, False, bulk=False)) - cm.addAction(_('Bulk convert'), - partial(self.convert_ebook, False, bulk=True)) - cm.addSeparator() - ac = cm.addAction(QIcon(I('catalog.png')), - _('Create a catalog of the books in your calibre library')) - ac.triggered.connect(self.gui.iactions['Generate Catalog'].generate_catalog) + cm('convert-bulk', _('Bulk convert'), + triggered=partial(self.convert_ebook, False, bulk=True)) + m.addSeparator() + cm('create-catalog', + _('Create a catalog of the books in your calibre library'), + icon='catalog.png', shortcut=False, + triggered=self.gui.iactions['Generate Catalog'].generate_catalog) self.qaction.triggered.connect(self.convert_ebook) - self.convert_menu = cm self.conversion_jobs = {} def location_selected(self, loc): diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py index 31195fd94c..0455f75043 100644 --- a/src/calibre/gui2/actions/delete.py +++ b/src/calibre/gui2/actions/delete.py @@ -90,21 +90,23 @@ class DeleteAction(InterfaceAction): def genesis(self): self.qaction.triggered.connect(self.delete_books) self.delete_menu = self.qaction.menu() - self.delete_menu.addAction( + m = partial(self.create_menu_action, self.delete_menu) + m('delete-specific', _('Remove files of a specific format from selected books..'), - self.delete_selected_formats) - self.delete_menu.addAction( + triggered=self.delete_selected_formats) + m('delete-except', _('Remove all formats from selected books, except...'), - self.delete_all_but_selected_formats) - self.delete_menu.addAction( + triggered=self.delete_all_but_selected_formats) + m('delete-all', _('Remove all formats from selected books'), - self.delete_all_formats) - self.delete_menu.addAction( - _('Remove covers from selected books'), self.delete_covers) + triggered=self.delete_all_formats) + m('delete-covers', + _('Remove covers from selected books'), + triggered=self.delete_covers) self.delete_menu.addSeparator() - self.delete_menu.addAction( + m('delete-matching', _('Remove matching books from device'), - self.remove_matching_books_from_device) + triggered=self.remove_matching_books_from_device) self.qaction.setMenu(self.delete_menu) self.delete_memory = {} diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index debcbb6c1a..d4ed26ba8a 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -60,6 +60,15 @@ class ShareConnMenu(QMenu): # {{{ self.email_actions = [] + if hasattr(parent, 'keyboard'): + r = parent.keyboard.register_shortcut + prefix = 'Share/Connect Menu ' + for attr in ('folder', 'bambook', 'itunes'): + if not (iswindows or isosx) and attr == 'itunes': + continue + ac = getattr(self, 'connect_to_%s_action'%attr) + r(prefix + attr, unicode(ac.text()), action=ac) + def server_state_changed(self, running): text = _('Start Content Server') if running: diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 5e220fdb1d..64d6f2cbd6 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import os from functools import partial -from PyQt4.Qt import Qt, QMenu, QModelIndex, QTimer +from PyQt4.Qt import QMenu, QModelIndex, QTimer from calibre.gui2 import error_dialog, Dispatcher, question_dialog from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog @@ -27,37 +27,38 @@ class EditMetadataAction(InterfaceAction): action_add_menu = True def genesis(self): - self.create_action(spec=(_('Merge book records'), 'merge_books.png', - None, _('M')), attr='action_merge') md = self.qaction.menu() - md.addAction(self.qaction.icon(), _('Edit metadata individually'), - partial(self.edit_metadata, False, bulk=False)) + cm = partial(self.create_menu_action, md) + cm('individual', _('Edit metadata individually'), icon=self.qaction.icon(), + triggered=partial(self.edit_metadata, False, bulk=False)) md.addSeparator() - md.addAction(_('Edit metadata in bulk'), - partial(self.edit_metadata, False, bulk=True)) + cm('bulk', _('Edit metadata in bulk'), + triggered=partial(self.edit_metadata, False, bulk=True)) md.addSeparator() - md.addAction(_('Download metadata and covers'), self.download_metadata, - Qt.ControlModifier+Qt.Key_D) + cm('download', _('Download metadata and covers'), + triggered=partial(self.download_metadata, ids=None), + shortcut='Ctrl+D') self.metadata_menu = md mb = QMenu() - mb.addAction(_('Merge into first selected book - delete others'), - self.merge_books) + cm2 = partial(self.create_menu_action, mb) + cm2('merge delete', _('Merge into first selected book - delete others'), + triggered=self.merge_books) mb.addSeparator() - mb.addAction(_('Merge into first selected book - keep others'), - partial(self.merge_books, safe_merge=True), - Qt.AltModifier+Qt.Key_M) + cm2('merge keep', _('Merge into first selected book - keep others'), + triggered=partial(self.merge_books, safe_merge=True), + shortcut='Alt+M') mb.addSeparator() - mb.addAction(_('Merge only formats into first selected book - delete others'), - partial(self.merge_books, merge_only_formats=True), - Qt.AltModifier+Qt.ShiftModifier+Qt.Key_M) + cm2('merge formats', _('Merge only formats into first selected book - delete others'), + triggered=partial(self.merge_books, merge_only_formats=True), + shortcut='Alt+Shift+M') self.merge_menu = mb - self.action_merge.setMenu(mb) md.addSeparator() - md.addAction(self.action_merge) + self.action_merge = cm('merge', _('Merge book records'), icon='merge_books.png', + shortcut=_('M'), triggered=self.merge_books) + self.action_merge.setMenu(mb) self.qaction.triggered.connect(self.edit_metadata) - self.action_merge.triggered.connect(self.merge_books) def location_selected(self, loc): enabled = loc == 'library' diff --git a/src/calibre/gui2/actions/preferences.py b/src/calibre/gui2/actions/preferences.py index 21a70ecf03..cd9de36fce 100644 --- a/src/calibre/gui2/actions/preferences.py +++ b/src/calibre/gui2/actions/preferences.py @@ -5,6 +5,8 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from functools import partial + from PyQt4.Qt import QIcon, Qt from calibre.gui2.actions import InterfaceAction @@ -21,18 +23,17 @@ class PreferencesAction(InterfaceAction): def genesis(self): pm = self.qaction.menu() + cm = partial(self.create_menu_action, pm) if isosx: pm.addAction(QIcon(I('config.png')), _('Preferences'), self.do_config) - pm.addAction(QIcon(I('wizard.png')), _('Run welcome wizard'), - self.gui.run_wizard) - pm.addAction(QIcon(I('plugins/plugin_updater.png')), - _('Get plugins to enhance calibre'), self.get_plugins) + cm('welcome wizard', _('Run welcome wizard'), + icon='wizard.png', triggered=self.gui.run_wizard) + cm('plugin updater', _('Get plugins to enhance calibre'), + icon='plugins/plugin_updater.png', triggered=self.get_plugins) if not DEBUG: pm.addSeparator() - ac = pm.addAction(QIcon(I('debug.png')), _('Restart in debug mode'), - self.debug_restart) - ac.setShortcut('Ctrl+Shift+R') - self.gui.addAction(ac) + cm('restart', _('Restart in debug mode'), icon='debug.png', + triggered=self.debug_restart, shortcut='Ctrl+Shift+R') self.preferences_menu = pm for x in (self.gui.preferences_action, self.qaction): diff --git a/src/calibre/gui2/actions/save_to_disk.py b/src/calibre/gui2/actions/save_to_disk.py index af3e1ebf34..9e9cbe5f54 100644 --- a/src/calibre/gui2/actions/save_to_disk.py +++ b/src/calibre/gui2/actions/save_to_disk.py @@ -44,15 +44,16 @@ class SaveToDiskAction(InterfaceAction): def genesis(self): self.qaction.triggered.connect(self.save_to_disk) self.save_menu = self.qaction.menu() - self.save_menu.addAction(_('Save to disk in a single directory'), - partial(self.save_to_single_dir, False)) - self.save_menu.addAction(_('Save only %s format to disk')% + cm = partial(self.create_menu_action, self.save_menu) + cm('single dir', _('Save to disk in a single directory'), + triggered=partial(self.save_to_single_dir, False)) + cm('single format', _('Save only %s format to disk')% prefs['output_format'].upper(), - partial(self.save_single_format_to_disk, False)) - self.save_menu.addAction( + triggered=partial(self.save_single_format_to_disk, False)) + cm('fingle dir and format', _('Save only %s format to disk in a single directory')% prefs['output_format'].upper(), - partial(self.save_single_fmt_to_single_dir, False)) + triggered=partial(self.save_single_fmt_to_single_dir, False)) self.save_sub_menu = SaveMenu(self.gui) self.save_sub_menu_action = self.save_menu.addMenu(self.save_sub_menu) self.save_sub_menu.save_fmt.connect(self.save_specific_format_disk) diff --git a/src/calibre/gui2/actions/store.py b/src/calibre/gui2/actions/store.py index 3e68229332..e843534c37 100644 --- a/src/calibre/gui2/actions/store.py +++ b/src/calibre/gui2/actions/store.py @@ -24,16 +24,21 @@ class StoreAction(InterfaceAction): def genesis(self): self.qaction.triggered.connect(self.do_search) self.store_menu = self.qaction.menu() - self.load_menu() - - def load_menu(self): - self.store_menu.clear() - self.store_menu.addAction(self.menuless_qaction) - self.store_menu.addAction(_('Search for this author'), self.search_author) - self.store_menu.addAction(_('Search for this title'), self.search_title) - self.store_menu.addAction(_('Search for this book'), self.search_author_title) + cm = partial(self.create_menu_action, self.store_menu) + for x, t in [('author', _('author')), ('title', _('title')), + ('book', _('book'))]: + func = getattr(self, 'search_%s'%('author_title' if x == 'book' + else x)) + ac = cm(x, _('Search for this %s'%t), triggered=func) + setattr(self, 'action_search_by_'+x, ac) self.store_menu.addSeparator() self.store_list_menu = self.store_menu.addMenu(_('Stores')) + self.load_menu() + self.store_menu.addSeparator() + cm('choose stores', _('Choose stores'), triggered=self.choose) + + def load_menu(self): + self.store_list_menu.clear() icon = QIcon() icon.addFile(I('donate.png'), QSize(16, 16)) for n, p in sorted(self.gui.istores.items(), key=lambda x: x[0].lower()): @@ -41,8 +46,6 @@ class StoreAction(InterfaceAction): self.store_list_menu.addAction(icon, n, partial(self.open_store, p)) else: self.store_list_menu.addAction(n, partial(self.open_store, p)) - self.store_menu.addSeparator() - self.store_menu.addAction(_('Choose stores'), self.choose) def do_search(self): return self.search() diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index f6797b5e8f..84060de786 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -6,6 +6,7 @@ __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' import os, time +from functools import partial from PyQt4.Qt import Qt, QAction, pyqtSignal @@ -43,36 +44,33 @@ class ViewAction(InterfaceAction): self.qaction.triggered.connect(self.view_book) self.view_action = self.menuless_qaction self.view_menu = self.qaction.menu() - ac = self.view_specific_action = QAction(_('View specific format'), - self.gui) - ac.setShortcut(Qt.AltModifier+Qt.Key_V) - ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection) - ac = self.create_action(spec=(_('Read a random book'), 'random.png', - None, None), attr='action_pick_random') - ac.triggered.connect(self.view_random) - ac = self.clear_history_action = QAction( - _('Clear recently viewed list'), self.gui) - ac.triggered.connect(self.clear_history) + cm = partial(self.create_menu_action, self.view_menu) + self.view_specific_action = cm('specific', _('View specific format'), + shortcut='Alt+V', triggered=self.view_specific_format) + self.action_pick_random = cm('pick random', _('Read a random book'), + icon='random.png', triggered=self.view_random) + self.clear_sep1 = self.view_menu.addSeparator() + self.clear_sep2 = self.view_menu.addSeparator() + self.clear_history_action = cm('clear history', + _('Clear recently viewed list'), triggered=self.clear_history) + self.history_actions = [self.clear_sep1] def initialization_complete(self): self.build_menus(self.gui.current_db) def build_menus(self, db): - self.view_menu.clear() - self.view_menu.addAction(self.view_action) - self.view_menu.addAction(self.view_specific_action) - self.view_menu.addSeparator() - self.view_menu.addAction(self.action_pick_random) + for ac in self.history_actions: + self.view_menu.removeAction(ac) self.history_actions = [] history = db.prefs.get('gui_view_history', []) if history: - self.view_menu.addSeparator() + self.view_menu.insertAction(self.clear_sep2, self.clear_sep1) + self.history_actions.append(self.clear_sep1) for id_, title in history: ac = HistoryAction(id_, title, self.view_menu) - self.view_menu.addAction(ac) + self.view_menu.insertAction(self.clear_sep2, ac) ac.view_historical.connect(self.view_historical) - self.view_menu.addSeparator() - self.view_menu.addAction(self.clear_history_action) + self.history_actions.append(ac) def clear_history(self): db = self.gui.current_db diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 4aa94fc8e1..4458104a3a 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -218,7 +218,7 @@ class LayoutMixin(object): # {{{ self.bd_splitter = Splitter('book_details_splitter', _('Book Details'), I('book.png'), orientation=Qt.Vertical, parent=self, side_index=1, - shortcut=_('Alt+D')) + shortcut=_('Shift+Alt+D')) self.bd_splitter.addWidget(self.stack) self.bd_splitter.addWidget(self.book_details) self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False) diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py new file mode 100644 index 0000000000..ee936f5f4f --- /dev/null +++ b/src/calibre/gui2/keyboard.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2011, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from collections import OrderedDict + +from PyQt4.Qt import (QObject, QKeySequence) + +from calibre.utils.config import JSONConfig +from calibre.constants import DEBUG +from calibre import prints + +class NameConflict(ValueError): + pass + +class Manager(QObject): + + def __init__(self, parent=None): + QObject.__init__(self, parent) + + self.config = JSONConfig('shortcuts/main') + self.custom_keys_map = {} + self.shortcuts = OrderedDict() + self.keys_map = {} + + for unique_name, keys in self.config.get( + 'map', {}).iteritems(): + self.custom_keys_map[unique_name] = tuple(keys) + + def register_shortcut(self, unique_name, name, default_keys=(), + description=None, action=None): + if unique_name in self.shortcuts: + name = self.shortcuts[unique_name]['name'] + raise NameConflict('Shortcut for %r already registered by %s'%( + unique_name, name)) + shortcut = {'name':name, 'desc':description, 'action': action, + 'default_keys':tuple(default_keys)} + self.shortcuts[unique_name] = shortcut + + def finalize(self): + seen = {} + for unique_name, shortcut in self.shortcuts.iteritems(): + custom_keys = self.custom_keys_map.get(unique_name, None) + if custom_keys is None: + candidates = shortcut['default_keys'] + else: + candidates = custom_keys + keys = [] + for x in candidates: + ks = QKeySequence(x, QKeySequence.PortableText) + x = unicode(ks.toString(QKeySequence.PortableText)) + if x in seen: + if DEBUG: + prints('Key %r for shortcut %s is already used by' + ' %s, ignoring'%(x, shortcut['name'], seen[x]['name'])) + continue + seen[x] = shortcut + keys.append(ks) + keys = tuple(keys) + #print (111111, unique_name, candidates, keys) + + self.keys_map[unique_name] = keys + ac = shortcut['action'] + if ac is not None: + ac.setShortcuts(list(keys)) + diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 76b9f5f9a2..423907d8fd 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' from functools import partial from PyQt4.Qt import (QIcon, Qt, QWidget, QSize, - pyqtSignal, QToolButton, QMenu, + pyqtSignal, QToolButton, QMenu, QAction, QObject, QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QActionGroup) @@ -178,7 +178,12 @@ class SearchBar(QWidget): # {{{ x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) parent.advanced_search_button = x = QToolButton(self) - parent.advanced_search_button.setShortcut(_("Shift+Ctrl+F")) + parent.advanced_search_toggle_action = ac = QAction(parent) + parent.addAction(ac) + parent.keyboard.register_shortcut('advanced search toggle', + _('Advanced search'), default_keys=(_("Shift+Ctrl+F"),), + action=ac) + ac.triggered.connect(x.click) x.setIcon(QIcon(I('search.png'))) l.addWidget(x) x.setToolTip(_("Advanced search")) diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 19cfb7417e..fd085923e2 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -376,9 +376,12 @@ class SearchBoxMixin(object): # {{{ self.search.clear() self.search.setMaximumWidth(self.width()-150) self.action_focus_search = QAction(self) - shortcuts = QKeySequence.keyBindings(QKeySequence.Find) - shortcuts = list(shortcuts) + [QKeySequence('/'), QKeySequence('Alt+S')] - self.action_focus_search.setShortcuts(shortcuts) + shortcuts = list( + map(lambda x:unicode(x.toString()), + QKeySequence.keyBindings(QKeySequence.Find))) + shortcuts += ['/', 'Alt+S'] + self.keyboard.register_shortcut('start search', _('Start search'), + default_keys=shortcuts, action=self.action_focus_search) self.action_focus_search.triggered.connect(self.focus_search_box) self.addAction(self.action_focus_search) self.search.setStatusTip(re.sub(r'<\w+>', ' ', diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 61df7e0e06..c1cc07f56c 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -16,7 +16,7 @@ from collections import OrderedDict from PyQt4.Qt import (Qt, SIGNAL, QTimer, QHelpEvent, QAction, QMenu, QIcon, pyqtSignal, QUrl, - QDialog, QSystemTrayIcon, QApplication, QKeySequence) + QDialog, QSystemTrayIcon, QApplication) from calibre import prints from calibre.constants import __appname__, isosx @@ -40,6 +40,7 @@ from calibre.gui2.init import LibraryViewMixin, LayoutMixin from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin from calibre.gui2.tag_browser.ui import TagBrowserMixin +from calibre.gui2.keyboard import Manager class Listener(Thread): # {{{ @@ -104,6 +105,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ def __init__(self, opts, parent=None, gui_debug=None): global _gui MainWindow.__init__(self, opts, parent=parent, disable_automatic_gc=True) + self.keyboard = Manager(self) _gui = self self.opts = opts self.device_connected = None @@ -238,7 +240,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.eject_action.setEnabled(False) self.addAction(self.quit_action) self.system_tray_menu.addAction(self.quit_action) - self.quit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) + self.keyboard.register_shortcut('quit calibre', _('Quit calibre'), + default_keys=('Ctrl+Q',), action=self.quit_action) self.system_tray_icon.setContextMenu(self.system_tray_menu) self.connect(self.quit_action, SIGNAL('triggered(bool)'), self.quit) self.connect(self.donate_action, SIGNAL('triggered(bool)'), self.donate) @@ -249,7 +252,9 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.esc_action = QAction(self) self.addAction(self.esc_action) - self.esc_action.setShortcut(QKeySequence(Qt.Key_Escape)) + self.keyboard.register_shortcut('clear current search', + _('Clear the current search'), default_keys=('Esc',), + action=self.esc_action) self.esc_action.triggered.connect(self.esc) ####################### Start spare job server ######################## @@ -340,6 +345,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ raise self.device_manager.set_current_library_uuid(db.library_id) + self.keyboard.finalize() + # Collect cycles now gc.collect() diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 96fbafe4d5..01f7029921 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -1063,9 +1063,16 @@ class Splitter(QSplitter): self.action_toggle = QAction(QIcon(icon), _('Toggle') + ' ' + label, self) self.action_toggle.triggered.connect(self.toggle_triggered) - self.action_toggle.setShortcut(shortcut) if parent is not None: parent.addAction(self.action_toggle) + if hasattr(parent, 'keyboard'): + parent.keyboard.register_shortcut('splitter %s %s'%(name, + label), unicode(self.action_toggle.text()), + default_keys=(shortcut,), action=self.action_toggle) + else: + self.action_toggle.setShortcut(shortcut) + else: + self.action_toggle.setShortcut(shortcut) def toggle_triggered(self, *args): self.toggle_side_pane() diff --git a/src/calibre/manual/gui.rst b/src/calibre/manual/gui.rst index db71b1ccc7..a1448dfe84 100755 --- a/src/calibre/manual/gui.rst +++ b/src/calibre/manual/gui.rst @@ -547,6 +547,8 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes - Toggle jobs list * - :kbd:`Alt+Shift+B` - Toggle Cover Browser + * - :kbd:`Alt+Shift+B` + - Toggle Book Details panel * - :kbd:`Alt+Shift+T` - Toggle Tag Browser * - :kbd:`Alt+A` From e4e5eb36e7720366983f9bb6adb1064914f55222 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 6 Aug 2011 10:21:55 +0100 Subject: [PATCH 05/10] Fix merge_metadata to not overwrite non-text fields ('bool', 'int', 'float', 'rating', 'datetime') that have a value of zero/false instead of none. Change the delegate for custom numeric columns to permit setting a value to undefined when editing on the library view. --- src/calibre/gui2/actions/edit_metadata.py | 2 +- src/calibre/gui2/library/delegates.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 64d6f2cbd6..28e2f21d23 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -418,7 +418,7 @@ class EditMetadataAction(InterfaceAction): db.set_custom(dest_id, dest_value, num=colnum) if db.field_metadata[key]['datatype'] in \ ('bool', 'int', 'float', 'rating', 'datetime') \ - and not dest_value: + and dest_value is None: db.set_custom(dest_id, src_value, num=colnum) if db.field_metadata[key]['datatype'] == 'series' \ and not dest_value: diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index b0fdef4c21..a9c71e526b 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -310,6 +310,12 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ editor.setDecimals(2) return editor + def setModelData(self, editor, model, index): + val = editor.value() + if val == editor.minimum(): + val = None + model.setData(index, QVariant(val), Qt.EditRole) + def setEditorData(self, editor, index): m = index.model() val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']] From 5d3674947479b18f6b3b94adf5078ea9b47fe5c4 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 6 Aug 2011 15:26:21 +0100 Subject: [PATCH 06/10] Small fixes to template functions sublist, list_item, and swap_around_comma to strip the list items. --- src/calibre/utils/formatter_functions.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index 0b54a85b9c..fbff64c800 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -432,7 +432,7 @@ class BuiltinSwapAroundComma(BuiltinFormatterFunction): 'returns val unchanged') def evaluate(self, formatter, kwargs, mi, locals, val): - return re.sub(r'^(.*?),(.*$)', r'\2 \1', val, flags=re.I) + return re.sub(r'^(.*?),\s*(.*$)', r'\2 \1', val, flags=re.I).strip() class BuiltinIfempty(BuiltinFormatterFunction): name = 'ifempty' @@ -502,7 +502,7 @@ class BuiltinListitem(BuiltinFormatterFunction): index = int(index) val = val.split(sep) try: - return val[index] + return val[index].strip() except: return '' @@ -620,7 +620,8 @@ class BuiltinSublist(BuiltinFormatterFunction): return '' si = int(start_index) ei = int(end_index) - val = val.split(sep) + # allow empty list items so counts are what the user expects + val = [v.strip() for v in val.split(sep)] try: if ei == 0: return sep.join(val[si:]) From 36bcb8a75424f41ace615bcb018d3c0736c71ccb Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 6 Aug 2011 16:55:46 +0100 Subject: [PATCH 07/10] Add strlen and strcat_max functions --- src/calibre/manual/template_lang.rst | 2 + src/calibre/utils/formatter_functions.py | 50 +++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/calibre/manual/template_lang.rst b/src/calibre/manual/template_lang.rst index f2d01474b6..e2750e1ebf 100644 --- a/src/calibre/manual/template_lang.rst +++ b/src/calibre/manual/template_lang.rst @@ -273,7 +273,9 @@ The following functions are available in addition to those described in single-f * ``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. * ``raw_field(name)`` -- returns the metadata field named by name without applying any formatting. * ``strcat(a, b, ...)`` -- can take any number of arguments. Returns a string formed by concatenating all the arguments. + * ``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 resulting string length is less than `max`. String1 is returned even if string1 is longer than max. You can pass as many `prefix, string` pairs as you wish. * ``strcmp(x, y, lt, eq, gt)`` -- does a case-insensitive comparison x and y as strings. Returns ``lt`` if x < y. Returns ``eq`` if x == y. Otherwise returns ``gt``. + * ``strlen(a)`` -- Returns the length of the string passed as the argument. * ``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 indicates the last character. For example, ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` returns ``'234'``. * ``subtract(x, y)`` -- returns x - y. Throws an exception if either x or y are not numbers. * ``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. diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index fbff64c800..3d6775c242 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -136,6 +136,19 @@ class BuiltinStrcat(BuiltinFormatterFunction): res += args[i] return res +class BuiltinStrlen(BuiltinFormatterFunction): + name = 'strlen' + arg_count = 1 + category = 'String Manipulation' + __doc__ = doc = _('strlen(a) -- Returns the length of the string passed as ' + 'the argument') + + def evaluate(self, formatter, kwargs, mi, locals, a): + try: + return len(a) + except: + return -1 + class BuiltinAdd(BuiltinFormatterFunction): name = 'add' arg_count = 2 @@ -345,6 +358,40 @@ class BuiltinSwitch(BuiltinFormatterFunction): return args[i+1] i += 2 +class BuiltinStrcatMax(BuiltinFormatterFunction): + name = 'strcat_max' + arg_count = -1 + category = 'String Manipulation' + __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 ' + 'resulting string length is less than `max`. String1 is returned ' + 'even if string1 is longer than max. You can pass as many ' + '`prefix, string` pairs as you wish.') + + def evaluate(self, formatter, kwargs, mi, locals, *args): + if len(args) < 2: + raise ValueError(_('strcat_max requires 2 or more arguments')) + if (len(args) % 2) != 0: + 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')) + + i = 2 + result = args[1] + try: + while i < len(args): + if (len(result) + len(args[i]) + len(args[i+1])) > max: + break + result = result + args[i] + args[i+1] + i += 2 + except: + pass + return result.strip() + class BuiltinInList(BuiltinFormatterFunction): name = 'in_list' arg_count = 5 @@ -956,7 +1003,8 @@ _formatter_builtins = [ BuiltinLowercase(), BuiltinMultiply(), BuiltinNot(), BuiltinOndevice(), BuiltinOr(), BuiltinPrint(), BuiltinRawField(), BuiltinRe(), BuiltinSelect(), BuiltinShorten(), BuiltinStrcat(), - BuiltinStrcmp(), BuiltinStrInList(), BuiltinSubitems(), + BuiltinStrcatMax(), + BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(), BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(), BuiltinSwitch(), BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(), BuiltinToday(), BuiltinUppercase(), From 7e24ed31e2f6d963baaf76c886d0ac2145f805ec Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 6 Aug 2011 17:54:12 +0100 Subject: [PATCH 08/10] Allow the formatter used in save_to_disk to toss exceptions. --- src/calibre/library/save_to_disk.py | 5 ++--- src/calibre/utils/formatter.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/calibre/library/save_to_disk.py b/src/calibre/library/save_to_disk.py index 3a95086faa..8fcdfc9855 100644 --- a/src/calibre/library/save_to_disk.py +++ b/src/calibre/library/save_to_disk.py @@ -131,7 +131,7 @@ def preprocess_template(template): template = template.decode(preferred_encoding, 'replace') return template -class SafeFormat(TemplateFormatter): +class Formatter(TemplateFormatter): ''' Provides a format function that substitutes '' for any missing value ''' @@ -225,8 +225,7 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250, format_args[key] = unicode(format_args[key]) else: format_args[key] = '' - components = SafeFormat().safe_format(template, format_args, - 'G_C-EXCEPTION!', mi) + components = Formatter().unsafe_format(template, format_args, mi) components = [x.strip() for x in components.split('/')] components = [sanitize_func(x) for x in components if x] if not components: diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py index 3a93c2b650..bc25f25043 100644 --- a/src/calibre/utils/formatter.py +++ b/src/calibre/utils/formatter.py @@ -310,7 +310,16 @@ class TemplateFormatter(string.Formatter): ans = string.Formatter.vformat(self, fmt, args, kwargs) return self.compress_spaces.sub(' ', ans).strip() - ########## a formatter guaranteed not to throw and exception ############ + ########## a formatter that throws exceptions ############ + + def unsafe_format(self, fmt, kwargs, book): + self.kwargs = kwargs + self.book = book + self.composite_values = {} + self.locals = {} + return self.vformat(fmt, [], kwargs).strip() + + ########## a formatter guaranteed not to throw an exception ############ def safe_format(self, fmt, kwargs, error_value, book): self.kwargs = kwargs From ae02ce25becf72aa7bf439c1a7238ef6c679ea88 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Aug 2011 11:07:34 -0600 Subject: [PATCH 09/10] Get Books: Always read metadata from the file contents, ignoring the setting in Preferences->Adding books --- src/calibre/gui2/ebook_download.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/ebook_download.py b/src/calibre/gui2/ebook_download.py index 2fea67b9f0..d39ea47e52 100644 --- a/src/calibre/gui2/ebook_download.py +++ b/src/calibre/gui2/ebook_download.py @@ -66,8 +66,8 @@ class EbookDownload(object): raise Exception(_('Not a support ebook format.')) from calibre.ebooks.metadata.meta import get_metadata - with open(filename) as f: - mi = get_metadata(f, ext) + with open(filename, 'rb') as f: + mi = get_metadata(f, ext, force_read_metadata=True) mi.tags.extend(tags) id = gui.library_view.model().db.create_book_entry(mi) From 76200fa4cd8639ab864b9b246f58a69b4282bb22 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Aug 2011 11:13:26 -0600 Subject: [PATCH 10/10] Fix #822004 (WSJ News Fetch Script is picking up buttons in article) --- recipes/wsj.recipe | 1 + recipes/wsj_free.recipe | 1 + 2 files changed, 2 insertions(+) diff --git a/recipes/wsj.recipe b/recipes/wsj.recipe index a3bc041d25..7a044aa5a7 100644 --- a/recipes/wsj.recipe +++ b/recipes/wsj.recipe @@ -38,6 +38,7 @@ class WallStreetJournal(BasicNewsRecipe): dict(id=["articleTabs_tab_article", "articleTabs_tab_comments", "articleTabs_tab_interactive","articleTabs_tab_video","articleTabs_tab_map","articleTabs_tab_slideshow","articleTabs_tab_quotes","articleTabs_tab_document"]), {'class':['footer_columns','network','insetCol3wide','interactive','video','slideshow','map','insettip','insetClose','more_in', "insetContent", 'articleTools_bottom', 'aTools', "tooltip", "adSummary", "nav-inline"]}, dict(rel='shortcut icon'), + {'class':lambda x: x and 'sTools' in x}, ] remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},] diff --git a/recipes/wsj_free.recipe b/recipes/wsj_free.recipe index dd42fb5540..331a393c03 100644 --- a/recipes/wsj_free.recipe +++ b/recipes/wsj_free.recipe @@ -40,6 +40,7 @@ class WallStreetJournal(BasicNewsRecipe): dict(name='div', attrs={'data-flash-settings':True}), {'class':['insetContent embedType-interactive insetCol3wide','insetCol6wide','insettipUnit']}, dict(rel='shortcut icon'), + {'class':lambda x: x and 'sTools' in x}, ] remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},]