From 0111c8aae1aeeffa94ff2a44d2fd1f743db985f2 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 4 Jun 2020 21:20:18 +0200 Subject: [PATCH 001/245] some changes for french translation --- contributors.txt | 2 +- src/application.py | 2 +- src/locales/fr/LC_MESSAGES/twblue.mo | Bin 52881 -> 52802 bytes src/locales/fr/LC_MESSAGES/twblue.po | 10 +++++----- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contributors.txt b/contributors.txt index b85f6699..1b92f9b6 100644 --- a/contributors.txt +++ b/contributors.txt @@ -39,4 +39,4 @@ florian Ionașcu Christian Leo Mameli Natalia Hedlund (Наталья Хедлунд) Valeria (Валерия) -Corentin Bacqué-Cazenave \ No newline at end of file +Oreonan \ No newline at end of file diff --git a/src/application.py b/src/application.py index 7e223ef6..60154859 100644 --- a/src/application.py +++ b/src/application.py @@ -16,7 +16,7 @@ authors = ["Manuel Cortéz", "José Manuel Delicado"] authorEmail = "manuel@manuelcortez.net" copyright = "Copyright (C) 2013-2018, Manuel cortéz." description = name+" is an app designed to use Twitter simply and efficiently while using minimal system resources. This app provides access to most Twitter features." -translators = ["Manuel Cortéz (English)", "Mohammed Al Shara, Hatoun Felemban (Arabic)", "Francisco Torres (Catalan)", "Manuel cortéz (Spanish)", "Sukil Etxenike Arizaleta (Basque)", "Jani Kinnunen (finnish)", "Rémy Ruiz (French)", "Juan Buño (Galician)", "Steffen Schultz (German)", "Zvonimir Stanečić (Croatian)", "Robert Osztolykan (Hungarian)", "Christian Leo Mameli (Italian)", "Riku (Japanese)", "Paweł Masarczyk (Polish)", "Odenilton Júnior Santos (Portuguese)", "Florian Ionașcu, Nicușor Untilă (Romanian)", "Natalia Hedlund, Valeria Kuznetsova (Russian)", "Aleksandar Đurić (Serbian)", "Burak Yüksek (Turkish)"] +translators = ["Manuel Cortéz (English)", "Mohammed Al Shara, Hatoun Felemban (Arabic)", "Francisco Torres (Catalan)", "Manuel cortéz (Spanish)", "Sukil Etxenike Arizaleta (Basque)", "Jani Kinnunen (finnish)", "Oreonan (Français)", "Juan Buño (Galician)", "Steffen Schultz (German)", "Zvonimir Stanečić (Croatian)", "Robert Osztolykan (Hungarian)", "Christian Leo Mameli (Italian)", "Riku (Japanese)", "Paweł Masarczyk (Polish)", "Odenilton Júnior Santos (Portuguese)", "Florian Ionașcu, Nicușor Untilă (Romanian)", "Natalia Hedlund, Valeria Kuznetsova (Russian)", "Aleksandar Đurić (Serbian)", "Burak Yüksek (Turkish)"] url = u"https://twblue.es" report_bugs_url = "https://github.com/manuelcortez/twblue/issues" supported_languages = [] \ No newline at end of file diff --git a/src/locales/fr/LC_MESSAGES/twblue.mo b/src/locales/fr/LC_MESSAGES/twblue.mo index 03e45525e7c9767ce83949811db501efa7034c60..c83284cf0f3be22bf81f266e6aa87282f93e65b5 100644 GIT binary patch delta 6070 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 Lk%g|~AN&6whpEmb delta 6122 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 C1=V^0 diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index 9eb03e89..aaa1ea81 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -2,14 +2,14 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" "POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" -"PO-Revision-Date: 2019-07-22 16:16+0200\n" +"PO-Revision-Date: 2020-06-04 21:19+0200\n" "Last-Translator: Corentin BACQUÉ-CAZENAVE \n" -"Language-Team: Corentin BACQUÉ-CAZENAVE \n" +"Language-Team: Oreonan \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.2.3\n" +"X-Generator: Poedit 2.3.1\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop\n" "X-Poedit-Basepath: .\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -262,7 +262,7 @@ msgstr "Listes" #: ../src\controller\mainController.py:378 #: ../src\controller\mainController.py:1399 msgid "List for {}" -msgstr "Liste de {}" +msgstr "Liste {}" #: ../src\controller\mainController.py:381 msgid "Searches" @@ -1988,7 +1988,7 @@ msgstr "Téléchargement de la nouvelle version en cours..." #: ../src\update\wxUpdater.py:28 msgid "Updating... %s of %s" -msgstr "Mise à jour en cours... %s de %s" +msgstr "Mise à jour en cours... %s sur %s" #: ../src\update\wxUpdater.py:31 msgid "Done!" From 22d48cb5d9b16d3739c843520cad89d888c0e2af Mon Sep 17 00:00:00 2001 From: riku Date: Fri, 22 Jan 2021 12:52:19 +0900 Subject: [PATCH 002/245] Update Japanese translation --- ... Kinnunen's conflicted copy 2019-04-03).po | 3441 ----------------- src/locales/ja/lc_messages/twblue.mo | Bin 56556 -> 58239 bytes src/locales/ja/lc_messages/twblue.po | 3309 ++++++++-------- 3 files changed, 1599 insertions(+), 5151 deletions(-) delete mode 100644 src/locales/ja/lc_messages/twblue (Jani Kinnunen's conflicted copy 2019-04-03).po diff --git a/src/locales/ja/lc_messages/twblue (Jani Kinnunen's conflicted copy 2019-04-03).po b/src/locales/ja/lc_messages/twblue (Jani Kinnunen's conflicted copy 2019-04-03).po deleted file mode 100644 index ef6cf70d..00000000 --- a/src/locales/ja/lc_messages/twblue (Jani Kinnunen's conflicted copy 2019-04-03).po +++ /dev/null @@ -1,3441 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2018-08-08 18:23+0900\n" -"Last-Translator: Manuel Cortez \n" -"Language-Team: \n" -"Language: ja_JP\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.1.1\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: ../src\controller\attach.py:23 -msgid "Photo" -msgstr "画像" - -#: ../src\controller\buffers\baseBuffers.py:95 -msgid "This action is not supported for this buffer" -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 -msgid "Home" -msgstr "ホーム" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 -msgid "Mentions" -msgstr "メンション" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 -msgid "Direct messages" -msgstr "ダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 -msgid "Sent direct messages" -msgstr "送信済みのダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 -msgid "Sent tweets" -msgstr "送信済みのツイート" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 -msgid "Likes" -msgstr "いいね" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 -msgid "Followers" -msgstr "フォロワー" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "フォロー" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 -msgid "Blocked users" -msgstr "ブロックしたユーザー" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 -msgid "Muted users" -msgstr "ミューとしたユーザー" - -#: ../src\controller\buffers\twitterBuffers.py:75 -#, fuzzy -msgid "{username}'s timeline" -msgstr "特定のユーザーのタイムラインを開く" - -#: ../src\controller\buffers\twitterBuffers.py:77 -msgid "{username}'s likes" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:79 -msgid "{username}'s followers" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:81 -msgid "{username}'s friends" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:83 -#, fuzzy -msgid "Unknown buffer" -msgstr "不明" - -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 -msgid "Tweet" -msgstr "ツイート" - -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 -msgid "Write the tweet here" -msgstr "ツイートを入力:" - -#: ../src\controller\buffers\twitterBuffers.py:194 -#, fuzzy -msgid "New tweet in {0}" -msgstr "新規ツイート" - -#: ../src\controller\buffers\twitterBuffers.py:197 -#, fuzzy -msgid "{0} new tweets in {1}." -msgstr "@{0} 引用付きツイート: {1}" - -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 -msgid "%s items retrieved" -msgstr "%s個のアイテムを取得しました" - -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "このバッファは、タイムラインではないため、削除できません" - -#: ../src\controller\buffers\twitterBuffers.py:402 -msgid "Reply to {arg0}" -msgstr "「{arg0}」への返信:" - -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 -msgid "Reply" -msgstr "返信" - -#: ../src\controller\buffers\twitterBuffers.py:405 -msgid "Reply to %s" -msgstr "「%s」への返信:" - -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "「%s」へのダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 -msgid "New direct message" -msgstr "新しいダイレクトメッセージ " - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Add your comment to the tweet" -msgstr "ツイートにコメントを追加" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Quote" -msgstr "引用" - -#: ../src\controller\buffers\twitterBuffers.py:572 -msgid "Opening URL..." -msgstr "URLを開いています" - -#: ../src\controller\buffers\twitterBuffers.py:607 -msgid "User details" -msgstr "ユーザーの詳細" - -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 -msgid "Opening item in web browser..." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -msgid "Mention to %s" -msgstr "%sへのメンション" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 -msgid "Mention" -msgstr "メンション" - -#: ../src\controller\buffers\twitterBuffers.py:728 -#, fuzzy -msgid "{0} new direct messages." -msgstr "新しいダイレクトメッセージ " - -#: ../src\controller\buffers\twitterBuffers.py:731 -#, fuzzy -msgid "This action is not supported in the buffer yet." -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: ../src\controller\buffers\twitterBuffers.py:741 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy -msgid "{0} new followers." -msgstr "新しいフォロワー" - -#: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy -msgid "This action is not supported in the buffer, yet." -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: ../src\controller\mainController.py:273 -msgid "Ready" -msgstr "準備完了" - -#: ../src\controller\mainController.py:345 -msgid "Timelines" -msgstr "タイムライン" - -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 -msgid "Timeline for {}" -msgstr "「{}」のタイムライン" - -#: ../src\controller\mainController.py:352 -msgid "Likes timelines" -msgstr "ほかのユーザーのいいね一覧" - -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 -msgid "Likes for {}" -msgstr "{}のいいね一覧" - -#: ../src\controller\mainController.py:359 -msgid "Followers' Timelines" -msgstr "フォロワー一覧" - -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 -msgid "Followers for {}" -msgstr "{}をフォローしているユーザー" - -#: ../src\controller\mainController.py:366 -msgid "Friends' Timelines" -msgstr "フォロー一覧" - -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 -msgid "Friends for {}" -msgstr "{}がフォローしているユーザー" - -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 -msgid "Lists" -msgstr "リスト" - -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 -msgid "List for {}" -msgstr "{}のリスト" - -#: ../src\controller\mainController.py:381 -msgid "Searches" -msgstr "検索" - -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 -msgid "Search for {}" -msgstr "「{}」の検索結果" - -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 -msgid "Trending topics for %s" -msgstr "{}の話題のトピック" - -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "" -"セッションが選択されていません。「次のセッション」または「前のセッション」の" -"ショートカットを利用して、セッションを選択してください。" - -#: ../src\controller\mainController.py:465 -msgid "Empty buffer." -msgstr "バッファをクリア" - -#: ../src\controller\mainController.py:472 -msgid "{0} not found." -msgstr "{0}が見つかりませんでした。" - -#: ../src\controller\mainController.py:482 -msgid "Filters cannot be applied on this buffer" -msgstr "" -"このバッファにフィルターは適応できません。その動作は、現在のバッファでは利用" -"できません。" - -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 -msgid "Select the user" -msgstr "ユーザーを選択" - -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy -msgid "MMM D, YYYY. H:m" -msgstr "YYYY年MMMMD日(dddd) H時m分s秒" - -#: ../src\controller\mainController.py:934 -msgid "Conversation with {0}" -msgstr "{0}との会話" - -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 -msgid "There are no coordinates in this tweet" -msgstr "このツイートには、ジェオタグは存在しません" - -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "このツイートのジェオタグには、なにも含まれていません" - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 -msgid "Error decoding coordinates. Try again later." -msgstr "ジェオタグの取得に失敗しました" - -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 -msgid "%s, %s of %s" -msgstr "%s %s/%s" - -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 -msgid "%s. Empty" -msgstr "%sは、からです。" - -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 -msgid "{0}: This account is not logged into Twitter." -msgstr "このアカウント{0}は、まだツイッターにログインしていません" - -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 -msgid "%s. %s, %s of %s" -msgstr "セッション:%s %s %s/%s/" - -#: ../src\controller\mainController.py:1170 -msgid "{0}: This account is not logged into twitter." -msgstr "このアカウント{0}は、まだツイッターにログインしていません" - -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "イベント" - -#: ../src\controller\mainController.py:1393 -msgid "This list is already opened" -msgstr "既に開かれています" - -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 -#, fuzzy -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "" -"バグを報告しようとしているときに、予期しないエラーが発生しました。後でやり直" -"してください" - -#: ../src\controller\mainController.py:1475 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "自動読み上げ 有効" - -#: ../src\controller\mainController.py:1478 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "自動読み上げ 無効" - -#: ../src\controller\mainController.py:1485 -msgid "Session mute on" -msgstr "このセッションのミュートを設定" - -#: ../src\controller\mainController.py:1488 -msgid "Session mute off" -msgstr "このセッションのミュートを解除" - -#: ../src\controller\mainController.py:1496 -msgid "Buffer mute on" -msgstr "このバッファのミュートを設定" - -#: ../src\controller\mainController.py:1499 -msgid "Buffer mute off" -msgstr "このバッファのミュートを解除" - -#: ../src\controller\mainController.py:1522 -msgid "Copied" -msgstr "コピーしました" - -#: ../src\controller\mainController.py:1549 -msgid "Unable to update this buffer." -msgstr "このバッファを更新できません。" - -#: ../src\controller\mainController.py:1552 -msgid "Updating buffer..." -msgstr "バッファを更新中…" - -#: ../src\controller\mainController.py:1555 -msgid "{0} items retrieved" -msgstr "{0}個のアイテムを取得しました" - -#: ../src\controller\mainController.py:1572 -msgid "Invalid buffer" -msgstr "無効なバッファ無効なユーザートークンです。" - -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "このツイートは、画像を含んでいません" - -#: ../src\controller\mainController.py:1579 -msgid "Picture {0}" -msgstr "画像{0}" - -#: ../src\controller\mainController.py:1580 -msgid "Select the picture" -msgstr "画像を選択" - -#: ../src\controller\mainController.py:1596 -msgid "Unable to extract text" -msgstr "テキストを抽出できません" - -#: ../src\controller\messages.py:54 -msgid "Translated" -msgstr "翻訳完了" - -#: ../src\controller\messages.py:61 -msgid "There's no URL to be shortened" -msgstr "短縮されたURLは、ありません" - -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 -msgid "URL shortened" -msgstr "URLを短縮しました" - -#: ../src\controller\messages.py:80 -msgid "There's no URL to be expanded" -msgstr "短縮を解除するURLはありません" - -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 -msgid "URL expanded" -msgstr "URLの短縮を解除しました" - -#: ../src\controller\messages.py:104 -msgid "%s - %s of %d characters" -msgstr "%s - %s/%d" - -#: ../src\controller\messages.py:108 -msgid "%s - %s characters" -msgstr "%s - %s文字" - -#: ../src\controller\messages.py:262 -msgid "View item" -msgstr "アイテムを見る" - -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "直接接続" - -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Ask" -msgstr "その都度、質問する" - -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet without comments" -msgstr "コメントを付けずにリツイート(公式RT)" - -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet with comments" -msgstr "コメントをつけてリツイート(非公式RT)" - -#: ../src\controller\settings.py:184 -msgid "Account settings for %s" -msgstr "%sのアカウント設定" - -#: ../src\controller\settings.py:284 -msgid "Direct Messages" -msgstr "ダイレクトメッセージ" - -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 -msgid "Error" -msgstr "エラー" - -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 -msgid "That user does not exist" -msgstr "そのユーザーは存在しません。" - -#: ../src\controller\user.py:30 -msgid "User has been suspended" -msgstr "ユーザーが凍結されています。" - -#: ../src\controller\user.py:36 -msgid "Information for %s" -msgstr "%sの情報" - -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 -msgid "Discarded" -msgstr "拒否されました" - -#: ../src\controller\user.py:95 -msgid "Username: @%s\n" -msgstr "ユーザー名: @%s\n" - -#: ../src\controller\user.py:96 -msgid "Name: %s\n" -msgstr "名前: %s\n" - -#: ../src\controller\user.py:98 -msgid "Location: %s\n" -msgstr "居住地: %s\n" - -#: ../src\controller\user.py:100 -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: ../src\controller\user.py:102 -msgid "Bio: %s\n" -msgstr "自己紹介: %s\n" - -#: ../src\controller\user.py:103 ../src\controller\user.py:118 -msgid "Yes" -msgstr "はい" - -#: ../src\controller\user.py:104 ../src\controller\user.py:119 -msgid "No" -msgstr "いいえ" - -#: ../src\controller\user.py:105 -msgid "Protected: %s\n" -msgstr "保護設定: %s\n" - -#: ../src\controller\user.py:110 -msgid "You follow {0}. " -msgstr "{0}をフォロー" - -#: ../src\controller\user.py:113 -msgid "{0} is following you." -msgstr " {0}がフォロー" - -#: ../src\controller\user.py:117 -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"フォロワー: %s\n" -"フォロー: %s\n" - -#: ../src\controller\user.py:120 -msgid "Verified: %s\n" -msgstr "認証済み: %s\n" - -#: ../src\controller\user.py:121 -msgid "Tweets: %s\n" -msgstr "ツイート数: %s\n" - -#: ../src\controller\user.py:122 -msgid "Likes: %s" -msgstr "いいね数: %s" - -#: ../src\controller\userActionsController.py:75 -msgid "You can't ignore direct messages" -msgstr "ダイレクトメッセージを無視することはできません" - -#: ../src\extra\AudioUploader\audioUploader.py:54 -msgid "Attaching..." -msgstr "添付中" - -#: ../src\extra\AudioUploader\audioUploader.py:71 -msgid "Pause" -msgstr "一時停止" - -#: ../src\extra\AudioUploader\audioUploader.py:73 -msgid "&Resume" -msgstr "再開(&R)" - -#: ../src\extra\AudioUploader\audioUploader.py:74 -msgid "Resume" -msgstr "再開" - -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 -msgid "&Pause" -msgstr "一時停止(&P)" - -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 -msgid "&Stop" -msgstr "停止(&S)" - -#: ../src\extra\AudioUploader\audioUploader.py:92 -msgid "Recording" -msgstr "録音中" - -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 -msgid "Stopped" -msgstr "停止" - -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 -msgid "&Record" -msgstr "録音(&R)" - -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 -msgid "Playing..." -msgstr "再生中" - -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 -msgid "&Play" -msgstr "再生(&P)" - -#: ../src\extra\AudioUploader\audioUploader.py:156 -msgid "Recoding audio..." -msgstr "音声を録音中" - -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 -msgid "Error in file upload: {0}" -msgstr "ファイルアップロードエラー: {0}" - -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 -msgid "%d day, " -msgstr "1日前" - -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 -msgid "%d days, " -msgstr "%s日" - -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 -msgid "%d hour, " -msgstr "1時間前" - -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 -msgid "%d hours, " -msgstr "%d時間" - -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 -msgid "%d minute, " -msgstr "1分前" - -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 -msgid "%d minutes, " -msgstr "%d分" - -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 -msgid "%s second" -msgstr "1秒前" - -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 -msgid "%s seconds" -msgstr "%s秒" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 -msgid "File" -msgstr "ファイル" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 -msgid "Transferred" -msgstr "転送済み" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 -msgid "Total file size" -msgstr "合計サイズ" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 -msgid "Transfer rate" -msgstr "転送速度" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 -msgid "Time left" -msgstr "残り時間" - -#: ../src\extra\AudioUploader\wx_ui.py:28 -msgid "Attach audio" -msgstr "音声を添付" - -#: ../src\extra\AudioUploader\wx_ui.py:40 -msgid "&Add an existing file" -msgstr "既存のファイルを追加(&A)" - -#: ../src\extra\AudioUploader\wx_ui.py:41 -msgid "&Discard" -msgstr "拒否(&D)" - -#: ../src\extra\AudioUploader\wx_ui.py:43 -msgid "Upload to" -msgstr "アップロード先:" - -#: ../src\extra\AudioUploader\wx_ui.py:48 -msgid "Attach" -msgstr "添付" - -#: ../src\extra\AudioUploader\wx_ui.py:50 -msgid "&Cancel" -msgstr "キャンセル(&C)" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "音声ファイル (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Select the audio file to be uploaded" -msgstr "アップロードする音声ファイルを選択" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 -msgid "Audio tweet." -msgstr "音声付きツイート" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "User timeline buffer created." -msgstr "ユーザーのタイムラインのバッファを作成" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "Buffer destroied." -msgstr "バッファを削除" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Direct message received." -msgstr "ダイレクトメッセージを受信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message sent." -msgstr "ダイレクトメッセージを送信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Error." -msgstr "エラー" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Tweet liked." -msgstr "ツイートがいいねされた" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Likes buffer updated." -msgstr "いいねバッファが更新された" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Geotweet." -msgstr "位置情報付きのツイート" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Tweet contains one or more images" -msgstr "ツイートに1つ以上の画像が含まれています" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Boundary reached." -msgstr "先頭または最後のツイート" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "List updated." -msgstr "リストが更新された" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "Too many characters." -msgstr "文字数オーバー" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Mention received." -msgstr "リプライを受信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "New event." -msgstr "新しいイベント" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "{0} is ready." -msgstr "{0}の準備完了" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -msgid "Mention sent." -msgstr "リプライを送信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Tweet retweeted." -msgstr "ツイートをリツイート" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Search buffer updated." -msgstr "検索バッファが更新された" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Tweet received." -msgstr "ツイートを受信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet sent." -msgstr "ツイートを送信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Trending topics buffer updated." -msgstr "トレンドの話題のバッファが更新された" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "New tweet in user timeline buffer." -msgstr "ユーザーのタイムラインに新しいツイートを受信" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New follower." -msgstr "新しいフォロワー" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "Volume changed." -msgstr "ボリュームを変更" - -#: ../src\extra\SoundsTutorial\wx_ui.py:8 -msgid "Sounds tutorial" -msgstr "サウンドの確認" - -#: ../src\extra\SoundsTutorial\wx_ui.py:11 -msgid "Press enter to listen to the sound for the selected event" -msgstr "選択されたイベントのサウンドを再生するには、Enterキーを押してください" - -#: ../src\extra\SpellChecker\spellchecker.py:57 -msgid "Misspelled word: %s" -msgstr "「%s」はスペルが間違っています" - -#: ../src\extra\SpellChecker\wx_ui.py:27 -msgid "Misspelled word" -msgstr "スペルミスの単語" - -#: ../src\extra\SpellChecker\wx_ui.py:32 -msgid "Context" -msgstr "コンテキスト" - -#: ../src\extra\SpellChecker\wx_ui.py:37 -msgid "Suggestions" -msgstr "提案" - -#: ../src\extra\SpellChecker\wx_ui.py:42 -msgid "&Ignore" -msgstr "無視(&I)" - -#: ../src\extra\SpellChecker\wx_ui.py:43 -msgid "I&gnore all" -msgstr "すべて無視(&G)" - -#: ../src\extra\SpellChecker\wx_ui.py:44 -msgid "&Replace" -msgstr "置き換え(&R)" - -#: ../src\extra\SpellChecker\wx_ui.py:45 -msgid "R&eplace all" -msgstr "すべて置き換え(&E)" - -#: ../src\extra\SpellChecker\wx_ui.py:46 -msgid "&Add to personal dictionary" -msgstr "個人辞書に追加(&A)" - -#: ../src\extra\SpellChecker\wx_ui.py:79 -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "エラーが発生しました。{0}で選択した言語用の辞書がありません" - -#: ../src\extra\SpellChecker\wx_ui.py:82 -msgid "Spell check complete." -msgstr "スペルチェックが完了しました" - -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 -msgid "You have to start writing" -msgstr "あなたは、書き込みを開始しなければなりません" - -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 -msgid "There are no results in your users database" -msgstr "あなたのユーザーのデータベースには、見つかりませんでした" - -#: ../src\extra\autocompletionUsers\completion.py:33 -msgid "Autocompletion only works for users." -msgstr "自動補完はユーザーのみで動作します" - -#: ../src\extra\autocompletionUsers\settings.py:27 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"データベースの更新中...あなたは今、このウィンドウを閉じることができます。 プ" -"ロセスが終了するとメッセージが表示されます" - -#: ../src\extra\autocompletionUsers\wx_manage.py:8 -msgid "Manage Autocompletion database" -msgstr "オートコンプリートのデータベースを管理" - -#: ../src\extra\autocompletionUsers\wx_manage.py:11 -msgid "Editing {0} users database" -msgstr "{0}のユーザーデータベースを編集中" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Username" -msgstr "ユーザー名" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "名前" - -#: ../src\extra\autocompletionUsers\wx_manage.py:15 -msgid "Add user" -msgstr "ユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Remove user" -msgstr "ユーザーを削除" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Add user to database" -msgstr "データベースにユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Twitter username" -msgstr "ツイッターのユーザー名" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -msgid "The user does not exist" -msgstr "そのユーザーは存在しません" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "Error!" -msgstr "エラー" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "オートコンプリートユーザーの設定" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "フォロワーからユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "フォロー中のユーザーからユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "データベースの管理" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "完了" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "{0}のユーザーのデータベースが更新されました" - -#: ../src\extra\ocr\OCRSpace.py:5 -msgid "Detect automatically" -msgstr "自動検出" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 -msgid "Danish" -msgstr "デンマーク語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 -msgid "Dutch" -msgstr "オランダ語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 -msgid "English" -msgstr "英語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 -msgid "Finnish" -msgstr "フィンランド語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 -msgid "French" -msgstr "フランス語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 -msgid "German" -msgstr "ドイツ語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 -msgid "Hungarian" -msgstr "ハンガリー語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 -msgid "Italian" -msgstr "イタリア語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 -msgid "Japanese" -msgstr "日本語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 -msgid "Korean" -msgstr "韓国語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 -msgid "Polish" -msgstr "ポーランド語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 -msgid "Portuguese" -msgstr "ポルトガル語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 -msgid "Russian" -msgstr "ロシア語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 -msgid "Spanish" -msgstr "スペイン語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 -msgid "Turkish" -msgstr "トルコ語" - -#: ../src\extra\translator\translator.py:12 -msgid "Afrikaans" -msgstr "アフリカ語" - -#: ../src\extra\translator\translator.py:13 -msgid "Albanian" -msgstr "アルバニア語" - -#: ../src\extra\translator\translator.py:14 -msgid "Amharic" -msgstr "アムハラ語" - -#: ../src\extra\translator\translator.py:15 -msgid "Arabic" -msgstr "アラビア語" - -#: ../src\extra\translator\translator.py:16 -msgid "Armenian" -msgstr "アルメニア語" - -#: ../src\extra\translator\translator.py:17 -msgid "Azerbaijani" -msgstr "アゼルバイジャン語" - -#: ../src\extra\translator\translator.py:18 -msgid "Basque" -msgstr "バスク語" - -#: ../src\extra\translator\translator.py:19 -msgid "Belarusian" -msgstr "ベラルーシ語" - -#: ../src\extra\translator\translator.py:20 -msgid "Bengali" -msgstr "ベンガル語" - -#: ../src\extra\translator\translator.py:21 -msgid "Bihari" -msgstr "ビハール語" - -#: ../src\extra\translator\translator.py:22 -msgid "Bulgarian" -msgstr "ブルガリア語" - -#: ../src\extra\translator\translator.py:23 -msgid "Burmese" -msgstr "ビルマ語" - -#: ../src\extra\translator\translator.py:24 -msgid "Catalan" -msgstr "カタロニア語" - -#: ../src\extra\translator\translator.py:25 -msgid "Cherokee" -msgstr "チェロキー語" - -#: ../src\extra\translator\translator.py:26 -msgid "Chinese" -msgstr "中国語" - -#: ../src\extra\translator\translator.py:27 -msgid "Chinese_simplified" -msgstr "簡体字中国語" - -#: ../src\extra\translator\translator.py:28 -msgid "Chinese_traditional" -msgstr "繁体字中国語" - -#: ../src\extra\translator\translator.py:29 -msgid "Croatian" -msgstr "クロアチア語" - -#: ../src\extra\translator\translator.py:30 -msgid "Czech" -msgstr "チェコ語" - -#: ../src\extra\translator\translator.py:32 -msgid "Dhivehi" -msgstr "ディベヒ語" - -#: ../src\extra\translator\translator.py:35 -msgid "Esperanto" -msgstr "エスペラント語" - -#: ../src\extra\translator\translator.py:36 -msgid "Estonian" -msgstr "エストニア語" - -#: ../src\extra\translator\translator.py:37 -msgid "Filipino" -msgstr "フィリピン語" - -#: ../src\extra\translator\translator.py:40 -msgid "Galician" -msgstr "ガリシア語" - -#: ../src\extra\translator\translator.py:41 -msgid "Georgian" -msgstr "ジョージア語" - -#: ../src\extra\translator\translator.py:43 -msgid "Greek" -msgstr "ギリシャ語" - -#: ../src\extra\translator\translator.py:44 -msgid "Guarani" -msgstr "グアラニ語" - -#: ../src\extra\translator\translator.py:45 -msgid "Gujarati" -msgstr "グジャラート語" - -#: ../src\extra\translator\translator.py:46 -msgid "Hebrew" -msgstr "ヘブライ語" - -#: ../src\extra\translator\translator.py:47 -msgid "Hindi" -msgstr "ヒンディー語" - -#: ../src\extra\translator\translator.py:49 -msgid "Icelandic" -msgstr "アイスランド語" - -#: ../src\extra\translator\translator.py:50 -msgid "Indonesian" -msgstr "インドネシア語" - -#: ../src\extra\translator\translator.py:51 -msgid "Inuktitut" -msgstr "イヌクティトゥト語" - -#: ../src\extra\translator\translator.py:52 -msgid "Irish" -msgstr "アイリス語" - -#: ../src\extra\translator\translator.py:55 -msgid "Kannada" -msgstr "カンナダ語" - -#: ../src\extra\translator\translator.py:56 -msgid "Kazakh" -msgstr "カザフ語" - -#: ../src\extra\translator\translator.py:57 -msgid "Khmer" -msgstr "クメール語" - -#: ../src\extra\translator\translator.py:59 -msgid "Kurdish" -msgstr "クルド語" - -#: ../src\extra\translator\translator.py:60 -msgid "Kyrgyz" -msgstr "キルギス語" - -#: ../src\extra\translator\translator.py:61 -msgid "Laothian" -msgstr "ラオス語" - -#: ../src\extra\translator\translator.py:62 -msgid "Latvian" -msgstr "ラトビア語" - -#: ../src\extra\translator\translator.py:63 -msgid "Lithuanian" -msgstr "リトアニア語" - -#: ../src\extra\translator\translator.py:64 -msgid "Macedonian" -msgstr "マケドニア語" - -#: ../src\extra\translator\translator.py:65 -msgid "Malay" -msgstr "マレー語" - -#: ../src\extra\translator\translator.py:66 -msgid "Malayalam" -msgstr "マラヤーラム語" - -#: ../src\extra\translator\translator.py:67 -msgid "Maltese" -msgstr "マルタ語" - -#: ../src\extra\translator\translator.py:68 -msgid "Marathi" -msgstr "マラーティー語" - -#: ../src\extra\translator\translator.py:69 -msgid "Mongolian" -msgstr "モンゴル語" - -#: ../src\extra\translator\translator.py:70 -msgid "Nepali" -msgstr "ネパール語" - -#: ../src\extra\translator\translator.py:71 -msgid "Norwegian" -msgstr "ノルウェー語" - -#: ../src\extra\translator\translator.py:72 -msgid "Oriya" -msgstr "オリヤー語" - -#: ../src\extra\translator\translator.py:73 -msgid "Pashto" -msgstr "パシュトウ語" - -#: ../src\extra\translator\translator.py:74 -msgid "Persian" -msgstr "ペルシア語" - -#: ../src\extra\translator\translator.py:77 -msgid "Punjabi" -msgstr "パンジャブ語" - -#: ../src\extra\translator\translator.py:78 -msgid "Romanian" -msgstr "ルーマニア語" - -#: ../src\extra\translator\translator.py:80 -msgid "Sanskrit" -msgstr "サンスクリット語" - -#: ../src\extra\translator\translator.py:81 -msgid "Serbian" -msgstr "セルビア語" - -#: ../src\extra\translator\translator.py:82 -msgid "Sindhi" -msgstr "シンド語" - -#: ../src\extra\translator\translator.py:83 -msgid "Sinhalese" -msgstr "シンハラ語" - -#: ../src\extra\translator\translator.py:84 -msgid "Slovak" -msgstr "スロバキア語" - -#: ../src\extra\translator\translator.py:85 -msgid "Slovenian" -msgstr "スロベニア語" - -#: ../src\extra\translator\translator.py:87 -msgid "Swahili" -msgstr "スワヒリ語" - -#: ../src\extra\translator\translator.py:88 -msgid "Swedish" -msgstr "スウェーデン語" - -#: ../src\extra\translator\translator.py:89 -msgid "Tajik" -msgstr "タジク語" - -#: ../src\extra\translator\translator.py:90 -msgid "Tamil" -msgstr "タミル語" - -#: ../src\extra\translator\translator.py:91 -msgid "Tagalog" -msgstr "タガログ語" - -#: ../src\extra\translator\translator.py:92 -msgid "Telugu" -msgstr "テルグ語" - -#: ../src\extra\translator\translator.py:93 -msgid "Thai" -msgstr "タイ語" - -#: ../src\extra\translator\translator.py:94 -msgid "Tibetan" -msgstr "チベット語" - -#: ../src\extra\translator\translator.py:96 -msgid "Ukrainian" -msgstr "ウクライナ語" - -#: ../src\extra\translator\translator.py:97 -msgid "Urdu" -msgstr "ウルドゥー語" - -#: ../src\extra\translator\translator.py:98 -msgid "Uzbek" -msgstr "ウズベク語" - -#: ../src\extra\translator\translator.py:99 -msgid "Uighur" -msgstr "ウイグル語" - -#: ../src\extra\translator\translator.py:100 -msgid "Vietnamese" -msgstr "ベトナム語" - -#: ../src\extra\translator\translator.py:101 -msgid "Welsh" -msgstr "ウェールズ語" - -#: ../src\extra\translator\translator.py:102 -msgid "Yiddish" -msgstr "イディッシュ語" - -#: ../src\extra\translator\wx_ui.py:44 -msgid "Translate message" -msgstr "メッセージを翻訳" - -#: ../src\extra\translator\wx_ui.py:47 -msgid "Target language" -msgstr "翻訳先の言語" - -#: ../src\issueReporter\issueReporter.py:30 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 -msgid "General" -msgstr "一般" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "always" -msgstr "常に" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "have not tried" -msgstr "試したことがない" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "random" -msgstr "ランダム" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "sometimes" -msgstr "時々" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "unable to duplicate" -msgstr "複製できません" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "block" -msgstr "ブロック" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "crash" -msgstr "クラッシュ" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "feature" -msgstr "特徴" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "major" -msgstr "メジャー" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "minor" -msgstr "マイナー" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "text" -msgstr "内容" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "trivial" -msgstr "些細な" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "tweak" -msgstr "微調整" - -#: ../src\issueReporter\wx_ui.py:25 -msgid "Report an error" -msgstr "エラーを報告" - -#: ../src\issueReporter\wx_ui.py:28 -msgid "Select a category" -msgstr "カテゴリを選択" - -#: ../src\issueReporter\wx_ui.py:36 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "簡単な説明" - -#: ../src\issueReporter\wx_ui.py:45 -msgid "Here, you can describe the bug in detail" -msgstr "バグの詳細な説明" - -#: ../src\issueReporter\wx_ui.py:55 -msgid "how often does this bug happen?" -msgstr "このバグが起こる頻度" - -#: ../src\issueReporter\wx_ui.py:62 -msgid "Select the importance that you think this bug has" -msgstr "このバグの重要性を選択" - -#: ../src\issueReporter\wx_ui.py:69 -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"私は、{0}のバグシステムが私に連絡して、すぐにバグを修正するために、ツイッター" -"のユーザー名を取得することを理解しています" - -#: ../src\issueReporter\wx_ui.py:72 -msgid "Send report" -msgstr "レポートを送信" - -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 -msgid "Cancel" -msgstr "キャンセル" - -#: ../src\issueReporter\wx_ui.py:83 -msgid "You must fill out both fields" -msgstr "あなたは、両方のフィールドに記入しなければなりません" - -#: ../src\issueReporter\wx_ui.py:86 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"必要な場合に連絡するため、ツイッターのユーザー名を私たちに送信するために、" -"チェックボックスにチェックをつける必要があります" - -#: ../src\issueReporter\wx_ui.py:89 -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"このバグを報告していただき、ありがとうございます!将来のバージョンでは、変更" -"のリストでそれを見つけることができるかもしれません。あなたは、バグ番号%iを報" -"しました" - -#: ../src\issueReporter\wx_ui.py:89 -msgid "reported" -msgstr "レポート完了" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "Error while reporting" -msgstr "エラー" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"バグを報告しようとしているときに、予期しないエラーが発生しました。後でやり直" -"してください" - -#: ../src\keystrokeEditor\constants.py:3 -msgid "Go up in the current buffer" -msgstr "現在のバッファで、前のツイートに移動" - -#: ../src\keystrokeEditor\constants.py:4 -msgid "Go down in the current buffer" -msgstr "現在のバッファで、次のツイートに移動" - -#: ../src\keystrokeEditor\constants.py:5 -msgid "Go to the previous buffer" -msgstr "前のバッファに移動" - -#: ../src\keystrokeEditor\constants.py:6 -msgid "Go to the next buffer" -msgstr "次のバッファに移動" - -#: ../src\keystrokeEditor\constants.py:7 -msgid "Focus the next session" -msgstr "次のセッションにフォーカス" - -#: ../src\keystrokeEditor\constants.py:8 -msgid "Focus the previous session" -msgstr "前のセッションにフォーカス" - -#: ../src\keystrokeEditor\constants.py:9 -msgid "Show or hide the GUI" -msgstr "GUIの表示と非表示を切り替え" - -#: ../src\keystrokeEditor\constants.py:10 -msgid "New tweet" -msgstr "新規ツイート" - -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 -msgid "Retweet" -msgstr "リツイート" - -#: ../src\keystrokeEditor\constants.py:13 -msgid "Send direct message" -msgstr "ダイレクトメッセージを作成" - -#: ../src\keystrokeEditor\constants.py:14 -msgid "Like a tweet" -msgstr "ツイートをいいねする" - -#: ../src\keystrokeEditor\constants.py:15 -msgid "Like/unlike a tweet" -msgstr "ツイートをいいね・いいね解除" - -#: ../src\keystrokeEditor\constants.py:16 -msgid "Unlike a tweet" -msgstr "ツイートのいいねを解除" - -#: ../src\keystrokeEditor\constants.py:17 -msgid "Open the user actions dialogue" -msgstr "ユーザーのアクションを選択する画面を表示" - -#: ../src\keystrokeEditor\constants.py:18 -msgid "See user details" -msgstr "ユーザーの詳細を表示" - -#: ../src\keystrokeEditor\constants.py:19 -msgid "Show tweet" -msgstr "ツイートを表示" - -#: ../src\keystrokeEditor\constants.py:20 -msgid "Quit" -msgstr "終了" - -#: ../src\keystrokeEditor\constants.py:21 -msgid "Open user timeline" -msgstr "特定のユーザーのタイムラインを開く" - -#: ../src\keystrokeEditor\constants.py:22 -msgid "Destroy buffer" -msgstr "現在のバッファを削除" - -#: ../src\keystrokeEditor\constants.py:23 -msgid "Interact with the currently focused tweet." -msgstr "現在フォーカス中のツイートを相呼応する" - -#: ../src\keystrokeEditor\constants.py:24 -msgid "Open URL" -msgstr "URLを開く" - -#: ../src\keystrokeEditor\constants.py:25 -#, fuzzy -msgid "View in Twitter" -msgstr "ツイッターを検索" - -#: ../src\keystrokeEditor\constants.py:26 -msgid "Increase volume by 5%" -msgstr "音量を5パーセント上げる" - -#: ../src\keystrokeEditor\constants.py:27 -msgid "Decrease volume by 5%" -msgstr "音量を5パーセント下げる" - -#: ../src\keystrokeEditor\constants.py:28 -msgid "Jump to the first element of a buffer" -msgstr "現在のバッファの先頭に移動" - -#: ../src\keystrokeEditor\constants.py:29 -msgid "Jump to the last element of the current buffer" -msgstr "現在のバッファの最後に移動" - -#: ../src\keystrokeEditor\constants.py:30 -msgid "Jump 20 elements up in the current buffer" -msgstr "20個前の要素に移動" - -#: ../src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements down in the current buffer" -msgstr "20個先の要素に移動" - -#: ../src\keystrokeEditor\constants.py:32 -msgid "Edit profile" -msgstr "プロフィールを編集" - -#: ../src\keystrokeEditor\constants.py:33 -msgid "Delete a tweet or direct message" -msgstr "ツイートまたはダイレクトメッセージを削除" - -#: ../src\keystrokeEditor\constants.py:34 -msgid "Empty the current buffer" -msgstr "現在のバッファをクリア" - -#: ../src\keystrokeEditor\constants.py:35 -msgid "Repeat last item" -msgstr "現在のアイテムをもう一度読み上げ" - -#: ../src\keystrokeEditor\constants.py:36 -msgid "Copy to clipboard" -msgstr "クリップボードにコピー" - -#: ../src\keystrokeEditor\constants.py:37 -msgid "Add to list" -msgstr "リストに追加" - -#: ../src\keystrokeEditor\constants.py:38 -msgid "Remove from list" -msgstr "リストから削除" - -#: ../src\keystrokeEditor\constants.py:39 -msgid "Mute/unmute the active buffer" -msgstr "現在のバッファのミュートを切り替え" - -#: ../src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the current session" -msgstr "現在のセッションのミュートを切り替え" - -#: ../src\keystrokeEditor\constants.py:41 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "新着のツイートを自動で読み上げるかどうかを設定" - -#: ../src\keystrokeEditor\constants.py:42 -msgid "Search on twitter" -msgstr "ツイッターを検索" - -#: ../src\keystrokeEditor\constants.py:43 -msgid "Find a string in the currently focused buffer" -msgstr "現在のバッファ内の文字列を検索" - -#: ../src\keystrokeEditor\constants.py:44 -msgid "Show the keystroke editor" -msgstr "キーストロークエディタを表示" - -#: ../src\keystrokeEditor\constants.py:45 -msgid "Show lists for a specified user" -msgstr "特定のユーザーのリストを表示" - -#: ../src\keystrokeEditor\constants.py:46 -msgid "load previous items" -msgstr "以前のアイテムを取得" - -#: ../src\keystrokeEditor\constants.py:47 -msgid "Get geolocation" -msgstr "位置情報を取得" - -#: ../src\keystrokeEditor\constants.py:48 -msgid "Display the tweet's geolocation in a dialog" -msgstr "位置情報を表示" - -#: ../src\keystrokeEditor\constants.py:49 -msgid "Create a trending topics buffer" -msgstr "トレンドの話題のバッファを作成" - -#: ../src\keystrokeEditor\constants.py:50 -msgid "View conversation" -msgstr "会話を見る" - -#: ../src\keystrokeEditor\constants.py:51 -msgid "Check and download updates" -msgstr "アップデートをチェックしてダウンロード" - -#: ../src\keystrokeEditor\constants.py:52 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"リストを作成したり、編集したり、削除したりするために「リストの管理」を開く" - -#: ../src\keystrokeEditor\constants.py:53 -msgid "Opens the global settings dialogue" -msgstr "「全般設定」ダイアログを開く" - -#: ../src\keystrokeEditor\constants.py:54 -#, fuzzy -msgid "Opens the list manager" -msgstr "リストの管理" - -#: ../src\keystrokeEditor\constants.py:55 -msgid "Opens the account settings dialogue" -msgstr "「アカウント設定」ダイアログを開く" - -#: ../src\keystrokeEditor\constants.py:56 -msgid "Try to play an audio file" -msgstr "音声ファイルの再生" - -#: ../src\keystrokeEditor\constants.py:57 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "バッファを更新して、取得に失敗したアイテムを取得" - -#: ../src\keystrokeEditor\constants.py:58 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "画像からテキストを抽出して、結果をダイアログで表示。" - -#: ../src\keystrokeEditor\wx_ui.py:8 -msgid "Keystroke editor" -msgstr "キーストロークエディタ" - -#: ../src\keystrokeEditor\wx_ui.py:12 -msgid "Select a keystroke to edit" -msgstr "編集するキーストロークを選択" - -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "キーストローク" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 -msgid "Action" -msgstr "操作" - -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 -msgid "Edit" -msgstr "編集" - -#: ../src\keystrokeEditor\wx_ui.py:20 -msgid "Execute action" -msgstr "現在の動作を実行" - -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 -msgid "Close" -msgstr "閉じる" - -#: ../src\keystrokeEditor\wx_ui.py:48 -msgid "Editing keystroke" -msgstr "キーストロークを編集" - -#: ../src\keystrokeEditor\wx_ui.py:51 -msgid "Control" -msgstr "コントロール" - -#: ../src\keystrokeEditor\wx_ui.py:52 -msgid "Alt" -msgstr "オルト" - -#: ../src\keystrokeEditor\wx_ui.py:53 -msgid "Shift" -msgstr "シフト" - -#: ../src\keystrokeEditor\wx_ui.py:54 -msgid "Windows" -msgstr "ウィンドウズ" - -#: ../src\keystrokeEditor\wx_ui.py:60 -msgid "Key" -msgstr "キー名" - -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 -msgid "OK" -msgstr "OK" - -#: ../src\keystrokeEditor\wx_ui.py:78 -msgid "You need to use the Windows key" -msgstr "ウィンドウズキーを使用する必要があります" - -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 -msgid "Invalid keystroke" -msgstr "無効なキーストローク" - -#: ../src\keystrokeEditor\wx_ui.py:81 -msgid "You must provide a character for the keystroke" -msgstr "キー名が入力されていません" - -#: ../src\languageHandler.py:99 -msgid "User default" -msgstr "ユーザーのデフォルト" - -#: ../src\main.py:105 -msgid "https://twblue.es/donate" -msgstr "https://twblue.es/donate" - -#: ../src\main.py:122 -msgid "" -"{0} is already running. Close the other instance before starting this one. " -"If you're sure that {0} isn't running, try deleting the file at {1}. If " -"you're unsure of how to do this, contact the {0} developers." -msgstr "" - -#: ../src\sessionmanager\wxUI.py:8 -msgid "Session manager" -msgstr "セッションの管理" - -#: ../src\sessionmanager\wxUI.py:11 -msgid "Accounts list" -msgstr "アカウントリスト" - -#: ../src\sessionmanager\wxUI.py:13 -msgid "Account" -msgstr "アカウント" - -#: ../src\sessionmanager\wxUI.py:17 -msgid "New account" -msgstr "新しいアカウントを連携" - -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 -msgid "Remove account" -msgstr "このアカウントを削除" - -#: ../src\sessionmanager\wxUI.py:19 -msgid "Global Settings" -msgstr "全体の設定" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "Account Error" -msgstr "アカウントエラー" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "You need to configure an account." -msgstr "アカウントを設定する必要があります" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "Authorization" -msgstr "認証" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "" -"The request to authorize your Twitter account will be opened in your " -"browser. You only need to do this once. Would you like to continue?" -msgstr "" -"アカウントを認証するために、ブラウザを開きます。あなたは、一度だけ、これを実" -"行する必要があります。続行しますか?" - -#: ../src\sessionmanager\wxUI.py:52 -msgid "Authorized account %d" -msgstr "認証したアカウント%d" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "Invalid user token" -msgstr "無効なユーザートークンです。" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "" -"Your access token is invalid or the authorization has failed. Please try " -"again." -msgstr "" -"あなたのアクセストークンが無効であるか、または許可が失敗しました。もう一度や" -"り直してください。" - -#: ../src\sessionmanager\wxUI.py:64 -msgid "Do you really want to delete this account?" -msgstr "本当にこのアカウントを削除しますか?" - -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 -msgid "dddd, MMMM D, YYYY H:m:s" -msgstr "YYYY年MMMMD日(dddd) H時m分s秒" - -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 -msgid "Dm to %s " -msgstr "「%s」へのDM" - -#: ../src\sessions\twitter\compose.py:141 -msgid "{0}. Quoted tweet from @{1}: {2}" -msgstr "{0} 引用:@{1}:{2}" - -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 -msgid "Unavailable" -msgstr "無効" - -#: ../src\sessions\twitter\compose.py:166 -msgid "" -"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " -"Twitter %s" -msgstr "" -"%s: @%s フォロワー: %s フォロー: %s ツイート数: %s 最後のツイート: %s ツイッ" -"ターへの参加: %s" - -#: ../src\sessions\twitter\compose.py:170 -msgid "No description available" -msgstr "説明はありません" - -#: ../src\sessions\twitter\compose.py:174 -msgid "private" -msgstr "プライベート" - -#: ../src\sessions\twitter\compose.py:175 -msgid "public" -msgstr "公式" - -#: ../src\sessions\twitter\session.py:169 -#, fuzzy -msgid "There are no more items to retrieve in this buffer." -msgstr "このツイートには、ジェオタグは存在しません" - -#: ../src\sessions\twitter\session.py:215 -msgid "%s failed. Reason: %s" -msgstr "%s" - -#: ../src\sessions\twitter\session.py:221 -msgid "%s succeeded." -msgstr "%sに成功しました。" - -#: ../src\sessions\twitter\utils.py:225 -msgid "Sorry, you are not authorised to see this status." -msgstr "申し訳ありませんが、あなたはこのステータスを表示する権限がありません" - -#: ../src\sessions\twitter\utils.py:227 -msgid "No status found with that ID" -msgstr "そのIDのステータスが見つかりませんでした" - -#: ../src\sessions\twitter\utils.py:229 -msgid "Error code {0}" -msgstr "エラーコード {0}" - -#: ../src\sessions\twitter\wxUI.py:6 -msgid "Authorising account..." -msgstr "アカウントを連携中…" - -#: ../src\sessions\twitter\wxUI.py:9 -msgid "Enter your PIN code here" -msgstr "PINコードを入力" - -#: ../src\sound.py:159 -msgid "Stopped." -msgstr "停止" - -#: ../src\update\wxUpdater.py:10 -msgid "New version for %s" -msgstr "「%s」の新しいバージョン" - -#: ../src\update\wxUpdater.py:10 -msgid "" -"There's a new %s version available, released on %s. Would you like to " -"download it now?\n" -"\n" -" %s version: %s\n" -"\n" -"Changes:\n" -"%s" -msgstr "" -"%sの新しいバージョンが%sにリリースされています。今すぐダウンロードします" -"か?\n" -"\n" -"%sバージョン:%s\n" -"\n" -"更新履歴:\n" -"%s" - -#: ../src\update\wxUpdater.py:18 -msgid "Download in Progress" -msgstr "ダウンロード中" - -#: ../src\update\wxUpdater.py:18 -msgid "Downloading the new version..." -msgstr "新しいバージョンをダウンロードしています" - -#: ../src\update\wxUpdater.py:28 -msgid "Updating... %s of %s" -msgstr "アップデート中… %s/%s" - -#: ../src\update\wxUpdater.py:31 -msgid "Done!" -msgstr "完了" - -#: ../src\update\wxUpdater.py:31 -msgid "" -"The update has been downloaded and installed successfully. Press OK to " -"continue." -msgstr "" -"アップデートは正常にインストールされました。続行する場合は、「OK」を押してく" -"ださい" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Client" -msgstr "クライアント" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Text" -msgstr "内容" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 -msgid "Date" -msgstr "日時" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 -msgid "User" -msgstr "ユーザー" - -#: ../src\wxUI\buffers\base.py:27 -msgid "Direct message" -msgstr "ダイレクトメッセージ" - -#: ../src\wxUI\buffers\events.py:13 -msgid "Event" -msgstr "イベント" - -#: ../src\wxUI\buffers\events.py:15 -msgid "Remove event" -msgstr "イベントを削除" - -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 -msgid "Login" -msgstr "ログイン" - -#: ../src\wxUI\buffers\panels.py:13 -msgid "Log in automatically" -msgstr "自動的にログインする" - -#: ../src\wxUI\buffers\panels.py:21 -msgid "Logout" -msgstr "ログアウト" - -#: ../src\wxUI\buffers\trends.py:8 -msgid "Trending topic" -msgstr "トレンドの話題" - -#: ../src\wxUI\buffers\trends.py:18 -msgid "Tweet about this trend" -msgstr "このトレンドのツイート" - -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 -msgid "Search topic" -msgstr "トピックを検索" - -#: ../src\wxUI\commonMessageDialogs.py:6 -msgid "" -"This retweet is over 140 characters. Would you like to post it as a mention " -"to the poster with your comments and a link to the original tweet?" -msgstr "" -"このリツイートは、140文字を超えています。投稿者へのリプライとコメント、お" -"よび元のツイートへのリンクで登校しますか?" - -#: ../src\wxUI\commonMessageDialogs.py:9 -msgid "Would you like to add a comment to this tweet?" -msgstr "このツイートにコメントをつけますか?" - -#: ../src\wxUI\commonMessageDialogs.py:12 -msgid "" -"Do you really want to delete this tweet? It will be deleted from Twitter as " -"well." -msgstr "" -"本当にこのツイートを削除しますか?このツイートは、ツイッターから削除されま" -"す。" - -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 -msgid "Delete" -msgstr "削除" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Do you really want to close {0}?" -msgstr "本当に「{0}」を終了しますか?" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Exit" -msgstr "終了確認" - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid " {0} must be restarted for these changes to take effect." -msgstr "これらの変更を有効にするには、「{0}」を再起動する必要があります。" - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid "Restart {0} " -msgstr "「{0}」を再起動" - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "" -"Are you sure you want to delete this user from the database? This user will " -"not appear in autocomplete results anymore." -msgstr "" -"データベースからこのユーザーを削除してもよろしいですか?このユーザーは、自動" -"補完結果には表示されません。" - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "Confirm" -msgstr "確認" - -#: ../src\wxUI\commonMessageDialogs.py:25 -msgid "Enter the name of the client : " -msgstr "クライアントの名前:" - -#: ../src\wxUI\commonMessageDialogs.py:25 -#: ../src\wxUI\dialogs\configuration.py:246 -msgid "Add client" -msgstr "クライアントを追加" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "" -"Do you really want to empty this buffer? It's items will be removed from " -"the list but not from Twitter" -msgstr "" -"本当にこのバッファをクリアしますか?これは、ツイッターからは削除されません。" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "Empty buffer" -msgstr "バッファをクリア" - -#: ../src\wxUI\commonMessageDialogs.py:35 -msgid "Do you really want to destroy this buffer?" -msgstr "本当にこのバッファを削除しますか?" - -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Attention" -msgstr "確認" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "A timeline for this user already exists. You can't open another" -msgstr "" -"そのユーザーのタイムラインは、既に開かれています。他のユーザーを開いてくださ" -"い。" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "Existing timeline" -msgstr "既存のタイムライン" - -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "This user has no tweets, so you can't open a timeline for them." -msgstr "" -"このユーザーは、何もツイートしていないため、タイムラインを開くことができませ" -"ん。" - -#: ../src\wxUI\commonMessageDialogs.py:47 -msgid "" -"This is a protected Twitter user, which means you can't open a timeline " -"using the Streaming API. The user's tweets will not update due to a twitter " -"policy. Do you want to continue?" -msgstr "" -"このアカウントは、保護されています。これは、ストリーミングAPIを利用して、タイ" -"ムラインを開くことができないことを意味します。ユーザーのツイートはTwitterのポ" -"リシーにより更新されません。続行しますか?" - -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "Warning" -msgstr "警告" - -#: ../src\wxUI\commonMessageDialogs.py:50 -msgid "" -"This is a protected user account, you need to follow this user to view their " -"tweets or likes." -msgstr "" -"このユーザーは保護されています。このユーザーのツイートやお気に入り一覧を見る" -"には、このユーザーをフォローする必要があります。" - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "" -"If you like {0} we need your help to keep it going. Help us by donating to " -"the project. This will help us pay for the server, the domain and some other " -"things to ensure that {0} will be actively maintained. Your donation will " -"give us the means to continue the development of {0}, and to keep {0} free. " -"Would you like to donate now?" -msgstr "" -"「{0}」が好きなら、私たちは、それを続けるために、助けを必要としています。プロ" -"ジェクトに寄付することで、私たちを助けてください。これは、私たちは{0}が積極的" -"に維持されることを保証するために、サーバー、ドメイン、およびいくつかの他のも" -"ののために支払うのに役立ちます。あなたの寄付は私たちに「{0}」の開発を継続する" -"ための手段を与え、自由な「{0}」を維持します。今すぐ寄付しますか?" - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "We need your help" -msgstr "寄付のお願い" - -#: ../src\wxUI\commonMessageDialogs.py:57 -msgid "This user has no tweets. {0} can't create a timeline." -msgstr "" -"このユーザーにはツイートがないため、「{0}」のタイムラインを作成することはでき" -"ません。" - -#: ../src\wxUI\commonMessageDialogs.py:60 -msgid "This user has no favorited tweets. {0} can't create a timeline." -msgstr "" -"このユーザーには、お気に入り登録されたツイートがないため、「{0}」のタイムライ" -"ンを作成することはできません。" - -#: ../src\wxUI\commonMessageDialogs.py:63 -msgid "This user has no followers. {0} can't create a timeline." -msgstr "" -"このユーザーのフォロワーがいないため、「{0}」でタイムラインを作ることはできま" -"せん。" - -#: ../src\wxUI\commonMessageDialogs.py:66 -msgid "This user has no friends. {0} can't create a timeline." -msgstr "" -"このユーザーは、誰もフォローしていないため、「{0}」でタイムラインを作ることは" -"できません。" - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geo data for this tweet" -msgstr "このツイートの位置情報" - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geolocation data: {0}" -msgstr "位置情報: {0}" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "Information" -msgstr "情報" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "" -"TWBlue has detected that you're running windows 10 and has changed the " -"default keymap to the Windows 10 keymap. It means that some keyboard " -"shorcuts could be different. Please check the keystroke editor by pressing " -"Alt+Win+K to see all available keystrokes for this keymap." -msgstr "" -"TWBlueは、Windows10で動作していることを検出したため、デフォルトのキーマップを" -"Windows10のキーマップに変更しました。これは、一部のキーボードショートカットが" -"違うことを意味します。このキーマップで使用できる全てのショートカットを見るに" -"は、Alt+Win+Kで、キーストロークエディタを開いて確認してください。" - -#: ../src\wxUI\commonMessageDialogs.py:76 -msgid "You have been blocked from viewing this content" -msgstr "このコンテンツの表示がブロックされています" - -#: ../src\wxUI\commonMessageDialogs.py:79 -msgid "" -"You have been blocked from viewing someone's content. In order to avoid " -"conflicts with the full session, TWBlue will remove the affected timeline." -msgstr "" -"他のユーザーのコンテンツを表示できないようになっています。フルセッションとの" -"競合を避けるため、TWBlueは影響を受けるタイムラインを削除します。" - -#: ../src\wxUI\commonMessageDialogs.py:82 -msgid "" -"TWBlue cannot load this timeline because the user has been suspended from " -"Twitter." -msgstr "" -"ユーザーがTwitterから凍結されているため、このタイムラインをロードできません。" - -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Do you really want to delete this filter?" -msgstr "本当に、このフィルターを削除しますか?" - -#: ../src\wxUI\commonMessageDialogs.py:88 -msgid "This filter already exists. Please use a different title" -msgstr "このフィルターはすでに利用されています。別の名前を利用してください" - -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "" -"{0} quit unexpectedly the last time it was run. If the problem persists, " -"please report it to the {0} developers." -msgstr "" - -#: ../src\wxUI\dialogs\attach.py:9 -msgid "Add an attachment" -msgstr "添付ファイルを追加" - -#: ../src\wxUI\dialogs\attach.py:12 -msgid "Attachments" -msgstr "添付ファイル" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Title" -msgstr "タイトル" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Type" -msgstr "形式" - -#: ../src\wxUI\dialogs\attach.py:18 -msgid "Add attachments" -msgstr "添付ファイルを追加" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "&Photo" -msgstr "画像(&P)" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "Remove attachment" -msgstr "添付ファイルを削除" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "画像ファイル (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Select the picture to be uploaded" -msgstr "アップロードする画像を選択" - -#: ../src\wxUI\dialogs\attach.py:43 -msgid "please provide a description" -msgstr "説明を入力" - -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 -msgid "Description" -msgstr "説明" - -#: ../src\wxUI\dialogs\configuration.py:16 -msgid "Language" -msgstr "言語" - -#: ../src\wxUI\dialogs\configuration.py:23 -msgid "Run {0} at Windows startup" -msgstr "Windows起動時に{0}を実行" - -#: ../src\wxUI\dialogs\configuration.py:24 -msgid "ask before exiting {0}" -msgstr "{0}を終了する前に確認" - -#: ../src\wxUI\dialogs\configuration.py:27 -msgid "Disable Streaming functions" -msgstr "ストリーミング機能を無効化する" - -#: ../src\wxUI\dialogs\configuration.py:30 -msgid "Buffer update interval, in minutes" -msgstr "バッファの更新間隔(分)" - -#: ../src\wxUI\dialogs\configuration.py:36 -msgid "Play a sound when {0} launches" -msgstr "{0}が起動したときに、音声を再生" - -#: ../src\wxUI\dialogs\configuration.py:38 -msgid "Speak a message when {0} launches" -msgstr "{0}が起動した際に、メッセージを読み上げ" - -#: ../src\wxUI\dialogs\configuration.py:40 -msgid "Use invisible interface's keyboard shortcuts while GUI is visible" -msgstr "GUI表示中でもGUI非表示時に利用できるショートカットを利用する" - -#: ../src\wxUI\dialogs\configuration.py:42 -msgid "Activate Sapi5 when any other screen reader is not being run" -msgstr "他のスクリーンリーダーが起動していないときは、Sapi5を利用する" - -#: ../src\wxUI\dialogs\configuration.py:44 -msgid "Hide GUI on launch" -msgstr "起動時にGUIを隠す" - -#: ../src\wxUI\dialogs\configuration.py:46 -msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" -msgstr "" -"Codeofduskを利用して長いツイートをできるようにする(パフォーマンスが低下する" -"場合があります)" - -#: ../src\wxUI\dialogs\configuration.py:48 -msgid "Remember state for mention all and long tweet" -msgstr "" -"「全員にリプライ」および「ツイートを短縮して投稿」のチェック状態を保持する" - -#: ../src\wxUI\dialogs\configuration.py:51 -msgid "Keymap" -msgstr "キーマップ" - -#: ../src\wxUI\dialogs\configuration.py:56 -msgid "Check for updates when {0} launches" -msgstr "{0}の起動時にアップデートを確認" - -#: ../src\wxUI\dialogs\configuration.py:66 -msgid "Proxy type: " -msgstr "プロキシタイプ: " - -#: ../src\wxUI\dialogs\configuration.py:73 -msgid "Proxy server: " -msgstr "プロキシサーバー:" - -#: ../src\wxUI\dialogs\configuration.py:79 -msgid "Port: " -msgstr "ポート:" - -#: ../src\wxUI\dialogs\configuration.py:85 -msgid "User: " -msgstr "ユーザー名:" - -#: ../src\wxUI\dialogs\configuration.py:91 -msgid "Password: " -msgstr "パスワード:" - -#: ../src\wxUI\dialogs\configuration.py:103 -msgid "Autocompletion settings..." -msgstr "自動保管の設定" - -#: ../src\wxUI\dialogs\configuration.py:105 -msgid "Relative timestamps" -msgstr "相対的な時刻を利用する" - -#: ../src\wxUI\dialogs\configuration.py:108 -msgid "Items on each API call" -msgstr "各API呼び出しの回数" - -#: ../src\wxUI\dialogs\configuration.py:114 -msgid "" -"Inverted buffers: The newest tweets will be shown at the beginning while the " -"oldest at the end" -msgstr "" -"バッファの並び順を入れ替える(新しいツイートを先頭に、古いツイートを最後に表" -"示)" - -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet mode" -msgstr "リツイートのモード" - -#: ../src\wxUI\dialogs\configuration.py:122 -msgid "Show screen names instead of full names" -msgstr "表示名の代わりに、ユーザー名を表示する" - -#: ../src\wxUI\dialogs\configuration.py:124 -msgid "" -"Number of items per buffer to cache in database (0 to disable caching, blank " -"for unlimited)" -msgstr "" -"バッファごとにデータベースにキャッシュする項目数(0はキャッシュしない、空欄の" -"場合は無制限)" - -#: ../src\wxUI\dialogs\configuration.py:134 -msgid "Enable automatic speech feedback" -msgstr "自動音声フィードバックを有効化" - -#: ../src\wxUI\dialogs\configuration.py:136 -msgid "Enable automatic Braille feedback" -msgstr "自動点字フィードバックを有効化" - -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "ステータス" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Buffer" -msgstr "バッファ" - -#: ../src\wxUI\dialogs\configuration.py:147 -msgid "Show/hide" -msgstr "表示または非表示" - -#: ../src\wxUI\dialogs\configuration.py:148 -msgid "Move up" -msgstr "上へ" - -#: ../src\wxUI\dialogs\configuration.py:149 -msgid "Move down" -msgstr "下へ" - -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 -msgid "Show" -msgstr "表示" - -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 -msgid "Hide" -msgstr "非表示" - -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 -msgid "Select a buffer first." -msgstr "最初にバッファを選んでください" - -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 -msgid "The buffer is hidden, show it first." -msgstr "そのバッファは非表示状態です。まず最初に、表示してください" - -#: ../src\wxUI\dialogs\configuration.py:175 -msgid "The buffer is already at the top of the list." -msgstr "既にそのバッファは、リストの先頭です" - -#: ../src\wxUI\dialogs\configuration.py:199 -msgid "The buffer is already at the bottom of the list." -msgstr "既にそのバッファは、リストの最後です" - -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 -msgid "Ignored clients" -msgstr "無視するクライアント" - -#: ../src\wxUI\dialogs\configuration.py:247 -msgid "Remove client" -msgstr "クライアントを削除" - -#: ../src\wxUI\dialogs\configuration.py:271 -msgid "Volume" -msgstr "ボリューム" - -#: ../src\wxUI\dialogs\configuration.py:282 -msgid "Session mute" -msgstr "セッションのミュート" - -#: ../src\wxUI\dialogs\configuration.py:284 -msgid "Output device" -msgstr "出力先デバイス" - -#: ../src\wxUI\dialogs\configuration.py:291 -msgid "Input device" -msgstr "入力デバイス" - -#: ../src\wxUI\dialogs\configuration.py:299 -msgid "Sound pack" -msgstr "サウンドパック" - -#: ../src\wxUI\dialogs\configuration.py:305 -msgid "Indicate audio tweets with sound" -msgstr "音声付きツイートを音で報告" - -#: ../src\wxUI\dialogs\configuration.py:307 -msgid "Indicate geotweets with sound" -msgstr "位置情報付きツイートを音で報告" - -#: ../src\wxUI\dialogs\configuration.py:309 -msgid "Indicate tweets containing images with sound" -msgstr "画像付きツイートを音で報告" - -#: ../src\wxUI\dialogs\configuration.py:332 -msgid "Language for OCR" -msgstr "OCRの言語" - -#: ../src\wxUI\dialogs\configuration.py:338 -msgid "API Key for SndUp" -msgstr "SndUpのAPIキー" - -#: ../src\wxUI\dialogs\configuration.py:353 -msgid "{0} preferences" -msgstr "{0}の設定" - -#: ../src\wxUI\dialogs\configuration.py:364 -msgid "Proxy" -msgstr "プロキシ" - -#: ../src\wxUI\dialogs\configuration.py:373 -msgid "Feedback" -msgstr "フィードバック" - -#: ../src\wxUI\dialogs\configuration.py:377 -msgid "Buffers" -msgstr "バッファ" - -#: ../src\wxUI\dialogs\configuration.py:385 -msgid "Sound" -msgstr "サウンド" - -#: ../src\wxUI\dialogs\configuration.py:389 -msgid "Extras" -msgstr "その他" - -#: ../src\wxUI\dialogs\configuration.py:394 -msgid "Save" -msgstr "保存" - -#: ../src\wxUI\dialogs\filterDialogs.py:15 -msgid "Create a filter for this buffer" -msgstr "このバッファのフィルタを作成" - -#: ../src\wxUI\dialogs\filterDialogs.py:16 -msgid "Filter title" -msgstr "フィルター名" - -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by word" -msgstr "単語でフィルター" - -#: ../src\wxUI\dialogs\filterDialogs.py:26 -msgid "Ignore tweets wich contain the following word" -msgstr "次の単語が含まれるツイートを無視する" - -#: ../src\wxUI\dialogs\filterDialogs.py:27 -msgid "Ignore tweets without the following word" -msgstr "次の単語が含まれないツイートを無視する" - -#: ../src\wxUI\dialogs\filterDialogs.py:32 -msgid "word" -msgstr "単語" - -#: ../src\wxUI\dialogs\filterDialogs.py:37 -msgid "Allow retweets" -msgstr "リツイートを許可する" - -#: ../src\wxUI\dialogs\filterDialogs.py:38 -msgid "Allow quoted tweets" -msgstr "引用ツイートを許可する" - -#: ../src\wxUI\dialogs\filterDialogs.py:39 -msgid "Allow replies" -msgstr "リプライを許可するフォロワー一覧" - -#: ../src\wxUI\dialogs\filterDialogs.py:47 -msgid "Use this term as a regular expression" -msgstr "正規表現を利用" - -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by language" -msgstr "言語でフィルター" - -#: ../src\wxUI\dialogs\filterDialogs.py:50 -msgid "Load tweets in the following languages" -msgstr "下記の言語のツイートを表示" - -#: ../src\wxUI\dialogs\filterDialogs.py:51 -msgid "Ignore tweets in the following languages" -msgstr "下記の言語のツイートを無視する" - -#: ../src\wxUI\dialogs\filterDialogs.py:52 -msgid "Don't filter by language" -msgstr "言語でフィルタしない" - -#: ../src\wxUI\dialogs\filterDialogs.py:63 -msgid "Supported languages" -msgstr "サポートしている言語" - -#: ../src\wxUI\dialogs\filterDialogs.py:68 -msgid "Add selected language to filter" -msgstr "選択した言語をフィルターに追加" - -#: ../src\wxUI\dialogs\filterDialogs.py:72 -msgid "Selected languages" -msgstr "選択した言語" - -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 -msgid "Remove" -msgstr "削除" - -#: ../src\wxUI\dialogs\filterDialogs.py:122 -msgid "Manage filters" -msgstr "フィルターの管理" - -#: ../src\wxUI\dialogs\filterDialogs.py:124 -msgid "Filters" -msgstr "フィルター" - -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter" -msgstr "フィルター" - -#: ../src\wxUI\dialogs\find.py:12 -msgid "Find in current buffer" -msgstr "現在のバッファ内を検索" - -#: ../src\wxUI\dialogs\find.py:13 -msgid "String" -msgstr "検索文字" - -#: ../src\wxUI\dialogs\lists.py:10 -msgid "Lists manager" -msgstr "リストの管理" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "List" -msgstr "リスト" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Members" -msgstr "メンバー" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Owner" -msgstr "所有者" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "mode" -msgstr "モード" - -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 -msgid "Create a new list" -msgstr "新しいリストを作成" - -#: ../src\wxUI\dialogs\lists.py:21 -msgid "Open in buffer" -msgstr "バッファで開く" - -#: ../src\wxUI\dialogs\lists.py:51 -msgid "Viewing lists for %s" -msgstr "「%s」のリストを閲覧中" - -#: ../src\wxUI\dialogs\lists.py:52 -msgid "Subscribe" -msgstr "登録" - -#: ../src\wxUI\dialogs\lists.py:53 -msgid "Unsubscribe" -msgstr "登録解除" - -#: ../src\wxUI\dialogs\lists.py:64 -msgid "Name (20 characters maximun)" -msgstr "名前(二〇文字以内)" - -#: ../src\wxUI\dialogs\lists.py:74 -msgid "Mode" -msgstr "モード" - -#: ../src\wxUI\dialogs\lists.py:75 -msgid "Public" -msgstr "公開" - -#: ../src\wxUI\dialogs\lists.py:76 -msgid "Private" -msgstr "プライベート" - -#: ../src\wxUI\dialogs\lists.py:96 -msgid "Editing the list %s" -msgstr "リスト「%s」を編集中" - -#: ../src\wxUI\dialogs\lists.py:107 -msgid "Select a list to add the user" -msgstr "ユーザーを追加するリストを選択" - -#: ../src\wxUI\dialogs\lists.py:108 -msgid "Add" -msgstr "追加" - -#: ../src\wxUI\dialogs\lists.py:130 -msgid "Select a list to remove the user" -msgstr "ユーザーを削除するには、リストを選択" - -#: ../src\wxUI\dialogs\lists.py:148 -msgid "Do you really want to delete this list?" -msgstr "本当に、このリストを削除しますか?" - -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "ツイートを短縮して投稿(&L)" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "画像をアップロード(&U)" - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 -msgid "Check &spelling..." -msgstr "スペルチェック(&S)" - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "音声を添付(&A)" - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "URLを短縮(&O)" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 -msgid "&Expand URL" -msgstr "URLを元に戻す(&E)" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 -msgid "&Translate..." -msgstr "翻訳(&T)..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "ユーザーを自動保管(&C)" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "送信(&D)" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 -msgid "C&lose" -msgstr "閉じる(&C)" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "送信先(&R)" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "全員にリプライ(&M)" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "ツイート - %i文字" - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "画像の説明" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "リツイート:" - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "いいね" - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "ソース:" - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -#, fuzzy -msgid "Date: " -msgstr "日時" - -#: ../src\wxUI\dialogs\message.py:405 -msgid "View" -msgstr "ツイート" - -#: ../src\wxUI\dialogs\message.py:407 -msgid "Item" -msgstr "アイテム" - -#: ../src\wxUI\dialogs\search.py:13 -msgid "Search on Twitter" -msgstr "ツイッターを検索" - -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 -msgid "&Search" -msgstr "検索(&S)" - -#: ../src\wxUI\dialogs\search.py:21 -msgid "Tweets" -msgstr "ツイート" - -#: ../src\wxUI\dialogs\search.py:22 -msgid "Users" -msgstr "ユーザー" - -#: ../src\wxUI\dialogs\search.py:29 -msgid "&Language for results: " -msgstr "結果の言語(&L):" - -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 -msgid "any" -msgstr "指定しない" - -#: ../src\wxUI\dialogs\search.py:37 -msgid "Results &type: " -msgstr "結果のタイプ(&T):" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 -msgid "Mixed" -msgstr "混合" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 -msgid "Recent" -msgstr "最近" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 -msgid "Popular" -msgstr "人気" - -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 -msgid "&OK" -msgstr "OK(&O)" - -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 -msgid "&Close" -msgstr "閉じる(&C)" - -#: ../src\wxUI\dialogs\show_user.py:11 -msgid "Details" -msgstr "詳細" - -#: ../src\wxUI\dialogs\show_user.py:16 -msgid "&Go to URL" -msgstr "URLへ移動(&G)" - -#: ../src\wxUI\dialogs\trends.py:12 -msgid "View trending topics" -msgstr "トレンドの話題を表示" - -#: ../src\wxUI\dialogs\trends.py:13 -msgid "Trending topics by" -msgstr "トレンドの話題" - -#: ../src\wxUI\dialogs\trends.py:15 -msgid "Country" -msgstr "国" - -#: ../src\wxUI\dialogs\trends.py:16 -msgid "City" -msgstr "都市" - -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 -msgid "&Location" -msgstr "場所(&L)" - -#: ../src\wxUI\dialogs\update_profile.py:9 -msgid "Update your profile" -msgstr "プロフィールを更新" - -#: ../src\wxUI\dialogs\update_profile.py:11 -msgid "&Name (50 characters maximum)" -msgstr "名前(50文字以内)(&N)" - -#: ../src\wxUI\dialogs\update_profile.py:22 -msgid "&Website" -msgstr "ウェブサイト(&W)" - -#: ../src\wxUI\dialogs\update_profile.py:27 -msgid "&Bio (160 characters maximum)" -msgstr "自己紹介(160文字以内)(&B)" - -#: ../src\wxUI\dialogs\update_profile.py:33 -msgid "Upload a &picture" -msgstr "画像をアップロード(&P)" - -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 -msgid "&Update profile" -msgstr "プロフィールを更新(&U)" - -#: ../src\wxUI\dialogs\update_profile.py:76 -msgid "Upload a picture" -msgstr "画像をアップロード" - -#: ../src\wxUI\dialogs\update_profile.py:78 -msgid "Discard image" -msgstr "画像をアップロードできません" - -#: ../src\wxUI\dialogs\urlList.py:5 -msgid "Select URL" -msgstr "URLを選択" - -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 -msgid "&User" -msgstr "ユーザー(&U)" - -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 -msgid "&Autocomplete users" -msgstr "自動保管されたユーザー" - -#: ../src\wxUI\dialogs\userActions.py:19 -msgid "&Follow" -msgstr "フォロー(&F)" - -#: ../src\wxUI\dialogs\userActions.py:20 -msgid "U&nfollow" -msgstr "フォロー解除(&N)" - -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 -msgid "&Mute" -msgstr "ミュート(&M)" - -#: ../src\wxUI\dialogs\userActions.py:22 -msgid "Unmu&te" -msgstr "ミュート解除(&T)" - -#: ../src\wxUI\dialogs\userActions.py:23 -msgid "&Block" -msgstr "ブロック(&B)" - -#: ../src\wxUI\dialogs\userActions.py:24 -msgid "Unbl&ock" -msgstr "ブロック解除(&O)" - -#: ../src\wxUI\dialogs\userActions.py:25 -msgid "&Report as spam" -msgstr "スパムとして報告(&R)" - -#: ../src\wxUI\dialogs\userActions.py:26 -msgid "&Ignore tweets from this client" -msgstr "このクライアントからのツイートを無視(&I)" - -#: ../src\wxUI\dialogs\userSelection.py:9 -msgid "Timeline for %s" -msgstr "「%s」のタイムライン" - -#: ../src\wxUI\dialogs\userSelection.py:18 -msgid "Buffer type" -msgstr "バッファのタイプ" - -#: ../src\wxUI\dialogs\userSelection.py:19 -msgid "&Tweets" -msgstr "ツイート(&T)" - -#: ../src\wxUI\dialogs\userSelection.py:20 -msgid "&Likes" -msgstr "いいね(&L)" - -#: ../src\wxUI\dialogs\userSelection.py:21 -msgid "&Followers" -msgstr "フォロワー(&F)" - -#: ../src\wxUI\dialogs\userSelection.py:22 -msgid "F&riends" -msgstr "フォロー(&R)" - -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 -msgid "&Retweet" -msgstr "リツイート(&R)" - -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 -msgid "Re&ply" -msgstr "リプライ(&P)" - -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 -msgid "&Like" -msgstr "いいね(&L)" - -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 -msgid "&Unlike" -msgstr "いいねを解除(&U)" - -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 -msgid "&Open URL" -msgstr "URLを開く(&O)" - -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -#, fuzzy -msgid "&Open in Twitter" -msgstr "ツイッターを検索" - -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 -msgid "&Play audio" -msgstr "音声を再生(&P)" - -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 -msgid "&Show tweet" -msgstr "ツイートを表示(&S)" - -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 -msgid "&Copy to clipboard" -msgstr "クリップボードにコピー(&C)" - -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 -msgid "&Delete" -msgstr "削除(&D)" - -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 -msgid "&User actions..." -msgstr "ユーザーのアクション(&U)" - -#: ../src\wxUI\menus.py:39 -msgid "&Show direct message" -msgstr "ダイレクトメッセージを表示(&S)" - -#: ../src\wxUI\menus.py:67 -msgid "&Show event" -msgstr "イベントを表示(&S)" - -#: ../src\wxUI\menus.py:77 -msgid "Direct &message" -msgstr "ダイレクトメッセージ(&M)" - -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 -msgid "&View lists" -msgstr "リストを見る(&V)" - -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 -msgid "Show user &profile" -msgstr "ユーザーのプロフィールを表示(&P)" - -#: ../src\wxUI\menus.py:84 -msgid "&Show user" -msgstr "ユーザーを表示(&S)" - -#: ../src\wxUI\menus.py:98 -msgid "&Tweet about this trend" -msgstr "このトレンドのツイート(&T)" - -#: ../src\wxUI\menus.py:100 -msgid "&Show item" -msgstr "アイテムを表示(&S)" - -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 -msgid "&Global settings" -msgstr "全般設定(&G)" - -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 -msgid "Account se&ttings" -msgstr "アカウント設定(&T(" - -#: ../src\wxUI\sysTrayIcon.py:37 -msgid "Update &profile" -msgstr "プロフィールを更新(&P)" - -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "&Show / hide" -msgstr "表示または非表示(&S)" - -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 -msgid "&Documentation" -msgstr "取扱説明書(&D)" - -#: ../src\wxUI\sysTrayIcon.py:40 -msgid "Check for &updates" -msgstr "アップデートを確認(&U)" - -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "&Exit" -msgstr "終了(&E)" - -#: ../src\wxUI\view.py:16 -msgid "&Manage accounts" -msgstr "アカウントの管理(&M)" - -#: ../src\wxUI\view.py:18 -msgid "&Hide window" -msgstr "ウィンドウを隠す(&H)" - -#: ../src\wxUI\view.py:20 -msgid "&Lists manager" -msgstr "リストの管理(&L)" - -#: ../src\wxUI\view.py:21 -msgid "&Edit keystrokes" -msgstr "キーストロークを編集(&E)" - -#: ../src\wxUI\view.py:24 -msgid "E&xit" -msgstr "終了(&X)" - -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 -msgid "&Tweet" -msgstr "ツイート(&T)" - -#: ../src\wxUI\view.py:34 -msgid "View &address" -msgstr "位置情報を表示(&A)" - -#: ../src\wxUI\view.py:35 -msgid "View conversa&tion" -msgstr "会話を見る(&T)" - -#: ../src\wxUI\view.py:36 -msgid "Read text in picture" -msgstr "画像からテキストを読み取り" - -#: ../src\wxUI\view.py:41 -msgid "&Actions..." -msgstr "操作(&A)" - -#: ../src\wxUI\view.py:42 -msgid "&View timeline..." -msgstr "タイムラインを表示(&V)" - -#: ../src\wxUI\view.py:43 -msgid "Direct me&ssage" -msgstr "ダイレクトメッセージ(&S)" - -#: ../src\wxUI\view.py:44 -msgid "&Add to list" -msgstr "リストに追加(&A)" - -#: ../src\wxUI\view.py:45 -msgid "R&emove from list" -msgstr "リストから削除(&E)" - -#: ../src\wxUI\view.py:48 -msgid "V&iew likes" -msgstr "いいね一覧を見る(&I)" - -#: ../src\wxUI\view.py:52 -msgid "&Update buffer" -msgstr "バッファを更新(&U)" - -#: ../src\wxUI\view.py:53 -msgid "New &trending topics buffer..." -msgstr "新しいトレンドの話題のバッファ(&T)" - -#: ../src\wxUI\view.py:54 -msgid "Create a &filter" -msgstr "新しいフィルターを作成(&F)" - -#: ../src\wxUI\view.py:55 -msgid "&Manage filters" -msgstr "フィルターの管理(&M)" - -#: ../src\wxUI\view.py:56 -msgid "Find a string in the currently focused buffer..." -msgstr "現在フォーカス中のバッファ内の文字列を検索" - -#: ../src\wxUI\view.py:57 -msgid "&Load previous items" -msgstr "以前のアイテムを取得(&L)" - -#: ../src\wxUI\view.py:60 -msgid "&Autoread" -msgstr "自動読み上げ(&A)" - -#: ../src\wxUI\view.py:61 -msgid "&Clear buffer" -msgstr "バッファをクリア(&C)" - -#: ../src\wxUI\view.py:62 -msgid "&Destroy" -msgstr "バッファを削除(&D)" - -#: ../src\wxUI\view.py:66 -msgid "&Seek back 5 seconds" -msgstr "5秒戻る(&S)" - -#: ../src\wxUI\view.py:67 -msgid "&Seek forward 5 seconds" -msgstr "5秒進む(&S)" - -#: ../src\wxUI\view.py:72 -msgid "Sounds &tutorial" -msgstr "サウンドの確認(&T)" - -#: ../src\wxUI\view.py:73 -msgid "&What's new in this version?" -msgstr "更新履歴(&W)" - -#: ../src\wxUI\view.py:74 -msgid "&Check for updates" -msgstr "アップデートを確認(&C)" - -#: ../src\wxUI\view.py:75 -msgid "&Report an error" -msgstr "エラーを報告(&R)" - -#: ../src\wxUI\view.py:76 -msgid "{0}'s &website" -msgstr "「{0}」のウェブサイト(&W)" - -#: ../src\wxUI\view.py:77 -msgid "Get soundpacks for TWBlue" -msgstr "" - -#: ../src\wxUI\view.py:78 -msgid "About &{0}" -msgstr "{0}について(&A)" - -#: ../src\wxUI\view.py:81 -msgid "&Application" -msgstr "アプリケーション(&A)" - -#: ../src\wxUI\view.py:84 -msgid "&Buffer" -msgstr "バッファ(&B)" - -#: ../src\wxUI\view.py:85 -msgid "&Audio" -msgstr "音声(&A)" - -#: ../src\wxUI\view.py:86 -msgid "&Help" -msgstr "ヘルプ(&H)" - -#: ../src\wxUI\view.py:172 -msgid "Address" -msgstr "アドレス" - -#: ../src\wxUI\view.py:203 -msgid "Update" -msgstr "アップデート" - -#: ../src\wxUI\view.py:203 -msgid "Your {0} version is up to date" -msgstr "「{0}」のバージョンは最新です" - -#~ msgid "Empty" -#~ msgstr "何もありません" - -#~ msgid "One mention from %s " -#~ msgstr "%sからの返信" - -#~ msgid "One tweet from %s" -#~ msgstr "「%s」からのツイート" - -#~ msgid "You've blocked %s" -#~ msgstr "「%s」をブロックしました。" - -#~ msgid "You've unblocked %s" -#~ msgstr "「%s」のブロックを解除しました" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "「%s: @%s」がフォローしました" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "「%s: @%s」をフォローしました" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "「%s: @%s」のフォローを解除しました" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "%s %sをいいねしました" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "%s(@%s)が「%s」をいいねしました" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "%s %sのいいねを解除しました" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "%s(@%s)が%sのいいねを解除しました" - -#~ msgid "You've created the list %s" -#~ msgstr "リスト「%s」を作成しました" - -#~ msgid "You've deleted the list %s" -#~ msgstr "リスト「%s」を削除しました" - -#~ msgid "You've updated the list %s" -#~ msgstr "リスト「%s」をアップデートしました" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "「%s: @%s」をリスト「%s」に追加しました" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "「%s: @%s」がリスト「%s」にあなたを追加しました" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "「%s: @%s」をリスト「%s」から削除しました" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "「%s: @%s」がリスト「%s」からあなたを削除しました" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "「%s: @%s」によって所有されているリスト「%s」に加入しました" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "「%s(@%s)」があなたのリスト「%s」を購読しました" - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "「%s: @%s」によって所有されているリスト「%s」から退会しました" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "「%s: @%s」によって所有されているリスト「%s」から退会してきました" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "「%s: @%s」がリツイートした「%s」をリツイートしました" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "「%s: @%s」があなたのリツイート「%s」をリツイートしました" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "APIの呼び出し数(1回のAPIの呼び出し=200、2回のAPIの呼び出し=400、など)" - -#~ msgid "Unable to upload the audio" -#~ msgstr "音声をアップロードできません" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "アカウント連携を待機しています…" - -#~ msgid "autodetect" -#~ msgstr "自動検出" - -#~ msgid "" -#~ "There's a new %s version available. Would you like to download it now?\n" -#~ "\n" -#~ " %s version: %s\n" -#~ "\n" -#~ "Changes:\n" -#~ "%s" -#~ msgstr "" -#~ "「%s」の新しいバージョンが利用可能です。今すぐダウンロードしますか?\n" -#~ "\n" -#~ "%sバージョン: %s\n" -#~ "\n" -#~ "更新履歴\n" -#~ "%s" - -#~ msgid "Start {0} after logging in windows" -#~ msgstr "Windowsログオン後に{0}を起動" - -#~ msgid "" -#~ "If you have a SndUp account, enter your API Key here. If your API Key is " -#~ "invalid, {0} will fail to upload. If there is no API Key here, {0} will " -#~ "upload annonymously." -#~ msgstr "" -#~ "SndUpアカウントをお持ちの場合は、ここにAPIキーを入力してください。APIキー" -#~ "が無効である場合、{0}のアップロードに失敗します。APIキーが存在しない場合" -#~ "は、{0}は、匿名でアップロードされます。" - -#~ msgid "Disconnect your Pocket account" -#~ msgstr "Poketとの連携を解除" - -#~ msgid "Connect your Pocket account" -#~ msgstr "Pocketアカウントと連携" - -#~ msgid "Pocket Authorization" -#~ msgstr "Pocketの認証" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. You only need " -#~ "to do this once. Do you want to continue?" -#~ msgstr "" -#~ "認証要求をブラウザで開きます。一度だけこれを実行する必要があります。続行し" -#~ "ますか?" - -#~ msgid "Error during authorization. Try again later." -#~ msgstr "認証中にエラーが発生しました。後でやり直してください。" - -#~ msgid "Services" -#~ msgstr "サービス" - -#~ msgid "Contains" -#~ msgstr "含む" - -#~ msgid "Doesn't contain" -#~ msgstr "含まない" - -#~ msgid "" -#~ "You have successfully logged into Twitter with {0}. You can close this " -#~ "window now." -#~ msgstr "" -#~ "{0}でのTwitterのログインに成功しました。今すぐこのウィンドウを閉じることが" -#~ "できます。" diff --git a/src/locales/ja/lc_messages/twblue.mo b/src/locales/ja/lc_messages/twblue.mo index 57e2037089b38b9a0f1f6ebbc8a610323355865f..ad4f40e33e172543b2718cb2824da4fc3fccc886 100644 GIT binary patch delta 19283 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 Xq@8snuU&Co(Eq1tm?zv0@x=WPH7&!o diff --git a/src/locales/ja/lc_messages/twblue.po b/src/locales/ja/lc_messages/twblue.po index cb3a697e..cc77b537 100644 --- a/src/locales/ja/lc_messages/twblue.po +++ b/src/locales/ja/lc_messages/twblue.po @@ -5,290 +5,165 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2019-07-06 23:53+0900\n" -"Last-Translator: Manuel Cortez \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-22 12:23+0900\n" +"PO-Revision-Date: 2021-01-22 12:49+0900\n" +"Last-Translator: 陸 \n" "Language-Team: \n" "Language: ja_JP\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.2.3\n" +"X-Generator: Poedit 2.4.2\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../src\controller\attach.py:23 +#: src\languageHandler.py:99 +msgid "User default" +msgstr "ユーザーのデフォルト" + +#: src\main.py:107 +msgid "https://twblue.es/donate" +msgstr "https://twblue.es/donate" + +#: src\main.py:124 +#, python-brace-format +msgid "" +"{0} is already running. Close the other instance before starting this one. " +"If you're sure that {0} isn't running, try deleting the file at {1}. If " +"you're unsure of how to do this, contact the {0} developers." +msgstr "" +"{0}は、すでに実行されています。このインスタンスを開始する前に、他のインスタン" +"スを閉じてください。{0}が実行されていないことが確実な場合は、{1}でファイルを" +"削除してみてください。これを行う方法がわからない場合は、{0}開発者に連絡してく" +"ださい。" + +#: src\sound.py:146 src\extra\AudioUploader\audioUploader.py:136 +msgid "Playing..." +msgstr "再生中…" + +#: src\sound.py:159 +msgid "Stopped." +msgstr "停止。" + +#: src\controller\attach.py:25 msgid "Photo" msgstr "画像" -#: ../src\controller\buffers\baseBuffers.py:95 -msgid "This action is not supported for this buffer" -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 -msgid "Home" -msgstr "ホーム" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 -msgid "Mentions" -msgstr "メンション" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 -msgid "Direct messages" -msgstr "ダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 -msgid "Sent direct messages" -msgstr "送信済みのダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 -msgid "Sent tweets" -msgstr "送信済みのツイート" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 -msgid "Likes" -msgstr "いいね" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 -msgid "Followers" -msgstr "フォロワー" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "フォロー" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 -msgid "Blocked users" -msgstr "ブロックしたユーザー" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 -msgid "Muted users" -msgstr "ミューとしたユーザー" - -#: ../src\controller\buffers\twitterBuffers.py:75 -msgid "{username}'s timeline" -msgstr "「{username}」のタイムライン" - -#: ../src\controller\buffers\twitterBuffers.py:77 -msgid "{username}'s likes" -msgstr "「{username}」のいいね一覧" - -#: ../src\controller\buffers\twitterBuffers.py:79 -msgid "{username}'s followers" -msgstr "「{username}」のフォロワー" - -#: ../src\controller\buffers\twitterBuffers.py:81 -msgid "{username}'s friends" -msgstr "「{username}」のフォロー" - -#: ../src\controller\buffers\twitterBuffers.py:83 -msgid "Unknown buffer" -msgstr "不明なバッファ" - -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 -msgid "Tweet" -msgstr "ツイート" - -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 -msgid "Write the tweet here" -msgstr "ツイートを入力" - -#: ../src\controller\buffers\twitterBuffers.py:194 -msgid "New tweet in {0}" -msgstr "「{0}」への新規ツイート" - -#: ../src\controller\buffers\twitterBuffers.py:197 -msgid "{0} new tweets in {1}." -msgstr "「{1}」への{0}個の新規ツイート" - -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 -msgid "%s items retrieved" -msgstr "%s個のアイテムを取得しました" - -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "このバッファは、タイムラインではないため、削除できません" - -#: ../src\controller\buffers\twitterBuffers.py:402 -msgid "Reply to {arg0}" -msgstr "「{arg0}」への返信:" - -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 -msgid "Reply" -msgstr "返信" - -#: ../src\controller\buffers\twitterBuffers.py:405 -msgid "Reply to %s" -msgstr "「%s」への返信" - -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "「%s」へのダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 -msgid "New direct message" -msgstr "新しいダイレクトメッセージ" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Add your comment to the tweet" -msgstr "ツイートにコメントを追加" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Quote" -msgstr "引用" - -#: ../src\controller\buffers\twitterBuffers.py:572 -msgid "Opening URL..." -msgstr "URLを開いています" - -#: ../src\controller\buffers\twitterBuffers.py:607 -msgid "User details" -msgstr "ユーザーの詳細" - -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 -msgid "Opening item in web browser..." -msgstr "アイテムをブラウザで開いています…" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -msgid "Mention to %s" -msgstr "%sへのメンション" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 -msgid "Mention" -msgstr "メンション" - -#: ../src\controller\buffers\twitterBuffers.py:728 -#, fuzzy -msgid "{0} new direct messages." -msgstr "新しいダイレクトメッセージ " - -#: ../src\controller\buffers\twitterBuffers.py:731 -#, fuzzy -msgid "This action is not supported in the buffer yet." -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: ../src\controller\buffers\twitterBuffers.py:741 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" -"このバッファでは、これ以上のアイテムを取得することはできません。代わりに、" -"「ダイレクトメッセージ」バッファを使用してください。" - -#: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy -msgid "{0} new followers." -msgstr "新しいフォロワー" - -#: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy -msgid "This action is not supported in the buffer, yet." -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: ../src\controller\mainController.py:273 +#: src\controller\mainController.py:272 msgid "Ready" msgstr "準備完了" -#: ../src\controller\mainController.py:345 +#: src\controller\mainController.py:305 src\controller\settings.py:285 +#: src\controller\buffers\twitterBuffers.py:70 +msgid "Home" +msgstr "ホーム" + +#: src\controller\mainController.py:309 src\controller\settings.py:286 +#: src\controller\buffers\twitterBuffers.py:70 +msgid "Mentions" +msgstr "メンション" + +#: src\controller\mainController.py:313 +#: src\controller\buffers\twitterBuffers.py:70 +msgid "Direct messages" +msgstr "ダイレクトメッセージ" + +#: src\controller\mainController.py:317 src\controller\settings.py:288 +#: src\controller\buffers\twitterBuffers.py:70 +msgid "Sent direct messages" +msgstr "送信済みのダイレクトメッセージ" + +#: src\controller\mainController.py:321 src\controller\settings.py:289 +#: src\controller\buffers\twitterBuffers.py:70 +msgid "Sent tweets" +msgstr "送信済みのツイート" + +#: src\controller\mainController.py:325 src\controller\mainController.py:1362 +#: src\controller\settings.py:290 src\controller\buffers\twitterBuffers.py:70 +msgid "Likes" +msgstr "いいね" + +#: src\controller\mainController.py:329 src\controller\mainController.py:1367 +#: src\controller\settings.py:291 src\controller\buffers\twitterBuffers.py:70 +msgid "Followers" +msgstr "フォロワー" + +#: src\controller\mainController.py:333 src\controller\mainController.py:1372 +#: src\controller\settings.py:292 src\controller\buffers\twitterBuffers.py:70 +msgid "Friends" +msgstr "フォロー" + +#: src\controller\mainController.py:337 src\controller\mainController.py:1377 +#: src\controller\settings.py:293 src\controller\buffers\twitterBuffers.py:70 +msgid "Blocked users" +msgstr "ブロックしたユーザー" + +#: src\controller\mainController.py:341 src\controller\mainController.py:1382 +#: src\controller\settings.py:294 src\controller\buffers\twitterBuffers.py:70 +msgid "Muted users" +msgstr "ミューとしたユーザー" + +#: src\controller\mainController.py:344 msgid "Timelines" msgstr "タイムライン" -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 +#: src\controller\mainController.py:348 src\controller\mainController.py:859 +#: src\controller\mainController.py:1558 msgid "Timeline for {}" msgstr "「{}」のタイムライン" -#: ../src\controller\mainController.py:352 +#: src\controller\mainController.py:351 msgid "Likes timelines" msgstr "ほかのユーザーのいいね一覧" -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 +#: src\controller\mainController.py:355 src\controller\mainController.py:878 +#: src\controller\mainController.py:1560 msgid "Likes for {}" msgstr "{}のいいね一覧" -#: ../src\controller\mainController.py:359 +#: src\controller\mainController.py:358 msgid "Followers' Timelines" msgstr "フォロワー一覧" -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 +#: src\controller\mainController.py:362 src\controller\mainController.py:897 +#: src\controller\mainController.py:1562 msgid "Followers for {}" msgstr "{}をフォローしているユーザー" -#: ../src\controller\mainController.py:366 +#: src\controller\mainController.py:365 msgid "Friends' Timelines" msgstr "フォロー一覧" -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 +#: src\controller\mainController.py:369 src\controller\mainController.py:916 +#: src\controller\mainController.py:1564 msgid "Friends for {}" msgstr "{}がフォローしているユーザー" -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 +#: src\controller\mainController.py:372 src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "リスト" -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 +#: src\controller\mainController.py:377 src\controller\mainController.py:1398 msgid "List for {}" msgstr "{}のリスト" -#: ../src\controller\mainController.py:381 +#: src\controller\mainController.py:380 msgid "Searches" msgstr "検索" -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 +#: src\controller\mainController.py:384 src\controller\mainController.py:443 msgid "Search for {}" msgstr "「{}」の検索結果" -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 +#: src\controller\mainController.py:390 src\controller\mainController.py:958 +#, python-format msgid "Trending topics for %s" -msgstr "{}の話題のトピック" +msgstr "%s のトレンド" -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 +#: src\controller\mainController.py:460 src\controller\mainController.py:476 +#: src\controller\mainController.py:1058 src\controller\mainController.py:1077 +#: src\controller\mainController.py:1096 src\controller\mainController.py:1115 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." @@ -296,285 +171,296 @@ msgstr "" "セッションが選択されていません。「次のセッション」または「前のセッション」の" "ショートカットを利用して、セッションを選択してください。" -#: ../src\controller\mainController.py:465 +#: src\controller\mainController.py:464 msgid "Empty buffer." -msgstr "バッファをクリア" +msgstr "からのバッファ。" -#: ../src\controller\mainController.py:472 +#: src\controller\mainController.py:471 +#, python-brace-format msgid "{0} not found." msgstr "{0}が見つかりませんでした。" -#: ../src\controller\mainController.py:482 +#: src\controller\mainController.py:481 msgid "Filters cannot be applied on this buffer" -msgstr "" -"このバッファにフィルターは適応できません。その動作は、現在のバッファでは利用" -"できません。" +msgstr "このバッファにはフィルターを適応できません" -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 +#: src\controller\mainController.py:534 src\controller\mainController.py:551 +#: src\controller\mainController.py:579 msgid "Select the user" msgstr "ユーザーを選択" -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy +#: src\controller\mainController.py:808 src\controller\messages.py:242 msgid "MMM D, YYYY. H:m" -msgstr "YYYY年MMMMD日(dddd) H時m分s秒" +msgstr "YYYY年MMMMD日 H時m分" -#: ../src\controller\mainController.py:934 +#: src\controller\mainController.py:933 +#, python-brace-format msgid "Conversation with {0}" msgstr "{0}との会話" -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 +#: src\controller\mainController.py:974 src\controller\mainController.py:993 msgid "There are no coordinates in this tweet" -msgstr "このツイートには、ジェオタグは存在しません" +msgstr "このツイートに位置情報は存在しません" -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 +#: src\controller\mainController.py:976 src\controller\mainController.py:995 msgid "There are no results for the coordinates in this tweet" -msgstr "このツイートのジェオタグには、なにも含まれていません" +msgstr "このツイートの位置情報には、なにも含まれていません" -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 +#: src\controller\mainController.py:978 src\controller\mainController.py:997 msgid "Error decoding coordinates. Try again later." -msgstr "ジェオタグの取得に失敗しました" +msgstr "位置情報の取得に失敗しました。あとで再試行してください。" -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 +#: src\controller\mainController.py:1106 src\controller\mainController.py:1125 +#, python-format msgid "%s, %s of %s" msgstr "%s %s/%s" -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 +#: src\controller\mainController.py:1108 src\controller\mainController.py:1127 +#: src\controller\mainController.py:1152 src\controller\mainController.py:1177 +#, python-format msgid "%s. Empty" -msgstr "%sは、からです。" +msgstr "%sは、からです" -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 +#: src\controller\mainController.py:1140 src\controller\mainController.py:1144 +#: src\controller\mainController.py:1165 +#, python-brace-format msgid "{0}: This account is not logged into Twitter." -msgstr "このアカウント{0}は、まだツイッターにログインしていません" +msgstr "{0}: このアカウントは、まだTwitterにログインしていません。" -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 +#: src\controller\mainController.py:1150 src\controller\mainController.py:1175 +#, python-format msgid "%s. %s, %s of %s" -msgstr "セッション:%s %s %s/%s/" +msgstr "セッション:%s %s %s/%s" -#: ../src\controller\mainController.py:1170 +#: src\controller\mainController.py:1169 +#, python-brace-format msgid "{0}: This account is not logged into twitter." -msgstr "このアカウント{0}は、まだツイッターにログインしていません" +msgstr "{0}: このアカウントは、まだTwitterにログインしていません。" -#: ../src\controller\mainController.py:1388 +#: src\controller\mainController.py:1387 msgid "Events" msgstr "イベント" -#: ../src\controller\mainController.py:1393 +#: src\controller\mainController.py:1392 msgid "This list is already opened" msgstr "既に開かれています" -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 -#, fuzzy +#: src\controller\mainController.py:1422 src\controller\mainController.py:1438 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" -"バグを報告しようとしているときに、予期しないエラーが発生しました。後でやり直" -"してください" +"サーバーへの接続中に、予期しないエラーが発生しました。あとで再試行してくださ" +"い。" -#: ../src\controller\mainController.py:1475 +#: src\controller\mainController.py:1474 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "自動読み上げ 有効" -#: ../src\controller\mainController.py:1478 +#: src\controller\mainController.py:1477 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "自動読み上げ 無効" -#: ../src\controller\mainController.py:1485 +#: src\controller\mainController.py:1484 msgid "Session mute on" msgstr "このセッションのミュートを設定" -#: ../src\controller\mainController.py:1488 +#: src\controller\mainController.py:1487 msgid "Session mute off" msgstr "このセッションのミュートを解除" -#: ../src\controller\mainController.py:1496 +#: src\controller\mainController.py:1495 msgid "Buffer mute on" msgstr "このバッファのミュートを設定" -#: ../src\controller\mainController.py:1499 +#: src\controller\mainController.py:1498 msgid "Buffer mute off" msgstr "このバッファのミュートを解除" -#: ../src\controller\mainController.py:1522 +#: src\controller\mainController.py:1521 msgid "Copied" msgstr "コピーしました" -#: ../src\controller\mainController.py:1549 +#: src\controller\mainController.py:1548 msgid "Unable to update this buffer." msgstr "このバッファを更新できません。" -#: ../src\controller\mainController.py:1552 +#: src\controller\mainController.py:1551 msgid "Updating buffer..." msgstr "バッファを更新中…" -#: ../src\controller\mainController.py:1555 +#: src\controller\mainController.py:1554 +#, python-brace-format msgid "{0} items retrieved" msgstr "{0}個のアイテムを取得しました" -#: ../src\controller\mainController.py:1572 +#: src\controller\mainController.py:1571 src\controller\mainController.py:1591 msgid "Invalid buffer" -msgstr "無効なバッファ無効なユーザートークンです。" +msgstr "無効なバッファ" -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "このツイートは、画像を含んでいません" - -#: ../src\controller\mainController.py:1579 +#: src\controller\mainController.py:1582 +#, python-brace-format msgid "Picture {0}" msgstr "画像{0}" -#: ../src\controller\mainController.py:1580 +#: src\controller\mainController.py:1583 msgid "Select the picture" msgstr "画像を選択" -#: ../src\controller\mainController.py:1596 +#: src\controller\mainController.py:1602 msgid "Unable to extract text" msgstr "テキストを抽出できません" -#: ../src\controller\messages.py:54 +#: src\controller\messages.py:53 msgid "Translated" msgstr "翻訳完了" -#: ../src\controller\messages.py:61 +#: src\controller\messages.py:60 msgid "There's no URL to be shortened" msgstr "短縮されたURLは、ありません" -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 +#: src\controller\messages.py:64 src\controller\messages.py:72 msgid "URL shortened" msgstr "URLを短縮しました" -#: ../src\controller\messages.py:80 +#: src\controller\messages.py:79 msgid "There's no URL to be expanded" msgstr "短縮を解除するURLはありません" -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 +#: src\controller\messages.py:83 src\controller\messages.py:91 msgid "URL expanded" msgstr "URLの短縮を解除しました" -#: ../src\controller\messages.py:104 +#: src\controller\messages.py:105 +#, python-format msgid "%s - %s of %d characters" msgstr "%s - %s/%d" -#: ../src\controller\messages.py:108 +#: src\controller\messages.py:109 +#, python-format msgid "%s - %s characters" msgstr "%s - %s文字" -#: ../src\controller\messages.py:262 +#: src\controller\messages.py:197 src\controller\buffers\twitterBuffers.py:459 +#, python-format +msgid "Direct message to %s" +msgstr "「%s」へのダイレクトメッセージ" + +#: src\controller\messages.py:211 src\controller\buffers\twitterBuffers.py:88 +#: src\controller\buffers\twitterBuffers.py:1218 src\wxUI\sysTrayIcon.py:35 +#: src\wxUI\buffers\base.py:25 src\wxUI\buffers\events.py:15 +#: src\wxUI\buffers\trends.py:18 src\wxUI\dialogs\message.py:306 +msgid "Tweet" +msgstr "ツイート" + +#: src\controller\messages.py:269 msgid "View item" msgstr "アイテムを見る" -#: ../src\controller\settings.py:75 +#: src\controller\settings.py:78 msgid "Direct connection" msgstr "直接接続" -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 +#: src\controller\settings.py:148 src\controller\settings.py:210 +#: src\wxUI\dialogs\configuration.py:119 msgid "Ask" msgstr "その都度、質問する" -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 +#: src\controller\settings.py:150 src\controller\settings.py:212 +#: src\wxUI\dialogs\configuration.py:119 msgid "Retweet without comments" msgstr "コメントを付けずにリツイート(公式RT)" -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 +#: src\controller\settings.py:152 src\wxUI\dialogs\configuration.py:119 msgid "Retweet with comments" msgstr "コメントをつけてリツイート(非公式RT)" -#: ../src\controller\settings.py:184 +#: src\controller\settings.py:187 +#, python-format msgid "Account settings for %s" msgstr "%sのアカウント設定" -#: ../src\controller\settings.py:284 +#: src\controller\settings.py:287 msgid "Direct Messages" msgstr "ダイレクトメッセージ" -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 +#: src\controller\user.py:29 src\wxUI\commonMessageDialogs.py:39 +msgid "That user does not exist" +msgstr "そのユーザーは存在しません" + +#: src\controller\user.py:29 src\controller\user.py:31 +#: src\extra\SpellChecker\wx_ui.py:80 src\issueReporter\wx_ui.py:84 +#: src\issueReporter\wx_ui.py:87 src\wxUI\commonMessageDialogs.py:39 +#: src\wxUI\commonMessageDialogs.py:51 src\wxUI\commonMessageDialogs.py:58 +#: src\wxUI\commonMessageDialogs.py:61 src\wxUI\commonMessageDialogs.py:64 +#: src\wxUI\commonMessageDialogs.py:67 src\wxUI\commonMessageDialogs.py:77 +#: src\wxUI\commonMessageDialogs.py:80 src\wxUI\commonMessageDialogs.py:83 +#: src\wxUI\commonMessageDialogs.py:89 src\wxUI\commonMessageDialogs.py:92 msgid "Error" msgstr "エラー" -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 -msgid "That user does not exist" -msgstr "そのユーザーは存在しません。" - -#: ../src\controller\user.py:30 +#: src\controller\user.py:31 msgid "User has been suspended" -msgstr "ユーザーが凍結されています。" +msgstr "ユーザーが凍結されています" -#: ../src\controller\user.py:36 +#: src\controller\user.py:37 +#, python-format msgid "Information for %s" msgstr "%sの情報" -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 +#: src\controller\user.py:67 src\extra\AudioUploader\audioUploader.py:127 msgid "Discarded" msgstr "拒否されました" -#: ../src\controller\user.py:95 +#: src\controller\user.py:95 +#, python-format msgid "Username: @%s\n" msgstr "ユーザー名: @%s\n" -#: ../src\controller\user.py:96 +#: src\controller\user.py:96 +#, python-format msgid "Name: %s\n" msgstr "名前: %s\n" -#: ../src\controller\user.py:98 +#: src\controller\user.py:98 +#, python-format msgid "Location: %s\n" msgstr "居住地: %s\n" -#: ../src\controller\user.py:100 +#: src\controller\user.py:100 +#, python-format msgid "URL: %s\n" msgstr "URL: %s\n" -#: ../src\controller\user.py:102 +#: src\controller\user.py:104 +#, python-format msgid "Bio: %s\n" msgstr "自己紹介: %s\n" -#: ../src\controller\user.py:103 ../src\controller\user.py:118 +#: src\controller\user.py:105 src\controller\user.py:120 msgid "Yes" msgstr "はい" -#: ../src\controller\user.py:104 ../src\controller\user.py:119 +#: src\controller\user.py:106 src\controller\user.py:121 msgid "No" msgstr "いいえ" -#: ../src\controller\user.py:105 +#: src\controller\user.py:107 +#, python-format msgid "Protected: %s\n" msgstr "保護設定: %s\n" -#: ../src\controller\user.py:110 +#: src\controller\user.py:112 +#, python-brace-format msgid "You follow {0}. " -msgstr "{0}をフォロー" +msgstr "{0}をフォロー。 " -#: ../src\controller\user.py:113 +#: src\controller\user.py:115 +#, python-brace-format msgid "{0} is following you." -msgstr " {0}がフォロー" +msgstr "{0}がフォロー。" -#: ../src\controller\user.py:117 +#: src\controller\user.py:119 +#, python-format msgid "" "Followers: %s\n" " Friends: %s\n" @@ -582,898 +468,1046 @@ msgstr "" "フォロワー: %s\n" "フォロー: %s\n" -#: ../src\controller\user.py:120 +#: src\controller\user.py:122 +#, python-format msgid "Verified: %s\n" msgstr "認証済み: %s\n" -#: ../src\controller\user.py:121 +#: src\controller\user.py:123 +#, python-format msgid "Tweets: %s\n" msgstr "ツイート数: %s\n" -#: ../src\controller\user.py:122 +#: src\controller\user.py:124 +#, python-format msgid "Likes: %s" msgstr "いいね数: %s" -#: ../src\controller\userActionsController.py:75 +#: src\controller\userActionsController.py:74 msgid "You can't ignore direct messages" msgstr "ダイレクトメッセージを無視することはできません" -#: ../src\extra\AudioUploader\audioUploader.py:54 -msgid "Attaching..." -msgstr "添付中" +#: src\controller\buffers\baseBuffers.py:97 +msgid "This action is not supported for this buffer" +msgstr "この動作は、現在のバッファではサポートされていません" -#: ../src\extra\AudioUploader\audioUploader.py:71 +#: src\controller\buffers\twitterBuffers.py:76 +#, python-brace-format +msgid "{username}'s timeline" +msgstr "「{username}」のタイムライン" + +#: src\controller\buffers\twitterBuffers.py:78 +#, python-brace-format +msgid "{username}'s likes" +msgstr "「{username}」のいいね一覧" + +#: src\controller\buffers\twitterBuffers.py:80 +#, python-brace-format +msgid "{username}'s followers" +msgstr "「{username}」のフォロワー" + +#: src\controller\buffers\twitterBuffers.py:82 +#, python-brace-format +msgid "{username}'s friends" +msgstr "「{username}」のフォロー" + +#: src\controller\buffers\twitterBuffers.py:84 +msgid "Unknown buffer" +msgstr "不明なバッファ" + +#: src\controller\buffers\twitterBuffers.py:89 +#: src\controller\buffers\twitterBuffers.py:1219 +msgid "Write the tweet here" +msgstr "ツイートを入力" + +#: src\controller\buffers\twitterBuffers.py:208 +#, python-brace-format +msgid "New tweet in {0}" +msgstr "「{0}」への新規ツイート" + +#: src\controller\buffers\twitterBuffers.py:211 +#, python-brace-format +msgid "{0} new tweets in {1}." +msgstr "「{1}」への{0}個の新規ツイート。" + +#: src\controller\buffers\twitterBuffers.py:245 +#: src\controller\buffers\twitterBuffers.py:680 +#: src\controller\buffers\twitterBuffers.py:921 +#: src\controller\buffers\twitterBuffers.py:1102 +#, python-format +msgid "%s items retrieved" +msgstr "%s個のアイテムを取得しました" + +#: src\controller\buffers\twitterBuffers.py:277 +#: src\controller\buffers\twitterBuffers.py:834 +msgid "This buffer is not a timeline; it can't be deleted." +msgstr "このバッファは、タイムラインではないため、削除できません。" + +#: src\controller\buffers\twitterBuffers.py:411 +#, python-brace-format +msgid "Reply to {arg0}" +msgstr "「{arg0}」への返信:" + +#: src\controller\buffers\twitterBuffers.py:413 +#: src\keystrokeEditor\constants.py:12 src\wxUI\buffers\base.py:27 +msgid "Reply" +msgstr "返信" + +#: src\controller\buffers\twitterBuffers.py:414 +#, python-format +msgid "Reply to %s" +msgstr "「%s」への返信" + +#: src\controller\buffers\twitterBuffers.py:459 +#: src\controller\buffers\twitterBuffers.py:723 +msgid "New direct message" +msgstr "新しいダイレクトメッセージ" + +#: src\controller\buffers\twitterBuffers.py:497 +msgid "Quote" +msgstr "引用" + +#: src\controller\buffers\twitterBuffers.py:497 +msgid "Add your comment to the tweet" +msgstr "ツイートにコメントを追加" + +#: src\controller\buffers\twitterBuffers.py:569 +msgid "Opening URL..." +msgstr "URLを開いています…" + +#: src\controller\buffers\twitterBuffers.py:604 +msgid "User details" +msgstr "ユーザーの詳細" + +#: src\controller\buffers\twitterBuffers.py:620 +#: src\controller\buffers\twitterBuffers.py:998 +msgid "Opening item in web browser..." +msgstr "ブラウザでアイテムを開いています…" + +#: src\controller\buffers\twitterBuffers.py:686 +#: src\controller\buffers\twitterBuffers.py:849 src\wxUI\buffers\people.py:17 +msgid "Mention" +msgstr "メンション" + +#: src\controller\buffers\twitterBuffers.py:686 +#: src\controller\buffers\twitterBuffers.py:849 +#, python-format +msgid "Mention to %s" +msgstr "%sへのメンション" + +#: src\controller\buffers\twitterBuffers.py:726 +#, python-brace-format +msgid "{0} new direct messages." +msgstr "{0}件の新しいダイレクトメッセージ。" + +#: src\controller\buffers\twitterBuffers.py:729 +msgid "This action is not supported in the buffer yet." +msgstr "この動作は、現在のバッファではサポートされていません。" + +#: src\controller\buffers\twitterBuffers.py:739 +msgid "" +"Getting more items cannot be done in this buffer. Use the direct messages " +"buffer instead." +msgstr "" +"このバッファでは、さらにアイテムを取得することはできません。代わりにダイレク" +"トメッセージバッファを使用してください。" + +#: src\controller\buffers\twitterBuffers.py:994 +#, python-brace-format +msgid "{0} new followers." +msgstr "{0}人の新しいフォロワー。" + +#: src\controller\buffers\twitterBuffers.py:1242 +msgid "This action is not supported in the buffer, yet." +msgstr "この動作は、現在のバッファではサポートされていません。" + +#: src\extra\AudioUploader\audioUploader.py:57 +msgid "Attaching..." +msgstr "添付中…" + +#: src\extra\AudioUploader\audioUploader.py:74 msgid "Pause" msgstr "一時停止" -#: ../src\extra\AudioUploader\audioUploader.py:73 +#: src\extra\AudioUploader\audioUploader.py:76 msgid "&Resume" msgstr "再開(&R)" -#: ../src\extra\AudioUploader\audioUploader.py:74 +#: src\extra\AudioUploader\audioUploader.py:77 msgid "Resume" msgstr "再開" -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 +#: src\extra\AudioUploader\audioUploader.py:79 +#: src\extra\AudioUploader\audioUploader.py:106 +#: src\extra\AudioUploader\wx_ui.py:37 msgid "&Pause" msgstr "一時停止(&P)" -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 +#: src\extra\AudioUploader\audioUploader.py:94 +#: src\extra\AudioUploader\audioUploader.py:140 msgid "&Stop" msgstr "停止(&S)" -#: ../src\extra\AudioUploader\audioUploader.py:92 +#: src\extra\AudioUploader\audioUploader.py:95 msgid "Recording" msgstr "録音中" -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 +#: src\extra\AudioUploader\audioUploader.py:100 +#: src\extra\AudioUploader\audioUploader.py:151 msgid "Stopped" msgstr "停止" -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 +#: src\extra\AudioUploader\audioUploader.py:102 +#: src\extra\AudioUploader\wx_ui.py:39 msgid "&Record" msgstr "録音(&R)" -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 -msgid "Playing..." -msgstr "再生中" - -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 +#: src\extra\AudioUploader\audioUploader.py:144 +#: src\extra\AudioUploader\audioUploader.py:154 +#: src\extra\AudioUploader\wx_ui.py:35 msgid "&Play" msgstr "再生(&P)" -#: ../src\extra\AudioUploader\audioUploader.py:156 +#: src\extra\AudioUploader\audioUploader.py:159 msgid "Recoding audio..." -msgstr "音声を録音中" +msgstr "音声を録音中…" -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 +#: src\extra\AudioUploader\transfer.py:82 +#: src\extra\AudioUploader\transfer.py:88 +#, python-brace-format msgid "Error in file upload: {0}" msgstr "ファイルアップロードエラー: {0}" -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 +#: src\extra\AudioUploader\utils.py:29 src\update\utils.py:29 +#, python-format msgid "%d day, " -msgstr "1日前" +msgstr "%d日 " -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 +#: src\extra\AudioUploader\utils.py:31 src\update\utils.py:31 +#, python-format msgid "%d days, " -msgstr "%s日" +msgstr "%d日 " -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 +#: src\extra\AudioUploader\utils.py:33 src\update\utils.py:33 +#, python-format msgid "%d hour, " -msgstr "1時間前" +msgstr "%d時間 " -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 +#: src\extra\AudioUploader\utils.py:35 src\update\utils.py:35 +#, python-format msgid "%d hours, " -msgstr "%d時間" +msgstr "%d時間 " -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 +#: src\extra\AudioUploader\utils.py:37 src\update\utils.py:37 +#, python-format msgid "%d minute, " -msgstr "1分前" +msgstr "%d分 " -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 +#: src\extra\AudioUploader\utils.py:39 src\update\utils.py:39 +#, python-format msgid "%d minutes, " -msgstr "%d分" +msgstr "%d分 " -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 +#: src\extra\AudioUploader\utils.py:41 src\update\utils.py:41 +#, python-format msgid "%s second" -msgstr "1秒前" +msgstr "%s秒" -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 +#: src\extra\AudioUploader\utils.py:43 src\update\utils.py:43 +#, python-format msgid "%s seconds" msgstr "%s秒" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 +#: src\extra\AudioUploader\wx_transfer_dialogs.py:15 msgid "File" msgstr "ファイル" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 +#: src\extra\AudioUploader\wx_transfer_dialogs.py:21 msgid "Transferred" msgstr "転送済み" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 +#: src\extra\AudioUploader\wx_transfer_dialogs.py:26 msgid "Total file size" msgstr "合計サイズ" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 +#: src\extra\AudioUploader\wx_transfer_dialogs.py:31 msgid "Transfer rate" msgstr "転送速度" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 +#: src\extra\AudioUploader\wx_transfer_dialogs.py:36 msgid "Time left" msgstr "残り時間" -#: ../src\extra\AudioUploader\wx_ui.py:28 +#: src\extra\AudioUploader\wx_ui.py:29 msgid "Attach audio" msgstr "音声を添付" -#: ../src\extra\AudioUploader\wx_ui.py:40 +#: src\extra\AudioUploader\wx_ui.py:41 msgid "&Add an existing file" msgstr "既存のファイルを追加(&A)" -#: ../src\extra\AudioUploader\wx_ui.py:41 +#: src\extra\AudioUploader\wx_ui.py:42 msgid "&Discard" msgstr "拒否(&D)" -#: ../src\extra\AudioUploader\wx_ui.py:43 +#: src\extra\AudioUploader\wx_ui.py:44 msgid "Upload to" -msgstr "アップロード先:" +msgstr "アップロード先" -#: ../src\extra\AudioUploader\wx_ui.py:48 +#: src\extra\AudioUploader\wx_ui.py:49 msgid "Attach" msgstr "添付" -#: ../src\extra\AudioUploader\wx_ui.py:50 +#: src\extra\AudioUploader\wx_ui.py:51 msgid "&Cancel" msgstr "キャンセル(&C)" -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "音声ファイル (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: src\extra\AudioUploader\wx_ui.py:76 msgid "Select the audio file to be uploaded" msgstr "アップロードする音声ファイルを選択" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 +#: src\extra\AudioUploader\wx_ui.py:76 +msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" +msgstr "音声ファイル (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" + +#: src\extra\autocompletionUsers\completion.py:23 +#: src\extra\autocompletionUsers\completion.py:41 +msgid "You have to start writing" +msgstr "あなたは、書き込みを開始しなければなりません" + +#: src\extra\autocompletionUsers\completion.py:33 +#: src\extra\autocompletionUsers\completion.py:50 +msgid "There are no results in your users database" +msgstr "あなたのユーザーのデータベースには、見つかりませんでした" + +#: src\extra\autocompletionUsers\completion.py:35 +msgid "Autocompletion only works for users." +msgstr "自動補完はユーザーのみで動作します。" + +#: src\extra\autocompletionUsers\settings.py:29 +msgid "" +"Updating database... You can close this window now. A message will tell you " +"when the process finishes." +msgstr "" +"データベースの更新中… なお、このウィンドウを閉じることができます。処理が終了" +"すると、メッセージが表示されます。" + +#: src\extra\autocompletionUsers\wx_manage.py:9 +msgid "Manage Autocompletion database" +msgstr "オートコンプリートのデータベースを管理" + +#: src\extra\autocompletionUsers\wx_manage.py:12 +#, python-brace-format +msgid "Editing {0} users database" +msgstr "{0}のユーザーデータベースを編集中" + +#: src\extra\autocompletionUsers\wx_manage.py:13 +msgid "Username" +msgstr "ユーザー名" + +#: src\extra\autocompletionUsers\wx_manage.py:13 +#: src\wxUI\dialogs\configuration.py:146 +msgid "Name" +msgstr "名前" + +#: src\extra\autocompletionUsers\wx_manage.py:16 +msgid "Add user" +msgstr "ユーザーを追加" + +#: src\extra\autocompletionUsers\wx_manage.py:17 +msgid "Remove user" +msgstr "ユーザーを削除" + +#: src\extra\autocompletionUsers\wx_manage.py:38 +msgid "Twitter username" +msgstr "Twitterのユーザー名" + +#: src\extra\autocompletionUsers\wx_manage.py:38 +msgid "Add user to database" +msgstr "データベースにユーザーを追加" + +#: src\extra\autocompletionUsers\wx_manage.py:44 +msgid "The user does not exist" +msgstr "そのユーザーは存在しません" + +#: src\extra\autocompletionUsers\wx_manage.py:44 +#: src\wxUI\commonMessageDialogs.py:45 +msgid "Error!" +msgstr "エラー!" + +#: src\extra\autocompletionUsers\wx_settings.py:9 +msgid "Autocomplete users' settings" +msgstr "オートコンプリートユーザーの設定" + +#: src\extra\autocompletionUsers\wx_settings.py:12 +msgid "Add users from followers buffer" +msgstr "フォロワーからユーザーを追加" + +#: src\extra\autocompletionUsers\wx_settings.py:13 +msgid "Add users from friends buffer" +msgstr "フォロー中のユーザーからユーザーを追加" + +#: src\extra\autocompletionUsers\wx_settings.py:16 +msgid "Manage database..." +msgstr "データベースの管理..." + +#: src\extra\autocompletionUsers\wx_settings.py:28 +#, python-brace-format +msgid "{0}'s database of users has been updated." +msgstr "{0}のユーザーのデータベースが更新されました。" + +#: src\extra\autocompletionUsers\wx_settings.py:28 +msgid "Done" +msgstr "完了" + +#: src\extra\ocr\OCRSpace.py:7 +msgid "Detect automatically" +msgstr "自動検出" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:33 +msgid "Danish" +msgstr "デンマーク語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:35 +msgid "Dutch" +msgstr "オランダ語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:36 +msgid "English" +msgstr "英語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:40 +msgid "Finnish" +msgstr "フィンランド語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:41 +msgid "French" +msgstr "フランス語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:44 +msgid "German" +msgstr "ドイツ語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:50 +msgid "Hungarian" +msgstr "ハンガリー語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:60 +msgid "Korean" +msgstr "韓国語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:55 +msgid "Italian" +msgstr "イタリア語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:56 +msgid "Japanese" +msgstr "日本語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:77 +msgid "Polish" +msgstr "ポーランド語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:78 +msgid "Portuguese" +msgstr "ポルトガル語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:81 +msgid "Russian" +msgstr "ロシア語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:88 +msgid "Spanish" +msgstr "スペイン語" + +#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:97 +msgid "Turkish" +msgstr "トルコ語" + +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:7 msgid "Audio tweet." -msgstr "音声付きツイート" +msgstr "音声付きツイート。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:8 msgid "User timeline buffer created." -msgstr "ユーザーのタイムラインのバッファを作成" +msgstr "ユーザーのタイムラインのバッファを作成。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:9 msgid "Buffer destroied." -msgstr "バッファを削除" +msgstr "バッファを削除。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:10 msgid "Direct message received." -msgstr "ダイレクトメッセージを受信" +msgstr "ダイレクトメッセージを受信。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:11 msgid "Direct message sent." -msgstr "ダイレクトメッセージを送信" +msgstr "ダイレクトメッセージを送信。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:12 msgid "Error." -msgstr "エラー" +msgstr "エラー。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:13 msgid "Tweet liked." -msgstr "ツイートがいいねされた" +msgstr "ツイートがいいねされた。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:14 msgid "Likes buffer updated." -msgstr "いいねバッファが更新された" +msgstr "いいねバッファが更新された。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:15 msgid "Geotweet." -msgstr "位置情報付きのツイート" +msgstr "位置情報付きのツイート。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:16 msgid "Tweet contains one or more images" msgstr "ツイートに1つ以上の画像が含まれています" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:17 msgid "Boundary reached." -msgstr "先頭または最後のツイート" +msgstr "先頭または最後のツイート。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:18 msgid "List updated." -msgstr "リストが更新された" +msgstr "リストが更新された。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:19 msgid "Too many characters." -msgstr "文字数オーバー" +msgstr "文字数オーバー。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:20 msgid "Mention received." -msgstr "リプライを受信" +msgstr "リプライを受信した。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:21 msgid "New event." -msgstr "新しいイベント" +msgstr "新しいイベント。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:22 +#, python-brace-format msgid "{0} is ready." -msgstr "{0}の準備完了" +msgstr "{0}の準備完了。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:23 msgid "Mention sent." -msgstr "リプライを送信" +msgstr "リプライを送信した。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:24 msgid "Tweet retweeted." -msgstr "ツイートをリツイート" +msgstr "ツイートをリツイートした。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:25 msgid "Search buffer updated." -msgstr "検索バッファが更新された" +msgstr "検索バッファが更新された。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:26 msgid "Tweet received." -msgstr "ツイートを受信" +msgstr "ツイートを受信した。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:27 msgid "Tweet sent." -msgstr "ツイートを送信" +msgstr "ツイートを送信した。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:28 msgid "Trending topics buffer updated." -msgstr "トレンドの話題のバッファが更新された" +msgstr "トレンドのバッファが更新された。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:29 msgid "New tweet in user timeline buffer." -msgstr "ユーザーのタイムラインに新しいツイートを受信" +msgstr "ユーザーのタイムラインに新しいツイートを受信した。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:30 msgid "New follower." -msgstr "新しいフォロワー" +msgstr "新しいフォロワー。" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 +#: src\extra\SoundsTutorial\soundsTutorial_constants.py:31 msgid "Volume changed." -msgstr "ボリュームを変更" +msgstr "ボリュームを変更した。" -#: ../src\extra\SoundsTutorial\wx_ui.py:8 +#: src\extra\SoundsTutorial\wx_ui.py:9 msgid "Sounds tutorial" msgstr "サウンドの確認" -#: ../src\extra\SoundsTutorial\wx_ui.py:11 +#: src\extra\SoundsTutorial\wx_ui.py:12 msgid "Press enter to listen to the sound for the selected event" msgstr "選択されたイベントのサウンドを再生するには、Enterキーを押してください" -#: ../src\extra\SpellChecker\spellchecker.py:57 +#: src\extra\SpellChecker\spellchecker.py:60 +#, python-format msgid "Misspelled word: %s" msgstr "「%s」はスペルが間違っています" -#: ../src\extra\SpellChecker\wx_ui.py:27 +#: src\extra\SpellChecker\wx_ui.py:28 msgid "Misspelled word" msgstr "スペルミスの単語" -#: ../src\extra\SpellChecker\wx_ui.py:32 +#: src\extra\SpellChecker\wx_ui.py:33 msgid "Context" msgstr "コンテキスト" -#: ../src\extra\SpellChecker\wx_ui.py:37 +#: src\extra\SpellChecker\wx_ui.py:38 msgid "Suggestions" msgstr "提案" -#: ../src\extra\SpellChecker\wx_ui.py:42 +#: src\extra\SpellChecker\wx_ui.py:43 msgid "&Ignore" msgstr "無視(&I)" -#: ../src\extra\SpellChecker\wx_ui.py:43 +#: src\extra\SpellChecker\wx_ui.py:44 msgid "I&gnore all" msgstr "すべて無視(&G)" -#: ../src\extra\SpellChecker\wx_ui.py:44 +#: src\extra\SpellChecker\wx_ui.py:45 msgid "&Replace" msgstr "置き換え(&R)" -#: ../src\extra\SpellChecker\wx_ui.py:45 +#: src\extra\SpellChecker\wx_ui.py:46 msgid "R&eplace all" msgstr "すべて置き換え(&E)" -#: ../src\extra\SpellChecker\wx_ui.py:46 +#: src\extra\SpellChecker\wx_ui.py:47 msgid "&Add to personal dictionary" msgstr "個人辞書に追加(&A)" -#: ../src\extra\SpellChecker\wx_ui.py:79 +#: src\extra\SpellChecker\wx_ui.py:80 +#, python-brace-format msgid "" "An error has occurred. There are no dictionaries available for the selected " "language in {0}" msgstr "エラーが発生しました。{0}で選択した言語用の辞書がありません" -#: ../src\extra\SpellChecker\wx_ui.py:82 +#: src\extra\SpellChecker\wx_ui.py:83 msgid "Spell check complete." -msgstr "スペルチェックが完了しました" +msgstr "スペルチェックが完了しました。" -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 -msgid "You have to start writing" -msgstr "あなたは、書き込みを開始しなければなりません" - -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 -msgid "There are no results in your users database" -msgstr "あなたのユーザーのデータベースには、見つかりませんでした" - -#: ../src\extra\autocompletionUsers\completion.py:33 -msgid "Autocompletion only works for users." -msgstr "自動補完はユーザーのみで動作します" - -#: ../src\extra\autocompletionUsers\settings.py:27 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"データベースの更新中...あなたは今、このウィンドウを閉じることができます。 プ" -"ロセスが終了するとメッセージが表示されます" - -#: ../src\extra\autocompletionUsers\wx_manage.py:8 -msgid "Manage Autocompletion database" -msgstr "オートコンプリートのデータベースを管理" - -#: ../src\extra\autocompletionUsers\wx_manage.py:11 -msgid "Editing {0} users database" -msgstr "{0}のユーザーデータベースを編集中" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Username" -msgstr "ユーザー名" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "名前" - -#: ../src\extra\autocompletionUsers\wx_manage.py:15 -msgid "Add user" -msgstr "ユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Remove user" -msgstr "ユーザーを削除" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Add user to database" -msgstr "データベースにユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Twitter username" -msgstr "ツイッターのユーザー名" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -msgid "The user does not exist" -msgstr "そのユーザーは存在しません" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "Error!" -msgstr "エラー" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "オートコンプリートユーザーの設定" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "フォロワーからユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "フォロー中のユーザーからユーザーを追加" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "データベースの管理" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "完了" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "{0}のユーザーのデータベースが更新されました" - -#: ../src\extra\ocr\OCRSpace.py:5 -msgid "Detect automatically" -msgstr "自動検出" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 -msgid "Danish" -msgstr "デンマーク語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 -msgid "Dutch" -msgstr "オランダ語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 -msgid "English" -msgstr "英語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 -msgid "Finnish" -msgstr "フィンランド語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 -msgid "French" -msgstr "フランス語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 -msgid "German" -msgstr "ドイツ語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 -msgid "Hungarian" -msgstr "ハンガリー語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 -msgid "Italian" -msgstr "イタリア語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 -msgid "Japanese" -msgstr "日本語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 -msgid "Korean" -msgstr "韓国語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 -msgid "Polish" -msgstr "ポーランド語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 -msgid "Portuguese" -msgstr "ポルトガル語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 -msgid "Russian" -msgstr "ロシア語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 -msgid "Spanish" -msgstr "スペイン語" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 -msgid "Turkish" -msgstr "トルコ語" - -#: ../src\extra\translator\translator.py:12 +#: src\extra\translator\translator.py:14 msgid "Afrikaans" msgstr "アフリカ語" -#: ../src\extra\translator\translator.py:13 +#: src\extra\translator\translator.py:15 msgid "Albanian" msgstr "アルバニア語" -#: ../src\extra\translator\translator.py:14 +#: src\extra\translator\translator.py:16 msgid "Amharic" msgstr "アムハラ語" -#: ../src\extra\translator\translator.py:15 +#: src\extra\translator\translator.py:17 msgid "Arabic" msgstr "アラビア語" -#: ../src\extra\translator\translator.py:16 +#: src\extra\translator\translator.py:18 msgid "Armenian" msgstr "アルメニア語" -#: ../src\extra\translator\translator.py:17 +#: src\extra\translator\translator.py:19 msgid "Azerbaijani" msgstr "アゼルバイジャン語" -#: ../src\extra\translator\translator.py:18 +#: src\extra\translator\translator.py:20 msgid "Basque" msgstr "バスク語" -#: ../src\extra\translator\translator.py:19 +#: src\extra\translator\translator.py:21 msgid "Belarusian" msgstr "ベラルーシ語" -#: ../src\extra\translator\translator.py:20 +#: src\extra\translator\translator.py:22 msgid "Bengali" msgstr "ベンガル語" -#: ../src\extra\translator\translator.py:21 +#: src\extra\translator\translator.py:23 msgid "Bihari" msgstr "ビハール語" -#: ../src\extra\translator\translator.py:22 +#: src\extra\translator\translator.py:24 msgid "Bulgarian" msgstr "ブルガリア語" -#: ../src\extra\translator\translator.py:23 +#: src\extra\translator\translator.py:25 msgid "Burmese" msgstr "ビルマ語" -#: ../src\extra\translator\translator.py:24 +#: src\extra\translator\translator.py:26 msgid "Catalan" msgstr "カタロニア語" -#: ../src\extra\translator\translator.py:25 +#: src\extra\translator\translator.py:27 msgid "Cherokee" msgstr "チェロキー語" -#: ../src\extra\translator\translator.py:26 +#: src\extra\translator\translator.py:28 msgid "Chinese" msgstr "中国語" -#: ../src\extra\translator\translator.py:27 +#: src\extra\translator\translator.py:29 msgid "Chinese_simplified" msgstr "簡体字中国語" -#: ../src\extra\translator\translator.py:28 +#: src\extra\translator\translator.py:30 msgid "Chinese_traditional" msgstr "繁体字中国語" -#: ../src\extra\translator\translator.py:29 +#: src\extra\translator\translator.py:31 msgid "Croatian" msgstr "クロアチア語" -#: ../src\extra\translator\translator.py:30 +#: src\extra\translator\translator.py:32 msgid "Czech" msgstr "チェコ語" -#: ../src\extra\translator\translator.py:32 +#: src\extra\translator\translator.py:34 msgid "Dhivehi" msgstr "ディベヒ語" -#: ../src\extra\translator\translator.py:35 +#: src\extra\translator\translator.py:37 msgid "Esperanto" msgstr "エスペラント語" -#: ../src\extra\translator\translator.py:36 +#: src\extra\translator\translator.py:38 msgid "Estonian" msgstr "エストニア語" -#: ../src\extra\translator\translator.py:37 +#: src\extra\translator\translator.py:39 msgid "Filipino" msgstr "フィリピン語" -#: ../src\extra\translator\translator.py:40 +#: src\extra\translator\translator.py:42 msgid "Galician" msgstr "ガリシア語" -#: ../src\extra\translator\translator.py:41 +#: src\extra\translator\translator.py:43 msgid "Georgian" msgstr "ジョージア語" -#: ../src\extra\translator\translator.py:43 +#: src\extra\translator\translator.py:45 msgid "Greek" msgstr "ギリシャ語" -#: ../src\extra\translator\translator.py:44 +#: src\extra\translator\translator.py:46 msgid "Guarani" msgstr "グアラニ語" -#: ../src\extra\translator\translator.py:45 +#: src\extra\translator\translator.py:47 msgid "Gujarati" msgstr "グジャラート語" -#: ../src\extra\translator\translator.py:46 +#: src\extra\translator\translator.py:48 msgid "Hebrew" msgstr "ヘブライ語" -#: ../src\extra\translator\translator.py:47 +#: src\extra\translator\translator.py:49 msgid "Hindi" msgstr "ヒンディー語" -#: ../src\extra\translator\translator.py:49 +#: src\extra\translator\translator.py:51 msgid "Icelandic" msgstr "アイスランド語" -#: ../src\extra\translator\translator.py:50 +#: src\extra\translator\translator.py:52 msgid "Indonesian" msgstr "インドネシア語" -#: ../src\extra\translator\translator.py:51 +#: src\extra\translator\translator.py:53 msgid "Inuktitut" msgstr "イヌクティトゥト語" -#: ../src\extra\translator\translator.py:52 +#: src\extra\translator\translator.py:54 msgid "Irish" msgstr "アイリス語" -#: ../src\extra\translator\translator.py:55 +#: src\extra\translator\translator.py:57 msgid "Kannada" msgstr "カンナダ語" -#: ../src\extra\translator\translator.py:56 +#: src\extra\translator\translator.py:58 msgid "Kazakh" msgstr "カザフ語" -#: ../src\extra\translator\translator.py:57 +#: src\extra\translator\translator.py:59 msgid "Khmer" msgstr "クメール語" -#: ../src\extra\translator\translator.py:59 +#: src\extra\translator\translator.py:61 msgid "Kurdish" msgstr "クルド語" -#: ../src\extra\translator\translator.py:60 +#: src\extra\translator\translator.py:62 msgid "Kyrgyz" msgstr "キルギス語" -#: ../src\extra\translator\translator.py:61 +#: src\extra\translator\translator.py:63 msgid "Laothian" msgstr "ラオス語" -#: ../src\extra\translator\translator.py:62 +#: src\extra\translator\translator.py:64 msgid "Latvian" msgstr "ラトビア語" -#: ../src\extra\translator\translator.py:63 +#: src\extra\translator\translator.py:65 msgid "Lithuanian" msgstr "リトアニア語" -#: ../src\extra\translator\translator.py:64 +#: src\extra\translator\translator.py:66 msgid "Macedonian" msgstr "マケドニア語" -#: ../src\extra\translator\translator.py:65 +#: src\extra\translator\translator.py:67 msgid "Malay" msgstr "マレー語" -#: ../src\extra\translator\translator.py:66 +#: src\extra\translator\translator.py:68 msgid "Malayalam" msgstr "マラヤーラム語" -#: ../src\extra\translator\translator.py:67 +#: src\extra\translator\translator.py:69 msgid "Maltese" msgstr "マルタ語" -#: ../src\extra\translator\translator.py:68 +#: src\extra\translator\translator.py:70 msgid "Marathi" msgstr "マラーティー語" -#: ../src\extra\translator\translator.py:69 +#: src\extra\translator\translator.py:71 msgid "Mongolian" msgstr "モンゴル語" -#: ../src\extra\translator\translator.py:70 +#: src\extra\translator\translator.py:72 msgid "Nepali" msgstr "ネパール語" -#: ../src\extra\translator\translator.py:71 +#: src\extra\translator\translator.py:73 msgid "Norwegian" msgstr "ノルウェー語" -#: ../src\extra\translator\translator.py:72 +#: src\extra\translator\translator.py:74 msgid "Oriya" msgstr "オリヤー語" -#: ../src\extra\translator\translator.py:73 +#: src\extra\translator\translator.py:75 msgid "Pashto" msgstr "パシュトウ語" -#: ../src\extra\translator\translator.py:74 +#: src\extra\translator\translator.py:76 msgid "Persian" msgstr "ペルシア語" -#: ../src\extra\translator\translator.py:77 +#: src\extra\translator\translator.py:79 msgid "Punjabi" msgstr "パンジャブ語" -#: ../src\extra\translator\translator.py:78 +#: src\extra\translator\translator.py:80 msgid "Romanian" msgstr "ルーマニア語" -#: ../src\extra\translator\translator.py:80 +#: src\extra\translator\translator.py:82 msgid "Sanskrit" msgstr "サンスクリット語" -#: ../src\extra\translator\translator.py:81 +#: src\extra\translator\translator.py:83 msgid "Serbian" msgstr "セルビア語" -#: ../src\extra\translator\translator.py:82 +#: src\extra\translator\translator.py:84 msgid "Sindhi" msgstr "シンド語" -#: ../src\extra\translator\translator.py:83 +#: src\extra\translator\translator.py:85 msgid "Sinhalese" msgstr "シンハラ語" -#: ../src\extra\translator\translator.py:84 +#: src\extra\translator\translator.py:86 msgid "Slovak" msgstr "スロバキア語" -#: ../src\extra\translator\translator.py:85 +#: src\extra\translator\translator.py:87 msgid "Slovenian" msgstr "スロベニア語" -#: ../src\extra\translator\translator.py:87 +#: src\extra\translator\translator.py:89 msgid "Swahili" msgstr "スワヒリ語" -#: ../src\extra\translator\translator.py:88 +#: src\extra\translator\translator.py:90 msgid "Swedish" msgstr "スウェーデン語" -#: ../src\extra\translator\translator.py:89 +#: src\extra\translator\translator.py:91 msgid "Tajik" msgstr "タジク語" -#: ../src\extra\translator\translator.py:90 +#: src\extra\translator\translator.py:92 msgid "Tamil" msgstr "タミル語" -#: ../src\extra\translator\translator.py:91 +#: src\extra\translator\translator.py:93 msgid "Tagalog" msgstr "タガログ語" -#: ../src\extra\translator\translator.py:92 +#: src\extra\translator\translator.py:94 msgid "Telugu" msgstr "テルグ語" -#: ../src\extra\translator\translator.py:93 +#: src\extra\translator\translator.py:95 msgid "Thai" msgstr "タイ語" -#: ../src\extra\translator\translator.py:94 +#: src\extra\translator\translator.py:96 msgid "Tibetan" msgstr "チベット語" -#: ../src\extra\translator\translator.py:96 +#: src\extra\translator\translator.py:98 msgid "Ukrainian" msgstr "ウクライナ語" -#: ../src\extra\translator\translator.py:97 +#: src\extra\translator\translator.py:99 msgid "Urdu" msgstr "ウルドゥー語" -#: ../src\extra\translator\translator.py:98 +#: src\extra\translator\translator.py:100 msgid "Uzbek" msgstr "ウズベク語" -#: ../src\extra\translator\translator.py:99 +#: src\extra\translator\translator.py:101 msgid "Uighur" msgstr "ウイグル語" -#: ../src\extra\translator\translator.py:100 +#: src\extra\translator\translator.py:102 msgid "Vietnamese" msgstr "ベトナム語" -#: ../src\extra\translator\translator.py:101 +#: src\extra\translator\translator.py:103 msgid "Welsh" msgstr "ウェールズ語" -#: ../src\extra\translator\translator.py:102 +#: src\extra\translator\translator.py:104 msgid "Yiddish" msgstr "イディッシュ語" -#: ../src\extra\translator\wx_ui.py:44 +#: src\extra\translator\wx_ui.py:45 msgid "Translate message" msgstr "メッセージを翻訳" -#: ../src\extra\translator\wx_ui.py:47 +#: src\extra\translator\wx_ui.py:48 msgid "Target language" msgstr "翻訳先の言語" -#: ../src\issueReporter\issueReporter.py:30 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 +#: src\issueReporter\issueReporter.py:32 src\wxUI\dialogs\configuration.py:361 +#: src\wxUI\dialogs\configuration.py:370 msgid "General" msgstr "一般" -#: ../src\issueReporter\issueReporter.py:31 +#: src\issueReporter\issueReporter.py:33 msgid "always" msgstr "常に" -#: ../src\issueReporter\issueReporter.py:31 -msgid "have not tried" -msgstr "試したことがない" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "random" -msgstr "ランダム" - -#: ../src\issueReporter\issueReporter.py:31 +#: src\issueReporter\issueReporter.py:33 msgid "sometimes" msgstr "時々" -#: ../src\issueReporter\issueReporter.py:31 +#: src\issueReporter\issueReporter.py:33 +msgid "random" +msgstr "ランダム" + +#: src\issueReporter\issueReporter.py:33 +msgid "have not tried" +msgstr "試したことがない" + +#: src\issueReporter\issueReporter.py:33 msgid "unable to duplicate" msgstr "複製できません" -#: ../src\issueReporter\issueReporter.py:32 +#: src\issueReporter\issueReporter.py:34 msgid "block" msgstr "ブロック" -#: ../src\issueReporter\issueReporter.py:32 +#: src\issueReporter\issueReporter.py:34 msgid "crash" msgstr "クラッシュ" -#: ../src\issueReporter\issueReporter.py:32 -msgid "feature" -msgstr "特徴" - -#: ../src\issueReporter\issueReporter.py:32 +#: src\issueReporter\issueReporter.py:34 msgid "major" msgstr "メジャー" -#: ../src\issueReporter\issueReporter.py:32 +#: src\issueReporter\issueReporter.py:34 msgid "minor" msgstr "マイナー" -#: ../src\issueReporter\issueReporter.py:32 -msgid "text" -msgstr "内容" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "trivial" -msgstr "些細な" - -#: ../src\issueReporter\issueReporter.py:32 +#: src\issueReporter\issueReporter.py:34 msgid "tweak" msgstr "微調整" -#: ../src\issueReporter\wx_ui.py:25 +#: src\issueReporter\issueReporter.py:34 +msgid "text" +msgstr "内容" + +#: src\issueReporter\issueReporter.py:34 +msgid "trivial" +msgstr "些細な" + +#: src\issueReporter\issueReporter.py:34 +msgid "feature" +msgstr "特徴" + +#: src\issueReporter\wx_ui.py:26 msgid "Report an error" msgstr "エラーを報告" -#: ../src\issueReporter\wx_ui.py:28 +#: src\issueReporter\wx_ui.py:29 msgid "Select a category" msgstr "カテゴリを選択" -#: ../src\issueReporter\wx_ui.py:36 +#: src\issueReporter\wx_ui.py:37 msgid "" "Briefly describe what happened. You will be able to thoroughly explain it " "later" msgstr "簡単な説明" -#: ../src\issueReporter\wx_ui.py:45 +#: src\issueReporter\wx_ui.py:46 msgid "Here, you can describe the bug in detail" msgstr "バグの詳細な説明" -#: ../src\issueReporter\wx_ui.py:55 +#: src\issueReporter\wx_ui.py:56 msgid "how often does this bug happen?" msgstr "このバグが起こる頻度" -#: ../src\issueReporter\wx_ui.py:62 +#: src\issueReporter\wx_ui.py:63 msgid "Select the importance that you think this bug has" msgstr "このバグの重要性を選択" -#: ../src\issueReporter\wx_ui.py:69 +#: src\issueReporter\wx_ui.py:70 +#, python-brace-format msgid "" "I know that the {0} bug system will get my Twitter username to contact me " "and fix the bug quickly" msgstr "" -"私は、{0}のバグシステムが私に連絡して、すぐにバグを修正するために、ツイッター" -"のユーザー名を取得することを理解しています" +"私は、{0}のバグシステムが私に連絡して、すぐにバグを修正するために、Twitterの" +"ユーザー名を取得することを理解しています" -#: ../src\issueReporter\wx_ui.py:72 +#: src\issueReporter\wx_ui.py:73 msgid "Send report" msgstr "レポートを送信" -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 +#: src\issueReporter\wx_ui.py:75 src\wxUI\dialogs\filterDialogs.py:84 +#: src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "キャンセル" -#: ../src\issueReporter\wx_ui.py:83 +#: src\issueReporter\wx_ui.py:84 msgid "You must fill out both fields" msgstr "あなたは、両方のフィールドに記入しなければなりません" -#: ../src\issueReporter\wx_ui.py:86 +#: src\issueReporter\wx_ui.py:87 msgid "" "You need to mark the checkbox to provide us your twitter username to contact " "you if it is necessary." msgstr "" -"必要な場合に連絡するため、ツイッターのユーザー名を私たちに送信するために、" -"チェックボックスにチェックをつける必要があります" +"必要な場合に連絡するため、Twitterのユーザー名を私たちに送信するために、チェッ" +"クボックスにチェックをつける必要があります。" -#: ../src\issueReporter\wx_ui.py:89 +#: src\issueReporter\wx_ui.py:90 +#, python-format msgid "" "Thanks for reporting this bug! In future versions, you may be able to find " "it in the changes list. You've reported the bug number %i" @@ -1482,374 +1516,350 @@ msgstr "" "のリストでそれを見つけることができるかもしれません。あなたは、バグ番号%iを報" "しました" -#: ../src\issueReporter\wx_ui.py:89 +#: src\issueReporter\wx_ui.py:90 msgid "reported" msgstr "レポート完了" -#: ../src\issueReporter\wx_ui.py:93 -msgid "Error while reporting" -msgstr "エラー" - -#: ../src\issueReporter\wx_ui.py:93 +#: src\issueReporter\wx_ui.py:94 msgid "" "Something unexpected occurred while trying to report the bug. Please, try " "again later" msgstr "" -"バグを報告しようとしているときに、予期しないエラーが発生しました。後でやり直" -"してください" +"バグの報告中に、予期しないエラーが発生しました。あとで再試行してください" -#: ../src\keystrokeEditor\constants.py:3 +#: src\issueReporter\wx_ui.py:94 +msgid "Error while reporting" +msgstr "エラー" + +#: src\keystrokeEditor\constants.py:4 msgid "Go up in the current buffer" msgstr "現在のバッファで、前のツイートに移動" -#: ../src\keystrokeEditor\constants.py:4 +#: src\keystrokeEditor\constants.py:5 msgid "Go down in the current buffer" msgstr "現在のバッファで、次のツイートに移動" -#: ../src\keystrokeEditor\constants.py:5 +#: src\keystrokeEditor\constants.py:6 msgid "Go to the previous buffer" msgstr "前のバッファに移動" -#: ../src\keystrokeEditor\constants.py:6 +#: src\keystrokeEditor\constants.py:7 msgid "Go to the next buffer" msgstr "次のバッファに移動" -#: ../src\keystrokeEditor\constants.py:7 +#: src\keystrokeEditor\constants.py:8 msgid "Focus the next session" msgstr "次のセッションにフォーカス" -#: ../src\keystrokeEditor\constants.py:8 +#: src\keystrokeEditor\constants.py:9 msgid "Focus the previous session" msgstr "前のセッションにフォーカス" -#: ../src\keystrokeEditor\constants.py:9 +#: src\keystrokeEditor\constants.py:10 msgid "Show or hide the GUI" msgstr "GUIの表示と非表示を切り替え" -#: ../src\keystrokeEditor\constants.py:10 +#: src\keystrokeEditor\constants.py:11 msgid "New tweet" msgstr "新規ツイート" -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 +#: src\keystrokeEditor\constants.py:13 src\wxUI\commonMessageDialogs.py:10 +#: src\wxUI\buffers\base.py:26 src\wxUI\dialogs\message.py:128 msgid "Retweet" msgstr "リツイート" -#: ../src\keystrokeEditor\constants.py:13 +#: src\keystrokeEditor\constants.py:14 msgid "Send direct message" msgstr "ダイレクトメッセージを作成" -#: ../src\keystrokeEditor\constants.py:14 +#: src\keystrokeEditor\constants.py:15 msgid "Like a tweet" msgstr "ツイートをいいねする" -#: ../src\keystrokeEditor\constants.py:15 +#: src\keystrokeEditor\constants.py:16 msgid "Like/unlike a tweet" msgstr "ツイートをいいね・いいね解除" -#: ../src\keystrokeEditor\constants.py:16 +#: src\keystrokeEditor\constants.py:17 msgid "Unlike a tweet" msgstr "ツイートのいいねを解除" -#: ../src\keystrokeEditor\constants.py:17 +#: src\keystrokeEditor\constants.py:18 msgid "Open the user actions dialogue" msgstr "ユーザーのアクションを選択する画面を表示" -#: ../src\keystrokeEditor\constants.py:18 +#: src\keystrokeEditor\constants.py:19 msgid "See user details" msgstr "ユーザーの詳細を表示" -#: ../src\keystrokeEditor\constants.py:19 +#: src\keystrokeEditor\constants.py:20 msgid "Show tweet" msgstr "ツイートを表示" -#: ../src\keystrokeEditor\constants.py:20 +#: src\keystrokeEditor\constants.py:21 msgid "Quit" msgstr "終了" -#: ../src\keystrokeEditor\constants.py:21 +#: src\keystrokeEditor\constants.py:22 msgid "Open user timeline" msgstr "特定のユーザーのタイムラインを開く" -#: ../src\keystrokeEditor\constants.py:22 +#: src\keystrokeEditor\constants.py:23 msgid "Destroy buffer" msgstr "現在のバッファを削除" -#: ../src\keystrokeEditor\constants.py:23 +#: src\keystrokeEditor\constants.py:24 msgid "Interact with the currently focused tweet." -msgstr "現在フォーカス中のツイートを相呼応する" +msgstr "現在フォーカス中のツイートを相呼応する。" -#: ../src\keystrokeEditor\constants.py:24 +#: src\keystrokeEditor\constants.py:25 msgid "Open URL" msgstr "URLを開く" -#: ../src\keystrokeEditor\constants.py:25 +#: src\keystrokeEditor\constants.py:26 msgid "View in Twitter" -msgstr "ツイッターで見る" +msgstr "Twitterで見る" -#: ../src\keystrokeEditor\constants.py:26 +#: src\keystrokeEditor\constants.py:27 msgid "Increase volume by 5%" msgstr "音量を5パーセント上げる" -#: ../src\keystrokeEditor\constants.py:27 +#: src\keystrokeEditor\constants.py:28 msgid "Decrease volume by 5%" msgstr "音量を5パーセント下げる" -#: ../src\keystrokeEditor\constants.py:28 +#: src\keystrokeEditor\constants.py:29 msgid "Jump to the first element of a buffer" msgstr "現在のバッファの先頭に移動" -#: ../src\keystrokeEditor\constants.py:29 +#: src\keystrokeEditor\constants.py:30 msgid "Jump to the last element of the current buffer" msgstr "現在のバッファの最後に移動" -#: ../src\keystrokeEditor\constants.py:30 +#: src\keystrokeEditor\constants.py:31 msgid "Jump 20 elements up in the current buffer" msgstr "20個前の要素に移動" -#: ../src\keystrokeEditor\constants.py:31 +#: src\keystrokeEditor\constants.py:32 msgid "Jump 20 elements down in the current buffer" msgstr "20個先の要素に移動" -#: ../src\keystrokeEditor\constants.py:32 +#: src\keystrokeEditor\constants.py:33 msgid "Edit profile" msgstr "プロフィールを編集" -#: ../src\keystrokeEditor\constants.py:33 +#: src\keystrokeEditor\constants.py:34 msgid "Delete a tweet or direct message" msgstr "ツイートまたはダイレクトメッセージを削除" -#: ../src\keystrokeEditor\constants.py:34 +#: src\keystrokeEditor\constants.py:35 msgid "Empty the current buffer" msgstr "現在のバッファをクリア" -#: ../src\keystrokeEditor\constants.py:35 +#: src\keystrokeEditor\constants.py:36 msgid "Repeat last item" msgstr "現在のアイテムをもう一度読み上げ" -#: ../src\keystrokeEditor\constants.py:36 +#: src\keystrokeEditor\constants.py:37 msgid "Copy to clipboard" msgstr "クリップボードにコピー" -#: ../src\keystrokeEditor\constants.py:37 +#: src\keystrokeEditor\constants.py:38 msgid "Add to list" msgstr "リストに追加" -#: ../src\keystrokeEditor\constants.py:38 +#: src\keystrokeEditor\constants.py:39 msgid "Remove from list" msgstr "リストから削除" -#: ../src\keystrokeEditor\constants.py:39 +#: src\keystrokeEditor\constants.py:40 msgid "Mute/unmute the active buffer" msgstr "現在のバッファのミュートを切り替え" -#: ../src\keystrokeEditor\constants.py:40 +#: src\keystrokeEditor\constants.py:41 msgid "Mute/unmute the current session" msgstr "現在のセッションのミュートを切り替え" -#: ../src\keystrokeEditor\constants.py:41 +#: src\keystrokeEditor\constants.py:42 msgid "toggle the automatic reading of incoming tweets in the active buffer" msgstr "新着のツイートを自動で読み上げるかどうかを設定" -#: ../src\keystrokeEditor\constants.py:42 +#: src\keystrokeEditor\constants.py:43 msgid "Search on twitter" -msgstr "ツイッターを検索" +msgstr "Twitterを検索" -#: ../src\keystrokeEditor\constants.py:43 +#: src\keystrokeEditor\constants.py:44 msgid "Find a string in the currently focused buffer" msgstr "現在のバッファ内の文字列を検索" -#: ../src\keystrokeEditor\constants.py:44 +#: src\keystrokeEditor\constants.py:45 msgid "Show the keystroke editor" msgstr "キーストロークエディタを表示" -#: ../src\keystrokeEditor\constants.py:45 +#: src\keystrokeEditor\constants.py:46 msgid "Show lists for a specified user" msgstr "特定のユーザーのリストを表示" -#: ../src\keystrokeEditor\constants.py:46 +#: src\keystrokeEditor\constants.py:47 msgid "load previous items" msgstr "以前のアイテムを取得" -#: ../src\keystrokeEditor\constants.py:47 +#: src\keystrokeEditor\constants.py:48 msgid "Get geolocation" msgstr "位置情報を取得" -#: ../src\keystrokeEditor\constants.py:48 +#: src\keystrokeEditor\constants.py:49 msgid "Display the tweet's geolocation in a dialog" msgstr "位置情報を表示" -#: ../src\keystrokeEditor\constants.py:49 +#: src\keystrokeEditor\constants.py:50 msgid "Create a trending topics buffer" -msgstr "トレンドの話題のバッファを作成" +msgstr "トレンドのバッファを作成" -#: ../src\keystrokeEditor\constants.py:50 +#: src\keystrokeEditor\constants.py:51 msgid "View conversation" msgstr "会話を見る" -#: ../src\keystrokeEditor\constants.py:51 +#: src\keystrokeEditor\constants.py:52 msgid "Check and download updates" msgstr "アップデートをチェックしてダウンロード" -#: ../src\keystrokeEditor\constants.py:52 +#: src\keystrokeEditor\constants.py:53 msgid "" "Opens the list manager, which allows you to create, edit, delete and open " "lists in buffers." msgstr "" -"リストを作成したり、編集したり、削除したりするために「リストの管理」を開く" +"リストを作成したり、編集したり、削除したりするために「リストの管理」を開く。" -#: ../src\keystrokeEditor\constants.py:53 +#: src\keystrokeEditor\constants.py:54 msgid "Opens the global settings dialogue" msgstr "「全般設定」ダイアログを開く" -#: ../src\keystrokeEditor\constants.py:54 -#, fuzzy +#: src\keystrokeEditor\constants.py:55 msgid "Opens the list manager" msgstr "リストの管理" -#: ../src\keystrokeEditor\constants.py:55 +#: src\keystrokeEditor\constants.py:56 msgid "Opens the account settings dialogue" msgstr "「アカウント設定」ダイアログを開く" -#: ../src\keystrokeEditor\constants.py:56 +#: src\keystrokeEditor\constants.py:57 msgid "Try to play an audio file" msgstr "音声ファイルの再生" -#: ../src\keystrokeEditor\constants.py:57 +#: src\keystrokeEditor\constants.py:58 msgid "Updates the buffer and retrieves possible lost items there." -msgstr "バッファを更新して、取得に失敗したアイテムを取得" +msgstr "バッファを更新して、取得に失敗したアイテムを取得。" -#: ../src\keystrokeEditor\constants.py:58 +#: src\keystrokeEditor\constants.py:59 msgid "Extracts the text from a picture and displays the result in a dialog." msgstr "画像からテキストを抽出して、結果をダイアログで表示。" -#: ../src\keystrokeEditor\wx_ui.py:8 +#: src\keystrokeEditor\wx_ui.py:9 msgid "Keystroke editor" msgstr "キーストロークエディタ" -#: ../src\keystrokeEditor\wx_ui.py:12 +#: src\keystrokeEditor\wx_ui.py:13 msgid "Select a keystroke to edit" msgstr "編集するキーストロークを選択" -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "キーストローク" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 +#: src\keystrokeEditor\wx_ui.py:14 src\wxUI\dialogs\userActions.py:10 +#: src\wxUI\dialogs\userActions.py:19 src\wxUI\dialogs\userActions.py:20 msgid "Action" msgstr "操作" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 +#: src\keystrokeEditor\wx_ui.py:14 +msgid "Keystroke" +msgstr "キーストローク" + +#: src\keystrokeEditor\wx_ui.py:19 src\wxUI\dialogs\filterDialogs.py:131 +#: src\wxUI\dialogs\lists.py:20 msgid "Edit" msgstr "編集" -#: ../src\keystrokeEditor\wx_ui.py:20 +#: src\keystrokeEditor\wx_ui.py:21 msgid "Execute action" msgstr "現在の動作を実行" -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 +#: src\keystrokeEditor\wx_ui.py:22 src\wxUI\dialogs\configuration.py:398 +#: src\wxUI\dialogs\utils.py:39 msgid "Close" msgstr "閉じる" -#: ../src\keystrokeEditor\wx_ui.py:48 +#: src\keystrokeEditor\wx_ui.py:49 msgid "Editing keystroke" msgstr "キーストロークを編集" -#: ../src\keystrokeEditor\wx_ui.py:51 +#: src\keystrokeEditor\wx_ui.py:52 msgid "Control" msgstr "コントロール" -#: ../src\keystrokeEditor\wx_ui.py:52 +#: src\keystrokeEditor\wx_ui.py:53 msgid "Alt" msgstr "オルト" -#: ../src\keystrokeEditor\wx_ui.py:53 +#: src\keystrokeEditor\wx_ui.py:54 msgid "Shift" msgstr "シフト" -#: ../src\keystrokeEditor\wx_ui.py:54 +#: src\keystrokeEditor\wx_ui.py:55 msgid "Windows" msgstr "ウィンドウズ" -#: ../src\keystrokeEditor\wx_ui.py:60 +#: src\keystrokeEditor\wx_ui.py:61 msgid "Key" msgstr "キー名" -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 +#: src\keystrokeEditor\wx_ui.py:66 src\wxUI\dialogs\filterDialogs.py:82 +#: src\wxUI\dialogs\find.py:21 src\wxUI\dialogs\utils.py:36 msgid "OK" msgstr "OK" -#: ../src\keystrokeEditor\wx_ui.py:78 +#: src\keystrokeEditor\wx_ui.py:79 msgid "You need to use the Windows key" msgstr "ウィンドウズキーを使用する必要があります" -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 +#: src\keystrokeEditor\wx_ui.py:79 src\keystrokeEditor\wx_ui.py:82 msgid "Invalid keystroke" msgstr "無効なキーストローク" -#: ../src\keystrokeEditor\wx_ui.py:81 +#: src\keystrokeEditor\wx_ui.py:82 msgid "You must provide a character for the keystroke" msgstr "キー名が入力されていません" -#: ../src\languageHandler.py:99 -msgid "User default" -msgstr "ユーザーのデフォルト" - -#: ../src\main.py:105 -msgid "https://twblue.es/donate" -msgstr "https://twblue.es/donate" - -#: ../src\main.py:122 -msgid "" -"{0} is already running. Close the other instance before starting this one. " -"If you're sure that {0} isn't running, try deleting the file at {1}. If " -"you're unsure of how to do this, contact the {0} developers." -msgstr "" -"{0} は、すでに起動しています。実行する前に、以前に起動しているものを終了させ" -"てください。{0} が起動していないことが確実な場合は、 {1} にあるファイルを削除" -"してみてください.削除方法が不明の場合は、 {0} の開発者までご連絡ください。" - -#: ../src\sessionmanager\wxUI.py:8 +#: src\sessionmanager\wxUI.py:9 msgid "Session manager" msgstr "セッションの管理" -#: ../src\sessionmanager\wxUI.py:11 +#: src\sessionmanager\wxUI.py:12 msgid "Accounts list" msgstr "アカウントリスト" -#: ../src\sessionmanager\wxUI.py:13 +#: src\sessionmanager\wxUI.py:14 msgid "Account" msgstr "アカウント" -#: ../src\sessionmanager\wxUI.py:17 +#: src\sessionmanager\wxUI.py:18 msgid "New account" msgstr "新しいアカウントを連携" -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 +#: src\sessionmanager\wxUI.py:19 src\sessionmanager\wxUI.py:65 msgid "Remove account" msgstr "このアカウントを削除" -#: ../src\sessionmanager\wxUI.py:19 +#: src\sessionmanager\wxUI.py:20 msgid "Global Settings" msgstr "全体の設定" -#: ../src\sessionmanager\wxUI.py:42 +#: src\sessionmanager\wxUI.py:43 +msgid "You need to configure an account." +msgstr "アカウントを設定する必要があります。" + +#: src\sessionmanager\wxUI.py:43 msgid "Account Error" msgstr "アカウントエラー" -#: ../src\sessionmanager\wxUI.py:42 -msgid "You need to configure an account." -msgstr "アカウントを設定する必要があります" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "Authorization" -msgstr "認証" - -#: ../src\sessionmanager\wxUI.py:48 +#: src\sessionmanager\wxUI.py:49 msgid "" "The request to authorize your Twitter account will be opened in your " "browser. You only need to do this once. Would you like to continue?" @@ -1857,15 +1867,16 @@ msgstr "" "アカウントを認証するために、ブラウザを開きます。あなたは、一度だけ、これを実" "行する必要があります。続行しますか?" -#: ../src\sessionmanager\wxUI.py:52 +#: src\sessionmanager\wxUI.py:49 +msgid "Authorization" +msgstr "認証" + +#: src\sessionmanager\wxUI.py:53 +#, python-format msgid "Authorized account %d" msgstr "認証したアカウント%d" -#: ../src\sessionmanager\wxUI.py:58 -msgid "Invalid user token" -msgstr "無効なユーザートークンです。" - -#: ../src\sessionmanager\wxUI.py:58 +#: src\sessionmanager\wxUI.py:59 msgid "" "Your access token is invalid or the authorization has failed. Please try " "again." @@ -1873,30 +1884,51 @@ msgstr "" "あなたのアクセストークンが無効であるか、または許可が失敗しました。もう一度や" "り直してください。" -#: ../src\sessionmanager\wxUI.py:64 +#: src\sessionmanager\wxUI.py:59 +msgid "Invalid user token" +msgstr "無効なユーザートークン" + +#: src\sessionmanager\wxUI.py:65 msgid "Do you really want to delete this account?" msgstr "本当にこのアカウントを削除しますか?" -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 +#: src\sessionmanager\wxUI.py:81 +msgid "" +"TWBlue is unable to authenticate the account for {} in Twitter. It might be " +"due to an invalid or expired token, revoqued access to the application, or " +"after an account reactivation. Please remove the account manually from your " +"Twitter sessions in order to stop seeing this message." +msgstr "" +"TWBlueはTwitterで {} のアカウントを認証できません。トークンが無効または期限切" +"れであるか、アプリケーションへのアクセスが取り消されているか、アカウントの再" +"アクティブ化が原因である可能性があります。このメッセージの表示を停止するに" +"は、Twitterセッションからアカウントを手動で削除してください。" + +#: src\sessionmanager\wxUI.py:81 +msgid "Authentication error for session {}" +msgstr "セッション {} の認証エラー" + +#: src\sessions\twitter\compose.py:45 src\sessions\twitter\compose.py:89 +#: src\sessions\twitter\compose.py:149 src\sessions\twitter\compose.py:158 msgid "dddd, MMMM D, YYYY H:m:s" msgstr "YYYY年MMMMD日(dddd) H時m分s秒" -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 +#: src\sessions\twitter\compose.py:97 src\sessions\twitter\compose.py:99 +#, python-format msgid "Dm to %s " -msgstr "「%s」へのDM" +msgstr "「%s」へのDM " -#: ../src\sessions\twitter\compose.py:141 +#: src\sessions\twitter\compose.py:138 +#, python-brace-format msgid "{0}. Quoted tweet from @{1}: {2}" msgstr "{0} 引用:@{1}:{2}" -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 +#: src\sessions\twitter\compose.py:160 src\sessions\twitter\compose.py:162 msgid "Unavailable" msgstr "無効" -#: ../src\sessions\twitter\compose.py:166 +#: src\sessions\twitter\compose.py:163 +#, python-format msgid "" "%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " "Twitter %s" @@ -1904,60 +1936,55 @@ msgstr "" "%s: @%s フォロワー: %s フォロー: %s ツイート数: %s 最後のツイート: %s ツイッ" "ターへの参加: %s" -#: ../src\sessions\twitter\compose.py:170 +#: src\sessions\twitter\compose.py:167 msgid "No description available" msgstr "説明はありません" -#: ../src\sessions\twitter\compose.py:174 +#: src\sessions\twitter\compose.py:171 msgid "private" msgstr "プライベート" -#: ../src\sessions\twitter\compose.py:175 +#: src\sessions\twitter\compose.py:172 msgid "public" msgstr "公式" -#: ../src\sessions\twitter\session.py:169 -#, fuzzy +#: src\sessions\twitter\session.py:170 msgid "There are no more items to retrieve in this buffer." -msgstr "このツイートには、ジェオタグは存在しません" +msgstr "このバッファで取得するアイテムはありません。" -#: ../src\sessions\twitter\session.py:215 +#: src\sessions\twitter\session.py:216 +#, python-format msgid "%s failed. Reason: %s" -msgstr "%s" +msgstr "%s が失敗しました。理由: %s" -#: ../src\sessions\twitter\session.py:221 +#: src\sessions\twitter\session.py:222 +#, python-format msgid "%s succeeded." msgstr "%sに成功しました。" -#: ../src\sessions\twitter\utils.py:225 +#: src\sessions\twitter\utils.py:203 msgid "Sorry, you are not authorised to see this status." -msgstr "申し訳ありませんが、あなたはこのステータスを表示する権限がありません" +msgstr "申し訳ありませんが、あなたはこのステータスを表示する権限がありません。" -#: ../src\sessions\twitter\utils.py:227 +#: src\sessions\twitter\utils.py:205 msgid "No status found with that ID" msgstr "そのIDのステータスが見つかりませんでした" -#: ../src\sessions\twitter\utils.py:229 +#: src\sessions\twitter\utils.py:207 +#, python-brace-format msgid "Error code {0}" msgstr "エラーコード {0}" -#: ../src\sessions\twitter\wxUI.py:6 +#: src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." msgstr "アカウントを連携中…" -#: ../src\sessions\twitter\wxUI.py:9 +#: src\sessions\twitter\wxUI.py:10 msgid "Enter your PIN code here" msgstr "PINコードを入力" -#: ../src\sound.py:159 -msgid "Stopped." -msgstr "停止" - -#: ../src\update\wxUpdater.py:10 -msgid "New version for %s" -msgstr "「%s」の新しいバージョン" - -#: ../src\update\wxUpdater.py:10 +#: src\update\wxUpdater.py:14 +#, python-format msgid "" "There's a new %s version available, released on %s. Would you like to " "download it now?\n" @@ -1970,90 +1997,42 @@ msgstr "" "%sの新しいバージョンが%sにリリースされています。今すぐダウンロードします" "か?\n" "\n" -"%sバージョン:%s\n" +"%sバージョン: %s\n" "\n" -"更新履歴:\n" +"更新履歴: \n" "%s" -#: ../src\update\wxUpdater.py:18 +#: src\update\wxUpdater.py:14 +#, python-format +msgid "New version for %s" +msgstr "「%s」の新しいバージョン" + +#: src\update\wxUpdater.py:22 msgid "Download in Progress" msgstr "ダウンロード中" -#: ../src\update\wxUpdater.py:18 +#: src\update\wxUpdater.py:22 msgid "Downloading the new version..." -msgstr "新しいバージョンをダウンロードしています" +msgstr "新しいバージョンをダウンロード中…" -#: ../src\update\wxUpdater.py:28 +#: src\update\wxUpdater.py:32 +#, python-format msgid "Updating... %s of %s" msgstr "アップデート中… %s/%s" -#: ../src\update\wxUpdater.py:31 -msgid "Done!" -msgstr "完了" - -#: ../src\update\wxUpdater.py:31 +#: src\update\wxUpdater.py:35 msgid "" "The update has been downloaded and installed successfully. Press OK to " "continue." msgstr "" -"アップデートは正常にインストールされました。続行する場合は、「OK」を押してく" -"ださい" +"アップデートは正常にダウンロードされ、インストールされました。続行する場合" +"は、「OK」を押してください。" -#: ../src\wxUI\buffers\base.py:11 -msgid "Client" -msgstr "クライアント" +#: src\update\wxUpdater.py:35 +msgid "Done!" +msgstr "完了!" -#: ../src\wxUI\buffers\base.py:11 -msgid "Text" -msgstr "内容" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 -msgid "Date" -msgstr "日時" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 -msgid "User" -msgstr "ユーザー" - -#: ../src\wxUI\buffers\base.py:27 -msgid "Direct message" -msgstr "ダイレクトメッセージ" - -#: ../src\wxUI\buffers\events.py:13 -msgid "Event" -msgstr "イベント" - -#: ../src\wxUI\buffers\events.py:15 -msgid "Remove event" -msgstr "イベントを削除" - -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 -msgid "Login" -msgstr "ログイン" - -#: ../src\wxUI\buffers\panels.py:13 -msgid "Log in automatically" -msgstr "自動的にログインする" - -#: ../src\wxUI\buffers\panels.py:21 -msgid "Logout" -msgstr "ログアウト" - -#: ../src\wxUI\buffers\trends.py:8 -msgid "Trending topic" -msgstr "トレンドの話題" - -#: ../src\wxUI\buffers\trends.py:18 -msgid "Tweet about this trend" -msgstr "このトレンドのツイート" - -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 -msgid "Search topic" -msgstr "トピックを検索" - -#: ../src\wxUI\commonMessageDialogs.py:6 +#: src\wxUI\commonMessageDialogs.py:7 msgid "" "This retweet is over 140 characters. Would you like to post it as a mention " "to the poster with your comments and a link to the original tweet?" @@ -2061,39 +2040,41 @@ msgstr "" "このリツイートは、140文字を超えています。投稿者へのリプライとコメント、お" "よび元のツイートへのリンクで登校しますか?" -#: ../src\wxUI\commonMessageDialogs.py:9 +#: src\wxUI\commonMessageDialogs.py:10 msgid "Would you like to add a comment to this tweet?" msgstr "このツイートにコメントをつけますか?" -#: ../src\wxUI\commonMessageDialogs.py:12 +#: src\wxUI\commonMessageDialogs.py:13 msgid "" "Do you really want to delete this tweet? It will be deleted from Twitter as " "well." msgstr "" -"本当にこのツイートを削除しますか?このツイートは、ツイッターから削除されま" -"す。" +"本当にこのツイートを削除しますか?このツイートは、Twitterから削除されます。" -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 +#: src\wxUI\commonMessageDialogs.py:13 src\wxUI\dialogs\lists.py:149 msgid "Delete" msgstr "削除" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: src\wxUI\commonMessageDialogs.py:16 +#, python-brace-format msgid "Do you really want to close {0}?" msgstr "本当に「{0}」を終了しますか?" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: src\wxUI\commonMessageDialogs.py:16 msgid "Exit" msgstr "終了確認" -#: ../src\wxUI\commonMessageDialogs.py:19 +#: src\wxUI\commonMessageDialogs.py:20 +#, python-brace-format msgid " {0} must be restarted for these changes to take effect." msgstr "これらの変更を有効にするには、「{0}」を再起動する必要があります。" -#: ../src\wxUI\commonMessageDialogs.py:19 +#: src\wxUI\commonMessageDialogs.py:20 +#, python-brace-format msgid "Restart {0} " msgstr "「{0}」を再起動" -#: ../src\wxUI\commonMessageDialogs.py:22 +#: src\wxUI\commonMessageDialogs.py:23 msgid "" "Are you sure you want to delete this user from the database? This user will " "not appear in autocomplete results anymore." @@ -2101,56 +2082,54 @@ msgstr "" "データベースからこのユーザーを削除してもよろしいですか?このユーザーは、自動" "補完結果には表示されません。" -#: ../src\wxUI\commonMessageDialogs.py:22 +#: src\wxUI\commonMessageDialogs.py:23 msgid "Confirm" msgstr "確認" -#: ../src\wxUI\commonMessageDialogs.py:25 +#: src\wxUI\commonMessageDialogs.py:26 msgid "Enter the name of the client : " -msgstr "クライアントの名前:" +msgstr "クライアントの名前: " -#: ../src\wxUI\commonMessageDialogs.py:25 -#: ../src\wxUI\dialogs\configuration.py:246 +#: src\wxUI\commonMessageDialogs.py:26 src\wxUI\dialogs\configuration.py:248 msgid "Add client" msgstr "クライアントを追加" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: src\wxUI\commonMessageDialogs.py:32 msgid "" "Do you really want to empty this buffer? It's items will be removed from " "the list but not from Twitter" msgstr "" -"本当にこのバッファをクリアしますか?これは、ツイッターからは削除されません。" +"本当にこのバッファをクリアしますか?これは、Twitterからは削除されません。" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: src\wxUI\commonMessageDialogs.py:32 msgid "Empty buffer" msgstr "バッファをクリア" -#: ../src\wxUI\commonMessageDialogs.py:35 +#: src\wxUI\commonMessageDialogs.py:36 msgid "Do you really want to destroy this buffer?" msgstr "本当にこのバッファを削除しますか?" -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 +#: src\wxUI\commonMessageDialogs.py:36 src\wxUI\commonMessageDialogs.py:86 msgid "Attention" msgstr "確認" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: src\wxUI\commonMessageDialogs.py:42 msgid "A timeline for this user already exists. You can't open another" msgstr "" "そのユーザーのタイムラインは、既に開かれています。他のユーザーを開いてくださ" "い。" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: src\wxUI\commonMessageDialogs.py:42 msgid "Existing timeline" msgstr "既存のタイムライン" -#: ../src\wxUI\commonMessageDialogs.py:44 +#: src\wxUI\commonMessageDialogs.py:45 msgid "This user has no tweets, so you can't open a timeline for them." msgstr "" "このユーザーは、何もツイートしていないため、タイムラインを開くことができませ" "ん。" -#: ../src\wxUI\commonMessageDialogs.py:47 +#: src\wxUI\commonMessageDialogs.py:48 msgid "" "This is a protected Twitter user, which means you can't open a timeline " "using the Streaming API. The user's tweets will not update due to a twitter " @@ -2160,12 +2139,11 @@ msgstr "" "ムラインを開くことができないことを意味します。ユーザーのツイートはTwitterのポ" "リシーにより更新されません。続行しますか?" -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 +#: src\wxUI\commonMessageDialogs.py:48 src\wxUI\commonMessageDialogs.py:95 msgid "Warning" msgstr "警告" -#: ../src\wxUI\commonMessageDialogs.py:50 +#: src\wxUI\commonMessageDialogs.py:51 msgid "" "This is a protected user account, you need to follow this user to view their " "tweets or likes." @@ -2173,7 +2151,8 @@ msgstr "" "このユーザーは保護されています。このユーザーのツイートやお気に入り一覧を見る" "には、このユーザーをフォローする必要があります。" -#: ../src\wxUI\commonMessageDialogs.py:53 +#: src\wxUI\commonMessageDialogs.py:54 +#, python-brace-format msgid "" "If you like {0} we need your help to keep it going. Help us by donating to " "the project. This will help us pay for the server, the domain and some other " @@ -2187,47 +2166,48 @@ msgstr "" "ののために支払うのに役立ちます。あなたの寄付は私たちに「{0}」の開発を継続する" "ための手段を与え、自由な「{0}」を維持します。今すぐ寄付しますか?" -#: ../src\wxUI\commonMessageDialogs.py:53 +#: src\wxUI\commonMessageDialogs.py:54 msgid "We need your help" msgstr "寄付のお願い" -#: ../src\wxUI\commonMessageDialogs.py:57 +#: src\wxUI\commonMessageDialogs.py:58 +#, python-brace-format msgid "This user has no tweets. {0} can't create a timeline." msgstr "" "このユーザーにはツイートがないため、「{0}」のタイムラインを作成することはでき" "ません。" -#: ../src\wxUI\commonMessageDialogs.py:60 +#: src\wxUI\commonMessageDialogs.py:61 +#, python-brace-format msgid "This user has no favorited tweets. {0} can't create a timeline." msgstr "" "このユーザーには、お気に入り登録されたツイートがないため、「{0}」のタイムライ" "ンを作成することはできません。" -#: ../src\wxUI\commonMessageDialogs.py:63 +#: src\wxUI\commonMessageDialogs.py:64 +#, python-brace-format msgid "This user has no followers. {0} can't create a timeline." msgstr "" "このユーザーのフォロワーがいないため、「{0}」でタイムラインを作ることはできま" "せん。" -#: ../src\wxUI\commonMessageDialogs.py:66 +#: src\wxUI\commonMessageDialogs.py:67 +#, python-brace-format msgid "This user has no friends. {0} can't create a timeline." msgstr "" "このユーザーは、誰もフォローしていないため、「{0}」でタイムラインを作ることは" "できません。" -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geo data for this tweet" -msgstr "このツイートの位置情報" - -#: ../src\wxUI\commonMessageDialogs.py:70 +#: src\wxUI\commonMessageDialogs.py:71 +#, python-brace-format msgid "Geolocation data: {0}" msgstr "位置情報: {0}" -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "Information" -msgstr "情報" +#: src\wxUI\commonMessageDialogs.py:71 +msgid "Geo data for this tweet" +msgstr "このツイートの位置情報" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: src\wxUI\commonMessageDialogs.py:74 msgid "" "TWBlue has detected that you're running windows 10 and has changed the " "default keymap to the Windows 10 keymap. It means that some keyboard " @@ -2239,11 +2219,15 @@ msgstr "" "違うことを意味します。このキーマップで使用できる全てのショートカットを見るに" "は、Alt+Win+Kで、キーストロークエディタを開いて確認してください。" -#: ../src\wxUI\commonMessageDialogs.py:76 +#: src\wxUI\commonMessageDialogs.py:74 +msgid "Information" +msgstr "情報" + +#: src\wxUI\commonMessageDialogs.py:77 msgid "You have been blocked from viewing this content" msgstr "このコンテンツの表示がブロックされています" -#: ../src\wxUI\commonMessageDialogs.py:79 +#: src\wxUI\commonMessageDialogs.py:80 msgid "" "You have been blocked from viewing someone's content. In order to avoid " "conflicts with the full session, TWBlue will remove the affected timeline." @@ -2251,170 +2235,515 @@ msgstr "" "他のユーザーのコンテンツを表示できないようになっています。フルセッションとの" "競合を避けるため、TWBlueは影響を受けるタイムラインを削除します。" -#: ../src\wxUI\commonMessageDialogs.py:82 +#: src\wxUI\commonMessageDialogs.py:83 msgid "" "TWBlue cannot load this timeline because the user has been suspended from " "Twitter." msgstr "" "ユーザーがTwitterから凍結されているため、このタイムラインをロードできません。" -#: ../src\wxUI\commonMessageDialogs.py:85 +#: src\wxUI\commonMessageDialogs.py:86 msgid "Do you really want to delete this filter?" msgstr "本当に、このフィルターを削除しますか?" -#: ../src\wxUI\commonMessageDialogs.py:88 +#: src\wxUI\commonMessageDialogs.py:89 msgid "This filter already exists. Please use a different title" msgstr "このフィルターはすでに利用されています。別の名前を利用してください" -#: ../src\wxUI\commonMessageDialogs.py:94 +#: src\wxUI\commonMessageDialogs.py:95 +#, python-brace-format msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." msgstr "" -"前回、 {0} は正常に終了しませんでした. この問題が継続して発生する場合には、 " -"{0} の開発者までレポートを送ってください。" +"{0}は、前回の実行時に予期せず終了しました。問題が解決しない場合は、{0}開発者" +"に報告してください。" -#: ../src\wxUI\dialogs\attach.py:9 +#: src\wxUI\menus.py:8 src\wxUI\view.py:32 +msgid "&Retweet" +msgstr "リツイート(&R)" + +#: src\wxUI\menus.py:10 src\wxUI\menus.py:34 src\wxUI\view.py:31 +msgid "Re&ply" +msgstr "リプライ(&P)" + +#: src\wxUI\menus.py:12 src\wxUI\view.py:33 +msgid "&Like" +msgstr "いいね(&L)" + +#: src\wxUI\menus.py:14 src\wxUI\view.py:34 +msgid "&Unlike" +msgstr "いいねを解除(&U)" + +#: src\wxUI\menus.py:16 src\wxUI\menus.py:36 src\wxUI\menus.py:52 +msgid "&Open URL" +msgstr "URLを開く(&O)" + +#: src\wxUI\menus.py:18 src\wxUI\menus.py:54 src\wxUI\menus.py:87 +msgid "&Open in Twitter" +msgstr "ツイッターを検索" + +#: src\wxUI\menus.py:20 src\wxUI\menus.py:38 src\wxUI\menus.py:56 +msgid "&Play audio" +msgstr "音声を再生(&P)" + +#: src\wxUI\menus.py:22 src\wxUI\menus.py:58 src\wxUI\view.py:35 +msgid "&Show tweet" +msgstr "ツイートを表示(&S)" + +#: src\wxUI\menus.py:24 src\wxUI\menus.py:42 src\wxUI\menus.py:60 +#: src\wxUI\menus.py:70 src\wxUI\menus.py:89 src\wxUI\menus.py:103 +msgid "&Copy to clipboard" +msgstr "クリップボードにコピー(&C)" + +#: src\wxUI\menus.py:26 src\wxUI\menus.py:44 src\wxUI\menus.py:62 +#: src\wxUI\menus.py:72 src\wxUI\view.py:39 +msgid "&Delete" +msgstr "削除(&D)" + +#: src\wxUI\menus.py:28 src\wxUI\menus.py:46 src\wxUI\menus.py:91 +msgid "&User actions..." +msgstr "ユーザーのアクション(&U)" + +#: src\wxUI\menus.py:40 +msgid "&Show direct message" +msgstr "ダイレクトメッセージを表示(&S)" + +#: src\wxUI\menus.py:68 +msgid "&Show event" +msgstr "イベントを表示(&S)" + +#: src\wxUI\menus.py:78 +msgid "Direct &message" +msgstr "ダイレクトメッセージ(&M)" + +#: src\wxUI\menus.py:80 src\wxUI\view.py:48 +msgid "&View lists" +msgstr "リストを見る(&V)" + +#: src\wxUI\menus.py:83 src\wxUI\view.py:49 +msgid "Show user &profile" +msgstr "ユーザーのプロフィールを表示(&P)" + +#: src\wxUI\menus.py:85 +msgid "&Show user" +msgstr "ユーザーを表示(&S)" + +#: src\wxUI\menus.py:97 src\wxUI\buffers\trends.py:20 +msgid "Search topic" +msgstr "トピックを検索" + +#: src\wxUI\menus.py:99 +msgid "&Tweet about this trend" +msgstr "このトレンドのツイート(&T)" + +#: src\wxUI\menus.py:101 +msgid "&Show item" +msgstr "アイテムを表示(&S)" + +#: src\wxUI\sysTrayIcon.py:36 src\wxUI\view.py:25 +msgid "&Global settings" +msgstr "全般設定(&G)" + +#: src\wxUI\sysTrayIcon.py:37 src\wxUI\view.py:24 +msgid "Account se&ttings" +msgstr "アカウント設定(&T(" + +#: src\wxUI\sysTrayIcon.py:38 +msgid "Update &profile" +msgstr "プロフィールを更新(&P)" + +#: src\wxUI\sysTrayIcon.py:39 +msgid "&Show / hide" +msgstr "表示または非表示(&S)" + +#: src\wxUI\sysTrayIcon.py:40 src\wxUI\view.py:73 +msgid "&Documentation" +msgstr "取扱説明書(&D)" + +#: src\wxUI\sysTrayIcon.py:41 +msgid "Check for &updates" +msgstr "アップデートを確認(&U)" + +#: src\wxUI\sysTrayIcon.py:42 +msgid "&Exit" +msgstr "終了(&E)" + +#: src\wxUI\view.py:18 +msgid "&Manage accounts" +msgstr "アカウントの管理(&M)" + +#: src\wxUI\view.py:19 src\wxUI\dialogs\update_profile.py:35 +msgid "&Update profile" +msgstr "プロフィールを更新(&U)" + +#: src\wxUI\view.py:20 +msgid "&Hide window" +msgstr "ウィンドウを隠す(&H)" + +#: src\wxUI\view.py:21 src\wxUI\dialogs\search.py:15 +msgid "&Search" +msgstr "検索(&S)" + +#: src\wxUI\view.py:22 +msgid "&Lists manager" +msgstr "リストの管理(&L)" + +#: src\wxUI\view.py:23 +msgid "&Edit keystrokes" +msgstr "キーストロークを編集(&E)" + +#: src\wxUI\view.py:26 +msgid "E&xit" +msgstr "終了(&X)" + +#: src\wxUI\view.py:30 src\wxUI\view.py:84 +msgid "&Tweet" +msgstr "ツイート(&T)" + +#: src\wxUI\view.py:36 +msgid "View &address" +msgstr "位置情報を表示(&A)" + +#: src\wxUI\view.py:37 +msgid "View conversa&tion" +msgstr "会話を見る(&T)" + +#: src\wxUI\view.py:38 +msgid "Read text in picture" +msgstr "画像からテキストを読み取り" + +#: src\wxUI\view.py:43 +msgid "&Actions..." +msgstr "操作(&A)" + +#: src\wxUI\view.py:44 +msgid "&View timeline..." +msgstr "タイムラインを表示(&V)" + +#: src\wxUI\view.py:45 +msgid "Direct me&ssage" +msgstr "ダイレクトメッセージ(&S)" + +#: src\wxUI\view.py:46 +msgid "&Add to list" +msgstr "リストに追加(&A)" + +#: src\wxUI\view.py:47 +msgid "R&emove from list" +msgstr "リストから削除(&E)" + +#: src\wxUI\view.py:50 +msgid "V&iew likes" +msgstr "いいね一覧を見る(&I)" + +#: src\wxUI\view.py:54 +msgid "&Update buffer" +msgstr "バッファを更新(&U)" + +#: src\wxUI\view.py:55 +msgid "New &trending topics buffer..." +msgstr "新しいトレンドのバッファ(&T)" + +#: src\wxUI\view.py:56 +msgid "Create a &filter" +msgstr "新しいフィルターを作成(&F)" + +#: src\wxUI\view.py:57 +msgid "&Manage filters" +msgstr "フィルターの管理(&M)" + +#: src\wxUI\view.py:58 +msgid "Find a string in the currently focused buffer..." +msgstr "現在フォーカス中のバッファ内の文字列を検索..." + +#: src\wxUI\view.py:59 +msgid "&Load previous items" +msgstr "以前のアイテムを取得(&L)" + +#: src\wxUI\view.py:61 src\wxUI\dialogs\userActions.py:22 +msgid "&Mute" +msgstr "ミュート(&M)" + +#: src\wxUI\view.py:62 +msgid "&Autoread" +msgstr "自動読み上げ(&A)" + +#: src\wxUI\view.py:63 +msgid "&Clear buffer" +msgstr "バッファをクリア(&C)" + +#: src\wxUI\view.py:64 +msgid "&Destroy" +msgstr "バッファを削除(&D)" + +#: src\wxUI\view.py:68 +msgid "&Seek back 5 seconds" +msgstr "5秒戻る(&S)" + +#: src\wxUI\view.py:69 +msgid "&Seek forward 5 seconds" +msgstr "5秒進む(&S)" + +#: src\wxUI\view.py:74 +msgid "Sounds &tutorial" +msgstr "サウンドの確認(&T)" + +#: src\wxUI\view.py:75 +msgid "&What's new in this version?" +msgstr "更新履歴(&W)" + +#: src\wxUI\view.py:76 +msgid "&Check for updates" +msgstr "アップデートを確認(&C)" + +#: src\wxUI\view.py:77 +msgid "&Report an error" +msgstr "エラーを報告(&R)" + +#: src\wxUI\view.py:78 +#, python-brace-format +msgid "{0}'s &website" +msgstr "「{0}」のウェブサイト(&W)" + +#: src\wxUI\view.py:79 +msgid "Get soundpacks for TWBlue" +msgstr "TWBlueのサウンドパックを入手" + +#: src\wxUI\view.py:80 +#, python-brace-format +msgid "About &{0}" +msgstr "{0}について(&A)" + +#: src\wxUI\view.py:83 +msgid "&Application" +msgstr "アプリケーション(&A)" + +#: src\wxUI\view.py:85 src\wxUI\dialogs\userActions.py:11 +msgid "&User" +msgstr "ユーザー(&U)" + +#: src\wxUI\view.py:86 +msgid "&Buffer" +msgstr "バッファ(&B)" + +#: src\wxUI\view.py:87 +msgid "&Audio" +msgstr "音声(&A)" + +#: src\wxUI\view.py:88 +msgid "&Help" +msgstr "ヘルプ(&H)" + +#: src\wxUI\view.py:174 +msgid "Address" +msgstr "アドレス" + +#: src\wxUI\view.py:205 +#, python-brace-format +msgid "Your {0} version is up to date" +msgstr "「{0}」のバージョンは最新です" + +#: src\wxUI\view.py:205 +msgid "Update" +msgstr "アップデート" + +#: src\wxUI\buffers\base.py:12 src\wxUI\buffers\people.py:12 +#: src\wxUI\buffers\user_searches.py:11 src\wxUI\dialogs\userSelection.py:11 +#: src\wxUI\dialogs\utils.py:32 +msgid "User" +msgstr "ユーザー" + +#: src\wxUI\buffers\base.py:12 +msgid "Text" +msgstr "内容" + +#: src\wxUI\buffers\base.py:12 src\wxUI\buffers\events.py:14 +msgid "Date" +msgstr "日時" + +#: src\wxUI\buffers\base.py:12 +msgid "Client" +msgstr "クライアント" + +#: src\wxUI\buffers\base.py:28 +msgid "Direct message" +msgstr "ダイレクトメッセージ" + +#: src\wxUI\buffers\events.py:14 +msgid "Event" +msgstr "イベント" + +#: src\wxUI\buffers\events.py:16 +msgid "Remove event" +msgstr "イベントを削除" + +#: src\wxUI\buffers\panels.py:12 src\wxUI\buffers\panels.py:20 +msgid "Login" +msgstr "ログイン" + +#: src\wxUI\buffers\panels.py:14 +msgid "Log in automatically" +msgstr "自動的にログインする" + +#: src\wxUI\buffers\panels.py:22 +msgid "Logout" +msgstr "ログアウト" + +#: src\wxUI\buffers\trends.py:9 +msgid "Trending topic" +msgstr "トレンド" + +#: src\wxUI\buffers\trends.py:19 +msgid "Tweet about this trend" +msgstr "このトレンドのツイート" + +#: src\wxUI\dialogs\attach.py:10 msgid "Add an attachment" msgstr "添付ファイルを追加" -#: ../src\wxUI\dialogs\attach.py:12 +#: src\wxUI\dialogs\attach.py:13 msgid "Attachments" msgstr "添付ファイル" -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Title" -msgstr "タイトル" - -#: ../src\wxUI\dialogs\attach.py:13 +#: src\wxUI\dialogs\attach.py:14 msgid "Type" msgstr "形式" -#: ../src\wxUI\dialogs\attach.py:18 +#: src\wxUI\dialogs\attach.py:14 +msgid "Title" +msgstr "タイトル" + +#: src\wxUI\dialogs\attach.py:19 msgid "Add attachments" msgstr "添付ファイルを追加" -#: ../src\wxUI\dialogs\attach.py:19 +#: src\wxUI\dialogs\attach.py:20 msgid "&Photo" msgstr "画像(&P)" -#: ../src\wxUI\dialogs\attach.py:20 +#: src\wxUI\dialogs\attach.py:21 msgid "Remove attachment" msgstr "添付ファイルを削除" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "画像ファイル (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: src\wxUI\dialogs\attach.py:37 src\wxUI\dialogs\message.py:118 +#: src\wxUI\dialogs\message.py:177 src\wxUI\dialogs\message.py:237 +#: src\wxUI\dialogs\update_profile.py:82 msgid "Select the picture to be uploaded" msgstr "アップロードする画像を選択" -#: ../src\wxUI\dialogs\attach.py:43 +#: src\wxUI\dialogs\attach.py:37 src\wxUI\dialogs\message.py:118 +#: src\wxUI\dialogs\message.py:177 src\wxUI\dialogs\message.py:237 +#: src\wxUI\dialogs\update_profile.py:82 +msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" +msgstr "画像ファイル (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" + +#: src\wxUI\dialogs\attach.py:44 msgid "please provide a description" msgstr "説明を入力" -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 +#: src\wxUI\dialogs\attach.py:44 src\wxUI\dialogs\lists.py:14 +#: src\wxUI\dialogs\lists.py:70 msgid "Description" msgstr "説明" -#: ../src\wxUI\dialogs\configuration.py:16 +#: src\wxUI\dialogs\configuration.py:18 msgid "Language" msgstr "言語" -#: ../src\wxUI\dialogs\configuration.py:23 +#: src\wxUI\dialogs\configuration.py:25 +#, python-brace-format msgid "Run {0} at Windows startup" msgstr "Windows起動時に{0}を実行" -#: ../src\wxUI\dialogs\configuration.py:24 +#: src\wxUI\dialogs\configuration.py:26 +#, python-brace-format msgid "ask before exiting {0}" msgstr "{0}を終了する前に確認" -#: ../src\wxUI\dialogs\configuration.py:27 +#: src\wxUI\dialogs\configuration.py:29 msgid "Disable Streaming functions" msgstr "ストリーミング機能を無効化する" -#: ../src\wxUI\dialogs\configuration.py:30 +#: src\wxUI\dialogs\configuration.py:32 msgid "Buffer update interval, in minutes" msgstr "バッファの更新間隔(分)" -#: ../src\wxUI\dialogs\configuration.py:36 +#: src\wxUI\dialogs\configuration.py:38 +#, python-brace-format msgid "Play a sound when {0} launches" msgstr "{0}が起動したときに、音声を再生" -#: ../src\wxUI\dialogs\configuration.py:38 +#: src\wxUI\dialogs\configuration.py:40 +#, python-brace-format msgid "Speak a message when {0} launches" msgstr "{0}が起動した際に、メッセージを読み上げ" -#: ../src\wxUI\dialogs\configuration.py:40 +#: src\wxUI\dialogs\configuration.py:42 msgid "Use invisible interface's keyboard shortcuts while GUI is visible" msgstr "GUI表示中でもGUI非表示時に利用できるショートカットを利用する" -#: ../src\wxUI\dialogs\configuration.py:42 +#: src\wxUI\dialogs\configuration.py:44 msgid "Activate Sapi5 when any other screen reader is not being run" msgstr "他のスクリーンリーダーが起動していないときは、Sapi5を利用する" -#: ../src\wxUI\dialogs\configuration.py:44 +#: src\wxUI\dialogs\configuration.py:46 msgid "Hide GUI on launch" msgstr "起動時にGUIを隠す" -#: ../src\wxUI\dialogs\configuration.py:46 +#: src\wxUI\dialogs\configuration.py:48 msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" msgstr "" "Codeofduskを利用して長いツイートをできるようにする(パフォーマンスが低下する" "場合があります)" -#: ../src\wxUI\dialogs\configuration.py:48 +#: src\wxUI\dialogs\configuration.py:50 msgid "Remember state for mention all and long tweet" msgstr "" "「全員にリプライ」および「ツイートを短縮して投稿」のチェック状態を保持する" -#: ../src\wxUI\dialogs\configuration.py:51 +#: src\wxUI\dialogs\configuration.py:53 msgid "Keymap" msgstr "キーマップ" -#: ../src\wxUI\dialogs\configuration.py:56 +#: src\wxUI\dialogs\configuration.py:58 +#, python-brace-format msgid "Check for updates when {0} launches" msgstr "{0}の起動時にアップデートを確認" -#: ../src\wxUI\dialogs\configuration.py:66 +#: src\wxUI\dialogs\configuration.py:68 msgid "Proxy type: " msgstr "プロキシタイプ: " -#: ../src\wxUI\dialogs\configuration.py:73 +#: src\wxUI\dialogs\configuration.py:75 msgid "Proxy server: " -msgstr "プロキシサーバー:" +msgstr "プロキシサーバー: " -#: ../src\wxUI\dialogs\configuration.py:79 +#: src\wxUI\dialogs\configuration.py:81 msgid "Port: " -msgstr "ポート:" +msgstr "ポート: " -#: ../src\wxUI\dialogs\configuration.py:85 +#: src\wxUI\dialogs\configuration.py:87 msgid "User: " -msgstr "ユーザー名:" +msgstr "ユーザー名: " -#: ../src\wxUI\dialogs\configuration.py:91 +#: src\wxUI\dialogs\configuration.py:93 msgid "Password: " -msgstr "パスワード:" +msgstr "パスワード: " -#: ../src\wxUI\dialogs\configuration.py:103 +#: src\wxUI\dialogs\configuration.py:105 msgid "Autocompletion settings..." -msgstr "自動保管の設定" +msgstr "自動保管の設定..." -#: ../src\wxUI\dialogs\configuration.py:105 +#: src\wxUI\dialogs\configuration.py:107 msgid "Relative timestamps" msgstr "相対的な時刻を利用する" -#: ../src\wxUI\dialogs\configuration.py:108 +#: src\wxUI\dialogs\configuration.py:110 msgid "Items on each API call" msgstr "各API呼び出しの回数" -#: ../src\wxUI\dialogs\configuration.py:114 +#: src\wxUI\dialogs\configuration.py:116 msgid "" "Inverted buffers: The newest tweets will be shown at the beginning while the " "oldest at the end" @@ -2422,15 +2751,15 @@ msgstr "" "バッファの並び順を入れ替える(新しいツイートを先頭に、古いツイートを最後に表" "示)" -#: ../src\wxUI\dialogs\configuration.py:116 +#: src\wxUI\dialogs\configuration.py:118 msgid "Retweet mode" msgstr "リツイートのモード" -#: ../src\wxUI\dialogs\configuration.py:122 +#: src\wxUI\dialogs\configuration.py:124 msgid "Show screen names instead of full names" msgstr "表示名の代わりに、ユーザー名を表示する" -#: ../src\wxUI\dialogs\configuration.py:124 +#: src\wxUI\dialogs\configuration.py:126 msgid "" "Number of items per buffer to cache in database (0 to disable caching, blank " "for unlimited)" @@ -2438,1006 +2767,566 @@ msgstr "" "バッファごとにデータベースにキャッシュする項目数(0はキャッシュしない、空欄の" "場合は無制限)" -#: ../src\wxUI\dialogs\configuration.py:134 +#: src\wxUI\dialogs\configuration.py:136 msgid "Enable automatic speech feedback" msgstr "自動音声フィードバックを有効化" -#: ../src\wxUI\dialogs\configuration.py:136 +#: src\wxUI\dialogs\configuration.py:138 msgid "Enable automatic Braille feedback" msgstr "自動点字フィードバックを有効化" -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "ステータス" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: src\wxUI\dialogs\configuration.py:146 src\wxUI\dialogs\filterDialogs.py:126 msgid "Buffer" msgstr "バッファ" -#: ../src\wxUI\dialogs\configuration.py:147 +#: src\wxUI\dialogs\configuration.py:146 +msgid "Status" +msgstr "ステータス" + +#: src\wxUI\dialogs\configuration.py:149 msgid "Show/hide" msgstr "表示または非表示" -#: ../src\wxUI\dialogs\configuration.py:148 +#: src\wxUI\dialogs\configuration.py:150 msgid "Move up" msgstr "上へ" -#: ../src\wxUI\dialogs\configuration.py:149 +#: src\wxUI\dialogs\configuration.py:151 msgid "Move down" msgstr "下へ" -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 +#: src\wxUI\dialogs\configuration.py:161 src\wxUI\dialogs\configuration.py:226 +#: src\wxUI\dialogs\configuration.py:229 src\wxUI\dialogs\configuration.py:234 msgid "Show" msgstr "表示" -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 +#: src\wxUI\dialogs\configuration.py:163 src\wxUI\dialogs\configuration.py:173 +#: src\wxUI\dialogs\configuration.py:197 src\wxUI\dialogs\configuration.py:227 msgid "Hide" msgstr "非表示" -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 +#: src\wxUI\dialogs\configuration.py:171 src\wxUI\dialogs\configuration.py:195 msgid "Select a buffer first." -msgstr "最初にバッファを選んでください" +msgstr "最初にバッファを選んでください。" -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 +#: src\wxUI\dialogs\configuration.py:174 src\wxUI\dialogs\configuration.py:198 msgid "The buffer is hidden, show it first." -msgstr "そのバッファは非表示状態です。まず最初に、表示してください" +msgstr "そのバッファは非表示状態です。まず最初に、表示してください。" -#: ../src\wxUI\dialogs\configuration.py:175 +#: src\wxUI\dialogs\configuration.py:177 msgid "The buffer is already at the top of the list." -msgstr "既にそのバッファは、リストの先頭です" +msgstr "既にそのバッファは、リストの先頭です。" -#: ../src\wxUI\dialogs\configuration.py:199 +#: src\wxUI\dialogs\configuration.py:201 msgid "The buffer is already at the bottom of the list." -msgstr "既にそのバッファは、リストの最後です" +msgstr "既にそのバッファは、リストの最後です。" -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 +#: src\wxUI\dialogs\configuration.py:242 src\wxUI\dialogs\configuration.py:383 msgid "Ignored clients" msgstr "無視するクライアント" -#: ../src\wxUI\dialogs\configuration.py:247 +#: src\wxUI\dialogs\configuration.py:249 msgid "Remove client" msgstr "クライアントを削除" -#: ../src\wxUI\dialogs\configuration.py:271 +#: src\wxUI\dialogs\configuration.py:273 msgid "Volume" msgstr "ボリューム" -#: ../src\wxUI\dialogs\configuration.py:282 +#: src\wxUI\dialogs\configuration.py:284 msgid "Session mute" msgstr "セッションのミュート" -#: ../src\wxUI\dialogs\configuration.py:284 +#: src\wxUI\dialogs\configuration.py:286 msgid "Output device" msgstr "出力先デバイス" -#: ../src\wxUI\dialogs\configuration.py:291 +#: src\wxUI\dialogs\configuration.py:293 msgid "Input device" msgstr "入力デバイス" -#: ../src\wxUI\dialogs\configuration.py:299 +#: src\wxUI\dialogs\configuration.py:301 msgid "Sound pack" msgstr "サウンドパック" -#: ../src\wxUI\dialogs\configuration.py:305 +#: src\wxUI\dialogs\configuration.py:307 msgid "Indicate audio tweets with sound" msgstr "音声付きツイートを音で報告" -#: ../src\wxUI\dialogs\configuration.py:307 +#: src\wxUI\dialogs\configuration.py:309 msgid "Indicate geotweets with sound" msgstr "位置情報付きツイートを音で報告" -#: ../src\wxUI\dialogs\configuration.py:309 +#: src\wxUI\dialogs\configuration.py:311 msgid "Indicate tweets containing images with sound" msgstr "画像付きツイートを音で報告" -#: ../src\wxUI\dialogs\configuration.py:332 +#: src\wxUI\dialogs\configuration.py:334 msgid "Language for OCR" msgstr "OCRの言語" -#: ../src\wxUI\dialogs\configuration.py:338 +#: src\wxUI\dialogs\configuration.py:340 msgid "API Key for SndUp" msgstr "SndUpのAPIキー" -#: ../src\wxUI\dialogs\configuration.py:353 +#: src\wxUI\dialogs\configuration.py:355 +#, python-brace-format msgid "{0} preferences" msgstr "{0}の設定" -#: ../src\wxUI\dialogs\configuration.py:364 +#: src\wxUI\dialogs\configuration.py:366 msgid "Proxy" msgstr "プロキシ" -#: ../src\wxUI\dialogs\configuration.py:373 +#: src\wxUI\dialogs\configuration.py:375 msgid "Feedback" msgstr "フィードバック" -#: ../src\wxUI\dialogs\configuration.py:377 +#: src\wxUI\dialogs\configuration.py:379 msgid "Buffers" msgstr "バッファ" -#: ../src\wxUI\dialogs\configuration.py:385 +#: src\wxUI\dialogs\configuration.py:387 msgid "Sound" msgstr "サウンド" -#: ../src\wxUI\dialogs\configuration.py:389 +#: src\wxUI\dialogs\configuration.py:391 msgid "Extras" msgstr "その他" -#: ../src\wxUI\dialogs\configuration.py:394 +#: src\wxUI\dialogs\configuration.py:396 msgid "Save" msgstr "保存" -#: ../src\wxUI\dialogs\filterDialogs.py:15 +#: src\wxUI\dialogs\filterDialogs.py:16 msgid "Create a filter for this buffer" msgstr "このバッファのフィルタを作成" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: src\wxUI\dialogs\filterDialogs.py:17 msgid "Filter title" msgstr "フィルター名" -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: src\wxUI\dialogs\filterDialogs.py:26 src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by word" msgstr "単語でフィルター" -#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: src\wxUI\dialogs\filterDialogs.py:27 msgid "Ignore tweets wich contain the following word" msgstr "次の単語が含まれるツイートを無視する" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: src\wxUI\dialogs\filterDialogs.py:28 msgid "Ignore tweets without the following word" msgstr "次の単語が含まれないツイートを無視する" -#: ../src\wxUI\dialogs\filterDialogs.py:32 +#: src\wxUI\dialogs\filterDialogs.py:33 msgid "word" msgstr "単語" -#: ../src\wxUI\dialogs\filterDialogs.py:37 +#: src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow retweets" msgstr "リツイートを許可する" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: src\wxUI\dialogs\filterDialogs.py:39 msgid "Allow quoted tweets" msgstr "引用ツイートを許可する" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: src\wxUI\dialogs\filterDialogs.py:40 msgid "Allow replies" msgstr "リプライを許可するフォロワー一覧" -#: ../src\wxUI\dialogs\filterDialogs.py:47 +#: src\wxUI\dialogs\filterDialogs.py:48 msgid "Use this term as a regular expression" msgstr "正規表現を利用" -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: src\wxUI\dialogs\filterDialogs.py:50 src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by language" msgstr "言語でフィルター" -#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: src\wxUI\dialogs\filterDialogs.py:51 msgid "Load tweets in the following languages" msgstr "下記の言語のツイートを表示" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: src\wxUI\dialogs\filterDialogs.py:52 msgid "Ignore tweets in the following languages" msgstr "下記の言語のツイートを無視する" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: src\wxUI\dialogs\filterDialogs.py:53 msgid "Don't filter by language" msgstr "言語でフィルタしない" -#: ../src\wxUI\dialogs\filterDialogs.py:63 +#: src\wxUI\dialogs\filterDialogs.py:64 msgid "Supported languages" msgstr "サポートしている言語" -#: ../src\wxUI\dialogs\filterDialogs.py:68 +#: src\wxUI\dialogs\filterDialogs.py:69 msgid "Add selected language to filter" msgstr "選択した言語をフィルターに追加" -#: ../src\wxUI\dialogs\filterDialogs.py:72 +#: src\wxUI\dialogs\filterDialogs.py:73 msgid "Selected languages" msgstr "選択した言語" -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 +#: src\wxUI\dialogs\filterDialogs.py:75 src\wxUI\dialogs\filterDialogs.py:133 +#: src\wxUI\dialogs\lists.py:21 src\wxUI\dialogs\lists.py:132 msgid "Remove" msgstr "削除" -#: ../src\wxUI\dialogs\filterDialogs.py:122 +#: src\wxUI\dialogs\filterDialogs.py:123 msgid "Manage filters" msgstr "フィルターの管理" -#: ../src\wxUI\dialogs\filterDialogs.py:124 +#: src\wxUI\dialogs\filterDialogs.py:125 msgid "Filters" msgstr "フィルター" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter" msgstr "フィルター" -#: ../src\wxUI\dialogs\find.py:12 +#: src\wxUI\dialogs\find.py:13 msgid "Find in current buffer" msgstr "現在のバッファ内を検索" -#: ../src\wxUI\dialogs\find.py:13 +#: src\wxUI\dialogs\find.py:14 msgid "String" msgstr "検索文字" -#: ../src\wxUI\dialogs\lists.py:10 +#: src\wxUI\dialogs\lists.py:11 msgid "Lists manager" msgstr "リストの管理" -#: ../src\wxUI\dialogs\lists.py:13 +#: src\wxUI\dialogs\lists.py:14 msgid "List" msgstr "リスト" -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Members" -msgstr "メンバー" - -#: ../src\wxUI\dialogs\lists.py:13 +#: src\wxUI\dialogs\lists.py:14 msgid "Owner" msgstr "所有者" -#: ../src\wxUI\dialogs\lists.py:13 +#: src\wxUI\dialogs\lists.py:14 +msgid "Members" +msgstr "メンバー" + +#: src\wxUI\dialogs\lists.py:14 msgid "mode" msgstr "モード" -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 +#: src\wxUI\dialogs\lists.py:19 src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "新しいリストを作成" -#: ../src\wxUI\dialogs\lists.py:21 +#: src\wxUI\dialogs\lists.py:22 msgid "Open in buffer" msgstr "バッファで開く" -#: ../src\wxUI\dialogs\lists.py:51 +#: src\wxUI\dialogs\lists.py:52 +#, python-format msgid "Viewing lists for %s" msgstr "「%s」のリストを閲覧中" -#: ../src\wxUI\dialogs\lists.py:52 +#: src\wxUI\dialogs\lists.py:53 msgid "Subscribe" msgstr "登録" -#: ../src\wxUI\dialogs\lists.py:53 +#: src\wxUI\dialogs\lists.py:54 msgid "Unsubscribe" msgstr "登録解除" -#: ../src\wxUI\dialogs\lists.py:64 +#: src\wxUI\dialogs\lists.py:65 msgid "Name (20 characters maximun)" msgstr "名前(二〇文字以内)" -#: ../src\wxUI\dialogs\lists.py:74 +#: src\wxUI\dialogs\lists.py:75 msgid "Mode" msgstr "モード" -#: ../src\wxUI\dialogs\lists.py:75 +#: src\wxUI\dialogs\lists.py:76 msgid "Public" msgstr "公開" -#: ../src\wxUI\dialogs\lists.py:76 +#: src\wxUI\dialogs\lists.py:77 msgid "Private" msgstr "プライベート" -#: ../src\wxUI\dialogs\lists.py:96 +#: src\wxUI\dialogs\lists.py:97 +#, python-format msgid "Editing the list %s" msgstr "リスト「%s」を編集中" -#: ../src\wxUI\dialogs\lists.py:107 +#: src\wxUI\dialogs\lists.py:108 msgid "Select a list to add the user" msgstr "ユーザーを追加するリストを選択" -#: ../src\wxUI\dialogs\lists.py:108 +#: src\wxUI\dialogs\lists.py:109 msgid "Add" msgstr "追加" -#: ../src\wxUI\dialogs\lists.py:130 +#: src\wxUI\dialogs\lists.py:131 msgid "Select a list to remove the user" msgstr "ユーザーを削除するには、リストを選択" -#: ../src\wxUI\dialogs\lists.py:148 +#: src\wxUI\dialogs\lists.py:149 msgid "Do you really want to delete this list?" msgstr "本当に、このリストを削除しますか?" -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 +#: src\wxUI\dialogs\message.py:75 src\wxUI\dialogs\message.py:256 msgid "&Long tweet" msgstr "ツイートを短縮して投稿(&L)" -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 +#: src\wxUI\dialogs\message.py:76 src\wxUI\dialogs\message.py:135 +#: src\wxUI\dialogs\message.py:257 msgid "&Upload image..." msgstr "画像をアップロード(&U)" -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 +#: src\wxUI\dialogs\message.py:77 src\wxUI\dialogs\message.py:136 +#: src\wxUI\dialogs\message.py:196 src\wxUI\dialogs\message.py:258 +#: src\wxUI\dialogs\message.py:359 src\wxUI\dialogs\message.py:432 msgid "Check &spelling..." msgstr "スペルチェック(&S)" -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 +#: src\wxUI\dialogs\message.py:78 src\wxUI\dialogs\message.py:137 +#: src\wxUI\dialogs\message.py:197 src\wxUI\dialogs\message.py:259 msgid "&Attach audio..." msgstr "音声を添付(&A)" -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 +#: src\wxUI\dialogs\message.py:79 src\wxUI\dialogs\message.py:138 +#: src\wxUI\dialogs\message.py:198 src\wxUI\dialogs\message.py:260 msgid "Sh&orten URL" msgstr "URLを短縮(&O)" -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 +#: src\wxUI\dialogs\message.py:80 src\wxUI\dialogs\message.py:139 +#: src\wxUI\dialogs\message.py:199 src\wxUI\dialogs\message.py:261 +#: src\wxUI\dialogs\message.py:360 src\wxUI\dialogs\message.py:433 msgid "&Expand URL" msgstr "URLを元に戻す(&E)" -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 +#: src\wxUI\dialogs\message.py:83 src\wxUI\dialogs\message.py:142 +#: src\wxUI\dialogs\message.py:202 src\wxUI\dialogs\message.py:264 +#: src\wxUI\dialogs\message.py:362 src\wxUI\dialogs\message.py:435 msgid "&Translate..." msgstr "翻訳(&T)..." -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 +#: src\wxUI\dialogs\message.py:84 src\wxUI\dialogs\message.py:143 +#: src\wxUI\dialogs\message.py:188 src\wxUI\dialogs\message.py:265 msgid "Auto&complete users" msgstr "ユーザーを自動保管(&C)" -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 +#: src\wxUI\dialogs\message.py:85 src\wxUI\dialogs\message.py:144 +#: src\wxUI\dialogs\message.py:203 src\wxUI\dialogs\message.py:266 msgid "Sen&d" msgstr "送信(&D)" -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 +#: src\wxUI\dialogs\message.py:87 src\wxUI\dialogs\message.py:146 +#: src\wxUI\dialogs\message.py:205 src\wxUI\dialogs\message.py:268 +#: src\wxUI\dialogs\message.py:363 src\wxUI\dialogs\message.py:436 msgid "C&lose" msgstr "閉じる(&C)" -#: ../src\wxUI\dialogs\message.py:184 +#: src\wxUI\dialogs\message.py:186 msgid "&Recipient" msgstr "送信先(&R)" -#: ../src\wxUI\dialogs\message.py:245 +#: src\wxUI\dialogs\message.py:247 msgid "&Mention to all" msgstr "全員にリプライ(&M)" -#: ../src\wxUI\dialogs\message.py:299 +#: src\wxUI\dialogs\message.py:301 +#, python-format msgid "Tweet - %i characters " msgstr "ツイート - %i文字" -#: ../src\wxUI\dialogs\message.py:316 +#: src\wxUI\dialogs\message.py:318 msgid "Image description" msgstr "画像の説明" -#: ../src\wxUI\dialogs\message.py:327 +#: src\wxUI\dialogs\message.py:329 msgid "Retweets: " -msgstr "リツイート:" +msgstr "リツイート: " -#: ../src\wxUI\dialogs\message.py:332 +#: src\wxUI\dialogs\message.py:334 msgid "Likes: " -msgstr "いいね" +msgstr "いいね: " -#: ../src\wxUI\dialogs\message.py:337 +#: src\wxUI\dialogs\message.py:339 msgid "Source: " -msgstr "ソース:" +msgstr "ソース: " -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -#, fuzzy +#: src\wxUI\dialogs\message.py:344 src\wxUI\dialogs\message.py:422 msgid "Date: " -msgstr "日時" +msgstr "日付: " -#: ../src\wxUI\dialogs\message.py:405 +#: src\wxUI\dialogs\message.py:407 msgid "View" msgstr "ツイート" -#: ../src\wxUI\dialogs\message.py:407 +#: src\wxUI\dialogs\message.py:409 msgid "Item" msgstr "アイテム" -#: ../src\wxUI\dialogs\search.py:13 +#: src\wxUI\dialogs\search.py:14 msgid "Search on Twitter" msgstr "ツイッターを検索" -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 -msgid "&Search" -msgstr "検索(&S)" - -#: ../src\wxUI\dialogs\search.py:21 +#: src\wxUI\dialogs\search.py:22 msgid "Tweets" msgstr "ツイート" -#: ../src\wxUI\dialogs\search.py:22 +#: src\wxUI\dialogs\search.py:23 msgid "Users" msgstr "ユーザー" -#: ../src\wxUI\dialogs\search.py:29 +#: src\wxUI\dialogs\search.py:30 msgid "&Language for results: " -msgstr "結果の言語(&L):" +msgstr "結果の言語(&L): " -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 +#: src\wxUI\dialogs\search.py:32 src\wxUI\dialogs\search.py:56 msgid "any" msgstr "指定しない" -#: ../src\wxUI\dialogs\search.py:37 +#: src\wxUI\dialogs\search.py:38 msgid "Results &type: " -msgstr "結果のタイプ(&T):" +msgstr "結果のタイプ(&T): " -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 +#: src\wxUI\dialogs\search.py:39 src\wxUI\dialogs\search.py:64 msgid "Mixed" msgstr "混合" -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 +#: src\wxUI\dialogs\search.py:39 src\wxUI\dialogs\search.py:65 msgid "Recent" msgstr "最近" -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 +#: src\wxUI\dialogs\search.py:39 src\wxUI\dialogs\search.py:66 msgid "Popular" msgstr "人気" -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 +#: src\wxUI\dialogs\search.py:44 src\wxUI\dialogs\trends.py:25 +#: src\wxUI\dialogs\userActions.py:41 src\wxUI\dialogs\userSelection.py:33 msgid "&OK" msgstr "OK(&O)" -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 +#: src\wxUI\dialogs\search.py:46 src\wxUI\dialogs\show_user.py:19 +#: src\wxUI\dialogs\trends.py:27 src\wxUI\dialogs\update_profile.py:37 +#: src\wxUI\dialogs\userActions.py:43 src\wxUI\dialogs\userSelection.py:35 msgid "&Close" msgstr "閉じる(&C)" -#: ../src\wxUI\dialogs\show_user.py:11 +#: src\wxUI\dialogs\show_user.py:12 msgid "Details" msgstr "詳細" -#: ../src\wxUI\dialogs\show_user.py:16 +#: src\wxUI\dialogs\show_user.py:17 msgid "&Go to URL" msgstr "URLへ移動(&G)" -#: ../src\wxUI\dialogs\trends.py:12 +#: src\wxUI\dialogs\trends.py:10 msgid "View trending topics" -msgstr "トレンドの話題を表示" +msgstr "トレンドを表示" -#: ../src\wxUI\dialogs\trends.py:13 +#: src\wxUI\dialogs\trends.py:11 msgid "Trending topics by" -msgstr "トレンドの話題" +msgstr "トレンド" -#: ../src\wxUI\dialogs\trends.py:15 +#: src\wxUI\dialogs\trends.py:12 msgid "Country" msgstr "国" -#: ../src\wxUI\dialogs\trends.py:16 +#: src\wxUI\dialogs\trends.py:13 msgid "City" msgstr "都市" -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 +#: src\wxUI\dialogs\trends.py:19 src\wxUI\dialogs\update_profile.py:18 msgid "&Location" msgstr "場所(&L)" -#: ../src\wxUI\dialogs\update_profile.py:9 +#: src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "プロフィールを更新" -#: ../src\wxUI\dialogs\update_profile.py:11 +#: src\wxUI\dialogs\update_profile.py:12 msgid "&Name (50 characters maximum)" msgstr "名前(50文字以内)(&N)" -#: ../src\wxUI\dialogs\update_profile.py:22 +#: src\wxUI\dialogs\update_profile.py:23 msgid "&Website" msgstr "ウェブサイト(&W)" -#: ../src\wxUI\dialogs\update_profile.py:27 +#: src\wxUI\dialogs\update_profile.py:28 msgid "&Bio (160 characters maximum)" msgstr "自己紹介(160文字以内)(&B)" -#: ../src\wxUI\dialogs\update_profile.py:33 +#: src\wxUI\dialogs\update_profile.py:34 msgid "Upload a &picture" msgstr "画像をアップロード(&P)" -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 -msgid "&Update profile" -msgstr "プロフィールを更新(&U)" - -#: ../src\wxUI\dialogs\update_profile.py:76 +#: src\wxUI\dialogs\update_profile.py:77 msgid "Upload a picture" msgstr "画像をアップロード" -#: ../src\wxUI\dialogs\update_profile.py:78 +#: src\wxUI\dialogs\update_profile.py:79 msgid "Discard image" msgstr "画像をアップロードできません" -#: ../src\wxUI\dialogs\urlList.py:5 +#: src\wxUI\dialogs\urlList.py:6 msgid "Select URL" msgstr "URLを選択" -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 -msgid "&User" -msgstr "ユーザー(&U)" - -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 +#: src\wxUI\dialogs\userActions.py:14 src\wxUI\dialogs\userSelection.py:14 +#: src\wxUI\dialogs\utils.py:31 msgid "&Autocomplete users" msgstr "自動保管されたユーザー" -#: ../src\wxUI\dialogs\userActions.py:19 +#: src\wxUI\dialogs\userActions.py:20 msgid "&Follow" msgstr "フォロー(&F)" -#: ../src\wxUI\dialogs\userActions.py:20 +#: src\wxUI\dialogs\userActions.py:21 msgid "U&nfollow" msgstr "フォロー解除(&N)" -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 -msgid "&Mute" -msgstr "ミュート(&M)" - -#: ../src\wxUI\dialogs\userActions.py:22 +#: src\wxUI\dialogs\userActions.py:23 msgid "Unmu&te" msgstr "ミュート解除(&T)" -#: ../src\wxUI\dialogs\userActions.py:23 +#: src\wxUI\dialogs\userActions.py:24 msgid "&Block" msgstr "ブロック(&B)" -#: ../src\wxUI\dialogs\userActions.py:24 +#: src\wxUI\dialogs\userActions.py:25 msgid "Unbl&ock" msgstr "ブロック解除(&O)" -#: ../src\wxUI\dialogs\userActions.py:25 +#: src\wxUI\dialogs\userActions.py:26 msgid "&Report as spam" msgstr "スパムとして報告(&R)" -#: ../src\wxUI\dialogs\userActions.py:26 +#: src\wxUI\dialogs\userActions.py:27 msgid "&Ignore tweets from this client" msgstr "このクライアントからのツイートを無視(&I)" -#: ../src\wxUI\dialogs\userSelection.py:9 +#: src\wxUI\dialogs\userSelection.py:10 +#, python-format msgid "Timeline for %s" msgstr "「%s」のタイムライン" -#: ../src\wxUI\dialogs\userSelection.py:18 +#: src\wxUI\dialogs\userSelection.py:19 msgid "Buffer type" msgstr "バッファのタイプ" -#: ../src\wxUI\dialogs\userSelection.py:19 +#: src\wxUI\dialogs\userSelection.py:20 msgid "&Tweets" msgstr "ツイート(&T)" -#: ../src\wxUI\dialogs\userSelection.py:20 +#: src\wxUI\dialogs\userSelection.py:21 msgid "&Likes" msgstr "いいね(&L)" -#: ../src\wxUI\dialogs\userSelection.py:21 +#: src\wxUI\dialogs\userSelection.py:22 msgid "&Followers" msgstr "フォロワー(&F)" -#: ../src\wxUI\dialogs\userSelection.py:22 +#: src\wxUI\dialogs\userSelection.py:23 msgid "F&riends" msgstr "フォロー(&R)" -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 -msgid "&Retweet" -msgstr "リツイート(&R)" - -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 -msgid "Re&ply" -msgstr "リプライ(&P)" - -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 -msgid "&Like" -msgstr "いいね(&L)" - -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 -msgid "&Unlike" -msgstr "いいねを解除(&U)" - -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 -msgid "&Open URL" -msgstr "URLを開く(&O)" - -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -#, fuzzy -msgid "&Open in Twitter" -msgstr "ツイッターを検索" - -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 -msgid "&Play audio" -msgstr "音声を再生(&P)" - -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 -msgid "&Show tweet" -msgstr "ツイートを表示(&S)" - -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 -msgid "&Copy to clipboard" -msgstr "クリップボードにコピー(&C)" - -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 -msgid "&Delete" -msgstr "削除(&D)" - -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 -msgid "&User actions..." -msgstr "ユーザーのアクション(&U)" - -#: ../src\wxUI\menus.py:39 -msgid "&Show direct message" -msgstr "ダイレクトメッセージを表示(&S)" - -#: ../src\wxUI\menus.py:67 -msgid "&Show event" -msgstr "イベントを表示(&S)" - -#: ../src\wxUI\menus.py:77 -msgid "Direct &message" -msgstr "ダイレクトメッセージ(&M)" - -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 -msgid "&View lists" -msgstr "リストを見る(&V)" - -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 -msgid "Show user &profile" -msgstr "ユーザーのプロフィールを表示(&P)" - -#: ../src\wxUI\menus.py:84 -msgid "&Show user" -msgstr "ユーザーを表示(&S)" - -#: ../src\wxUI\menus.py:98 -msgid "&Tweet about this trend" -msgstr "このトレンドのツイート(&T)" - -#: ../src\wxUI\menus.py:100 -msgid "&Show item" -msgstr "アイテムを表示(&S)" - -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 -msgid "&Global settings" -msgstr "全般設定(&G)" - -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 -msgid "Account se&ttings" -msgstr "アカウント設定(&T(" - -#: ../src\wxUI\sysTrayIcon.py:37 -msgid "Update &profile" -msgstr "プロフィールを更新(&P)" - -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "&Show / hide" -msgstr "表示または非表示(&S)" - -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 -msgid "&Documentation" -msgstr "取扱説明書(&D)" - -#: ../src\wxUI\sysTrayIcon.py:40 -msgid "Check for &updates" -msgstr "アップデートを確認(&U)" - -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "&Exit" -msgstr "終了(&E)" - -#: ../src\wxUI\view.py:16 -msgid "&Manage accounts" -msgstr "アカウントの管理(&M)" - -#: ../src\wxUI\view.py:18 -msgid "&Hide window" -msgstr "ウィンドウを隠す(&H)" - -#: ../src\wxUI\view.py:20 -msgid "&Lists manager" -msgstr "リストの管理(&L)" - -#: ../src\wxUI\view.py:21 -msgid "&Edit keystrokes" -msgstr "キーストロークを編集(&E)" - -#: ../src\wxUI\view.py:24 -msgid "E&xit" -msgstr "終了(&X)" - -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 -msgid "&Tweet" -msgstr "ツイート(&T)" - -#: ../src\wxUI\view.py:34 -msgid "View &address" -msgstr "位置情報を表示(&A)" - -#: ../src\wxUI\view.py:35 -msgid "View conversa&tion" -msgstr "会話を見る(&T)" - -#: ../src\wxUI\view.py:36 -msgid "Read text in picture" -msgstr "画像からテキストを読み取り" - -#: ../src\wxUI\view.py:41 -msgid "&Actions..." -msgstr "操作(&A)" - -#: ../src\wxUI\view.py:42 -msgid "&View timeline..." -msgstr "タイムラインを表示(&V)" - -#: ../src\wxUI\view.py:43 -msgid "Direct me&ssage" -msgstr "ダイレクトメッセージ(&S)" - -#: ../src\wxUI\view.py:44 -msgid "&Add to list" -msgstr "リストに追加(&A)" - -#: ../src\wxUI\view.py:45 -msgid "R&emove from list" -msgstr "リストから削除(&E)" - -#: ../src\wxUI\view.py:48 -msgid "V&iew likes" -msgstr "いいね一覧を見る(&I)" - -#: ../src\wxUI\view.py:52 -msgid "&Update buffer" -msgstr "バッファを更新(&U)" - -#: ../src\wxUI\view.py:53 -msgid "New &trending topics buffer..." -msgstr "新しいトレンドの話題のバッファ(&T)" - -#: ../src\wxUI\view.py:54 -msgid "Create a &filter" -msgstr "新しいフィルターを作成(&F)" - -#: ../src\wxUI\view.py:55 -msgid "&Manage filters" -msgstr "フィルターの管理(&M)" - -#: ../src\wxUI\view.py:56 -msgid "Find a string in the currently focused buffer..." -msgstr "現在フォーカス中のバッファ内の文字列を検索" - -#: ../src\wxUI\view.py:57 -msgid "&Load previous items" -msgstr "以前のアイテムを取得(&L)" - -#: ../src\wxUI\view.py:60 -msgid "&Autoread" -msgstr "自動読み上げ(&A)" - -#: ../src\wxUI\view.py:61 -msgid "&Clear buffer" -msgstr "バッファをクリア(&C)" - -#: ../src\wxUI\view.py:62 -msgid "&Destroy" -msgstr "バッファを削除(&D)" - -#: ../src\wxUI\view.py:66 -msgid "&Seek back 5 seconds" -msgstr "5秒戻る(&S)" - -#: ../src\wxUI\view.py:67 -msgid "&Seek forward 5 seconds" -msgstr "5秒進む(&S)" - -#: ../src\wxUI\view.py:72 -msgid "Sounds &tutorial" -msgstr "サウンドの確認(&T)" - -#: ../src\wxUI\view.py:73 -msgid "&What's new in this version?" -msgstr "更新履歴(&W)" - -#: ../src\wxUI\view.py:74 -msgid "&Check for updates" -msgstr "アップデートを確認(&C)" - -#: ../src\wxUI\view.py:75 -msgid "&Report an error" -msgstr "エラーを報告(&R)" - -#: ../src\wxUI\view.py:76 -msgid "{0}'s &website" -msgstr "「{0}」のウェブサイト(&W)" - -#: ../src\wxUI\view.py:77 -msgid "Get soundpacks for TWBlue" -msgstr "TWBlue のサウンドパックを入手" - -#: ../src\wxUI\view.py:78 -msgid "About &{0}" -msgstr "{0}について(&A)" - -#: ../src\wxUI\view.py:81 -msgid "&Application" -msgstr "アプリケーション(&A)" - -#: ../src\wxUI\view.py:84 -msgid "&Buffer" -msgstr "バッファ(&B)" - -#: ../src\wxUI\view.py:85 -msgid "&Audio" -msgstr "音声(&A)" - -#: ../src\wxUI\view.py:86 -msgid "&Help" -msgstr "ヘルプ(&H)" - -#: ../src\wxUI\view.py:172 -msgid "Address" -msgstr "アドレス" - -#: ../src\wxUI\view.py:203 -msgid "Update" -msgstr "アップデート" - -#: ../src\wxUI\view.py:203 -msgid "Your {0} version is up to date" -msgstr "「{0}」のバージョンは最新です" - -#~ msgid "Empty" -#~ msgstr "何もありません" - -#~ msgid "One mention from %s " -#~ msgstr "%sからの返信" - -#~ msgid "One tweet from %s" -#~ msgstr "「%s」からのツイート" - -#~ msgid "You've blocked %s" -#~ msgstr "「%s」をブロックしました。" - -#~ msgid "You've unblocked %s" -#~ msgstr "「%s」のブロックを解除しました" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "「%s: @%s」がフォローしました" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "「%s: @%s」をフォローしました" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "「%s: @%s」のフォローを解除しました" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "%s %sをいいねしました" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "%s(@%s)が「%s」をいいねしました" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "%s %sのいいねを解除しました" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "%s(@%s)が%sのいいねを解除しました" - -#~ msgid "You've created the list %s" -#~ msgstr "リスト「%s」を作成しました" - -#~ msgid "You've deleted the list %s" -#~ msgstr "リスト「%s」を削除しました" - -#~ msgid "You've updated the list %s" -#~ msgstr "リスト「%s」をアップデートしました" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "「%s: @%s」をリスト「%s」に追加しました" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "「%s: @%s」がリスト「%s」にあなたを追加しました" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "「%s: @%s」をリスト「%s」から削除しました" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "「%s: @%s」がリスト「%s」からあなたを削除しました" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "「%s: @%s」によって所有されているリスト「%s」に加入しました" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "「%s(@%s)」があなたのリスト「%s」を購読しました" - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "「%s: @%s」によって所有されているリスト「%s」から退会しました" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "「%s: @%s」によって所有されているリスト「%s」から退会してきました" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "「%s: @%s」がリツイートした「%s」をリツイートしました" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "「%s: @%s」があなたのリツイート「%s」をリツイートしました" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "APIの呼び出し数(1回のAPIの呼び出し=200、2回のAPIの呼び出し=400、など)" - -#~ msgid "Unable to upload the audio" -#~ msgstr "音声をアップロードできません" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "アカウント連携を待機しています…" - -#~ msgid "autodetect" -#~ msgstr "自動検出" - -#~ msgid "" -#~ "There's a new %s version available. Would you like to download it now?\n" -#~ "\n" -#~ " %s version: %s\n" -#~ "\n" -#~ "Changes:\n" -#~ "%s" -#~ msgstr "" -#~ "「%s」の新しいバージョンが利用可能です。今すぐダウンロードしますか?\n" -#~ "\n" -#~ "%sバージョン: %s\n" -#~ "\n" -#~ "更新履歴\n" -#~ "%s" - -#~ msgid "Start {0} after logging in windows" -#~ msgstr "Windowsログオン後に{0}を起動" - -#~ msgid "" -#~ "If you have a SndUp account, enter your API Key here. If your API Key is " -#~ "invalid, {0} will fail to upload. If there is no API Key here, {0} will " -#~ "upload annonymously." -#~ msgstr "" -#~ "SndUpアカウントをお持ちの場合は、ここにAPIキーを入力してください。APIキー" -#~ "が無効である場合、{0}のアップロードに失敗します。APIキーが存在しない場合" -#~ "は、{0}は、匿名でアップロードされます。" - -#~ msgid "Disconnect your Pocket account" -#~ msgstr "Poketとの連携を解除" - -#~ msgid "Connect your Pocket account" -#~ msgstr "Pocketアカウントと連携" - -#~ msgid "Pocket Authorization" -#~ msgstr "Pocketの認証" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. You only need " -#~ "to do this once. Do you want to continue?" -#~ msgstr "" -#~ "認証要求をブラウザで開きます。一度だけこれを実行する必要があります。続行し" -#~ "ますか?" - -#~ msgid "Error during authorization. Try again later." -#~ msgstr "認証中にエラーが発生しました。後でやり直してください。" - -#~ msgid "Services" -#~ msgstr "サービス" - -#~ msgid "Contains" -#~ msgstr "含む" - -#~ msgid "Doesn't contain" -#~ msgstr "含まない" - -#~ msgid "" -#~ "You have successfully logged into Twitter with {0}. You can close this " -#~ "window now." -#~ msgstr "" -#~ "{0}でのTwitterのログインに成功しました。今すぐこのウィンドウを閉じることが" -#~ "できます。" +#~ msgid "This tweet doesn't contain images" +#~ msgstr "このツイートは、画像を含んでいません" From 304d91e8b7506d0a4494aaa5c3607bf3a8b6fcfb Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 22 Jan 2021 17:55:15 -0600 Subject: [PATCH 003/245] Started replacing yandex.translate with googletrans --- src/controller/messages.py | 8 ++++++-- src/extra/translator/translator.py | 21 ++++++--------------- src/extra/translator/wx_ui.py | 26 +++++--------------------- 3 files changed, 17 insertions(+), 38 deletions(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 880ec4a2..62d4a5fa 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -45,8 +45,12 @@ class basicTweet(object): dlg = translator.gui.translateDialog() if dlg.get_response() == widgetUtils.OK: text_to_translate = self.message.get_text() - dest = [x[0] for x in translator.translator.available_languages()][dlg.get("dest_lang")] - msg = translator.translator.translate(text=text_to_translate, target=dest) + language_dict = translator.translator.available_languages() + print(dlg.dest_lang.GetStringSelection()) + for k in language_dict: + if language_dict[k] == dlg.dest_lang.GetStringSelection(): + dst = k + msg = translator.translator.translate(text=text_to_translate, target=dst) self.message.set_text(msg) self.text_processor() self.message.text_focus() diff --git a/src/extra/translator/translator.py b/src/extra/translator/translator.py index f390fbf2..e1a24091 100644 --- a/src/extra/translator/translator.py +++ b/src/extra/translator/translator.py @@ -1,15 +1,13 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals -from builtins import zip -from yandex_translate import YandexTranslate +from googletrans import Translator, LANGUAGES def translate(text="", target="en"): - t = YandexTranslate("trnsl.1.1.20161012T134532Z.d01b9c75fc39aa74.7d1be75a5166a80583eeb020e10f584168da6bf7") - vars = dict(text=text, lang=target) - return t.translate(**vars)["text"][0] + t = Translator() + vars = dict(text=text, dst=target) + return t.translate(**vars).text supported_langs = None -d = None + languages = { "af": _(u"Afrikaans"), "sq": _(u"Albanian"), @@ -105,11 +103,4 @@ languages = { } def available_languages(): - global supported_langs, d - if supported_langs == None and d == None: - t = YandexTranslate("trnsl.1.1.20161012T134532Z.d01b9c75fc39aa74.7d1be75a5166a80583eeb020e10f584168da6bf7") - supported_langs = t.langs - d = [] - for i in supported_langs: - d.append(languages[i]) - return sorted(zip(supported_langs, d)) + return languages diff --git a/src/extra/translator/wx_ui.py b/src/extra/translator/wx_ui.py index 14d2a88e..8b9672e3 100644 --- a/src/extra/translator/wx_ui.py +++ b/src/extra/translator/wx_ui.py @@ -16,37 +16,21 @@ # along with this program. If not, see . # ############################################################ -from __future__ import absolute_import -from __future__ import unicode_literals -# -*- coding: utf-8 -*- -############################################################ -# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################ from . import translator import wx from wxUI.dialogs import baseDialog class translateDialog(baseDialog.BaseWXDialog): def __init__(self): + languages = [] + language_dict = translator.available_languages() + for k in language_dict: + languages.append(language_dict[k]) super(translateDialog, self).__init__(None, -1, title=_(u"Translate message")) panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) staticDest = wx.StaticText(panel, -1, _(u"Target language")) - self.dest_lang = wx.ComboBox(panel, -1, choices=[x[1] for x in translator.available_languages()], style = wx.CB_READONLY) + self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY) self.dest_lang.SetFocus() self.dest_lang.SetSelection(0) listSizer = wx.BoxSizer(wx.HORIZONTAL) From fb3e6b537c8c8fdec5daade2f315074ac002d6e1 Mon Sep 17 00:00:00 2001 From: riku Date: Sat, 23 Jan 2021 09:05:35 +0900 Subject: [PATCH 004/245] Updated Japanese translation --- src/locales/ja/lc_messages/twblue.mo | Bin 58239 -> 58524 bytes src/locales/ja/lc_messages/twblue.po | 37 ++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/locales/ja/lc_messages/twblue.mo b/src/locales/ja/lc_messages/twblue.mo index ad4f40e33e172543b2718cb2824da4fc3fccc886..4140b2802d78542ee05d48224c6d42dfd56d9213 100644 GIT binary patch delta 16354 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 a#peVE#Z_N^HGSNG-BpvvT|RI!=l=n}^gz-8 diff --git a/src/locales/ja/lc_messages/twblue.po b/src/locales/ja/lc_messages/twblue.po index cc77b537..f26c1c4b 100644 --- a/src/locales/ja/lc_messages/twblue.po +++ b/src/locales/ja/lc_messages/twblue.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-01-22 12:23+0900\n" -"PO-Revision-Date: 2021-01-22 12:49+0900\n" +"POT-Creation-Date: 2021-01-23 09:00+0900\n" +"PO-Revision-Date: 2021-01-23 09:05+0900\n" "Last-Translator: 陸 \n" "Language-Team: \n" "Language: ja_JP\n" @@ -22,11 +22,11 @@ msgstr "" msgid "User default" msgstr "ユーザーのデフォルト" -#: src\main.py:107 +#: src\main.py:120 msgid "https://twblue.es/donate" msgstr "https://twblue.es/donate" -#: src\main.py:124 +#: src\main.py:137 #, python-brace-format msgid "" "{0} is already running. Close the other instance before starting this one. " @@ -356,9 +356,29 @@ msgstr "ツイート" msgid "View item" msgstr "アイテムを見る" -#: src\controller\settings.py:78 -msgid "Direct connection" -msgstr "直接接続" +#: src\controller\settings.py:77 +msgid "System default" +msgstr "システムのデフォルト" + +#: src\controller\settings.py:77 +msgid "HTTP" +msgstr "HTTP" + +#: src\controller\settings.py:77 +msgid "SOCKS v4" +msgstr "SOCKS v4" + +#: src\controller\settings.py:77 +msgid "SOCKS v4 with DNS support" +msgstr "DNSをサポートする SOCKS v4" + +#: src\controller\settings.py:77 +msgid "SOCKS v5" +msgstr "SOCKS v5" + +#: src\controller\settings.py:77 +msgid "SOCKS v5 with DNS support" +msgstr "DNSをサポートする SOCKS v5" #: src\controller\settings.py:148 src\controller\settings.py:210 #: src\wxUI\dialogs\configuration.py:119 @@ -3328,5 +3348,8 @@ msgstr "フォロワー(&F)" msgid "F&riends" msgstr "フォロー(&R)" +#~ msgid "Direct connection" +#~ msgstr "直接接続" + #~ msgid "This tweet doesn't contain images" #~ msgstr "このツイートは、画像を含んでいません" From 351f7009272086cf516eaf887ab3d11afd6fed1f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Jan 2021 16:01:26 -0600 Subject: [PATCH 005/245] Replaced translation services. Fixes #355 --- doc/changelog.md | 1 + requirements.txt | 4 +++- src/extra/translator/translator.py | 16 +++++++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index f299071e..3dc37288 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -12,6 +12,7 @@ * TWBlue can upload images in Tweets and replies again. ([#240,](https://github.com/manuelcortez/TWBlue/issues/240)) * Fixed the way we use to count characters in Twitter. The new methods in TWBlue take into account special characters and URLS as documented in Twitter. ([#199,](https://github.com/manuelcortez/TWBlue/issues/199) [#315](https://github.com/manuelcortez/TWBlue/issues/315)) * Proxy support now works as expected. +* Changed translation service from yandex.translate to Google Translator. ([#355,](https://github.com/manuelcortez/TWBlue/issues/355)) * And more. ([#352,](https://github.com/manuelcortez/TWBlue/issues/352)) ## Changes in version 0.95 diff --git a/requirements.txt b/requirements.txt index 6bf36fff..b95337d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,9 @@ futures winpaths PySocks win_inet_pton -yandex.translate +# Install the latest RC of this lib +# see https://github.com/ssut/py-googletrans/issues/234 +googletrans==4.0.0-rc1 idna<3,>=2.5 chardet urllib3 diff --git a/src/extra/translator/translator.py b/src/extra/translator/translator.py index e1a24091..ae08a4e8 100644 --- a/src/extra/translator/translator.py +++ b/src/extra/translator/translator.py @@ -1,9 +1,19 @@ # -*- coding: utf-8 -*- +import logging from googletrans import Translator, LANGUAGES +log = logging.getLogger("extras.translator") + +# create a single translator instance +# see https://github.com/ssut/py-googletrans/issues/234 +t = None + def translate(text="", target="en"): - t = Translator() - vars = dict(text=text, dst=target) + global t + log.debug("Received translation request for language %s, text=%s" % (target, text)) + if t == None: + t = Translator() + vars = dict(text=text, dest=target) return t.translate(**vars).text supported_langs = None @@ -103,4 +113,4 @@ languages = { } def available_languages(): - return languages + return dict(sorted(languages.items(), key=lambda x: x[1])) From 1a76913aac37377014a4b4b638374df101d561a6 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Jan 2021 16:09:55 -0600 Subject: [PATCH 006/245] Removed debug info --- src/controller/messages.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 62d4a5fa..9af6152f 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -46,7 +46,6 @@ class basicTweet(object): if dlg.get_response() == widgetUtils.OK: text_to_translate = self.message.get_text() language_dict = translator.translator.available_languages() - print(dlg.dest_lang.GetStringSelection()) for k in language_dict: if language_dict[k] == dlg.dest_lang.GetStringSelection(): dst = k From 91955e80d2145b0c463a454f1364c2cc1abf0cb0 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Jan 2021 16:23:48 -0600 Subject: [PATCH 007/245] Fixed Picture OCR. Fixes #356 --- src/controller/mainController.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 608dc900..a7b4f3c9 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1572,12 +1572,12 @@ class Controller(object): return tweet = buffer.get_tweet() media_list = [] - if ("entities" in tweet) and ("media" in tweet["entities"]): - [media_list.append(i) for i in tweet["entities"]["media"] if i not in media_list] - elif "retweeted_status" in tweet and "media" in tweet["retweeted_status"]["entities"]: - [media_list.append(i) for i in tweet["retweeted_status"]["entities"]["media"] if i not in media_list] - elif "quoted_status" in tweet and "media" in tweet["quoted_status"]["entities"]: - [media_list.append(i) for i in tweet["quoted_status"]["entities"]["media"] if i not in media_list] + if hasattr(tweet, "entities") and tweet.entities.get("media") != None: + [media_list.append(i) for i in tweet.entities["media"] if i not in media_list] + elif hasattr(tweet, "retweeted_status") and tweet.retweeted_status.get("media") != None: + [media_list.append(i) for i in tweet.retweeted_status.entities["media"] if i not in media_list] + elif hasattr(tweet, "quoted_status") and tweet.quoted_status.entities.get("media") != None: + [media_list.append(i) for i in tweet.quoted_status.entities["media"] if i not in media_list] if len(media_list) > 1: image_list = [_(u"Picture {0}").format(i,) for i in range(0, len(media_list))] dialog = dialogs.urlList.urlList(title=_(u"Select the picture")) @@ -1593,7 +1593,7 @@ class Controller(object): if buffer.session.settings["mysc"]["ocr_language"] != "": ocr_lang = buffer.session.settings["mysc"]["ocr_language"] else: - ocr_lang = ocr.OCRSpace.short_langs.index(tweet["lang"]) + ocr_lang = ocr.OCRSpace.short_langs.index(tweet.lang) ocr_lang = ocr.OCRSpace.OcrLangs[ocr_lang] api = ocr.OCRSpace.OCRSpaceAPI() try: From 890359f8c7e5dfc86dabe5e26edea9a604873954 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Jan 2021 17:09:38 -0600 Subject: [PATCH 008/245] Fixed Rate limit issue in cursored functions. Closes #354 --- src/controller/buffers/twitterBuffers.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index bef1836c..6e4d68c0 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -175,11 +175,12 @@ class baseBufferController(baseBuffers.buffer): cursor = self.session.db["cursors"].get(self.name) try: # We need to assign all results somewhere else so the cursor variable would b generated. - val = Cursor(getattr(self.session.twitter, self.function), *self.args, **self.kwargs).items(count) + val = Cursor(getattr(self.session.twitter, self.function), count=count, *self.args, **self.kwargs).items(count) results = [i for i in val] self.session.db["cursors"][self.name] = val.page_iterator.next_cursor val = results val.reverse() + log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function)) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return @@ -217,7 +218,7 @@ class baseBufferController(baseBuffers.buffer): else: last_id = self.session.db[self.name][-1].id try: - items = Cursor(getattr(self.session.twitter, self.function), max_id=last_id, *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) + items = Cursor(getattr(self.session.twitter, self.function), max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return @@ -233,6 +234,7 @@ class baseBufferController(baseBuffers.buffer): else: self.session.db[self.name].append(i) selection = self.buffer.list.get_selected() + log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function)) if self.session.settings["general"]["reverse_timelines"] == False: for i in elements: tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) @@ -634,10 +636,11 @@ class directMessagesController(baseBufferController): # try to retrieve the cursor for the current buffer. cursor = self.session.db["cursors"].get(self.name) try: - items = Cursor(getattr(self.session.twitter, self.function), cursor=cursor, *self.args, **self.kwargs).items(count) + items = Cursor(getattr(self.session.twitter, self.function), cursor=cursor, count=count, *self.args, **self.kwargs).items(count) results = [i for i in items] self.session.db["cursors"][self.name] = items.page_iterator.next_cursor items = results + log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return @@ -870,11 +873,12 @@ class peopleBufferController(baseBufferController): cursor = self.session.db["cursors"].get(self.name) try: # We need to assign all results somewhere else so the cursor variable would b generated. - val = Cursor(getattr(self.session.twitter, self.function), *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) + val = Cursor(getattr(self.session.twitter, self.function), count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) results = [i for i in val] self.session.db["cursors"][self.name] = val.page_iterator.next_cursor val = results val.reverse() + log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return @@ -894,10 +898,11 @@ class peopleBufferController(baseBufferController): def get_more_items(self): try: cursor = self.session.db["cursors"].get(self.name) - items = Cursor(getattr(self.session.twitter, self.function), users=True, cursor=cursor, *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) + items = Cursor(getattr(self.session.twitter, self.function), users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) results = [i for i in items] self.session.db["cursors"][self.name] = items.page_iterator.next_cursor items = results + log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return From c95a2feb5e8ba964fa187aa6f0f9871d33b6ca5e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 10:36:44 -0600 Subject: [PATCH 009/245] Faster implementation of dm loading due to a call to lookup_users instead to get_user --- doc/changelog.md | 1 + src/controller/buffers/twitterBuffers.py | 6 +++++- src/sessions/twitter/session.py | 14 +++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 3dc37288..651f215f 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -13,6 +13,7 @@ * Fixed the way we use to count characters in Twitter. The new methods in TWBlue take into account special characters and URLS as documented in Twitter. ([#199,](https://github.com/manuelcortez/TWBlue/issues/199) [#315](https://github.com/manuelcortez/TWBlue/issues/315)) * Proxy support now works as expected. * Changed translation service from yandex.translate to Google Translator. ([#355,](https://github.com/manuelcortez/TWBlue/issues/355)) +* Improved method to load direct messages in the buffers. Now it should be faster due to less calls to Twitter API performed from the client. * And more. ([#352,](https://github.com/manuelcortez/TWBlue/issues/352)) ## Changes in version 0.95 diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 6e4d68c0..5e5d03ff 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -181,11 +181,14 @@ class baseBufferController(baseBuffers.buffer): val = results val.reverse() log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function)) + user_ids = [item.message_create["sender_id"] for item in val] + self.session.save_users(user_ids) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return number_of_items = self.session.order_buffer(self.name, val) log.debug("Number of items retrieved: %d" % (number_of_items,)) + self.put_items_on_list(number_of_items) if hasattr(self, "finished_timeline") and self.finished_timeline == False: if "-timeline" in self.name: @@ -664,9 +667,10 @@ class directMessagesController(baseBufferController): self.session.db[self.name].append(i) received.insert(0, i) total = total+1 + user_ids = [item.message_create["sender_id"] for item in items] + self.session.save_users(user_ids) pub.sendMessage("more-sent-dms", data=sent, account=self.session.db["user_name"]) selected = self.buffer.list.get_selected() - if self.session.settings["general"]["reverse_timelines"] == True: for i in received: if int(i.message_create["sender_id"]) == self.session.db["user_id"]: diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index fcdbea79..e480f83c 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -430,4 +430,16 @@ class Session(base.baseSession): return self.db["users"][i].id_str user = utils.if_user_exists(self.twitter, screen_name) self.db["users"][user.id_str] = user - return user.id_str \ No newline at end of file + return user.id_str + + def save_users(self, user_ids): + """ Adds all new users to the users database. """ + log.debug("Received %d user IDS to be added in the database." % (len(user_ids))) + users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]] + # Remove duplicates + users_to_retrieve = list(dict.fromkeys(users_to_retrieve)) + log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) + users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") + for user in users: + self.db["users"][user.id_str] = user + log.debug("Added %d new users" % (len(users))) \ No newline at end of file From 6688dc1163553cedceace14714b47c9baed926a5 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 13:19:16 -0600 Subject: [PATCH 010/245] Removed unneeded parameters when retrieving direct messages --- src/controller/mainController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index a7b4f3c9..5061d9e6 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -308,7 +308,7 @@ class Controller(object): self.buffers.append(mentions) self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'dm': - dm = twitterBuffers.directMessagesController(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg", full_text=True, items="events") + dm = twitterBuffers.directMessagesController(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg") self.buffers.append(dm) self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'sent_dm': From 9444939c35141caaab460a24ed052bfdc3378814 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 13:20:47 -0600 Subject: [PATCH 011/245] Replaced cursored calls for manual calls to function with return_cursors. This way we will avoid hitting TWitter Rate limits accidentally --- src/controller/buffers/twitterBuffers.py | 39 +++++++++++++++--------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 5e5d03ff..ec01dd85 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -172,12 +172,14 @@ class baseBufferController(baseBuffers.buffer): else: count = self.session.settings["general"]["max_tweets_per_call"] # try to retrieve the cursor for the current buffer. - cursor = self.session.db["cursors"].get(self.name) try: - # We need to assign all results somewhere else so the cursor variable would b generated. - val = Cursor(getattr(self.session.twitter, self.function), count=count, *self.args, **self.kwargs).items(count) + val = getattr(self.session.twitter, self.function)(return_cursors=True, count=count, *self.args, **self.kwargs) + if type(val) == tuple: + val, cursor = val + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor results = [i for i in val] - self.session.db["cursors"][self.name] = val.page_iterator.next_cursor val = results val.reverse() log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function)) @@ -221,7 +223,7 @@ class baseBufferController(baseBuffers.buffer): else: last_id = self.session.db[self.name][-1].id try: - items = Cursor(getattr(self.session.twitter, self.function), max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) + items = getattr(self.session.twitter, self.function)(max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) except TweepError as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return @@ -639,9 +641,13 @@ class directMessagesController(baseBufferController): # try to retrieve the cursor for the current buffer. cursor = self.session.db["cursors"].get(self.name) try: - items = Cursor(getattr(self.session.twitter, self.function), cursor=cursor, count=count, *self.args, **self.kwargs).items(count) + items = getattr(self.session.twitter, self.function)(return_cursors=True, cursor=cursor, count=count, *self.args, **self.kwargs) + if type(items) == tuple: + items, cursor = items + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor results = [i for i in items] - self.session.db["cursors"][self.name] = items.page_iterator.next_cursor items = results log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) except TweepError as e: @@ -873,13 +879,14 @@ class peopleBufferController(baseBufferController): self.execution_time = current_time log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,)) log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) - # try to retrieve the cursor for the current buffer. - cursor = self.session.db["cursors"].get(self.name) try: - # We need to assign all results somewhere else so the cursor variable would b generated. - val = Cursor(getattr(self.session.twitter, self.function), count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) + val = getattr(self.session.twitter, self.function)(return_cursors=True, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + if type(val) == tuple: + val, cursor = val + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor results = [i for i in val] - self.session.db["cursors"][self.name] = val.page_iterator.next_cursor val = results val.reverse() log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) @@ -902,9 +909,13 @@ class peopleBufferController(baseBufferController): def get_more_items(self): try: cursor = self.session.db["cursors"].get(self.name) - items = Cursor(getattr(self.session.twitter, self.function), users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs).items(self.session.settings["general"]["max_tweets_per_call"]) + items = getattr(self.session.twitter, self.function)(return_cursors=True, users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + if type(items) == tuple: + items, cursor = items + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor results = [i for i in items] - self.session.db["cursors"][self.name] = items.page_iterator.next_cursor items = results log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) except TweepError as e: From 2f278b7f3c5f9dea42f18067de20917c66e710c0 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 13:30:37 -0600 Subject: [PATCH 012/245] Removed yet another reference to Twython --- src/mysc/thread_utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mysc/thread_utils.py b/src/mysc/thread_utils.py index 3a112e33..05cd8564 100644 --- a/src/mysc/thread_utils.py +++ b/src/mysc/thread_utils.py @@ -10,8 +10,6 @@ def call_threaded(func, *args, **kwargs): def new_func(*a, **k): try: func(*a, **k) - except TwythonRateLimitError: - pass except: log.exception("Thread %d with function %r, args of %r, and kwargs of %r failed to run." % (threading.current_thread().ident, func, a, k)) # pass From 23df8f8a7fc648d33bca9f354de3725c5edd18fd Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 14:00:29 -0600 Subject: [PATCH 013/245] Updated python version in CI config file --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cfd3a2c2..6fc07d83 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,8 +10,8 @@ environment: matrix: # List of python versions we want to work with. - - PYTHON: "C:\\Python37" - PYTHON_VERSION: "3.7.x" # currently 2.7.9 + - PYTHON: "C:\\Python38" + PYTHON_VERSION: "3.8.x" # currently 2.7.9 PYTHON_ARCH: "32" # perhaps we may enable this one in future? From ae57cc34042ef05a5a25942e178bc5fd47c5c722 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 15:03:47 -0600 Subject: [PATCH 014/245] Retrieve up to 5000 users when getting list IDS --- src/controller/buffers/twitterBuffers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index ec01dd85..8466fd9c 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -776,7 +776,7 @@ class listBufferController(baseBufferController): super(listBufferController, self).start_stream(mandatory, play_sound, avoid_autoreading) def get_user_ids(self): - for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True).items(): + for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): if i.id not in self.users: self.users.append(i.id) From 63d7cbe7c4a94e3baf268627ff2331d1dfd38221 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 16:27:33 -0600 Subject: [PATCH 015/245] Implemented user searches. --- src/controller/buffers/twitterBuffers.py | 88 +++--------------------- 1 file changed, 10 insertions(+), 78 deletions(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 8466fd9c..05870eef 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -1020,26 +1020,6 @@ class peopleBufferController(baseBufferController): webbrowser.open(url) class searchBufferController(baseBufferController): - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: - self.execution_time = current_time - log.debug("Starting stream for %s buffer, %s account and %s type" % (self.name, self.account, self.type)) - log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) - log.debug("Function: %s" % (self.function,)) -# try: - val = self.session.search(self.name, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) -# except: -# return None - num = self.session.order_buffer(self.name, val) - self.put_items_on_list(num) - if num > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and num > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(num) - return num def remove_buffer(self, force=False): if force == False: @@ -1057,69 +1037,21 @@ class searchBufferController(baseBufferController): return False class searchPeopleBufferController(peopleBufferController): - + """ This is identical to a normal peopleBufferController, except that uses the page parameter instead of a cursor.""" def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs): super(searchPeopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) - log.debug("Initializing buffer %s, account %s" % (name, account,)) -# self.compose_function = compose.compose_followers_list - log.debug("Compose_function: %s" % (self.compose_function,)) - self.args = args - self.kwargs = kwargs - self.function = function if ("page" in self.kwargs) == False: - self.kwargs["page"] = 1 - - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=True): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: - self.execution_time = current_time - log.debug("starting stream for %s buffer, %s account and %s type" % (self.name, self.account, self.type)) - log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) - log.debug("Function: %s" % (self.function,)) -# try: - val = self.session.call_paged(self.function, *self.args, **self.kwargs) -# except: -# return - number_of_items = self.session.order_cursored_buffer(self.name, val) - log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) - if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(number_of_items) - return number_of_items + self.page = 1 + else: + self.page = self.kwargs.pop("page") def get_more_items(self, *args, **kwargs): - self.kwargs["page"] += 1 - try: - items = self.session.get_more_items(self.function, users=True, name=self.name, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - except TweepError as e: - output.speak(e.reason, True) - return - if items == None: - return - for i in items: - if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) - else: - self.session.db[self.name].append(i) - selected = self.buffer.list.get_selected() -# self.put_items_on_list(len(items)) - if self.session.settings["general"]["reverse_timelines"] == True: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(True, *tweet) - self.buffer.list.select_item(selected) - else: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(True, *tweet) -# self.buffer.list.select_item(selection) -# else: -# self.buffer.list.select_item(selection-elements) - output.speak(_(u"%s items retrieved") % (len(items)), True) + # Add 1 to the page parameter, put it in kwargs and calls to get_more_items in the parent buffer. + self.page = self.page +1 + self.kwargs["page"] = self.page + super(searchPeopleBufferController, self).get_more_items(*args, **kwargs) + # remove the parameter again to make sure start_stream won't fetch items for this page indefinitely. + self.kwargs.pop("page") def remove_buffer(self, force=False): if force == False: From 36cc3f93652a6fe20a5b1a10779c0d1f29781a19 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 17:30:10 -0600 Subject: [PATCH 016/245] Fix call to retrieve muted user IDS on twitter session --- src/sessions/twitter/session.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index e480f83c..9f05d83a 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -283,7 +283,7 @@ class Session(base.baseSession): # @_require_login def get_muted_users(self): """ Gets muted users (oh really?).""" - self.db["muted_users"] = self.twitter.mutes_ids + self.db["muted_users"] = self.twitter.mutes_ids() # @_require_login def get_stream(self, name, function, *args, **kwargs): @@ -434,10 +434,14 @@ class Session(base.baseSession): def save_users(self, user_ids): """ Adds all new users to the users database. """ + if len(user_ids) == 0: + return log.debug("Received %d user IDS to be added in the database." % (len(user_ids))) users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]] # Remove duplicates users_to_retrieve = list(dict.fromkeys(users_to_retrieve)) + if len(users_to_retrieve) == 0: + return log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") for user in users: From eca0c0dbbd7b618584344de269acafe71ac31a40 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 17:31:14 -0600 Subject: [PATCH 017/245] Fixed shelve method --- src/sessions/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sessions/base.py b/src/sessions/base.py index 8d58e5bf..235245e8 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -75,7 +75,7 @@ class baseSession(object): def shelve(self): """Shelve the database to allow for persistance.""" - shelfname=os.path.join(paths.config_path(), str(self.session_id)+"/cache") + shelfname=os.path.join(paths.config_path(), str(self.session_id), "cache") if self.settings["general"]["persist_size"] == 0: if os.path.exists(shelfname+".dat"): os.remove(shelfname+".dat") @@ -84,7 +84,7 @@ class baseSession(object): if not os.path.exists(shelfname+".dat"): output.speak("Generating database, this might take a while.",True) shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') - for key,value in list(self.db.items()): + for key, value in list(self.db.items()): if type(key) != str and type(key) != str: output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True) log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!") From e2e8b84e6a46f01807ae34191bb42e08e0d7637f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 17:32:12 -0600 Subject: [PATCH 018/245] Fixed focus when search dialog opens. Fixes #364 --- src/wxUI/dialogs/search.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wxUI/dialogs/search.py b/src/wxUI/dialogs/search.py index 13cc45ce..b8b6da56 100644 --- a/src/wxUI/dialogs/search.py +++ b/src/wxUI/dialogs/search.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals import widgetUtils from . import baseDialog import wx @@ -14,6 +12,7 @@ class searchDialog(baseDialog.BaseWXDialog): self.SetTitle(_(u"Search on Twitter")) label = wx.StaticText(panel, -1, _(u"&Search")) self.term = wx.TextCtrl(panel, -1, value) + self.term.SetFocus() dc = wx.WindowDC(self.term) dc.SetFont(self.term.GetFont()) self.term.SetSize(dc.GetTextExtent("0"*40)) From cba7c39a0e2c46c41665680f023e06e2fcf1ad70 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Jan 2021 17:49:59 -0600 Subject: [PATCH 019/245] Updated to snapshot 4 --- src/application.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/application.py b/src/application.py index 7e223ef6..728c8b09 100644 --- a/src/application.py +++ b/src/application.py @@ -9,12 +9,12 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "3" + version = "4" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] authorEmail = "manuel@manuelcortez.net" -copyright = "Copyright (C) 2013-2018, Manuel cortéz." +copyright = "Copyright (C) 2013-2021, Manuel cortéz." description = name+" is an app designed to use Twitter simply and efficiently while using minimal system resources. This app provides access to most Twitter features." translators = ["Manuel Cortéz (English)", "Mohammed Al Shara, Hatoun Felemban (Arabic)", "Francisco Torres (Catalan)", "Manuel cortéz (Spanish)", "Sukil Etxenike Arizaleta (Basque)", "Jani Kinnunen (finnish)", "Rémy Ruiz (French)", "Juan Buño (Galician)", "Steffen Schultz (German)", "Zvonimir Stanečić (Croatian)", "Robert Osztolykan (Hungarian)", "Christian Leo Mameli (Italian)", "Riku (Japanese)", "Paweł Masarczyk (Polish)", "Odenilton Júnior Santos (Portuguese)", "Florian Ionașcu, Nicușor Untilă (Romanian)", "Natalia Hedlund, Valeria Kuznetsova (Russian)", "Aleksandar Đurić (Serbian)", "Burak Yüksek (Turkish)"] url = u"https://twblue.es" From 9cb6eafbbc6cec7c86fcda19b9df1015d1044cf1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 4 Feb 2021 12:30:20 -0600 Subject: [PATCH 020/245] Fixed issue in autocomplete users feature. closes #367 --- doc/changelog.md | 1 + src/extra/autocompletionUsers/completion.py | 3 --- src/extra/autocompletionUsers/manage.py | 11 +++-------- src/extra/autocompletionUsers/settings.py | 20 ++++++++------------ src/extra/autocompletionUsers/storage.py | 2 -- src/extra/autocompletionUsers/wx_manage.py | 2 +- src/extra/autocompletionUsers/wx_menu.py | 1 - src/extra/autocompletionUsers/wx_settings.py | 1 - 8 files changed, 13 insertions(+), 28 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 651f215f..e20517a4 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Fixed autocomplete users feature. ([#367,](https://github.com/manuelcortez/TWBlue/issues/367)) * Fixed error when displaying an URL at the end of a line, when the tweet or direct message contained multiple lines. Now the URL should be displayed correctly. ([#305,](https://github.com/manuelcortez/TWBlue/issues/305) [#272,](https://github.com/manuelcortez/TWBlue/issues/272)) * TWBlue has been migrated completely to Python 3 (currently, the software builds with Python 3.8). * TWBlue should be restarted gracefully. Before, the application was alerting users of not being closed properly every time the application restarted by itself. diff --git a/src/extra/autocompletionUsers/completion.py b/src/extra/autocompletionUsers/completion.py index 562788cb..25875d8c 100644 --- a/src/extra/autocompletionUsers/completion.py +++ b/src/extra/autocompletionUsers/completion.py @@ -1,7 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -from builtins import object import output from . import storage from . import wx_menu diff --git a/src/extra/autocompletionUsers/manage.py b/src/extra/autocompletionUsers/manage.py index ba3a224c..ae7dd957 100644 --- a/src/extra/autocompletionUsers/manage.py +++ b/src/extra/autocompletionUsers/manage.py @@ -1,11 +1,6 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -# -*- coding: utf-8 -*- -from builtins import object -from . import storage import widgetUtils -from . import wx_manage +from . import storage, wx_manage from wxUI import commonMessageDialogs class autocompletionManage(object): @@ -32,11 +27,11 @@ class autocompletionManage(object): if usr == False: return try: - data = self.session.twitter.twitter.show_user(screen_name=usr) + data = self.session.twitter.twitter.get_user(screen_name=usr) except: self.dialog.show_invalid_user_error() return - self.database.set_user(data["screen_name"], data["name"], 0) + self.database.set_user(data.screen_name, data.name, 0) self.update_list() def remove_user(self, ev): diff --git a/src/extra/autocompletionUsers/settings.py b/src/extra/autocompletionUsers/settings.py index d14ba62b..283c217c 100644 --- a/src/extra/autocompletionUsers/settings.py +++ b/src/extra/autocompletionUsers/settings.py @@ -1,13 +1,9 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -# -*- coding: utf-8 -*- -from builtins import object -from . import storage import widgetUtils +import output from . import wx_settings from . import manage -import output +from . import storage from mysc.thread_utils import call_threaded class autocompletionSettings(object): @@ -30,14 +26,14 @@ class autocompletionSettings(object): database = storage.storage(self.buffer.session.session_id) if self.dialog.get("followers_buffer") == True: buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"]) - for i in buffer.session.db[buffer.name]["items"]: - database.set_user(i["screen_name"], i["name"], 1) + for i in buffer.session.db[buffer.name]: + database.set_user(i.screen_name, i.name, 1) else: database.remove_by_buffer(1) if self.dialog.get("friends_buffer") == True: buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"]) - for i in buffer.session.db[buffer.name]["items"]: - database.set_user(i["screen_name"], i["name"], 2) + for i in buffer.session.db[buffer.name]: + database.set_user(i.screen_name, i.name, 2) else: database.remove_by_buffer(2) wx_settings.show_success_dialog() @@ -52,12 +48,12 @@ def execute_at_startup(window, buffer, config): if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True: buffer = window.search_buffer("followers", config["twitter"]["user_name"]) for i in buffer.session.db[buffer.name]: - database.set_user(i["screen_name"], i["name"], 1) + database.set_user(i.screen_name, i.name, 1) else: database.remove_by_buffer(1) if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True: buffer = window.search_buffer("friends", config["twitter"]["user_name"]) for i in buffer.session.db[buffer.name]: - database.set_user(i["screen_name"], i["name"], 2) + database.set_user(i.screen_name, i.name, 2) else: database.remove_by_buffer(2) \ No newline at end of file diff --git a/src/extra/autocompletionUsers/storage.py b/src/extra/autocompletionUsers/storage.py index 9a34ef68..4d5df88f 100644 --- a/src/extra/autocompletionUsers/storage.py +++ b/src/extra/autocompletionUsers/storage.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals -from builtins import object import os, sqlite3, paths class storage(object): diff --git a/src/extra/autocompletionUsers/wx_manage.py b/src/extra/autocompletionUsers/wx_manage.py index dad0d0dd..3db4de67 100644 --- a/src/extra/autocompletionUsers/wx_manage.py +++ b/src/extra/autocompletionUsers/wx_manage.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals import wx import widgetUtils from multiplatform_widgets import widgets import application + class autocompletionManageDialog(widgetUtils.BaseDialog): def __init__(self): super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database")) diff --git a/src/extra/autocompletionUsers/wx_menu.py b/src/extra/autocompletionUsers/wx_menu.py index bf94e7f0..55d81458 100644 --- a/src/extra/autocompletionUsers/wx_menu.py +++ b/src/extra/autocompletionUsers/wx_menu.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals import wx class menu(wx.Menu): diff --git a/src/extra/autocompletionUsers/wx_settings.py b/src/extra/autocompletionUsers/wx_settings.py index e5520d4f..068decf6 100644 --- a/src/extra/autocompletionUsers/wx_settings.py +++ b/src/extra/autocompletionUsers/wx_settings.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals import wx import widgetUtils import application From 2f263a23b7f6326db477e2efdff67a98dc8097e2 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Feb 2021 09:34:30 -0600 Subject: [PATCH 021/245] Avoid giving false positive errors when buffers are updating --- src/controller/mainController.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 5061d9e6..89774396 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1326,16 +1326,19 @@ class Controller(object): i.start_stream() else: i.start_stream(play_sound=False) - except TweepError: - buff = self.view.search(i.name, i.account) - i.remove_buffer(force=True) - commonMessageDialogs.blocked_timeline() - if self.get_current_buffer() == i: - self.right() - self.view.delete_buffer(buff) - self.buffers.remove(i) - del i - continue + except TweepError as err: + log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) + # Determine if this error was caused by a block applied to the current user (IE permission errors). + if err.api_code != None: # A twitter error, so safely try to remove the buffer. + buff = self.view.search(i.name, i.account) + i.remove_buffer(force=True) + commonMessageDialogs.blocked_timeline() + if self.get_current_buffer() == i: + self.right() + self.view.delete_buffer(buff) + self.buffers.remove(i) + del i + continue if change_title: pub.sendMessage("buffer-title-changed", buffer=i) From 9c086cfa0f652f65b5be5c3dbf398682a94c67d2 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 11 Feb 2021 12:50:09 -0600 Subject: [PATCH 022/245] Prevend some errors to be identified as current user being blocked --- src/controller/mainController.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 89774396..edb16c9a 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -253,7 +253,7 @@ class Controller(object): # Connection checker executed each minute. self.checker_function = RepeatingTimer(60, self.check_connection) - self.checker_function.start() +# self.checker_function.start() self.save_db = RepeatingTimer(300, self.save_data_in_db) self.save_db.start() log.debug("Setting updates to buffers every %d seconds..." % (60*config.app["app-settings"]["update_period"],)) @@ -1535,15 +1535,18 @@ class Controller(object): if i.session != None and i.session.is_logged == True: try: i.start_stream(mandatory=True) - except TweepError: - buff = self.view.search(i.name, i.account) - i.remove_buffer(force=True) - commonMessageDialogs.blocked_timeline() - if self.get_current_buffer() == i: - self.right() - self.view.delete_buffer(buff) - self.buffers.remove(i) - del i + except TweepError as err: + log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) + # Determine if this error was caused by a block applied to the current user (IE permission errors). + if err.api_code != None: # A twitter error, so safely try to remove the buffer. + buff = self.view.search(i.name, i.account) + i.remove_buffer(force=True) + commonMessageDialogs.blocked_timeline() + if self.get_current_buffer() == i: + self.right() + self.view.delete_buffer(buff) + self.buffers.remove(i) + del i def update_buffer(self, *args, **kwargs): bf = self.get_current_buffer() From 0065af2aef06b51e23fa51f9fc75df79ab36e92b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 25 Feb 2021 16:57:32 -0600 Subject: [PATCH 023/245] Avoid removing buffers when api_error=130 --- src/controller/mainController.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index edb16c9a..9a8757c6 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1329,7 +1329,8 @@ class Controller(object): except TweepError as err: log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) # Determine if this error was caused by a block applied to the current user (IE permission errors). - if err.api_code != None: # A twitter error, so safely try to remove the buffer. + errors_allowed = [130] + if err.api_code != None and err.api_code not in errors_allowed: # A twitter error, so safely try to remove the buffer. buff = self.view.search(i.name, i.account) i.remove_buffer(force=True) commonMessageDialogs.blocked_timeline() @@ -1538,7 +1539,8 @@ class Controller(object): except TweepError as err: log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) # Determine if this error was caused by a block applied to the current user (IE permission errors). - if err.api_code != None: # A twitter error, so safely try to remove the buffer. + errors_allowed = [130] + if err.api_code != None and err.api_code not in errors_allowed: # A twitter error, so safely try to remove the buffer. buff = self.view.search(i.name, i.account) i.remove_buffer(force=True) commonMessageDialogs.blocked_timeline() From ee234b80a71e3814d4d344f161b26aeaa0fbbd6c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 9 Mar 2021 11:35:52 -0600 Subject: [PATCH 024/245] Fixed error when parsing long tweets. --- src/sessions/twitter/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 9f05d83a..2795932f 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -388,7 +388,7 @@ class Session(base.baseSession): tweet.quoted_status.twishort = True for i in tweet.quoted_status.entities["user_mentions"]: if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != tweet.user.screen_name: - if hasattr(tweet["quoted_status"], "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: + if hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: continue tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message) else: From 5b0b26799d79df760e6d9aba8ce80d006e2c43d2 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 9 Mar 2021 16:36:23 -0600 Subject: [PATCH 025/245] Install platform_utils, accessible_output2, libloader and sound_lib from upstream. Closes #369 --- doc/changelog.md | 1 + requirements.txt | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index e20517a4..267cf3f2 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Fixed an error that was causing TWBlue to be unable to output to screen readers at times. ([#369,](https://github.com/manuelcortez/TWBlue/issues/369)) * Fixed autocomplete users feature. ([#367,](https://github.com/manuelcortez/TWBlue/issues/367)) * Fixed error when displaying an URL at the end of a line, when the tweet or direct message contained multiple lines. Now the URL should be displayed correctly. ([#305,](https://github.com/manuelcortez/TWBlue/issues/305) [#272,](https://github.com/manuelcortez/TWBlue/issues/272)) * TWBlue has been migrated completely to Python 3 (currently, the software builds with Python 3.8). diff --git a/requirements.txt b/requirements.txt index b95337d7..ae1296b8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,7 +31,7 @@ cx_freeze tweepy twitter-text-parser pyenchant -git+https://github.com/manuelcortez/libloader -git+https://github.com/manuelcortez/platform_utils -git+https://github.com/manuelcortez/accessible_output2 -git+https://github.com/jmdaweb/sound_lib \ No newline at end of file +git+https://github.com/accessibleapps/libloader +git+https://github.com/accessibleapps/platform_utils +git+https://github.com/accessibleapps/accessible_output2 +git+https://github.com/accessibleapps/sound_lib \ No newline at end of file From 45deae3402eba9239f4341f0826ef5a99d8466ff Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 9 Mar 2021 16:41:58 -0600 Subject: [PATCH 026/245] Fixed rendering of retweets of quoted tweets. Fixes #365 --- doc/changelog.md | 1 + src/sessions/twitter/long_tweets/tweets.py | 2 +- src/sessions/twitter/session.py | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 267cf3f2..bb2ad5eb 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* TWBlue should render correctly retweets of quoted tweets. ([#365,](https://github.com/manuelcortez/TWBlue/issues/365)) * Fixed an error that was causing TWBlue to be unable to output to screen readers at times. ([#369,](https://github.com/manuelcortez/TWBlue/issues/369)) * Fixed autocomplete users feature. ([#367,](https://github.com/manuelcortez/TWBlue/issues/367)) * Fixed error when displaying an URL at the end of a line, when the tweet or direct message contained multiple lines. Now the URL should be displayed correctly. ([#305,](https://github.com/manuelcortez/TWBlue/issues/305) [#272,](https://github.com/manuelcortez/TWBlue/issues/272)) diff --git a/src/sessions/twitter/long_tweets/tweets.py b/src/sessions/twitter/long_tweets/tweets.py index 2ba1b48f..3ab7140d 100644 --- a/src/sessions/twitter/long_tweets/tweets.py +++ b/src/sessions/twitter/long_tweets/tweets.py @@ -25,7 +25,7 @@ def is_long(tweet): returns True if a quote is detected, False otherwise.""" if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"): return tweet.quoted_status_id - elif hasattr(tweet, "retweeted_status") and hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"): + elif hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "quoted_status_id") and hasattr(tweet.retweeted_status, "quoted_status"): return tweet.retweeted_status.quoted_status_id return False diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 2795932f..ff2badbf 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -352,16 +352,16 @@ class Session(base.baseSession): return tweet def get_quoted_tweet(self, tweet): - """ Process a tweet and extract all information related to the quote.""" + """ Process a tweet and extract all information related to the quote. """ quoted_tweet = tweet if hasattr(tweet, "full_text"): value = "full_text" else: value = "text" setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities)) - if hasattr(quoted_tweet, "quoted_status"): + if quoted_tweet.is_quote_status == True and hasattr(quoted_tweet, "quoted_status"): original_tweet = quoted_tweet.quoted_status - elif hasattr(quoted_tweet, "retweeted_status") and hasattr(quoted_tweet.retweeted_status, "quoted_status"): + elif hasattr(quoted_tweet, "retweeted_status") and quoted_tweet.retweeted_status.is_quote_status == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"): original_tweet = quoted_tweet.retweeted_status.quoted_status else: return quoted_tweet From eb0679cb9681745c0fc5b8531bfc0de164d7cc51 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 17 Apr 2021 13:00:30 -0500 Subject: [PATCH 027/245] Make unexistent users to throw an error when loading a timeline --- src/controller/mainController.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 9a8757c6..de600aab 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1330,7 +1330,7 @@ class Controller(object): log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) # Determine if this error was caused by a block applied to the current user (IE permission errors). errors_allowed = [130] - if err.api_code != None and err.api_code not in errors_allowed: # A twitter error, so safely try to remove the buffer. + if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. buff = self.view.search(i.name, i.account) i.remove_buffer(force=True) commonMessageDialogs.blocked_timeline() @@ -1540,7 +1540,7 @@ class Controller(object): log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) # Determine if this error was caused by a block applied to the current user (IE permission errors). errors_allowed = [130] - if err.api_code != None and err.api_code not in errors_allowed: # A twitter error, so safely try to remove the buffer. + if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. buff = self.view.search(i.name, i.account) i.remove_buffer(force=True) commonMessageDialogs.blocked_timeline() From 30f739c42ee6202857ad2746ee5fb9b9ca659451 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 19 Apr 2021 16:51:26 -0500 Subject: [PATCH 028/245] Updated version to a new snapshot --- src/application.py | 2 +- updates/snapshots.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/application.py b/src/application.py index 728c8b09..d62d55b6 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "4" + version = "5" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] diff --git a/updates/snapshots.json b/updates/snapshots.json index 6fdd3182..f12f4a45 100644 --- a/updates/snapshots.json +++ b/updates/snapshots.json @@ -1,4 +1,4 @@ -{"current_version": "3", +{"current_version": "5", "description": "Snapshot version.", "date": "unknown", "downloads": From 9346bba7a01512a5d7cdd106c01354fe53c8d447 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 3 May 2021 10:05:14 -0500 Subject: [PATCH 029/245] Fixed a small bug when sending long tweets via twyshort --- src/controller/messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 9af6152f..5eac4e13 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -109,7 +109,7 @@ class basicTweet(object): if results.weightedLength > self.max: self.session.sound.play("max_length.ogg") else: - self.message.set_title(_(u"%s - %s characters") % (self.title, results.weightedLength)) + self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text()))) def spellcheck(self, event=None): text = self.message.get_text() From 7d6e230fd97650029fb59f7930060f4d667830e6 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 7 May 2021 16:52:10 -0500 Subject: [PATCH 030/245] Fix issue that avoids TWBlue to use Shift+F10 as menu key. Fixes #353 --- doc/changelog.md | 1 + src/controller/buffers/baseBuffers.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/changelog.md b/doc/changelog.md index bb2ad5eb..7effe95a 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* TWBlue will take Shift+F10 again as the contextual menu key in the list of items in a buffer. This stopped working after we have migrated to WX 4.1. ([#353,](https://github.com/manuelcortez/TWBlue/issues/353)) * TWBlue should render correctly retweets of quoted tweets. ([#365,](https://github.com/manuelcortez/TWBlue/issues/365)) * Fixed an error that was causing TWBlue to be unable to output to screen readers at times. ([#369,](https://github.com/manuelcortez/TWBlue/issues/369)) * Fixed autocomplete users feature. ([#367,](https://github.com/manuelcortez/TWBlue/issues/367)) diff --git a/src/controller/buffers/baseBuffers.py b/src/controller/buffers/baseBuffers.py index 728a5e62..2bb09c80 100644 --- a/src/controller/buffers/baseBuffers.py +++ b/src/controller/buffers/baseBuffers.py @@ -59,15 +59,21 @@ class buffer(object): elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status" + # Raise a Special event when pressed Shift+F10 because Wx==4.1.x does not seems to trigger this by itself. + # See https://github.com/manuelcortez/TWBlue/issues/353 + elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu" else: event = None ev.Skip() if event != None: try: + ### ToDo: Remove after WX fixes issue #353 in the widgets. + if event == "show_menu": + return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) getattr(self, event)() except AttributeError: pass - + def volume_down(self): """ Decreases volume by 5%""" if self.session.settings["sound"]["volume"] > 0.0: From b10aeb046d52ca425ca43fa99be3fd7c6a53bac3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 7 May 2021 17:18:21 -0500 Subject: [PATCH 031/245] Changed label of direct message's text field so it will not reference any username in the hint. Closes #366 --- doc/changelog.md | 1 + src/wxUI/dialogs/message.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog.md b/doc/changelog.md index 7effe95a..e4369880 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Changed the label in the direct message's text control so it will indicate that the user needs to write the text there, without referring to any username in particular. ([#366,](https://github.com/manuelcortez/TWBlue/issues/366)) * TWBlue will take Shift+F10 again as the contextual menu key in the list of items in a buffer. This stopped working after we have migrated to WX 4.1. ([#353,](https://github.com/manuelcortez/TWBlue/issues/353)) * TWBlue should render correctly retweets of quoted tweets. ([#365,](https://github.com/manuelcortez/TWBlue/issues/365)) * Fixed an error that was causing TWBlue to be unable to output to screen readers at times. ([#369,](https://github.com/manuelcortez/TWBlue/issues/369)) diff --git a/src/wxUI/dialogs/message.py b/src/wxUI/dialogs/message.py index 50e380d7..97f8a22a 100644 --- a/src/wxUI/dialogs/message.py +++ b/src/wxUI/dialogs/message.py @@ -221,7 +221,7 @@ class dm(textLimited): def __init__(self, title, message, users, *args, **kwargs): super(dm, self).__init__() - self.createControls(message, title, users) + self.createControls(title, message, users) # self.onTimer(wx.EVT_CHAR_HOOK) # self.SetClientSize(self.mainBox.CalcMin()) From 2a791d43bff3156d83d59cbd57641dcaefc02a0d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 14 May 2021 09:52:19 -0500 Subject: [PATCH 032/245] Fixed an error when parsing a DM sent from an deleted account --- src/sessions/twitter/compose.py | 2 -- src/sessions/twitter/session.py | 10 +++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sessions/twitter/compose.py b/src/sessions/twitter/compose.py index 98370391..89dc6f16 100644 --- a/src/sessions/twitter/compose.py +++ b/src/sessions/twitter/compose.py @@ -77,8 +77,6 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No return [user+", ", text, ts+", ", source] def compose_direct_message(item, db, relative_times, show_screen_names=False, session=None): - # for a while this function will be together with compose_dm. - # this one composes direct messages based on events (new API Endpoints). if system == "Windows": # Let's remove the last 3 digits in the timestamp string. # Twitter sends their "epoch" timestamp with 3 digits for milliseconds and arrow doesn't like it. diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index ff2badbf..7dd1fb79 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -11,6 +11,7 @@ import application from pubsub import pub import tweepy from tweepy.error import TweepError +from tweepy.models import User as UserModel from mysc.thread_utils import call_threaded from keys import keyring from sessions import base @@ -404,13 +405,16 @@ class Session(base.baseSession): def get_user(self, id): """ Returns an user object associated with an ID. id str: User identifier, provided by Twitter. - returns an user dict.""" + returns a tweepy user object.""" if ("users" in self.db) == False or (id in self.db["users"]) == False: try: user = self.twitter.get_user(id=id) except TweepError as err: - user = dict(screen_name="deleted_account", name="Deleted account") - return user + user = UserModel(None) + user.screen_name = "deleted_user" + user.id = id + user.name = _("Deleted account") + user.id_str = id self.db["users"][user.id_str] = user return user else: From 2aaa4eced3ad7c628c7ae2d7373669143f4abf39 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 16 Jun 2021 16:17:16 -0500 Subject: [PATCH 033/245] Removed Catala and Basque locale as they are in arrow already. Disabled Galician locale cause it's not fully implemented and fails --- src/fixes/fix_arrow.py | 115 +++++++++++------------------------------ 1 file changed, 31 insertions(+), 84 deletions(-) diff --git a/src/fixes/fix_arrow.py b/src/fixes/fix_arrow.py index aef8581e..d1d3dca4 100644 --- a/src/fixes/fix_arrow.py +++ b/src/fixes/fix_arrow.py @@ -1,95 +1,42 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals from arrow import locales from arrow.locales import Locale def fix(): - # insert a modified function so if there is no language available in arrow, returns English locale. - locales.get_locale = get_locale + # insert a modified function so if there is no language available in arrow, returns English locale. + locales.get_locale = get_locale def get_locale(name): - locale_cls = locales._locales.get(name.lower()) - if locale_cls is None: - name = name[:2] - locale_cls = locales._locales.get(name.lower()) - if locale_cls == None: - return locales.EnglishLocale() - return locale_cls() + locale_cls = locales._locale_map.get(name.lower()) + if locale_cls is None: + name = name[:2] + locale_cls = locales._locale_map.get(name.lower()) + if locale_cls == None: + return locales.EnglishLocale() + return locale_cls() -class CatalaLocale(Locale): - names = ['ca', 'ca_es', 'ca_ca'] - past = 'Fa {0}' - future = '{0}' # I don't know what's the right phrase in catala for the future. +class GalicianLocale(object): + names = ['gl', 'gl_es', 'gl_gl'] + past = 'Fai {0}' + future = 'En {0}' - timeframes = { - 'now': 'Ara mateix', - 'seconds': 'segons', - 'minute': '1 minut', - 'minutes': '{0} minuts', - 'hour': 'una hora', - 'hours': '{0} hores', - 'day': 'un dia', - 'days': '{0} dies', - 'month': 'un mes', - 'months': '{0} messos', - 'year': 'un any', - 'years': '{0} anys', - } + timeframes = { + 'now': 'Agora mesmo', + 'seconds': 'segundos', + 'minute': 'un minuto', + 'minutes': '{0} minutos', + 'hour': 'una hora', + 'hours': '{0} horas', + 'day': 'un día', + 'days': '{0} días', + 'month': 'un mes', + 'months': '{0} meses', + 'year': 'un ano', + 'years': '{0} anos', + } - month_names = ['', 'Jener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juliol', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Decembre'] - month_abbreviations = ['', 'Jener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juliol', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Decembre'] - day_names = ['', 'Dilluns', 'Dimars', 'Dimecres', 'Dijous', 'Divendres', 'Disabte', 'Diumenge'] - day_abbreviations = ['', 'Dilluns', 'Dimars', 'Dimecres', 'Dijous', 'Divendres', 'Disabte', 'Diumenge'] - -class GalicianLocale(Locale): - names = ['gl', 'gl_es', 'gl_gl'] - past = 'Fai {0}' - future = 'En {0}' - - timeframes = { - 'now': 'Agora mesmo', - 'seconds': 'segundos', - 'minute': 'un minuto', - 'minutes': '{0} minutos', - 'hour': 'una hora', - 'hours': '{0} horas', - 'day': 'un día', - 'days': '{0} días', - 'month': 'un mes', - 'months': '{0} meses', - 'year': 'un ano', - 'years': '{0} anos', - } - - month_names = ['', 'Xaneiro', 'Febreiro', 'Marzo', 'Abril', 'Maio', 'Xuño', 'Xullo', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Decembro'] - month_abbreviations = ['', 'Xan', 'Feb', 'Mar', 'Abr', 'Mai', 'Xun', 'Xul', 'Ago', 'Set', 'Out', 'Nov', 'Dec'] - day_names = ['', 'Luns', 'Martes', 'Mércores', 'Xoves', 'Venres', 'Sábado', 'Domingo'] - day_abbreviations = ['', 'Lun', 'Mar', 'Mer', 'xov', 'Ven' 'Sab', 'Dom'] - -class BasqueLocale(Locale): - names = ['eu', 'eu_es', 'eu_eu'] - past = 'duela {0}' - future = '{0} igarota' - - timeframes = { - 'now': 'Orain', - # 'second': 'segundu bat', - 'seconds': 'segundu batzuk', # without specifying a number. - #'seconds': '{0} segundu', # specifying a number - 'minute': 'minutu bat', - 'minutes': '{0} minutu', - 'hour': 'ordu bat', - 'hours': '{0} ordu', - 'day': 'egun bat', - 'days': '{0} egun', - 'month': 'hilabete bat', - 'months': '{0} hilabete', - 'year': 'urte bat', - 'years': '{0} urte', - } - - month_names = ['', 'Urtarrilak', 'Otsailak', 'Martxoak', 'Apirilak', 'Maiatzak', 'Ekainak', 'Uztailak', 'Abuztuak', 'Irailak', 'Urriak', 'Azaroak', 'Abenduak'] - month_abbreviations = ['', 'urt', 'ots', 'mar', 'api', 'mai', 'eka', 'uzt', 'abu', 'ira', 'urr', 'aza', 'abe'] - day_names = ['', 'Asteleehna', 'Asteartea', 'Asteazkena', 'Osteguna', 'Ostirala', 'Larunbata', 'Igandea'] - day_abbreviations = ['', 'al', 'ar', 'az', 'og', 'ol', 'lr', 'ig'] + month_names = ['', 'Xaneiro', 'Febreiro', 'Marzo', 'Abril', 'Maio', 'Xuño', 'Xullo', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Decembro'] + month_abbreviations = ['', 'Xan', 'Feb', 'Mar', 'Abr', 'Mai', 'Xun', 'Xul', 'Ago', 'Set', 'Out', 'Nov', 'Dec'] + day_names = ['', 'Luns', 'Martes', 'Mércores', 'Xoves', 'Venres', 'Sábado', 'Domingo'] + day_abbreviations = ['', 'Lun', 'Mar', 'Mer', 'xov', 'Ven' 'Sab', 'Dom'] From 39e1fb017cdad654f41d75d1ae282e58b40cb405 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 16 Jun 2021 16:18:41 -0500 Subject: [PATCH 034/245] Made code indentation to comply with PEP8 --- src/application.py | 14 +- src/audio_services/__init__.py | 34 +- src/audio_services/services.py | 44 +- src/audio_services/youtube_utils.py | 16 +- src/config.py | 22 +- src/config_utils.py | 112 +- src/controller/attach.py | 54 +- src/controller/buffers/__init__.py | 2 +- src/controller/buffers/baseBuffers.py | 326 +- src/controller/buffers/twitterBuffers.py | 2210 ++++++------ src/controller/filterController.py | 124 +- src/controller/listsController.py | 180 +- src/controller/mainController.py | 3066 ++++++++--------- src/controller/messages.py | 498 +-- src/controller/settings.py | 502 +-- src/controller/trendingTopics.py | 72 +- src/controller/user.py | 216 +- src/controller/userActionsController.py | 120 +- src/extra/AudioUploader/audioUploader.py | 256 +- src/extra/AudioUploader/transfer.py | 138 +- src/extra/AudioUploader/utils.py | 74 +- .../AudioUploader/wx_transfer_dialogs.py | 102 +- src/extra/AudioUploader/wx_ui.py | 98 +- src/extra/SoundsTutorial/gtk_ui.py | 36 +- src/extra/SoundsTutorial/reverse_sort.py | 4 +- src/extra/SoundsTutorial/soundsTutorial.py | 42 +- .../soundsTutorial_constants.py | 48 +- src/extra/SoundsTutorial/wx_ui.py | 46 +- src/extra/SpellChecker/__init__.py | 2 +- src/extra/SpellChecker/spellchecker.py | 112 +- src/extra/SpellChecker/wx_ui.py | 102 +- src/extra/autocompletionUsers/__init__.py | 2 +- src/extra/autocompletionUsers/completion.py | 80 +- src/extra/autocompletionUsers/manage.py | 66 +- src/extra/autocompletionUsers/settings.py | 92 +- src/extra/autocompletionUsers/storage.py | 70 +- src/extra/autocompletionUsers/wx_manage.py | 68 +- src/extra/autocompletionUsers/wx_menu.py | 36 +- src/extra/autocompletionUsers/wx_settings.py | 38 +- src/extra/ocr/OCRSpace.py | 56 +- src/extra/ocr/__init__.py | 2 +- src/extra/translator/__init__.py | 4 +- src/extra/translator/translator.py | 196 +- src/extra/translator/wx_ui.py | 42 +- src/fixes/__init__.py | 10 +- src/fixes/fix_libloader.py | 40 +- src/fixes/fix_requests.py | 6 +- src/fixes/fix_urllib3_warnings.py | 4 +- src/fixes/fix_win32com.py | 6 +- src/issueReporter/issueReporter.py | 72 +- src/issueReporter/wx_ui.py | 136 +- src/keyboard_handler/global_handler.py | 6 +- src/keyboard_handler/key_constants.py | 246 +- src/keyboard_handler/linux.py | 84 +- src/keyboard_handler/main.py | 146 +- src/keyboard_handler/osx.py | 70 +- src/keyboard_handler/windows.py | 58 +- src/keyboard_handler/wx_handler.py | 200 +- src/keys/__init__.py | 30 +- src/keys/linuxKeys.py | 4 +- src/keystrokeEditor/__init__.py | 2 +- src/keystrokeEditor/constants.py | 114 +- src/keystrokeEditor/keystrokeEditor.py | 92 +- src/keystrokeEditor/wx_ui.py | 132 +- src/languageHandler.py | 340 +- src/logger.py | 8 +- src/main.py | 204 +- src/multiplatform_widgets/__init__.py | 2 +- src/multiplatform_widgets/widgets.py | 138 +- src/mysc/autostart.py | 52 +- src/mysc/localization.py | 20 +- src/mysc/repeating_timer.py | 54 +- src/mysc/restart.py | 20 +- src/mysc/thread_utils.py | 20 +- src/notifier/__init__.py | 22 +- src/notifier/linux.py | 36 +- src/notifier/windows.py | 4 +- src/output.py | 42 +- src/paths.py | 82 +- src/sessionmanager/__init__.py | 2 +- src/sessionmanager/gtkUI.py | 88 +- src/sessionmanager/manager.py | 64 +- src/sessionmanager/sessionManager.py | 182 +- src/sessionmanager/wxUI.py | 120 +- src/sessions/__init__.py | 2 +- src/sessions/base.py | 178 +- src/sessions/session_exceptions.py | 2 +- src/sessions/twitter/__init__.py | 2 +- src/sessions/twitter/compose.py | 277 +- src/sessions/twitter/long_tweets/__init__.py | 2 +- src/sessions/twitter/long_tweets/tweets.py | 56 +- src/sessions/twitter/long_tweets/twishort.py | 136 +- src/sessions/twitter/session.py | 786 ++--- src/sessions/twitter/utils.py | 338 +- src/sessions/twitter/wxUI.py | 28 +- src/setup.py | 56 +- src/sound.py | 220 +- src/update/__init__.py | 14 +- src/update/update.py | 172 +- src/update/updater.py | 20 +- src/update/utils.py | 74 +- src/update/wxUpdater.py | 30 +- src/url_shortener/__main__.py | 48 +- src/url_shortener/shorteners/acortame.py | 40 +- src/url_shortener/shorteners/clckru.py | 22 +- src/url_shortener/shorteners/hkcim.py | 22 +- src/url_shortener/shorteners/isgd.py | 22 +- src/url_shortener/shorteners/onjme.py | 22 +- src/url_shortener/shorteners/tinyarrows.py | 22 +- src/url_shortener/shorteners/tinyurl.py | 22 +- src/url_shortener/shorteners/url_shortener.py | 64 +- src/url_shortener/shorteners/xedcc.py | 22 +- src/widgetUtils/__init__.py | 2 +- src/widgetUtils/gtkUtils.py | 170 +- src/widgetUtils/wxUtils.py | 102 +- src/wxUI/buffers/__init__.py | 2 +- src/wxUI/buffers/base.py | 72 +- src/wxUI/buffers/dm.py | 12 +- src/wxUI/buffers/events.py | 32 +- src/wxUI/buffers/favourites.py | 6 +- src/wxUI/buffers/lists.py | 6 +- src/wxUI/buffers/panels.py | 50 +- src/wxUI/buffers/people.py | 16 +- src/wxUI/buffers/trends.py | 52 +- src/wxUI/buffers/tweet_searches.py | 6 +- src/wxUI/buffers/user_searches.py | 14 +- src/wxUI/commonMessageDialogs.py | 72 +- src/wxUI/dialogs/attach.py | 76 +- src/wxUI/dialogs/baseDialog.py | 42 +- src/wxUI/dialogs/configuration.py | 716 ++-- src/wxUI/dialogs/filterDialogs.py | 250 +- src/wxUI/dialogs/find.py | 42 +- src/wxUI/dialogs/lists.py | 222 +- src/wxUI/dialogs/message.py | 808 ++--- src/wxUI/dialogs/search.py | 124 +- src/wxUI/dialogs/show_user.py | 40 +- src/wxUI/dialogs/trends.py | 74 +- src/wxUI/dialogs/update_profile.py | 170 +- src/wxUI/dialogs/urlList.py | 54 +- src/wxUI/dialogs/userActions.py | 158 +- src/wxUI/dialogs/userSelection.py | 110 +- src/wxUI/dialogs/utils.py | 46 +- src/wxUI/menus.py | 178 +- src/wxUI/sysTrayIcon.py | 36 +- src/wxUI/view.py | 320 +- 145 files changed, 9577 insertions(+), 9584 deletions(-) diff --git a/src/application.py b/src/application.py index bfd6a88a..41869e88 100644 --- a/src/application.py +++ b/src/application.py @@ -5,13 +5,13 @@ name = 'TWBlue' short_name='twblue' snapshot = True if snapshot == False: - version = "0.95" - update_url = 'https://twblue.es/updates/stable.php' - mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' + version = "0.95" + update_url = 'https://twblue.es/updates/stable.php' + mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "5" - update_url = 'https://twblue.es/updates/snapshot.php' - mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' + version = "5" + update_url = 'https://twblue.es/updates/snapshot.php' + mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] authorEmail = "manuel@manuelcortez.net" copyright = "Copyright (C) 2013-2021, Manuel cortéz." @@ -19,4 +19,4 @@ description = name+" is an app designed to use Twitter simply and efficiently wh translators = ["Manuel Cortéz (English)", "Mohammed Al Shara, Hatoun Felemban (Arabic)", "Francisco Torres (Catalan)", "Manuel cortéz (Spanish)", "Sukil Etxenike Arizaleta (Basque)", "Jani Kinnunen (finnish)", "Oreonan (Français)", "Juan Buño (Galician)", "Steffen Schultz (German)", "Zvonimir Stanečić (Croatian)", "Robert Osztolykan (Hungarian)", "Christian Leo Mameli (Italian)", "Riku (Japanese)", "Paweł Masarczyk (Polish)", "Odenilton Júnior Santos (Portuguese)", "Florian Ionașcu, Nicușor Untilă (Romanian)", "Natalia Hedlund, Valeria Kuznetsova (Russian)", "Aleksandar Đurić (Serbian)", "Burak Yüksek (Turkish)"] url = u"https://twblue.es" report_bugs_url = "https://github.com/manuelcortez/twblue/issues" -supported_languages = [] \ No newline at end of file +supported_languages = [] diff --git a/src/audio_services/__init__.py b/src/audio_services/__init__.py index 4d092b4c..d33809cb 100644 --- a/src/audio_services/__init__.py +++ b/src/audio_services/__init__.py @@ -2,22 +2,22 @@ from __future__ import unicode_literals from functools import wraps def matches_url(url): - def url_setter(func): - @wraps(func) - def internal_url_setter(*args, **kwargs): - return func(*args, **kwargs) - internal_url_setter.url = url - return internal_url_setter - return url_setter + def url_setter(func): + @wraps(func) + def internal_url_setter(*args, **kwargs): + return func(*args, **kwargs) + internal_url_setter.url = url + return internal_url_setter + return url_setter def find_url_transformer(url): - from audio_services import services - funcs = [] - for i in dir(services): - possible = getattr(services, i) - if callable(possible) and hasattr(possible, 'url'): - funcs.append(possible) - for f in funcs: - if url.lower().startswith(f.url.lower()): - return f - return services.convert_generic_audio + from audio_services import services + funcs = [] + for i in dir(services): + possible = getattr(services, i) + if callable(possible) and hasattr(possible, 'url'): + funcs.append(possible) + for f in funcs: + if url.lower().startswith(f.url.lower()): + return f + return services.convert_generic_audio diff --git a/src/audio_services/services.py b/src/audio_services/services.py index eefde7d5..b19ab68d 100644 --- a/src/audio_services/services.py +++ b/src/audio_services/services.py @@ -5,37 +5,37 @@ from . import youtube_utils @matches_url('https://audioboom.com') def convert_audioboom(url): - if "audioboom.com" not in url.lower(): - raise TypeError('%r is not a valid URL' % url) - audio_id = url.split('.com/')[-1] - return 'https://audioboom.com/%s.mp3' % audio_id + if "audioboom.com" not in url.lower(): + raise TypeError('%r is not a valid URL' % url) + audio_id = url.split('.com/')[-1] + return 'https://audioboom.com/%s.mp3' % audio_id @matches_url ('https://soundcloud.com/') def convert_soundcloud (url): - client_id = "df8113ca95c157b6c9731f54b105b473" - with requests.get('http://api.soundcloud.com/resolve.json', client_id=client_id, url=url) as permalink: - if permalink.status_code==404: - raise TypeError('%r is not a valid URL' % permalink.url) - else: - resolved_url = permalink.url - with requests.get(resolved_url) as track_url: - track_data = track_url.json() + client_id = "df8113ca95c157b6c9731f54b105b473" + with requests.get('http://api.soundcloud.com/resolve.json', client_id=client_id, url=url) as permalink: + if permalink.status_code==404: + raise TypeError('%r is not a valid URL' % permalink.url) + else: + resolved_url = permalink.url + with requests.get(resolved_url) as track_url: + track_data = track_url.json() - if track_data ['streamable']: - return track_data ['stream_url'] + "?client_id=%s" %client_id - else: - raise TypeError('%r is not streamable' % url) + if track_data ['streamable']: + return track_data ['stream_url'] + "?client_id=%s" %client_id + else: + raise TypeError('%r is not streamable' % url) @matches_url ('https://www.youtube.com/watch') def convert_youtube_long (url): - return youtube_utils.get_video_url(url) + return youtube_utils.get_video_url(url) @matches_url ('http://anyaudio.net/listen') def convert_anyaudio(url): - values = url.split("audio=") - if len(values) != 2: - raise TypeError('%r is not streamable' % url) - return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],) + values = url.split("audio=") + if len(values) != 2: + raise TypeError('%r is not streamable' % url) + return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],) def convert_generic_audio(url): - return url + return url diff --git a/src/audio_services/youtube_utils.py b/src/audio_services/youtube_utils.py index 3c4430a9..7341cfbf 100644 --- a/src/audio_services/youtube_utils.py +++ b/src/audio_services/youtube_utils.py @@ -3,11 +3,11 @@ from __future__ import unicode_literals import youtube_dl def get_video_url(url): - ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': 'bestaudio/best', 'outtmpl': u'%(id)s%(ext)s'}) - with ydl: - result = ydl.extract_info(url, download=False) - if 'entries' in result: - video = result['entries'][0] - else: - video = result - return video["formats"][0]["url"] + ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': 'bestaudio/best', 'outtmpl': u'%(id)s%(ext)s'}) + with ydl: + result = ydl.extract_info(url, download=False) + if 'entries' in result: + video = result['entries'][0] + else: + video = result + return video["formats"][0]["url"] diff --git a/src/config.py b/src/config.py index a7e94eb6..1954c628 100644 --- a/src/config.py +++ b/src/config.py @@ -15,14 +15,14 @@ keymap=None changed_keymap = False def setup (): - global app - log.debug("Loading global app settings...") - app = config_utils.load_config(os.path.join(paths.config_path(), MAINFILE), os.path.join(paths.app_path(), MAINSPEC)) - log.debug("Loading keymap...") - global keymap - if float(platform.version()[:2]) >= 10 and app["app-settings"]["load_keymap"] == "default.keymap": - app["app-settings"]["load_keymap"] = "Windows 10.keymap" - app.write() - global changed_keymap - changed_keymap = True - keymap = config_utils.load_config(os.path.join(paths.config_path(), "keymap.keymap"), os.path.join(paths.app_path(), "keymaps/"+app['app-settings']['load_keymap']), copy=False) + global app + log.debug("Loading global app settings...") + app = config_utils.load_config(os.path.join(paths.config_path(), MAINFILE), os.path.join(paths.app_path(), MAINSPEC)) + log.debug("Loading keymap...") + global keymap + if float(platform.version()[:2]) >= 10 and app["app-settings"]["load_keymap"] == "default.keymap": + app["app-settings"]["load_keymap"] = "Windows 10.keymap" + app.write() + global changed_keymap + changed_keymap = True + keymap = config_utils.load_config(os.path.join(paths.config_path(), "keymap.keymap"), os.path.join(paths.app_path(), "keymaps/"+app['app-settings']['load_keymap']), copy=False) diff --git a/src/config_utils.py b/src/config_utils.py index f2cc10e6..fb0b2ccf 100644 --- a/src/config_utils.py +++ b/src/config_utils.py @@ -9,69 +9,69 @@ log = getLogger("config_utils") class ConfigLoadError(Exception): pass def load_config(config_path, configspec_path=None, copy=True, *args, **kwargs): - spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True) - try: - config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs) - except ParseError: - raise ConfigLoadError("Unable to load %r" % config_path) - validator = Validator() - validated = config.validate(validator, preserve_errors=False, copy=copy) - if validated == True: - config.write() - return config - else: - log.exception("Error in config file: {0}".format(validated,)) + spec = ConfigObj(configspec_path, encoding='UTF8', list_values=False, _inspec=True) + try: + config = ConfigObj(infile=config_path, configspec=spec, create_empty=True, encoding='UTF8', *args, **kwargs) + except ParseError: + raise ConfigLoadError("Unable to load %r" % config_path) + validator = Validator() + validated = config.validate(validator, preserve_errors=False, copy=copy) + if validated == True: + config.write() + return config + else: + log.exception("Error in config file: {0}".format(validated,)) def is_blank(arg): - "Check if a line is blank." - for c in arg: - if c not in string.whitespace: - return False - return True + "Check if a line is blank." + for c in arg: + if c not in string.whitespace: + return False + return True def get_keys(path): - "Gets the keys of a configobj config file." - res=[] - fin=open(path) - for line in fin: - if not is_blank(line): - res.append(line[0:line.find('=')].strip()) - fin.close() - return res + "Gets the keys of a configobj config file." + res=[] + fin=open(path) + for line in fin: + if not is_blank(line): + res.append(line[0:line.find('=')].strip()) + fin.close() + return res def hist(keys): - "Generates a histogram of an iterable." - res={} - for k in keys: - res[k]=res.setdefault(k,0)+1 - return res + "Generates a histogram of an iterable." + res={} + for k in keys: + res[k]=res.setdefault(k,0)+1 + return res def find_problems(hist): - "Takes a histogram and returns a list of items occurring more than once." - res=[] - for k,v in hist.items(): - if v>1: - res.append(k) - return res + "Takes a histogram and returns a list of items occurring more than once." + res=[] + for k,v in hist.items(): + if v>1: + res.append(k) + return res def clean_config(path): - "Cleans a config file. If duplicate values are found, delete all of them and just use the default." - orig=[] - cleaned=[] - fin=open(path) - for line in fin: - orig.append(line) - fin.close() - for p in find_problems(hist(get_keys(path))): - for o in orig: - o.strip() - if p not in o: - cleaned.append(o) - if len(cleaned) != 0: - cam=open(path,'w') - for c in cleaned: - cam.write(c) - cam.close() - return True - else: - return False \ No newline at end of file + "Cleans a config file. If duplicate values are found, delete all of them and just use the default." + orig=[] + cleaned=[] + fin=open(path) + for line in fin: + orig.append(line) + fin.close() + for p in find_problems(hist(get_keys(path))): + for o in orig: + o.strip() + if p not in o: + cleaned.append(o) + if len(cleaned) != 0: + cam=open(path,'w') + for c in cleaned: + cam.write(c) + cam.close() + return True + else: + return False diff --git a/src/controller/attach.py b/src/controller/attach.py index 666e55f3..08427142 100644 --- a/src/controller/attach.py +++ b/src/controller/attach.py @@ -8,33 +8,33 @@ from wxUI.dialogs import attach as gui log = logging.getLogger("controller.attach") class attach(object): - def __init__(self): - self.attachments = list() - self.dialog = gui.attachDialog() - widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image) - widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment) - self.dialog.get_response() - log.debug("Attachments controller started.") + def __init__(self): + self.attachments = list() + self.dialog = gui.attachDialog() + widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image) + widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment) + self.dialog.get_response() + log.debug("Attachments controller started.") - def upload_image(self, *args, **kwargs): - image, description = self.dialog.get_image() - if image != None: - imageInfo = {"type": "photo", "file": image, "description": description} - log.debug("Image data to upload: %r" % (imageInfo,)) - self.attachments.append(imageInfo) - info = [_(u"Photo"), description] - self.dialog.attachments.insert_item(False, *info) - self.dialog.remove.Enable(True) + def upload_image(self, *args, **kwargs): + image, description = self.dialog.get_image() + if image != None: + imageInfo = {"type": "photo", "file": image, "description": description} + log.debug("Image data to upload: %r" % (imageInfo,)) + self.attachments.append(imageInfo) + info = [_(u"Photo"), description] + self.dialog.attachments.insert_item(False, *info) + self.dialog.remove.Enable(True) - def remove_attachment(self, *args, **kwargs): - current_item = self.dialog.attachments.get_selected() - log.debug("Removing item %d" % (current_item,)) - if current_item == -1: current_item = 0 - self.attachments.pop(current_item) - self.dialog.attachments.remove_item(current_item) - self.check_remove_status() - log.debug("Removed") + def remove_attachment(self, *args, **kwargs): + current_item = self.dialog.attachments.get_selected() + log.debug("Removing item %d" % (current_item,)) + if current_item == -1: current_item = 0 + self.attachments.pop(current_item) + self.dialog.attachments.remove_item(current_item) + self.check_remove_status() + log.debug("Removed") - def check_remove_status(self): - if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0: - self.dialog.remove.Enable(False) + def check_remove_status(self): + if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0: + self.dialog.remove.Enable(False) diff --git a/src/controller/buffers/__init__.py b/src/controller/buffers/__init__.py index 2900a6e9..4e7aa78c 100644 --- a/src/controller/buffers/__init__.py +++ b/src/controller/buffers/__init__.py @@ -5,4 +5,4 @@ * baseBuffers: Define a set of functions and structure to be expected in all buffers. New buffers should inherit its classes from one of the classes present here. * twitterBuffers: All other code, specific to Twitter. """ -from __future__ import unicode_literals \ No newline at end of file +from __future__ import unicode_literals diff --git a/src/controller/buffers/baseBuffers.py b/src/controller/buffers/baseBuffers.py index 2bb09c80..7437aa48 100644 --- a/src/controller/buffers/baseBuffers.py +++ b/src/controller/buffers/baseBuffers.py @@ -14,196 +14,196 @@ from wxUI import buffers log = logging.getLogger("controller.buffers.baseBuffers") def _items_exist(function): - """ A decorator to execute a function only if the selected buffer contains at least one item.""" - def function_(self, *args, **kwargs): - if self.buffer.list.get_count() > 0: - function(self, *args, **kwargs) - return function_ + """ A decorator to execute a function only if the selected buffer contains at least one item.""" + def function_(self, *args, **kwargs): + if self.buffer.list.get_count() > 0: + function(self, *args, **kwargs) + return function_ class buffer(object): - """ A basic buffer object. This should be the base class for all other derived buffers.""" + """ A basic buffer object. This should be the base class for all other derived buffers.""" - def __init__(self, parent=None, function=None, session=None, *args, **kwargs): - """Inits the main controller for this buffer: - @ parent wx.Treebook object: Container where we will put this buffer. - @ function str or None: function to be called periodically and update items on this buffer. - @ session sessionmanager.session object or None: Session handler for settings, database and data access. - """ - super(buffer, self).__init__() - self.function = function - # Compose_function will be used to render an object on this buffer. Normally, signature is as follows: - # compose_function(item, db, relative_times, show_screen_names=False, session=None) - # Read more about compose functions in twitter/compose.py. - self.compose_function = None - self.args = args - self.kwargs = kwargs - # This will be used as a reference to the wx.Panel object wich stores the buffer GUI. - self.buffer = None - # This should countains the account associated to this buffer. - self.account = "" - # This controls whether the start_stream function should be called when starting the program. - self.needs_init = True - # if this is set to False, the buffer will be ignored on the invisible interface. - self.invisible = False - # Control variable, used to track time of execution for calls to start_stream. - self.execution_time = 0 + def __init__(self, parent=None, function=None, session=None, *args, **kwargs): + """Inits the main controller for this buffer: + @ parent wx.Treebook object: Container where we will put this buffer. + @ function str or None: function to be called periodically and update items on this buffer. + @ session sessionmanager.session object or None: Session handler for settings, database and data access. + """ + super(buffer, self).__init__() + self.function = function + # Compose_function will be used to render an object on this buffer. Normally, signature is as follows: + # compose_function(item, db, relative_times, show_screen_names=False, session=None) + # Read more about compose functions in twitter/compose.py. + self.compose_function = None + self.args = args + self.kwargs = kwargs + # This will be used as a reference to the wx.Panel object wich stores the buffer GUI. + self.buffer = None + # This should countains the account associated to this buffer. + self.account = "" + # This controls whether the start_stream function should be called when starting the program. + self.needs_init = True + # if this is set to False, the buffer will be ignored on the invisible interface. + self.invisible = False + # Control variable, used to track time of execution for calls to start_stream. + self.execution_time = 0 - def clear_list(self): - pass + def clear_list(self): + pass - def get_event(self, ev): - """ Catch key presses in the WX interface and generate the corresponding event names.""" - if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio" - elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url" - elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down" - elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" - elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" - elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status" - # Raise a Special event when pressed Shift+F10 because Wx==4.1.x does not seems to trigger this by itself. - # See https://github.com/manuelcortez/TWBlue/issues/353 - elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu" - else: - event = None - ev.Skip() - if event != None: - try: - ### ToDo: Remove after WX fixes issue #353 in the widgets. - if event == "show_menu": - return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) - getattr(self, event)() - except AttributeError: - pass + def get_event(self, ev): + """ Catch key presses in the WX interface and generate the corresponding event names.""" + if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio" + elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url" + elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down" + elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up" + elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list" + elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status" + # Raise a Special event when pressed Shift+F10 because Wx==4.1.x does not seems to trigger this by itself. + # See https://github.com/manuelcortez/TWBlue/issues/353 + elif ev.GetKeyCode() == wx.WXK_F10 and ev.ShiftDown(): event = "show_menu" + else: + event = None + ev.Skip() + if event != None: + try: + ### ToDo: Remove after WX fixes issue #353 in the widgets. + if event == "show_menu": + return self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) + getattr(self, event)() + except AttributeError: + pass - def volume_down(self): - """ Decreases volume by 5%""" - if self.session.settings["sound"]["volume"] > 0.0: - if self.session.settings["sound"]["volume"] <= 0.05: - self.session.settings["sound"]["volume"] = 0.0 - else: - self.session.settings["sound"]["volume"] -=0.05 - sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0)) - self.session.sound.play("volume_changed.ogg") - self.session.settings.write() + def volume_down(self): + """ Decreases volume by 5%""" + if self.session.settings["sound"]["volume"] > 0.0: + if self.session.settings["sound"]["volume"] <= 0.05: + self.session.settings["sound"]["volume"] = 0.0 + else: + self.session.settings["sound"]["volume"] -=0.05 + sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0)) + self.session.sound.play("volume_changed.ogg") + self.session.settings.write() - def volume_up(self): - """ Increases volume by 5%.""" - if self.session.settings["sound"]["volume"] < 1.0: - if self.session.settings["sound"]["volume"] >= 0.95: - self.session.settings["sound"]["volume"] = 1.0 - else: - self.session.settings["sound"]["volume"] +=0.05 - sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100)) - self.session.sound.play("volume_changed.ogg") - self.session.settings.write() + def volume_up(self): + """ Increases volume by 5%.""" + if self.session.settings["sound"]["volume"] < 1.0: + if self.session.settings["sound"]["volume"] >= 0.95: + self.session.settings["sound"]["volume"] = 1.0 + else: + self.session.settings["sound"]["volume"] +=0.05 + sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100)) + self.session.sound.play("volume_changed.ogg") + self.session.settings.write() - def start_stream(self, mandatory=False, play_sound=True): - pass + def start_stream(self, mandatory=False, play_sound=True): + pass - def get_more_items(self): - output.speak(_(u"This action is not supported for this buffer"), True) + def get_more_items(self): + output.speak(_(u"This action is not supported for this buffer"), True) - def put_items_on_list(self, items): - pass + def put_items_on_list(self, items): + pass - def remove_buffer(self): - return False + def remove_buffer(self): + return False - def remove_item(self, item): - f = self.buffer.list.get_selected() - self.buffer.list.remove_item(item) - self.buffer.list.select_item(f) + def remove_item(self, item): + f = self.buffer.list.get_selected() + self.buffer.list.remove_item(item) + self.buffer.list.select_item(f) - def bind_events(self): - pass + def bind_events(self): + pass - def get_object(self): - return self.buffer + def get_object(self): + return self.buffer - def get_message(self): - pass + def get_message(self): + pass - def set_list_position(self, reversed=False): - if reversed == False: - self.buffer.list.select_item(-1) - else: - self.buffer.list.select_item(0) + def set_list_position(self, reversed=False): + if reversed == False: + self.buffer.list.select_item(-1) + else: + self.buffer.list.select_item(0) - def reply(self): - pass + def reply(self): + pass - def send_message(self): - pass + def send_message(self): + pass - def share_item(self): - pass + def share_item(self): + pass - def destroy_status(self): - pass + def destroy_status(self): + pass - def post_status(self, *args, **kwargs): - pass + def post_status(self, *args, **kwargs): + pass - def save_positions(self): - try: - self.session.db[self.name+"_pos"]=self.buffer.list.get_selected() - except AttributeError: - pass + def save_positions(self): + try: + self.session.db[self.name+"_pos"]=self.buffer.list.get_selected() + except AttributeError: + pass class accountPanel(buffer): - def __init__(self, parent, name, account, account_id): - super(accountPanel, self).__init__(parent, None, name) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - self.buffer = buffers.accountPanel(parent, name) - self.type = self.buffer.type - self.compose_function = None - self.session = None - self.needs_init = False - self.account = account - self.buffer.account = account - self.name = name - self.account_id = account_id + def __init__(self, parent, name, account, account_id): + super(accountPanel, self).__init__(parent, None, name) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + self.buffer = buffers.accountPanel(parent, name) + self.type = self.buffer.type + self.compose_function = None + self.session = None + self.needs_init = False + self.account = account + self.buffer.account = account + self.name = name + self.account_id = account_id - def setup_account(self): - widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account) - if self.account_id in config.app["sessions"]["ignored_sessions"]: - self.buffer.change_autostart(False) - else: - self.buffer.change_autostart(True) - if not hasattr(self, "logged"): - self.buffer.change_login(login=False) - widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout) - else: - self.buffer.change_login(login=True) - widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login) + def setup_account(self): + widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account) + if self.account_id in config.app["sessions"]["ignored_sessions"]: + self.buffer.change_autostart(False) + else: + self.buffer.change_autostart(True) + if not hasattr(self, "logged"): + self.buffer.change_login(login=False) + widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout) + else: + self.buffer.change_login(login=True) + widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login) - def login(self, *args, **kwargs): - del self.logged - self.setup_account() - pub.sendMessage("login", session_id=self.account_id) + def login(self, *args, **kwargs): + del self.logged + self.setup_account() + pub.sendMessage("login", session_id=self.account_id) - def logout(self, *args, **kwargs): - self.logged = False - self.setup_account() - pub.sendMessage("logout", session_id=self.account_id) + def logout(self, *args, **kwargs): + self.logged = False + self.setup_account() + pub.sendMessage("logout", session_id=self.account_id) - def autostart(self, *args, **kwargs): - if self.account_id in config.app["sessions"]["ignored_sessions"]: - self.buffer.change_autostart(True) - config.app["sessions"]["ignored_sessions"].remove(self.account_id) - else: - self.buffer.change_autostart(False) - config.app["sessions"]["ignored_sessions"].append(self.account_id) - config.app.write() + def autostart(self, *args, **kwargs): + if self.account_id in config.app["sessions"]["ignored_sessions"]: + self.buffer.change_autostart(True) + config.app["sessions"]["ignored_sessions"].remove(self.account_id) + else: + self.buffer.change_autostart(False) + config.app["sessions"]["ignored_sessions"].append(self.account_id) + config.app.write() class emptyPanel(buffer): - def __init__(self, parent, name, account): - super(emptyPanel, self).__init__(parent=parent) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - self.buffer = buffers.emptyPanel(parent, name) - self.type = self.buffer.type - self.compose_function = None - self.account = account - self.buffer.account = account - self.name = name - self.session = None - self.needs_init = True + def __init__(self, parent, name, account): + super(emptyPanel, self).__init__(parent=parent) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + self.buffer = buffers.emptyPanel(parent, name) + self.type = self.buffer.type + self.compose_function = None + self.account = account + self.buffer.account = account + self.name = name + self.session = None + self.needs_init = True diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 05870eef..0fdacac4 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -2,12 +2,12 @@ import time import platform if platform.system() == "Windows": - import wx - from wxUI import buffers, dialogs, commonMessageDialogs, menus - from controller import user + import wx + from wxUI import buffers, dialogs, commonMessageDialogs, menus + from controller import user elif platform.system() == "Linux": - from gi.repository import Gtk - from gtkUI import buffers, dialogs, commonMessageDialogs + from gi.repository import Gtk + from gtkUI import buffers, dialogs, commonMessageDialogs from controller import messages import widgetUtils import arrow @@ -29,1217 +29,1217 @@ from sessions.twitter.long_tweets import twishort, tweets log = logging.getLogger("controller.buffers") def _tweets_exist(function): - """ A decorator to execute a function only if the selected buffer contains at least one item.""" - def function_(self, *args, **kwargs): - if self.buffer.list.get_count() > 0: - function(self, *args, **kwargs) - return function_ + """ A decorator to execute a function only if the selected buffer contains at least one item.""" + def function_(self, *args, **kwargs): + if self.buffer.list.get_count() > 0: + function(self, *args, **kwargs) + return function_ class baseBufferController(baseBuffers.buffer): - def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, compose_func="compose_tweet", *args, **kwargs): - super(baseBufferController, self).__init__(parent, function, *args, **kwargs) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - if bufferType != None: - self.buffer = getattr(buffers, bufferType)(parent, name) - else: - self.buffer = buffers.basePanel(parent, name) - self.invisible = True - self.name = name - self.type = self.buffer.type - self.session = sessionObject - self.compose_function = getattr(compose, compose_func) - log.debug("Compose_function: %s" % (self.compose_function,)) - self.account = account - self.buffer.account = account - self.bind_events() - self.sound = sound - if "-timeline" in self.name or "-favorite" in self.name: - self.finished_timeline = False - # Add a compatibility layer for username based timelines from config. - # ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory. - try: - int(self.kwargs["user_id"]) - except ValueError: - self.is_screen_name = True - self.kwargs["screen_name"] = self.kwargs["user_id"] - self.kwargs.pop("user_id") + def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, compose_func="compose_tweet", *args, **kwargs): + super(baseBufferController, self).__init__(parent, function, *args, **kwargs) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + if bufferType != None: + self.buffer = getattr(buffers, bufferType)(parent, name) + else: + self.buffer = buffers.basePanel(parent, name) + self.invisible = True + self.name = name + self.type = self.buffer.type + self.session = sessionObject + self.compose_function = getattr(compose, compose_func) + log.debug("Compose_function: %s" % (self.compose_function,)) + self.account = account + self.buffer.account = account + self.bind_events() + self.sound = sound + if "-timeline" in self.name or "-favorite" in self.name: + self.finished_timeline = False + # Add a compatibility layer for username based timelines from config. + # ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory. + try: + int(self.kwargs["user_id"]) + except ValueError: + self.is_screen_name = True + self.kwargs["screen_name"] = self.kwargs["user_id"] + self.kwargs.pop("user_id") - def get_buffer_name(self): - """ Get buffer name from a set of different techniques.""" - # firstly let's take the easier buffers. - basic_buffers = dict(home_timeline=_(u"Home"), mentions=_(u"Mentions"), direct_messages=_(u"Direct messages"), sent_direct_messages=_(u"Sent direct messages"), sent_tweets=_(u"Sent tweets"), favourites=_(u"Likes"), followers=_(u"Followers"), friends=_(u"Friends"), blocked=_(u"Blocked users"), muted=_(u"Muted users")) - if self.name in list(basic_buffers.keys()): - return basic_buffers[self.name] - # Check user timelines - elif hasattr(self, "username"): - if "-timeline" in self.name: - return _(u"{username}'s timeline").format(username=self.username,) - elif "-favorite" in self.name: - return _(u"{username}'s likes").format(username=self.username,) - elif "-followers" in self.name: - return _(u"{username}'s followers").format(username=self.username,) - elif "-friends" in self.name: - return _(u"{username}'s friends").format(username=self.username,) - log.error("Error getting name for buffer %s" % (self.name,)) - return _(u"Unknown buffer") + def get_buffer_name(self): + """ Get buffer name from a set of different techniques.""" + # firstly let's take the easier buffers. + basic_buffers = dict(home_timeline=_(u"Home"), mentions=_(u"Mentions"), direct_messages=_(u"Direct messages"), sent_direct_messages=_(u"Sent direct messages"), sent_tweets=_(u"Sent tweets"), favourites=_(u"Likes"), followers=_(u"Followers"), friends=_(u"Friends"), blocked=_(u"Blocked users"), muted=_(u"Muted users")) + if self.name in list(basic_buffers.keys()): + return basic_buffers[self.name] + # Check user timelines + elif hasattr(self, "username"): + if "-timeline" in self.name: + return _(u"{username}'s timeline").format(username=self.username,) + elif "-favorite" in self.name: + return _(u"{username}'s likes").format(username=self.username,) + elif "-followers" in self.name: + return _(u"{username}'s followers").format(username=self.username,) + elif "-friends" in self.name: + return _(u"{username}'s friends").format(username=self.username,) + log.error("Error getting name for buffer %s" % (self.name,)) + return _(u"Unknown buffer") - def post_status(self, *args, **kwargs): - item = None - title = _(u"Tweet") - caption = _(u"Write the tweet here") - tweet = messages.tweet(self.session, title, caption, "") - if tweet.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = tweet.message.long_tweet.GetValue() - config.app.write() - text = tweet.message.get_text() - if len(text) > 280 and tweet.message.get("long_tweet") == True: - if not hasattr(tweet, "attachments"): - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - if not hasattr(tweet, "attachments") or len(tweet.attachments) == 0: - item = self.session.api_call(call_name="update_status", status=text, _sound="tweet_send.ogg", tweet_mode="extended") - else: - call_threaded(self.post_with_media, text=text, attachments=tweet.attachments) - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - if hasattr(tweet.message, "destroy"): tweet.message.destroy() - self.session.settings.write() + def post_status(self, *args, **kwargs): + item = None + title = _(u"Tweet") + caption = _(u"Write the tweet here") + tweet = messages.tweet(self.session, title, caption, "") + if tweet.message.get_response() == widgetUtils.OK: + if config.app["app-settings"]["remember_mention_and_longtweet"]: + config.app["app-settings"]["longtweet"] = tweet.message.long_tweet.GetValue() + config.app.write() + text = tweet.message.get_text() + if len(text) > 280 and tweet.message.get("long_tweet") == True: + if not hasattr(tweet, "attachments"): + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) + else: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) + if not hasattr(tweet, "attachments") or len(tweet.attachments) == 0: + item = self.session.api_call(call_name="update_status", status=text, _sound="tweet_send.ogg", tweet_mode="extended") + else: + call_threaded(self.post_with_media, text=text, attachments=tweet.attachments) + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + if hasattr(tweet.message, "destroy"): tweet.message.destroy() + self.session.settings.write() - def post_with_media(self, text, attachments): - media_ids = [] - for i in attachments: - img = self.session.twitter.media_upload(i["file"]) - self.session.twitter.create_media_metadata(media_id=img.media_id, alt_text=i["description"]) - media_ids.append(img.media_id) - item = self.session.twitter.update_status(status=text, media_ids=media_ids) - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + def post_with_media(self, text, attachments): + media_ids = [] + for i in attachments: + img = self.session.twitter.media_upload(i["file"]) + self.session.twitter.create_media_metadata(media_id=img.media_id, alt_text=i["description"]) + media_ids.append(img.media_id) + item = self.session.twitter.update_status(status=text, media_ids=media_ids) + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - def get_formatted_message(self): - if self.type == "dm" or self.name == "direct_messages": - return self.compose_function(self.get_right_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)[1] - return self.get_message() + def get_formatted_message(self): + if self.type == "dm" or self.name == "direct_messages": + return self.compose_function(self.get_right_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)[1] + return self.get_message() - def get_message(self): - tweet = self.get_right_tweet() - return " ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)) + def get_message(self): + tweet = self.get_right_tweet() + return " ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)) - def get_full_tweet(self): - tweet = self.get_right_tweet() - tweetsList = [] - tweet_id = tweet.id - message = None - if hasattr(tweet, "message"): - message = tweet.message - try: - tweet = self.session.twitter.get_status(id=tweet_id, include_ext_alt_text=True, tweet_mode="extended") - tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities) - except TweepError as e: - utils.twitter_error(e) - return - if message != None: - tweet.message = message - l = tweets.is_long(tweet) - while l != False: - tweetsList.append(tweet) - try: - tweet = self.session.twitter.get_status(id=l, include_ext_alt_text=True, tweet_mode="extended") - tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities) - except TweepError as e: - utils.twitter_error(e) - return - l = tweets.is_long(tweet) - if l == False: - tweetsList.append(tweet) - return (tweet, tweetsList) + def get_full_tweet(self): + tweet = self.get_right_tweet() + tweetsList = [] + tweet_id = tweet.id + message = None + if hasattr(tweet, "message"): + message = tweet.message + try: + tweet = self.session.twitter.get_status(id=tweet_id, include_ext_alt_text=True, tweet_mode="extended") + tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities) + except TweepError as e: + utils.twitter_error(e) + return + if message != None: + tweet.message = message + l = tweets.is_long(tweet) + while l != False: + tweetsList.append(tweet) + try: + tweet = self.session.twitter.get_status(id=l, include_ext_alt_text=True, tweet_mode="extended") + tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities) + except TweepError as e: + utils.twitter_error(e) + return + l = tweets.is_long(tweet) + if l == False: + tweetsList.append(tweet) + return (tweet, tweetsList) - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: - self.execution_time = current_time - log.debug("Starting stream for buffer %s, account %s and type %s" % (self.name, self.account, self.type)) - log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) - if self.name != "direct_messages": - val = self.session.call_paged(self.function, *self.args, **self.kwargs) - else: - # 50 results are allowed per API call, so let's assume max value can be 50. - # reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events - if self.session.settings["general"]["max_tweets_per_call"] > 50: - count = 50 - else: - count = self.session.settings["general"]["max_tweets_per_call"] - # try to retrieve the cursor for the current buffer. - try: - val = getattr(self.session.twitter, self.function)(return_cursors=True, count=count, *self.args, **self.kwargs) - if type(val) == tuple: - val, cursor = val - if type(cursor) == tuple: - cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor - results = [i for i in val] - val = results - val.reverse() - log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function)) - user_ids = [item.message_create["sender_id"] for item in val] - self.session.save_users(user_ids) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - number_of_items = self.session.order_buffer(self.name, val) - log.debug("Number of items retrieved: %d" % (number_of_items,)) + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: + self.execution_time = current_time + log.debug("Starting stream for buffer %s, account %s and type %s" % (self.name, self.account, self.type)) + log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) + if self.name != "direct_messages": + val = self.session.call_paged(self.function, *self.args, **self.kwargs) + else: + # 50 results are allowed per API call, so let's assume max value can be 50. + # reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events + if self.session.settings["general"]["max_tweets_per_call"] > 50: + count = 50 + else: + count = self.session.settings["general"]["max_tweets_per_call"] + # try to retrieve the cursor for the current buffer. + try: + val = getattr(self.session.twitter, self.function)(return_cursors=True, count=count, *self.args, **self.kwargs) + if type(val) == tuple: + val, cursor = val + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor + results = [i for i in val] + val = results + val.reverse() + log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function)) + user_ids = [item.message_create["sender_id"] for item in val] + self.session.save_users(user_ids) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + number_of_items = self.session.order_buffer(self.name, val) + log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) - if hasattr(self, "finished_timeline") and self.finished_timeline == False: - if "-timeline" in self.name: - self.username = val[0].user.screen_name - elif "-favorite" in self.name: - self.username = self.session.api_call("get_user", **self.kwargs).screen_name - self.finished_timeline = True - if number_of_items > 0 and self.name != "sent_tweets" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(number_of_items) - return number_of_items + self.put_items_on_list(number_of_items) + if hasattr(self, "finished_timeline") and self.finished_timeline == False: + if "-timeline" in self.name: + self.username = val[0].user.screen_name + elif "-favorite" in self.name: + self.username = self.session.api_call("get_user", **self.kwargs).screen_name + self.finished_timeline = True + if number_of_items > 0 and self.name != "sent_tweets" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) + # Autoread settings + if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: + self.auto_read(number_of_items) + return number_of_items - def auto_read(self, number_of_items): - if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - if self.session.settings["general"]["reverse_timelines"] == False: - tweet = self.session.db[self.name][-1] - else: - tweet = self.session.db[self.name][0] - output.speak(_(u"New tweet in {0}").format(self.get_buffer_name())) - output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) - elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(_(u"{0} new tweets in {1}.").format(number_of_items, self.get_buffer_name())) + def auto_read(self, number_of_items): + if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + if self.session.settings["general"]["reverse_timelines"] == False: + tweet = self.session.db[self.name][-1] + else: + tweet = self.session.db[self.name][0] + output.speak(_(u"New tweet in {0}").format(self.get_buffer_name())) + output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) + elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(_(u"{0} new tweets in {1}.").format(number_of_items, self.get_buffer_name())) - def get_more_items(self): - elements = [] - if self.session.settings["general"]["reverse_timelines"] == False: - last_id = self.session.db[self.name][0].id - else: - last_id = self.session.db[self.name][-1].id - try: - items = getattr(self.session.twitter, self.function)(max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - if items == None: - return - for i in items: - if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i.id, self.session.db[self.name]) == None: - i = self.session.check_quoted_status(i) - i = self.session.check_long_tweet(i) - elements.append(i) - if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) - else: - self.session.db[self.name].append(i) - selection = self.buffer.list.get_selected() - log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function)) - if self.session.settings["general"]["reverse_timelines"] == False: - for i in elements: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(True, *tweet) - else: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) - self.buffer.list.select_item(selection) - output.speak(_(u"%s items retrieved") % (str(len(elements))), True) + def get_more_items(self): + elements = [] + if self.session.settings["general"]["reverse_timelines"] == False: + last_id = self.session.db[self.name][0].id + else: + last_id = self.session.db[self.name][-1].id + try: + items = getattr(self.session.twitter, self.function)(max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + if items == None: + return + for i in items: + if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i.id, self.session.db[self.name]) == None: + i = self.session.check_quoted_status(i) + i = self.session.check_long_tweet(i) + elements.append(i) + if self.session.settings["general"]["reverse_timelines"] == False: + self.session.db[self.name].insert(0, i) + else: + self.session.db[self.name].append(i) + selection = self.buffer.list.get_selected() + log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function)) + if self.session.settings["general"]["reverse_timelines"] == False: + for i in elements: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(True, *tweet) + else: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) + self.buffer.list.select_item(selection) + output.speak(_(u"%s items retrieved") % (str(len(elements))), True) - def remove_buffer(self, force=False): - if "-timeline" in self.name: - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-9] in self.session.settings["other_buffers"]["timelines"]: - self.session.settings["other_buffers"]["timelines"].remove(self.name[:-9]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False - elif "favorite" in self.name: - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-9] in self.session.settings["other_buffers"]["favourites_timelines"]: - self.session.settings["other_buffers"]["favourites_timelines"].remove(self.name[:-9]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False - else: - output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True) - return False + def remove_buffer(self, force=False): + if "-timeline" in self.name: + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-9] in self.session.settings["other_buffers"]["timelines"]: + self.session.settings["other_buffers"]["timelines"].remove(self.name[:-9]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False + elif "favorite" in self.name: + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-9] in self.session.settings["other_buffers"]["favourites_timelines"]: + self.session.settings["other_buffers"]["favourites_timelines"].remove(self.name[:-9]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False + else: + output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True) + return False - def remove_tweet(self, id): - if type(self.session.db[self.name]) == dict: return - for i in range(0, len(self.session.db[self.name])): - if self.session.db[self.name][i].id == id: - self.session.db[self.name].pop(i) - self.remove_item(i) + def remove_tweet(self, id): + if type(self.session.db[self.name]) == dict: return + for i in range(0, len(self.session.db[self.name])): + if self.session.db[self.name][i].id == id: + self.session.db[self.name].pop(i) + self.remove_item(i) - def put_items_on_list(self, number_of_items): - list_to_use = self.session.db[self.name] - if number_of_items == 0 and self.session.settings["general"]["persist_size"] == 0: return - log.debug("The list contains %d items " % (self.buffer.list.get_count(),)) - log.debug("Putting %d items on the list" % (number_of_items,)) - if self.buffer.list.get_count() == 0: - for i in list_to_use: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) - self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) - elif self.buffer.list.get_count() > 0 and number_of_items > 0: - if self.session.settings["general"]["reverse_timelines"] == False: - items = list_to_use[len(list_to_use)-number_of_items:] - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) - else: - items = list_to_use[0:number_of_items] - items.reverse() - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(True, *tweet) - log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),)) + def put_items_on_list(self, number_of_items): + list_to_use = self.session.db[self.name] + if number_of_items == 0 and self.session.settings["general"]["persist_size"] == 0: return + log.debug("The list contains %d items " % (self.buffer.list.get_count(),)) + log.debug("Putting %d items on the list" % (number_of_items,)) + if self.buffer.list.get_count() == 0: + for i in list_to_use: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) + self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) + elif self.buffer.list.get_count() > 0 and number_of_items > 0: + if self.session.settings["general"]["reverse_timelines"] == False: + items = list_to_use[len(list_to_use)-number_of_items:] + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) + else: + items = list_to_use[0:number_of_items] + items.reverse() + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(True, *tweet) + log.debug("Now the list contains %d items " % (self.buffer.list.get_count(),)) - def add_new_item(self, item): - tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - if self.session.settings["general"]["reverse_timelines"] == False: - self.buffer.list.insert_item(False, *tweet) - else: - self.buffer.list.insert_item(True, *tweet) - if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(" ".join(tweet[:2]), speech=self.session.settings["reporting"]["speech_reporting"], braille=self.session.settings["reporting"]["braille_reporting"]) - #Improve performance on Windows + def add_new_item(self, item): + tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + if self.session.settings["general"]["reverse_timelines"] == False: + self.buffer.list.insert_item(False, *tweet) + else: + self.buffer.list.insert_item(True, *tweet) + if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(" ".join(tweet[:2]), speech=self.session.settings["reporting"]["speech_reporting"], braille=self.session.settings["reporting"]["braille_reporting"]) + #Improve performance on Windows # if platform.system() == "Windows": # call_threaded(utils.is_audio,item) - def bind_events(self): - log.debug("Binding events...") - self.buffer.set_focus_function(self.onFocus) - widgetUtils.connect_event(self.buffer.list.list, widgetUtils.KEYPRESS, self.get_event) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet) + def bind_events(self): + log.debug("Binding events...") + self.buffer.set_focus_function(self.onFocus) + widgetUtils.connect_event(self.buffer.list.list, widgetUtils.KEYPRESS, self.get_event) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet) # if self.type == "baseBuffer": - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.share_item, self.buffer.retweet) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.send_message, self.buffer.dm) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.reply, self.buffer.reply) - # Replace for the correct way in other platforms. - widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu) - widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.share_item, self.buffer.retweet) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.send_message, self.buffer.dm) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.reply, self.buffer.reply) + # Replace for the correct way in other platforms. + widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu) + widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key) - def show_menu(self, ev, pos=0, *args, **kwargs): - if self.buffer.list.get_count() == 0: return - if self.name == "sent_tweets" or self.name == "direct_messages": - menu = menus.sentPanelMenu() - elif self.name == "direct_messages": - menu = menus.dmPanelMenu() - widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) - else: - menu = menus.basePanelMenu() - widgetUtils.connect_event(menu, widgetUtils.MENU, self.reply, menuitem=menu.reply) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.share_item, menuitem=menu.retweet) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.fav, menuitem=menu.fav) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.unfav, menuitem=menu.unfav) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.url_, menuitem=menu.openUrl) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.audio, menuitem=menu.play) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove) - if hasattr(menu, "openInBrowser"): - widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser) - if pos != 0: - self.buffer.PopupMenu(menu, pos) - else: - self.buffer.PopupMenu(menu, ev.GetPosition()) + def show_menu(self, ev, pos=0, *args, **kwargs): + if self.buffer.list.get_count() == 0: return + if self.name == "sent_tweets" or self.name == "direct_messages": + menu = menus.sentPanelMenu() + elif self.name == "direct_messages": + menu = menus.dmPanelMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) + else: + menu = menus.basePanelMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.reply, menuitem=menu.reply) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.share_item, menuitem=menu.retweet) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.fav, menuitem=menu.fav) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.unfav, menuitem=menu.unfav) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.url_, menuitem=menu.openUrl) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.audio, menuitem=menu.play) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove) + if hasattr(menu, "openInBrowser"): + widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser) + if pos != 0: + self.buffer.PopupMenu(menu, pos) + else: + self.buffer.PopupMenu(menu, ev.GetPosition()) - def view(self, *args, **kwargs): - pub.sendMessage("execute-action", action="view_item") + def view(self, *args, **kwargs): + pub.sendMessage("execute-action", action="view_item") - def copy(self, *args, **kwargs): - pub.sendMessage("execute-action", action="copy_to_clipboard") + def copy(self, *args, **kwargs): + pub.sendMessage("execute-action", action="copy_to_clipboard") - def user_actions(self, *args, **kwargs): - pub.sendMessage("execute-action", action="follow") + def user_actions(self, *args, **kwargs): + pub.sendMessage("execute-action", action="follow") - def fav(self, *args, **kwargs): - pub.sendMessage("execute-action", action="add_to_favourites") + def fav(self, *args, **kwargs): + pub.sendMessage("execute-action", action="add_to_favourites") - def unfav(self, *args, **kwargs): - pub.sendMessage("execute-action", action="remove_from_favourites") + def unfav(self, *args, **kwargs): + pub.sendMessage("execute-action", action="remove_from_favourites") - def delete_item_(self, *args, **kwargs): - pub.sendMessage("execute-action", action="delete_item") + def delete_item_(self, *args, **kwargs): + pub.sendMessage("execute-action", action="delete_item") - def url_(self, *args, **kwargs): - self.url() + def url_(self, *args, **kwargs): + self.url() - def show_menu_by_key(self, ev): - if self.buffer.list.get_count() == 0: - return - if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: - self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) + def show_menu_by_key(self, ev): + if self.buffer.list.get_count() == 0: + return + if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: + self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) - def get_tweet(self): - if hasattr(self.session.db[self.name][self.buffer.list.get_selected()], "retweeted_status"): - tweet = self.session.db[self.name][self.buffer.list.get_selected()].retweeted_status - else: - tweet = self.session.db[self.name][self.buffer.list.get_selected()] - return tweet + def get_tweet(self): + if hasattr(self.session.db[self.name][self.buffer.list.get_selected()], "retweeted_status"): + tweet = self.session.db[self.name][self.buffer.list.get_selected()].retweeted_status + else: + tweet = self.session.db[self.name][self.buffer.list.get_selected()] + return tweet - def get_right_tweet(self): - tweet = self.session.db[self.name][self.buffer.list.get_selected()] - return tweet + def get_right_tweet(self): + tweet = self.session.db[self.name][self.buffer.list.get_selected()] + return tweet - @_tweets_exist - def reply(self, *args, **kwargs): - tweet = self.get_right_tweet() - screen_name = tweet.user.screen_name - id = tweet.id - twishort_enabled = hasattr(tweet, "twishort") - users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name") - ids = utils.get_all_mentioned(tweet, self.session.db, field="id_str") - # Build the window title - if len(users) < 1: - title=_("Reply to {arg0}").format(arg0=screen_name) - else: - title=_("Reply") - message = messages.reply(self.session, title, _(u"Reply to %s") % (screen_name,), "", users=users, ids=ids) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - if len(users) > 0: - config.app["app-settings"]["mention_all"] = message.message.mentionAll.GetValue() - config.app.write() - params = {"_sound": "reply_send.ogg", "in_reply_to_status_id": id, "tweet_mode": "extended"} - text = message.message.get_text() - if twishort_enabled == False: - excluded_ids = message.get_ids() - params["exclude_reply_user_ids"] =excluded_ids - params["auto_populate_reply_metadata"] =True - else: - mentioned_people = message.get_people() - text = "@"+screen_name+" "+mentioned_people+u" "+text - if len(text) > 280 and message.message.get("long_tweet") == True: - if message.image == None: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - params["status"] = text - if message.image == None: - params["call_name"] = "update_status" - else: - params["call_name"] = "update_status_with_media" - params["media"] = message.file - item = self.session.api_call(**params) - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - if hasattr(message.message, "destroy"): message.message.destroy() - self.session.settings.write() + @_tweets_exist + def reply(self, *args, **kwargs): + tweet = self.get_right_tweet() + screen_name = tweet.user.screen_name + id = tweet.id + twishort_enabled = hasattr(tweet, "twishort") + users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name") + ids = utils.get_all_mentioned(tweet, self.session.db, field="id_str") + # Build the window title + if len(users) < 1: + title=_("Reply to {arg0}").format(arg0=screen_name) + else: + title=_("Reply") + message = messages.reply(self.session, title, _(u"Reply to %s") % (screen_name,), "", users=users, ids=ids) + if message.message.get_response() == widgetUtils.OK: + if config.app["app-settings"]["remember_mention_and_longtweet"]: + config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() + if len(users) > 0: + config.app["app-settings"]["mention_all"] = message.message.mentionAll.GetValue() + config.app.write() + params = {"_sound": "reply_send.ogg", "in_reply_to_status_id": id, "tweet_mode": "extended"} + text = message.message.get_text() + if twishort_enabled == False: + excluded_ids = message.get_ids() + params["exclude_reply_user_ids"] =excluded_ids + params["auto_populate_reply_metadata"] =True + else: + mentioned_people = message.get_people() + text = "@"+screen_name+" "+mentioned_people+u" "+text + if len(text) > 280 and message.message.get("long_tweet") == True: + if message.image == None: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) + else: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) + params["status"] = text + if message.image == None: + params["call_name"] = "update_status" + else: + params["call_name"] = "update_status_with_media" + params["media"] = message.file + item = self.session.api_call(**params) + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + if hasattr(message.message, "destroy"): message.message.destroy() + self.session.settings.write() - @_tweets_exist - def send_message(self, *args, **kwargs): - tweet = self.get_right_tweet() - if self.type == "dm": - screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name - users = [screen_name] - elif self.type == "people": - screen_name = tweet.screen_name - users = [screen_name] - else: - screen_name = tweet.user.screen_name - users = utils.get_all_users(tweet, self.session.db) - dm = messages.dm(self.session, _(u"Direct message to %s") % (screen_name,), _(u"New direct message"), users) - if dm.message.get_response() == widgetUtils.OK: - screen_name = dm.message.get("cb") - user = self.session.get_user_by_screen_name(screen_name) - recipient_id = user - text = dm.message.get_text() - val = self.session.api_call(call_name="send_direct_message", recipient_id=recipient_id, text=text) - if val != None: - if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db["sent_direct_messages"].append(val) - else: - self.session.db["sent_direct_messages"].insert(0, val) - pub.sendMessage("sent-dm", data=val, user=self.session.db["user_name"]) - if hasattr(dm.message, "destroy"): dm.message.destroy() + @_tweets_exist + def send_message(self, *args, **kwargs): + tweet = self.get_right_tweet() + if self.type == "dm": + screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name + users = [screen_name] + elif self.type == "people": + screen_name = tweet.screen_name + users = [screen_name] + else: + screen_name = tweet.user.screen_name + users = utils.get_all_users(tweet, self.session.db) + dm = messages.dm(self.session, _(u"Direct message to %s") % (screen_name,), _(u"New direct message"), users) + if dm.message.get_response() == widgetUtils.OK: + screen_name = dm.message.get("cb") + user = self.session.get_user_by_screen_name(screen_name) + recipient_id = user + text = dm.message.get_text() + val = self.session.api_call(call_name="send_direct_message", recipient_id=recipient_id, text=text) + if val != None: + if self.session.settings["general"]["reverse_timelines"] == False: + self.session.db["sent_direct_messages"].append(val) + else: + self.session.db["sent_direct_messages"].insert(0, val) + pub.sendMessage("sent-dm", data=val, user=self.session.db["user_name"]) + if hasattr(dm.message, "destroy"): dm.message.destroy() - @_tweets_exist - def share_item(self, *args, **kwargs): - tweet = self.get_right_tweet() - id = tweet.id - if self.session.settings["general"]["retweet_mode"] == "ask": - answer = commonMessageDialogs.retweet_question(self.buffer) - if answer == widgetUtils.YES: - self._retweet_with_comment(tweet, id) - elif answer == widgetUtils.NO: - self._direct_retweet(id) - elif self.session.settings["general"]["retweet_mode"] == "direct": - self._direct_retweet(id) - else: - self._retweet_with_comment(tweet, id) + @_tweets_exist + def share_item(self, *args, **kwargs): + tweet = self.get_right_tweet() + id = tweet.id + if self.session.settings["general"]["retweet_mode"] == "ask": + answer = commonMessageDialogs.retweet_question(self.buffer) + if answer == widgetUtils.YES: + self._retweet_with_comment(tweet, id) + elif answer == widgetUtils.NO: + self._direct_retweet(id) + elif self.session.settings["general"]["retweet_mode"] == "direct": + self._direct_retweet(id) + else: + self._retweet_with_comment(tweet, id) - def _retweet_with_comment(self, tweet, id, comment=''): - # If quoting a retweet, let's quote the original tweet instead the retweet. - if hasattr(tweet, "retweeted_status"): - tweet = tweet.retweeted_status - if hasattr(tweet, "full_text"): - comments = tweet.full_text - else: - comments = tweet.text - retweet = messages.tweet(self.session, _(u"Quote"), _(u"Add your comment to the tweet"), u"“@%s: %s ”" % (tweet.user.screen_name, comments), max=256, messageType="retweet") - if comment != '': - retweet.message.set_text(comment) - if retweet.message.get_response() == widgetUtils.OK: - text = retweet.message.get_text() - text = text+" https://twitter.com/{0}/status/{1}".format(tweet.user.screen_name, id) - if retweet.image == None: - item = self.session.api_call(call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id, tweet_mode="extended") - if item != None: - new_item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") - pub.sendMessage("sent-tweet", data=new_item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=text, media=retweet.image) - if hasattr(retweet.message, "destroy"): retweet.message.destroy() + def _retweet_with_comment(self, tweet, id, comment=''): + # If quoting a retweet, let's quote the original tweet instead the retweet. + if hasattr(tweet, "retweeted_status"): + tweet = tweet.retweeted_status + if hasattr(tweet, "full_text"): + comments = tweet.full_text + else: + comments = tweet.text + retweet = messages.tweet(self.session, _(u"Quote"), _(u"Add your comment to the tweet"), u"“@%s: %s ”" % (tweet.user.screen_name, comments), max=256, messageType="retweet") + if comment != '': + retweet.message.set_text(comment) + if retweet.message.get_response() == widgetUtils.OK: + text = retweet.message.get_text() + text = text+" https://twitter.com/{0}/status/{1}".format(tweet.user.screen_name, id) + if retweet.image == None: + item = self.session.api_call(call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id, tweet_mode="extended") + if item != None: + new_item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") + pub.sendMessage("sent-tweet", data=new_item, user=self.session.db["user_name"]) + else: + call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=text, media=retweet.image) + if hasattr(retweet.message, "destroy"): retweet.message.destroy() - def _direct_retweet(self, id): - item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id) - if item != None: - # Retweets are returned as non-extended tweets, so let's get the object as extended - # just before sending the event message. See https://github.com/manuelcortez/TWBlue/issues/253 - item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + def _direct_retweet(self, id): + item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id) + if item != None: + # Retweets are returned as non-extended tweets, so let's get the object as extended + # just before sending the event message. See https://github.com/manuelcortez/TWBlue/issues/253 + item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - def onFocus(self, *args, **kwargs): - tweet = self.get_tweet() - if platform.system() == "Windows" and self.session.settings["general"]["relative_times"] == True: - # fix this: - original_date = arrow.get(self.session.db[self.name][self.buffer.list.get_selected()].created_at, locale="en") - ts = original_date.humanize(locale=languageHandler.getLanguage()) - self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts) - if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet): - self.session.sound.play("audio.ogg") - if self.session.settings['sound']['indicate_geo'] and utils.is_geocoded(tweet): - self.session.sound.play("geo.ogg") - if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet): - self.session.sound.play("image.ogg") + def onFocus(self, *args, **kwargs): + tweet = self.get_tweet() + if platform.system() == "Windows" and self.session.settings["general"]["relative_times"] == True: + # fix this: + original_date = arrow.get(self.session.db[self.name][self.buffer.list.get_selected()].created_at, locale="en") + ts = original_date.humanize(locale=languageHandler.getLanguage()) + self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts) + if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet): + self.session.sound.play("audio.ogg") + if self.session.settings['sound']['indicate_geo'] and utils.is_geocoded(tweet): + self.session.sound.play("geo.ogg") + if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet): + self.session.sound.play("image.ogg") - def audio(self, url='', *args, **kwargs): - if sound.URLPlayer.player.is_playing(): - return sound.URLPlayer.stop_audio() - tweet = self.get_tweet() - if tweet == None: return - urls = utils.find_urls(tweet) - if len(urls) == 1: - url=urls[0] - elif len(urls) > 1: - urls_list = dialogs.urlList.urlList() - urls_list.populate_list(urls) - if urls_list.get_response() == widgetUtils.OK: - url=urls_list.get_string() - if hasattr(urls_list, "destroy"): urls_list.destroy() - if url != '': -# try: - sound.URLPlayer.play(url, self.session.settings["sound"]["volume"]) + def audio(self, url='', *args, **kwargs): + if sound.URLPlayer.player.is_playing(): + return sound.URLPlayer.stop_audio() + tweet = self.get_tweet() + if tweet == None: return + urls = utils.find_urls(tweet) + if len(urls) == 1: + url=urls[0] + elif len(urls) > 1: + urls_list = dialogs.urlList.urlList() + urls_list.populate_list(urls) + if urls_list.get_response() == widgetUtils.OK: + url=urls_list.get_string() + if hasattr(urls_list, "destroy"): urls_list.destroy() + if url != '': + # try: + sound.URLPlayer.play(url, self.session.settings["sound"]["volume"]) # except: # log.error("Exception while executing audio method.") # @_tweets_exist - def url(self, url='', announce=True, *args, **kwargs): - if url == '': - tweet = self.get_tweet() - urls = utils.find_urls(tweet) - if len(urls) == 1: - url=urls[0] - elif len(urls) > 1: - urls_list = dialogs.urlList.urlList() - urls_list.populate_list(urls) - if urls_list.get_response() == widgetUtils.OK: - url=urls_list.get_string() - if hasattr(urls_list, "destroy"): urls_list.destroy() - if url != '': - if announce: - output.speak(_(u"Opening URL..."), True) - webbrowser.open_new_tab(url) + def url(self, url='', announce=True, *args, **kwargs): + if url == '': + tweet = self.get_tweet() + urls = utils.find_urls(tweet) + if len(urls) == 1: + url=urls[0] + elif len(urls) > 1: + urls_list = dialogs.urlList.urlList() + urls_list.populate_list(urls) + if urls_list.get_response() == widgetUtils.OK: + url=urls_list.get_string() + if hasattr(urls_list, "destroy"): urls_list.destroy() + if url != '': + if announce: + output.speak(_(u"Opening URL..."), True) + webbrowser.open_new_tab(url) - def clear_list(self): - dlg = commonMessageDialogs.clear_list() - if dlg == widgetUtils.YES: - self.session.db[self.name] = [] - self.buffer.list.clear() + def clear_list(self): + dlg = commonMessageDialogs.clear_list() + if dlg == widgetUtils.YES: + self.session.db[self.name] = [] + self.buffer.list.clear() - @_tweets_exist - def destroy_status(self, *args, **kwargs): - index = self.buffer.list.get_selected() - if self.type == "events" or self.type == "people" or self.type == "empty" or self.type == "account": return - answer = commonMessageDialogs.delete_tweet_dialog(None) - if answer == widgetUtils.YES: - try: - if self.name == "direct_messages" or self.name == "sent_direct_messages": - self.session.twitter.destroy_direct_message(id=self.get_right_tweet().id) - self.session.db[self.name].pop(index) - else: - self.session.twitter.destroy_status(id=self.get_right_tweet().id) - self.session.db[self.name].pop(index) - self.buffer.list.remove_item(index) - except TweepError: - self.session.sound.play("error.ogg") + @_tweets_exist + def destroy_status(self, *args, **kwargs): + index = self.buffer.list.get_selected() + if self.type == "events" or self.type == "people" or self.type == "empty" or self.type == "account": return + answer = commonMessageDialogs.delete_tweet_dialog(None) + if answer == widgetUtils.YES: + try: + if self.name == "direct_messages" or self.name == "sent_direct_messages": + self.session.twitter.destroy_direct_message(id=self.get_right_tweet().id) + self.session.db[self.name].pop(index) + else: + self.session.twitter.destroy_status(id=self.get_right_tweet().id) + self.session.db[self.name].pop(index) + self.buffer.list.remove_item(index) + except TweepError: + self.session.sound.play("error.ogg") - @_tweets_exist - def user_details(self): - tweet = self.get_right_tweet() - if self.type == "dm": - users = [self.session.get_user(tweet.message_create["sender_id"]).screen_name] - elif self.type == "people": - users = [tweet.screen_name] - else: - users = utils.get_all_users(tweet, self.session.db) - dlg = dialogs.utils.selectUserDialog(title=_(u"User details"), users=users) - if dlg.get_response() == widgetUtils.OK: - user.profileController(session=self.session, user=dlg.get_user()) - if hasattr(dlg, "destroy"): dlg.destroy() + @_tweets_exist + def user_details(self): + tweet = self.get_right_tweet() + if self.type == "dm": + users = [self.session.get_user(tweet.message_create["sender_id"]).screen_name] + elif self.type == "people": + users = [tweet.screen_name] + else: + users = utils.get_all_users(tweet, self.session.db) + dlg = dialogs.utils.selectUserDialog(title=_(u"User details"), users=users) + if dlg.get_response() == widgetUtils.OK: + user.profileController(session=self.session, user=dlg.get_user()) + if hasattr(dlg, "destroy"): dlg.destroy() - def get_quoted_tweet(self, tweet): - quoted_tweet = self.session.twitter.get_status(id=tweet.id) - quoted_tweet.text = utils.find_urls_in_text(quoted_tweet.text, quoted_tweet.entities) - l = tweets.is_long(quoted_tweet) - id = tweets.get_id(l) - original_tweet = self.session.twitter.get_status(id=id) - original_tweet.text = utils.find_urls_in_text(original_tweet.text, original_tweet.entities) - return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"]) + def get_quoted_tweet(self, tweet): + quoted_tweet = self.session.twitter.get_status(id=tweet.id) + quoted_tweet.text = utils.find_urls_in_text(quoted_tweet.text, quoted_tweet.entities) + l = tweets.is_long(quoted_tweet) + id = tweets.get_id(l) + original_tweet = self.session.twitter.get_status(id=id) + original_tweet.text = utils.find_urls_in_text(original_tweet.text, original_tweet.entities) + return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"]) - def open_in_browser(self, *args, **kwargs): - tweet = self.get_tweet() - output.speak(_(u"Opening item in web browser...")) - url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=tweet.user.screen_name, tweet_id=tweet.id) - webbrowser.open(url) + def open_in_browser(self, *args, **kwargs): + tweet = self.get_tweet() + output.speak(_(u"Opening item in web browser...")) + url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=tweet.user.screen_name, tweet_id=tweet.id) + webbrowser.open(url) class directMessagesController(baseBufferController): - def get_more_items(self): - # 50 results are allowed per API call, so let's assume max value can be 50. - # reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events - if self.session.settings["general"]["max_tweets_per_call"] > 50: - count = 50 - else: - count = self.session.settings["general"]["max_tweets_per_call"] - total = 0 - # try to retrieve the cursor for the current buffer. - cursor = self.session.db["cursors"].get(self.name) - try: - items = getattr(self.session.twitter, self.function)(return_cursors=True, cursor=cursor, count=count, *self.args, **self.kwargs) - if type(items) == tuple: - items, cursor = items - if type(cursor) == tuple: - cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor - results = [i for i in items] - items = results - log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - if items == None: - return - sent = [] - received = [] - for i in items: - if int(i.message_create["sender_id"]) == self.session.db["user_id"]: - if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db["sent_direct_messages"].insert(0, i) - sent.append(i) - else: - self.session.db["sent_direct_messages"].append(i) - sent.insert(0, i) - else: - if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) - received.append(i) - else: - self.session.db[self.name].append(i) - received.insert(0, i) - total = total+1 - user_ids = [item.message_create["sender_id"] for item in items] - self.session.save_users(user_ids) - pub.sendMessage("more-sent-dms", data=sent, account=self.session.db["user_name"]) - selected = self.buffer.list.get_selected() - if self.session.settings["general"]["reverse_timelines"] == True: - for i in received: - if int(i.message_create["sender_id"]) == self.session.db["user_id"]: - continue - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(True, *tweet) - self.buffer.list.select_item(selected) - else: - for i in received: - if int(i.message_create["sender_id"]) == self.session.db["user_id"]: - continue - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(True, *tweet) - output.speak(_(u"%s items retrieved") % (total), True) + def get_more_items(self): + # 50 results are allowed per API call, so let's assume max value can be 50. + # reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events + if self.session.settings["general"]["max_tweets_per_call"] > 50: + count = 50 + else: + count = self.session.settings["general"]["max_tweets_per_call"] + total = 0 + # try to retrieve the cursor for the current buffer. + cursor = self.session.db["cursors"].get(self.name) + try: + items = getattr(self.session.twitter, self.function)(return_cursors=True, cursor=cursor, count=count, *self.args, **self.kwargs) + if type(items) == tuple: + items, cursor = items + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor + results = [i for i in items] + items = results + log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + if items == None: + return + sent = [] + received = [] + for i in items: + if int(i.message_create["sender_id"]) == self.session.db["user_id"]: + if self.session.settings["general"]["reverse_timelines"] == False: + self.session.db["sent_direct_messages"].insert(0, i) + sent.append(i) + else: + self.session.db["sent_direct_messages"].append(i) + sent.insert(0, i) + else: + if self.session.settings["general"]["reverse_timelines"] == False: + self.session.db[self.name].insert(0, i) + received.append(i) + else: + self.session.db[self.name].append(i) + received.insert(0, i) + total = total+1 + user_ids = [item.message_create["sender_id"] for item in items] + self.session.save_users(user_ids) + pub.sendMessage("more-sent-dms", data=sent, account=self.session.db["user_name"]) + selected = self.buffer.list.get_selected() + if self.session.settings["general"]["reverse_timelines"] == True: + for i in received: + if int(i.message_create["sender_id"]) == self.session.db["user_id"]: + continue + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(True, *tweet) + self.buffer.list.select_item(selected) + else: + for i in received: + if int(i.message_create["sender_id"]) == self.session.db["user_id"]: + continue + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(True, *tweet) + output.speak(_(u"%s items retrieved") % (total), True) - @_tweets_exist - def reply(self, *args, **kwargs): - tweet = self.get_right_tweet() - screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name - message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - config.app.write() - if message.image == None: - item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) - if hasattr(message.message, "destroy"): message.message.destroy() + @_tweets_exist + def reply(self, *args, **kwargs): + tweet = self.get_right_tweet() + screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name + message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) + if message.message.get_response() == widgetUtils.OK: + if config.app["app-settings"]["remember_mention_and_longtweet"]: + config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() + config.app.write() + if message.image == None: + item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + else: + call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) + if hasattr(message.message, "destroy"): message.message.destroy() - def onFocus(self, *args, **kwargs): - tweet = self.get_tweet() - if platform.system() == "Windows" and self.session.settings["general"]["relative_times"] == True: - # fix this: - original_date = arrow.get(int(tweet.created_timestamp)) - ts = original_date.humanize(locale=languageHandler.getLanguage()) - self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts) - if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet): - self.session.sound.play("audio.ogg") - if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet): - self.session.sound.play("image.ogg") + def onFocus(self, *args, **kwargs): + tweet = self.get_tweet() + if platform.system() == "Windows" and self.session.settings["general"]["relative_times"] == True: + # fix this: + original_date = arrow.get(int(tweet.created_timestamp)) + ts = original_date.humanize(locale=languageHandler.getLanguage()) + self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts) + if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet): + self.session.sound.play("audio.ogg") + if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet): + self.session.sound.play("image.ogg") - def clear_list(self): - dlg = commonMessageDialogs.clear_list() - if dlg == widgetUtils.YES: - self.session.db[self.name] = [] - self.buffer.list.clear() + def clear_list(self): + dlg = commonMessageDialogs.clear_list() + if dlg == widgetUtils.YES: + self.session.db[self.name] = [] + self.buffer.list.clear() - def auto_read(self, number_of_items): - if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - if self.session.settings["general"]["reverse_timelines"] == False: - tweet = self.session.db[self.name][-1] - else: - tweet = self.session.db[self.name][0] - output.speak(_(u"New direct message")) - output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) - elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(_(u"{0} new direct messages.").format(number_of_items,)) + def auto_read(self, number_of_items): + if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + if self.session.settings["general"]["reverse_timelines"] == False: + tweet = self.session.db[self.name][-1] + else: + tweet = self.session.db[self.name][0] + output.speak(_(u"New direct message")) + output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) + elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(_(u"{0} new direct messages.").format(number_of_items,)) - def open_in_browser(self, *args, **kwargs): - output.speak(_(u"This action is not supported in the buffer yet.")) + def open_in_browser(self, *args, **kwargs): + output.speak(_(u"This action is not supported in the buffer yet.")) class sentDirectMessagesController(directMessagesController): - def __init__(self, *args, **kwargs): - super(sentDirectMessagesController, self).__init__(*args, **kwargs) - if ("sent_direct_messages" in self.session.db) == False: - self.session.db["sent_direct_messages"] = [] + def __init__(self, *args, **kwargs): + super(sentDirectMessagesController, self).__init__(*args, **kwargs) + if ("sent_direct_messages" in self.session.db) == False: + self.session.db["sent_direct_messages"] = [] - def get_more_items(self): - output.speak(_(u"Getting more items cannot be done in this buffer. Use the direct messages buffer instead.")) + def get_more_items(self): + output.speak(_(u"Getting more items cannot be done in this buffer. Use the direct messages buffer instead.")) - def start_stream(self, *args, **kwargs): - pass + def start_stream(self, *args, **kwargs): + pass - def put_more_items(self, items): - if self.session.settings["general"]["reverse_timelines"] == True: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) - else: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) + def put_more_items(self, items): + if self.session.settings["general"]["reverse_timelines"] == True: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) + else: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) class listBufferController(baseBufferController): - def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, list_id=None, *args, **kwargs): - super(listBufferController, self).__init__(parent, function, name, sessionObject, account, sound=None, bufferType=None, *args, **kwargs) - self.users = [] - self.list_id = list_id - self.kwargs["list_id"] = list_id + def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, list_id=None, *args, **kwargs): + super(listBufferController, self).__init__(parent, function, name, sessionObject, account, sound=None, bufferType=None, *args, **kwargs) + self.users = [] + self.list_id = list_id + self.kwargs["list_id"] = list_id - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - self.get_user_ids() - super(listBufferController, self).start_stream(mandatory, play_sound, avoid_autoreading) + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + self.get_user_ids() + super(listBufferController, self).start_stream(mandatory, play_sound, avoid_autoreading) - def get_user_ids(self): - for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): - if i.id not in self.users: - self.users.append(i.id) + def get_user_ids(self): + for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): + if i.id not in self.users: + self.users.append(i.id) - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-5] in self.session.settings["other_buffers"]["lists"]: - self.session.settings["other_buffers"]["lists"].remove(self.name[:-5]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-5] in self.session.settings["other_buffers"]["lists"]: + self.session.settings["other_buffers"]["lists"].remove(self.name[:-5]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False class peopleBufferController(baseBufferController): - def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs): - super(peopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - self.compose_function = compose.compose_followers_list - log.debug("Compose_function: %s" % (self.compose_function,)) - self.get_tweet = self.get_right_tweet - self.url = self.interact - if "-followers" in self.name or "-friends" in self.name: - self.finished_timeline = False - # Add a compatibility layer for username based timelines from config. - # ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory. - try: - int(self.kwargs["user_id"]) - except ValueError: - self.is_screen_name = True - self.kwargs["screen_name"] = self.kwargs["user_id"] - self.kwargs.pop("user_id") + def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs): + super(peopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + self.compose_function = compose.compose_followers_list + log.debug("Compose_function: %s" % (self.compose_function,)) + self.get_tweet = self.get_right_tweet + self.url = self.interact + if "-followers" in self.name or "-friends" in self.name: + self.finished_timeline = False + # Add a compatibility layer for username based timelines from config. + # ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory. + try: + int(self.kwargs["user_id"]) + except ValueError: + self.is_screen_name = True + self.kwargs["screen_name"] = self.kwargs["user_id"] + self.kwargs.pop("user_id") - def remove_buffer(self, force=True): - if "-followers" in self.name: - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]: - self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False - elif "-friends" in self.name: - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]: - self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False - else: - output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True) - return False + def remove_buffer(self, force=True): + if "-followers" in self.name: + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]: + self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False + elif "-friends" in self.name: + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]: + self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False + else: + output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True) + return False - def onFocus(self, ev): - pass + def onFocus(self, ev): + pass - def get_message(self): - return " ".join(self.compose_function(self.get_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)) + def get_message(self): + return " ".join(self.compose_function(self.get_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)) - def delete_item(self): pass + def delete_item(self): pass - @_tweets_exist - def reply(self, *args, **kwargs): - tweet = self.get_right_tweet() - screen_name = tweet.screen_name - message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - config.app.write() - if message.image == None: - item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) - if hasattr(message.message, "destroy"): message.message.destroy() + @_tweets_exist + def reply(self, *args, **kwargs): + tweet = self.get_right_tweet() + screen_name = tweet.screen_name + message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) + if message.message.get_response() == widgetUtils.OK: + if config.app["app-settings"]["remember_mention_and_longtweet"]: + config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() + config.app.write() + if message.image == None: + item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + else: + call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) + if hasattr(message.message, "destroy"): message.message.destroy() - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: - self.execution_time = current_time - log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,)) - log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) - try: - val = getattr(self.session.twitter, self.function)(return_cursors=True, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - if type(val) == tuple: - val, cursor = val - if type(cursor) == tuple: - cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor - results = [i for i in val] - val = results - val.reverse() - log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - number_of_items = self.session.order_people(self.name, val) - log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) - if hasattr(self, "finished_timeline") and self.finished_timeline == False: - self.username = self.session.api_call("get_user", **self.kwargs).screen_name - self.finished_timeline = True - if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(number_of_items) - return number_of_items + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: + self.execution_time = current_time + log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,)) + log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) + try: + val = getattr(self.session.twitter, self.function)(return_cursors=True, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + if type(val) == tuple: + val, cursor = val + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor + results = [i for i in val] + val = results + val.reverse() + log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + number_of_items = self.session.order_people(self.name, val) + log.debug("Number of items retrieved: %d" % (number_of_items,)) + self.put_items_on_list(number_of_items) + if hasattr(self, "finished_timeline") and self.finished_timeline == False: + self.username = self.session.api_call("get_user", **self.kwargs).screen_name + self.finished_timeline = True + if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) + # Autoread settings + if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: + self.auto_read(number_of_items) + return number_of_items - def get_more_items(self): - try: - cursor = self.session.db["cursors"].get(self.name) - items = getattr(self.session.twitter, self.function)(return_cursors=True, users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - if type(items) == tuple: - items, cursor = items - if type(cursor) == tuple: - cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor - results = [i for i in items] - items = results - log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - if items == None: - return - for i in items: - if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) - else: - self.session.db[self.name].append(i) - selected = self.buffer.list.get_selected() - if self.session.settings["general"]["reverse_timelines"] == True: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(True, *tweet) - self.buffer.list.select_item(selected) - else: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(True, *tweet) - output.speak(_(u"%s items retrieved") % (len(items)), True) + def get_more_items(self): + try: + cursor = self.session.db["cursors"].get(self.name) + items = getattr(self.session.twitter, self.function)(return_cursors=True, users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + if type(items) == tuple: + items, cursor = items + if type(cursor) == tuple: + cursor = cursor[1] + self.session.db["cursors"][self.name] = cursor + results = [i for i in items] + items = results + log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + if items == None: + return + for i in items: + if self.session.settings["general"]["reverse_timelines"] == False: + self.session.db[self.name].insert(0, i) + else: + self.session.db[self.name].append(i) + selected = self.buffer.list.get_selected() + if self.session.settings["general"]["reverse_timelines"] == True: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) + self.buffer.list.insert_item(True, *tweet) + self.buffer.list.select_item(selected) + else: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) + self.buffer.list.insert_item(True, *tweet) + output.speak(_(u"%s items retrieved") % (len(items)), True) - def put_items_on_list(self, number_of_items): - log.debug("The list contains %d items" % (self.buffer.list.get_count(),)) + def put_items_on_list(self, number_of_items): + log.debug("The list contains %d items" % (self.buffer.list.get_count(),)) # log.debug("Putting %d items on the list..." % (number_of_items,)) - if self.buffer.list.get_count() == 0: - for i in self.session.db[self.name]: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(False, *tweet) - self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) + if self.buffer.list.get_count() == 0: + for i in self.session.db[self.name]: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) + self.buffer.list.insert_item(False, *tweet) + self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) # self.buffer.set_list_position() - elif self.buffer.list.get_count() > 0: - if self.session.settings["general"]["reverse_timelines"] == False: - for i in self.session.db[self.name][len(self.session.db[self.name])-number_of_items:]: - tweet = self.compose_function(i, self.session.db) - self.buffer.list.insert_item(False, *tweet) - else: - items = self.session.db[self.name][0:number_of_items] - items.reverse() - for i in items: - tweet = self.compose_function(i, self.session.db) - self.buffer.list.insert_item(True, *tweet) - log.debug("now the list contains %d items" % (self.buffer.list.get_count(),)) + elif self.buffer.list.get_count() > 0: + if self.session.settings["general"]["reverse_timelines"] == False: + for i in self.session.db[self.name][len(self.session.db[self.name])-number_of_items:]: + tweet = self.compose_function(i, self.session.db) + self.buffer.list.insert_item(False, *tweet) + else: + items = self.session.db[self.name][0:number_of_items] + items.reverse() + for i in items: + tweet = self.compose_function(i, self.session.db) + self.buffer.list.insert_item(True, *tweet) + log.debug("now the list contains %d items" % (self.buffer.list.get_count(),)) - def get_right_tweet(self): - tweet = self.session.db[self.name][self.buffer.list.get_selected()] - return tweet + def get_right_tweet(self): + tweet = self.session.db[self.name][self.buffer.list.get_selected()] + return tweet - def add_new_item(self, item): - tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session) - if self.session.settings["general"]["reverse_timelines"] == False: - self.buffer.list.insert_item(False, *tweet) - else: - self.buffer.list.insert_item(True, *tweet) - if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(" ".join(tweet)) + def add_new_item(self, item): + tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session) + if self.session.settings["general"]["reverse_timelines"] == False: + self.buffer.list.insert_item(False, *tweet) + else: + self.buffer.list.insert_item(True, *tweet) + if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(" ".join(tweet)) - def clear_list(self): - dlg = commonMessageDialogs.clear_list() - if dlg == widgetUtils.YES: - self.session.db[self.name] = [] - self.session.db["cursors"][self.name] = -1 - self.buffer.list.clear() + def clear_list(self): + dlg = commonMessageDialogs.clear_list() + if dlg == widgetUtils.YES: + self.session.db[self.name] = [] + self.session.db["cursors"][self.name] = -1 + self.buffer.list.clear() - def interact(self): - user.profileController(self.session, user=self.get_right_tweet().screen_name) + def interact(self): + user.profileController(self.session, user=self.get_right_tweet().screen_name) - def show_menu(self, ev, pos=0, *args, **kwargs): - menu = menus.peoplePanelMenu() - widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details) + def show_menu(self, ev, pos=0, *args, **kwargs): + menu = menus.peoplePanelMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details) # widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) - if hasattr(menu, "openInBrowser"): - widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser) - if pos != 0: - self.buffer.PopupMenu(menu, pos) - else: - self.buffer.PopupMenu(menu, ev.GetPosition()) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) + if hasattr(menu, "openInBrowser"): + widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser) + if pos != 0: + self.buffer.PopupMenu(menu, pos) + else: + self.buffer.PopupMenu(menu, ev.GetPosition()) - def details(self, *args, **kwargs): - pub.sendMessage("execute-action", action="user_details") + def details(self, *args, **kwargs): + pub.sendMessage("execute-action", action="user_details") - def auto_read(self, number_of_items): - if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - if self.session.settings["general"]["reverse_timelines"] == False: - tweet = self.session.db[self.name][-1] - else: - tweet = self.session.db[self.name][0] - output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) - elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(_(u"{0} new followers.").format(number_of_items)) + def auto_read(self, number_of_items): + if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + if self.session.settings["general"]["reverse_timelines"] == False: + tweet = self.session.db[self.name][-1] + else: + tweet = self.session.db[self.name][0] + output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) + elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(_(u"{0} new followers.").format(number_of_items)) - def open_in_browser(self, *args, **kwargs): - tweet = self.get_tweet() - output.speak(_(u"Opening item in web browser...")) - url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name) - webbrowser.open(url) + def open_in_browser(self, *args, **kwargs): + tweet = self.get_tweet() + output.speak(_(u"Opening item in web browser...")) + url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name) + webbrowser.open(url) class searchBufferController(baseBufferController): - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: - self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: + self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False class searchPeopleBufferController(peopleBufferController): - """ This is identical to a normal peopleBufferController, except that uses the page parameter instead of a cursor.""" - def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs): - super(searchPeopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) - if ("page" in self.kwargs) == False: - self.page = 1 - else: - self.page = self.kwargs.pop("page") + """ This is identical to a normal peopleBufferController, except that uses the page parameter instead of a cursor.""" + def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs): + super(searchPeopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) + if ("page" in self.kwargs) == False: + self.page = 1 + else: + self.page = self.kwargs.pop("page") - def get_more_items(self, *args, **kwargs): - # Add 1 to the page parameter, put it in kwargs and calls to get_more_items in the parent buffer. - self.page = self.page +1 - self.kwargs["page"] = self.page - super(searchPeopleBufferController, self).get_more_items(*args, **kwargs) - # remove the parameter again to make sure start_stream won't fetch items for this page indefinitely. - self.kwargs.pop("page") + def get_more_items(self, *args, **kwargs): + # Add 1 to the page parameter, put it in kwargs and calls to get_more_items in the parent buffer. + self.page = self.page +1 + self.kwargs["page"] = self.page + super(searchPeopleBufferController, self).get_more_items(*args, **kwargs) + # remove the parameter again to make sure start_stream won't fetch items for this page indefinitely. + self.kwargs.pop("page") - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: - self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: + self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False class trendsBufferController(baseBuffers.buffer): - def __init__(self, parent, name, session, account, trendsFor, *args, **kwargs): - super(trendsBufferController, self).__init__(parent=parent, session=session) - self.trendsFor = trendsFor - self.session = session - self.account = account - self.invisible = True - self.buffer = buffers.trendsPanel(parent, name) - self.buffer.account = account - self.type = self.buffer.type - self.bind_events() - self.sound = "trends_updated.ogg" - self.trends = [] - self.name = name - self.buffer.name = name - self.compose_function = self.compose_function_ - self.get_formatted_message = self.get_message - self.reply = self.search_topic + def __init__(self, parent, name, session, account, trendsFor, *args, **kwargs): + super(trendsBufferController, self).__init__(parent=parent, session=session) + self.trendsFor = trendsFor + self.session = session + self.account = account + self.invisible = True + self.buffer = buffers.trendsPanel(parent, name) + self.buffer.account = account + self.type = self.buffer.type + self.bind_events() + self.sound = "trends_updated.ogg" + self.trends = [] + self.name = name + self.buffer.name = name + self.compose_function = self.compose_function_ + self.get_formatted_message = self.get_message + self.reply = self.search_topic - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: - self.execution_time = current_time - try: - data = self.session.twitter.trends_place(id=self.trendsFor) - except TweepError as err: - log.error("Error %s: %s" % (err.api_code, err.reason)) - if not hasattr(self, "name_"): - self.name_ = data[0]["locations"][0]["name"] - self.trends = data[0]["trends"] - self.put_items_on_the_list() - if self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: + self.execution_time = current_time + try: + data = self.session.twitter.trends_place(id=self.trendsFor) + except TweepError as err: + log.error("Error %s: %s" % (err.api_code, err.reason)) + if not hasattr(self, "name_"): + self.name_ = data[0]["locations"][0]["name"] + self.trends = data[0]["trends"] + self.put_items_on_the_list() + if self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) - def put_items_on_the_list(self): - selected_item = self.buffer.list.get_selected() - self.buffer.list.clear() - for i in self.trends: - tweet = self.compose_function(i) - self.buffer.list.insert_item(False, *tweet) - self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) + def put_items_on_the_list(self): + selected_item = self.buffer.list.get_selected() + self.buffer.list.clear() + for i in self.trends: + tweet = self.compose_function(i) + self.buffer.list.insert_item(False, *tweet) + self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) - def compose_function_(self, trend): - return [trend["name"]] + def compose_function_(self, trend): + return [trend["name"]] - def bind_events(self): - log.debug("Binding events...") - self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.tweet_about_this_trend, self.buffer.tweetTrendBtn) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet) - widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu) - widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.search_topic, self.buffer.search_topic) + def bind_events(self): + log.debug("Binding events...") + self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.tweet_about_this_trend, self.buffer.tweetTrendBtn) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet) + widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu) + widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.search_topic, self.buffer.search_topic) - def get_message(self): - return self.compose_function(self.trends[self.buffer.list.get_selected()])[0] + def get_message(self): + return self.compose_function(self.trends[self.buffer.list.get_selected()])[0] - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]: - self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]: + self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False - def url(self, *args, **kwargs): - self.tweet_about_this_trend() + def url(self, *args, **kwargs): + self.tweet_about_this_trend() - def search_topic(self, *args, **kwargs): - topic = self.trends[self.buffer.list.get_selected()]["name"] - pub.sendMessage("search", term=topic) + def search_topic(self, *args, **kwargs): + topic = self.trends[self.buffer.list.get_selected()]["name"] + pub.sendMessage("search", term=topic) - def show_menu(self, ev, pos=0, *args, **kwargs): - menu = menus.trendsPanelMenu() - widgetUtils.connect_event(menu, widgetUtils.MENU, self.search_topic, menuitem=menu.search_topic) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.tweet_about_this_trend, menuitem=menu.tweetThisTrend) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) - if pos != 0: - self.buffer.PopupMenu(menu, pos) - else: - self.buffer.PopupMenu(menu, ev.GetPosition()) + def show_menu(self, ev, pos=0, *args, **kwargs): + menu = menus.trendsPanelMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.search_topic, menuitem=menu.search_topic) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.tweet_about_this_trend, menuitem=menu.tweetThisTrend) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) + if pos != 0: + self.buffer.PopupMenu(menu, pos) + else: + self.buffer.PopupMenu(menu, ev.GetPosition()) - def view(self, *args, **kwargs): - pub.sendMessage("execute-action", action="view_item") + def view(self, *args, **kwargs): + pub.sendMessage("execute-action", action="view_item") - def copy(self, *args, **kwargs): - pub.sendMessage("execute-action", action="copy_to_clipboard") + def copy(self, *args, **kwargs): + pub.sendMessage("execute-action", action="copy_to_clipboard") - def tweet_about_this_trend(self, *args, **kwargs): - if self.buffer.list.get_count() == 0: return - title = _(u"Tweet") - caption = _(u"Write the tweet here") - tweet = messages.tweet(self.session, title, caption, self.get_message()+ " ") - tweet.message.set_cursor_at_end() - if tweet.message.get_response() == widgetUtils.OK: - text = tweet.message.get_text() - if len(text) > 280 and tweet.message.get("long_tweet") == True: - if tweet.image == None: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - if tweet.image == None: - call_threaded(self.session.api_call, call_name="update_status", status=text) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image) - if hasattr(tweet.message, "destroy"): tweet.message.destroy() + def tweet_about_this_trend(self, *args, **kwargs): + if self.buffer.list.get_count() == 0: return + title = _(u"Tweet") + caption = _(u"Write the tweet here") + tweet = messages.tweet(self.session, title, caption, self.get_message()+ " ") + tweet.message.set_cursor_at_end() + if tweet.message.get_response() == widgetUtils.OK: + text = tweet.message.get_text() + if len(text) > 280 and tweet.message.get("long_tweet") == True: + if tweet.image == None: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) + else: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) + if tweet.image == None: + call_threaded(self.session.api_call, call_name="update_status", status=text) + else: + call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image) + if hasattr(tweet.message, "destroy"): tweet.message.destroy() - def show_menu_by_key(self, ev): - if self.buffer.list.get_count() == 0: - return - if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: - self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) + def show_menu_by_key(self, ev): + if self.buffer.list.get_count() == 0: + return + if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: + self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) - def open_in_browser(self, *args, **kwargs): - output.speak(_(u"This action is not supported in the buffer, yet.")) + def open_in_browser(self, *args, **kwargs): + output.speak(_(u"This action is not supported in the buffer, yet.")) class conversationBufferController(searchBufferController): - def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: - self.execution_time = current_time - if start == True: - self.statuses = [] - self.ids = [] - self.statuses.append(self.tweet) - self.ids.append(self.tweet.id) - tweet = self.tweet - while tweet.in_reply_to_status_id != None: - try: - tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") - except TweepError as err: - break - self.statuses.insert(0, tweet) - self.ids.append(tweet.id) - if tweet.in_reply_to_status_id == None: - self.kwargs["since_id"] = tweet.id - self.ids.append(tweet.id) - val2 = self.session.search(self.name, tweet_mode="extended", *self.args, **self.kwargs) - for i in val2: - if i.in_reply_to_status_id in self.ids: - self.statuses.append(i) - self.ids.append(i.id) - tweet = i - number_of_items = self.session.order_buffer(self.name, self.statuses) - log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) - if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(number_of_items) - return number_of_items + def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: + self.execution_time = current_time + if start == True: + self.statuses = [] + self.ids = [] + self.statuses.append(self.tweet) + self.ids.append(self.tweet.id) + tweet = self.tweet + while tweet.in_reply_to_status_id != None: + try: + tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") + except TweepError as err: + break + self.statuses.insert(0, tweet) + self.ids.append(tweet.id) + if tweet.in_reply_to_status_id == None: + self.kwargs["since_id"] = tweet.id + self.ids.append(tweet.id) + val2 = self.session.search(self.name, tweet_mode="extended", *self.args, **self.kwargs) + for i in val2: + if i.in_reply_to_status_id in self.ids: + self.statuses.append(i) + self.ids.append(i.id) + tweet = i + number_of_items = self.session.order_buffer(self.name, self.statuses) + log.debug("Number of items retrieved: %d" % (number_of_items,)) + self.put_items_on_list(number_of_items) + if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) + # Autoread settings + if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: + self.auto_read(number_of_items) + return number_of_items - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False diff --git a/src/controller/filterController.py b/src/controller/filterController.py index 5f6fa6ed..f1262d19 100644 --- a/src/controller/filterController.py +++ b/src/controller/filterController.py @@ -8,71 +8,71 @@ from wxUI.dialogs import filterDialogs from wxUI import commonMessageDialogs class filter(object): - def __init__(self, buffer, filter_title=None, if_word_exists=None, in_lang=None, regexp=None, word=None, in_buffer=None): - self.buffer = buffer - self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages]) - if self.dialog.get_response() == widgetUtils.OK: - title = self.dialog.get("title") - contains = self.dialog.get("contains") - term = self.dialog.get("term") - regexp = self.dialog.get("regexp") - allow_rts = self.dialog.get("allow_rts") - allow_quotes = self.dialog.get("allow_quotes") - allow_replies = self.dialog.get("allow_replies") - load_language = self.dialog.get("load_language") - ignore_language = self.dialog.get("ignore_language") - lang_option = None - if ignore_language: - lang_option = False - elif load_language: - lang_option = True - langs = self.dialog.get_selected_langs() - langcodes = [] - for i in application.supported_languages: - if i["name"] in langs: - langcodes.append(i["code"]) - d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies) - if title in self.buffer.session.settings["filters"]: - return commonMessageDialogs.existing_filter() - self.buffer.session.settings["filters"][title] = d - self.buffer.session.settings.write() + def __init__(self, buffer, filter_title=None, if_word_exists=None, in_lang=None, regexp=None, word=None, in_buffer=None): + self.buffer = buffer + self.dialog = filterDialogs.filterDialog(languages=[i["name"] for i in application.supported_languages]) + if self.dialog.get_response() == widgetUtils.OK: + title = self.dialog.get("title") + contains = self.dialog.get("contains") + term = self.dialog.get("term") + regexp = self.dialog.get("regexp") + allow_rts = self.dialog.get("allow_rts") + allow_quotes = self.dialog.get("allow_quotes") + allow_replies = self.dialog.get("allow_replies") + load_language = self.dialog.get("load_language") + ignore_language = self.dialog.get("ignore_language") + lang_option = None + if ignore_language: + lang_option = False + elif load_language: + lang_option = True + langs = self.dialog.get_selected_langs() + langcodes = [] + for i in application.supported_languages: + if i["name"] in langs: + langcodes.append(i["code"]) + d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies) + if title in self.buffer.session.settings["filters"]: + return commonMessageDialogs.existing_filter() + self.buffer.session.settings["filters"][title] = d + self.buffer.session.settings.write() class filterManager(object): - def __init__(self, session): - self.session = session - self.dialog = filterDialogs.filterManagerDialog() - self.insert_filters(self.session.settings["filters"]) - if self.dialog.filters.get_count() == 0: - self.dialog.edit.Enable(False) - self.dialog.delete.Enable(False) - else: - widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter) - widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter) - response = self.dialog.get_response() + def __init__(self, session): + self.session = session + self.dialog = filterDialogs.filterManagerDialog() + self.insert_filters(self.session.settings["filters"]) + if self.dialog.filters.get_count() == 0: + self.dialog.edit.Enable(False) + self.dialog.delete.Enable(False) + else: + widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_filter) + widgetUtils.connect_event(self.dialog.delete, widgetUtils.BUTTON_PRESSED, self.delete_filter) + response = self.dialog.get_response() - def insert_filters(self, filters): - self.dialog.filters.clear() - for f in list(filters.keys()): - filterName = f - buffer = filters[f]["in_buffer"] - if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "": - filter_by_word = "True" - else: - filter_by_word = "False" - filter_by_lang = "" - if filters[f]["in_lang"] != "None": - filter_by_lang = "True" - b = [f, buffer, filter_by_word, filter_by_lang] - self.dialog.filters.insert_item(False, *b) + def insert_filters(self, filters): + self.dialog.filters.clear() + for f in list(filters.keys()): + filterName = f + buffer = filters[f]["in_buffer"] + if filters[f]["if_word_exists"] == "True" and filters[f]["word"] != "": + filter_by_word = "True" + else: + filter_by_word = "False" + filter_by_lang = "" + if filters[f]["in_lang"] != "None": + filter_by_lang = "True" + b = [f, buffer, filter_by_word, filter_by_lang] + self.dialog.filters.insert_item(False, *b) - def edit_filter(self, *args, **kwargs): - pass + def edit_filter(self, *args, **kwargs): + pass - def delete_filter(self, *args, **kwargs): - filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0) - response = commonMessageDialogs.delete_filter() - if response == widgetUtils.YES: - self.session.settings["filters"].pop(filter_title) - self.session.settings.write() - self.insert_filters(self.session.settings["filters"]) \ No newline at end of file + def delete_filter(self, *args, **kwargs): + filter_title = self.dialog.filters.get_text_column(self.dialog.filters.get_selected(), 0) + response = commonMessageDialogs.delete_filter() + if response == widgetUtils.YES: + self.session.settings["filters"].pop(filter_title) + self.session.settings.write() + self.insert_filters(self.session.settings["filters"]) diff --git a/src/controller/listsController.py b/src/controller/listsController.py index 776b0604..b1d49249 100644 --- a/src/controller/listsController.py +++ b/src/controller/listsController.py @@ -10,101 +10,101 @@ from pubsub import pub log = logging.getLogger("controller.listsController") class listsController(object): - def __init__(self, session, user=None): - super(listsController, self).__init__() - self.session = session - if user == None: - self.dialog = lists.listViewer() - self.dialog.populate_list(self.get_all_lists()) - widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.create_list) - widgetUtils.connect_event(self.dialog.editBtn, widgetUtils.BUTTON_PRESSED, self.edit_list) - widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list) - widgetUtils.connect_event(self.dialog.view, widgetUtils.BUTTON_PRESSED, self.open_list_as_buffer) - widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list) - else: - self.dialog = lists.userListViewer(user) - self.dialog.populate_list(self.get_user_lists(user)) - widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.subscribe) - widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe) - self.dialog.get_response() + def __init__(self, session, user=None): + super(listsController, self).__init__() + self.session = session + if user == None: + self.dialog = lists.listViewer() + self.dialog.populate_list(self.get_all_lists()) + widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.create_list) + widgetUtils.connect_event(self.dialog.editBtn, widgetUtils.BUTTON_PRESSED, self.edit_list) + widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list) + widgetUtils.connect_event(self.dialog.view, widgetUtils.BUTTON_PRESSED, self.open_list_as_buffer) + widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.remove_list) + else: + self.dialog = lists.userListViewer(user) + self.dialog.populate_list(self.get_user_lists(user)) + widgetUtils.connect_event(self.dialog.createBtn, widgetUtils.BUTTON_PRESSED, self.subscribe) + widgetUtils.connect_event(self.dialog.deleteBtn, widgetUtils.BUTTON_PRESSED, self.unsubscribe) + self.dialog.get_response() - def get_all_lists(self): - return [compose.compose_list(item) for item in self.session.db["lists"]] + def get_all_lists(self): + return [compose.compose_list(item) for item in self.session.db["lists"]] - def get_user_lists(self, user): - self.lists = self.session.twitter.lists_all(reverse=True, screen_name=user) - return [compose.compose_list(item) for item in self.lists] + def get_user_lists(self, user): + self.lists = self.session.twitter.lists_all(reverse=True, screen_name=user) + return [compose.compose_list(item) for item in self.lists] - def create_list(self, *args, **kwargs): - dialog = lists.createListDialog() - if dialog.get_response() == widgetUtils.OK: - name = dialog.get("name") - description = dialog.get("description") - p = dialog.get("public") - if p == True: - mode = "public" - else: - mode = "private" - try: - new_list = self.session.twitter.create_list(name=name, description=description, mode=mode) - self.session.db["lists"].append(new_list) - self.dialog.lista.insert_item(False, *compose.compose_list(new_list)) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) - log.exception("error %s: %s" % (e.api_code, e.reason)) - dialog.destroy() + def create_list(self, *args, **kwargs): + dialog = lists.createListDialog() + if dialog.get_response() == widgetUtils.OK: + name = dialog.get("name") + description = dialog.get("description") + p = dialog.get("public") + if p == True: + mode = "public" + else: + mode = "private" + try: + new_list = self.session.twitter.create_list(name=name, description=description, mode=mode) + self.session.db["lists"].append(new_list) + self.dialog.lista.insert_item(False, *compose.compose_list(new_list)) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) + log.exception("error %s: %s" % (e.api_code, e.reason)) + dialog.destroy() - def edit_list(self, *args, **kwargs): - if self.dialog.lista.get_count() == 0: return - list = self.session.db["lists"][self.dialog.get_item()] - dialog = lists.editListDialog(list) - if dialog.get_response() == widgetUtils.OK: - name = dialog.get("name") - description = dialog.get("description") - p = dialog.get("public") - if p == True: - mode = "public" - else: - mode = "private" - try: - self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode) - self.session.get_lists() - self.dialog.populate_list(self.get_all_lists(), True) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) - dialog.destroy() + def edit_list(self, *args, **kwargs): + if self.dialog.lista.get_count() == 0: return + list = self.session.db["lists"][self.dialog.get_item()] + dialog = lists.editListDialog(list) + if dialog.get_response() == widgetUtils.OK: + name = dialog.get("name") + description = dialog.get("description") + p = dialog.get("public") + if p == True: + mode = "public" + else: + mode = "private" + try: + self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode) + self.session.get_lists() + self.dialog.populate_list(self.get_all_lists(), True) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) + dialog.destroy() - def remove_list(self, *args, **kwargs): - if self.dialog.lista.get_count() == 0: return - list = self.session.db["lists"][self.dialog.get_item()].id - if lists.remove_list() == widgetUtils.YES: - try: - self.session.twitter.destroy_list(list_id=list) - self.session.db["lists"].pop(self.dialog.get_item()) - self.dialog.lista.remove_item(self.dialog.get_item()) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + def remove_list(self, *args, **kwargs): + if self.dialog.lista.get_count() == 0: return + list = self.session.db["lists"][self.dialog.get_item()].id + if lists.remove_list() == widgetUtils.YES: + try: + self.session.twitter.destroy_list(list_id=list) + self.session.db["lists"].pop(self.dialog.get_item()) + self.dialog.lista.remove_item(self.dialog.get_item()) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) - def open_list_as_buffer(self, *args, **kwargs): - if self.dialog.lista.get_count() == 0: return - list = self.session.db["lists"][self.dialog.get_item()] - pub.sendMessage("create-new-buffer", buffer="list", account=self.session.db["user_name"], create=list.name) + def open_list_as_buffer(self, *args, **kwargs): + if self.dialog.lista.get_count() == 0: return + list = self.session.db["lists"][self.dialog.get_item()] + pub.sendMessage("create-new-buffer", buffer="list", account=self.session.db["user_name"], create=list.name) - def subscribe(self, *args, **kwargs): - if self.dialog.lista.get_count() == 0: return - list_id = self.lists[self.dialog.get_item()].id - try: - list = self.session.twitter.subscribe_list(list_id=list_id) - item = utils.find_item(list.id, self.session.db["lists"]) - self.session.db["lists"].append(list) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + def subscribe(self, *args, **kwargs): + if self.dialog.lista.get_count() == 0: return + list_id = self.lists[self.dialog.get_item()].id + try: + list = self.session.twitter.subscribe_list(list_id=list_id) + item = utils.find_item(list.id, self.session.db["lists"]) + self.session.db["lists"].append(list) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) - def unsubscribe(self, *args, **kwargs): - if self.dialog.lista.get_count() == 0: return - list_id = self.lists[self.dialog.get_item()].id - try: - list = self.session.twitter.unsubscribe_list(list_id=list_id) - self.session.db["lists"].remove(list) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + def unsubscribe(self, *args, **kwargs): + if self.dialog.lista.get_count() == 0: return + list_id = self.lists[self.dialog.get_item()].id + try: + list = self.session.twitter.unsubscribe_list(list_id=list_id) + self.session.db["lists"].remove(list) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index de600aab..ed8bf128 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -6,20 +6,20 @@ import requests from audio_services import youtube_utils import arrow if system == "Windows": - from update import updater - from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon) - from . import settings - from extra import SoundsTutorial, ocr - import keystrokeEditor - from keyboard_handler.wx_handler import WXKeyboardHandler - from . import userActionsController - from . import trendingTopics - from . import user - from . import listsController - from . import filterController + from update import updater + from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon) + from . import settings + from extra import SoundsTutorial, ocr + import keystrokeEditor + from keyboard_handler.wx_handler import WXKeyboardHandler + from . import userActionsController + from . import trendingTopics + from . import user + from . import listsController + from . import filterController # from issueReporter import issueReporter elif system == "Linux": - from gtkUI import (view, commonMessageDialogs) + from gtkUI import (view, commonMessageDialogs) from sessions.twitter import utils, compose from sessionmanager import manager, sessionManager @@ -50,1577 +50,1577 @@ geocoder = pygeocoder.Geocoder() class Controller(object): - """ Main Controller for TWBlue. It manages the main window and sessions.""" + """ Main Controller for TWBlue. It manages the main window and sessions.""" - def search_buffer(self, name_, user): + def search_buffer(self, name_, user): - """ Searches a buffer. - name_ str: The name for the buffer - user str: The account for the buffer. - for example you may want to search the home_timeline buffer for the tw_blue2 user. - Return type: buffers.buffer object.""" - for i in self.buffers: - if i.name == name_ and i.account == user: return i + """ Searches a buffer. + name_ str: The name for the buffer + user str: The account for the buffer. + for example you may want to search the home_timeline buffer for the tw_blue2 user. + Return type: buffers.buffer object.""" + for i in self.buffers: + if i.name == name_ and i.account == user: return i - def get_current_buffer(self): - """ Get the current focused bufferObject. - Return type: buffers.buffer object.""" - buffer = self.view.get_current_buffer() - if hasattr(buffer, "account"): - buffer = self.search_buffer(buffer.name, buffer.account) - return buffer + def get_current_buffer(self): + """ Get the current focused bufferObject. + Return type: buffers.buffer object.""" + buffer = self.view.get_current_buffer() + if hasattr(buffer, "account"): + buffer = self.search_buffer(buffer.name, buffer.account) + return buffer - def get_best_buffer(self): - """ Get the best buffer for doing something using the session object. - This function is useful when you need to open a timeline or post a tweet, and the user is in a buffer without a session, for example the events buffer. - Return type: twitterBuffers.buffer object.""" - # Gets the parent buffer to know what account is doing an action - view_buffer = self.view.get_current_buffer() - # If the account has no session attached, we will need to search the first available non-empty buffer for that account to use its session. - if view_buffer.type == "account" or view_buffer.type == "empty": - buffer = self.get_first_buffer(view_buffer.account) - else: - buffer = self.search_buffer(view_buffer.name, view_buffer.account) - if buffer != None: return buffer + def get_best_buffer(self): + """ Get the best buffer for doing something using the session object. + This function is useful when you need to open a timeline or post a tweet, and the user is in a buffer without a session, for example the events buffer. + Return type: twitterBuffers.buffer object.""" + # Gets the parent buffer to know what account is doing an action + view_buffer = self.view.get_current_buffer() + # If the account has no session attached, we will need to search the first available non-empty buffer for that account to use its session. + if view_buffer.type == "account" or view_buffer.type == "empty": + buffer = self.get_first_buffer(view_buffer.account) + else: + buffer = self.search_buffer(view_buffer.name, view_buffer.account) + if buffer != None: return buffer - def get_first_buffer(self, account): - """ Gets the first valid buffer for an account. - account str: A twitter username. - The first valid buffer is the home timeline.""" - for i in self.buffers: - if i.account == account and i.invisible == True and i.session != None: - return i + def get_first_buffer(self, account): + """ Gets the first valid buffer for an account. + account str: A twitter username. + The first valid buffer is the home timeline.""" + for i in self.buffers: + if i.account == account and i.invisible == True and i.session != None: + return i - def get_last_buffer(self, account): - """ Gets the last valid buffer for an account. - account str: A twitter username. - The last valid buffer is the last buffer that contains a session object assigned.""" - results = self.get_buffers_for_account(account) - return results[-1] + def get_last_buffer(self, account): + """ Gets the last valid buffer for an account. + account str: A twitter username. + The last valid buffer is the last buffer that contains a session object assigned.""" + results = self.get_buffers_for_account(account) + return results[-1] - def get_first_buffer_index(self, account): - buff = self.get_first_buffer(account) - return self.view.search(buff.name, buff.account) + def get_first_buffer_index(self, account): + buff = self.get_first_buffer(account) + return self.view.search(buff.name, buff.account) - def get_last_buffer_index(self, account): - buff = self.get_last_buffer(account) - return self.view.search(buff.name, buff.account) + def get_last_buffer_index(self, account): + buff = self.get_last_buffer(account) + return self.view.search(buff.name, buff.account) - def get_buffers_for_account(self, account): - results = [] - buffers = self.view.get_buffers() - [results.append(self.search_buffer(i.name, i.account)) for i in buffers if i.account == account and (i.type != "account")] - return results + def get_buffers_for_account(self, account): + results = [] + buffers = self.view.get_buffers() + [results.append(self.search_buffer(i.name, i.account)) for i in buffers if i.account == account and (i.type != "account")] + return results - def bind_other_events(self): - """ Binds the local application events with their functions.""" - log.debug("Binding other application events...") - pub.subscribe(self.buffer_title_changed, "buffer-title-changed") - pub.subscribe(self.manage_sent_dm, "sent-dm") - widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit_) - pub.subscribe(self.logout_account, "logout") - pub.subscribe(self.login_account, "login") - pub.subscribe(self.create_new_buffer, "create-new-buffer") - pub.subscribe(self.execute_action, "execute-action") - pub.subscribe(self.search_topic, "search") - pub.subscribe(self.update_sent_dms, "sent-dms-updated") - pub.subscribe(self.more_dms, "more-sent-dms") - pub.subscribe(self.manage_sent_tweets, "sent-tweet") - pub.subscribe(self.manage_friend, "friend") - pub.subscribe(self.manage_unfollowing, "unfollowing") - pub.subscribe(self.manage_favourite, "favourite") - pub.subscribe(self.manage_unfavourite, "unfavourite") - pub.subscribe(self.manage_blocked_user, "blocked-user") - pub.subscribe(self.manage_unblocked_user, "unblocked-user") - if system == "Windows": - pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed") - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.search, menuitem=self.view.menuitem_search) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.list_manager, menuitem=self.view.lists) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_trending_topics, menuitem=self.view.trends) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.filter, menuitem=self.view.filter) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_filters, menuitem=self.view.manage_filters) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.find, menuitem=self.view.find) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.accountConfiguration, menuitem=self.view.account_settings) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.ocr_image, menuitem=self.view.ocr) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.learn_sounds, menuitem=self.view.sounds_tutorial) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.exit, menuitem=self.view.close) - widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit) - if widgetUtils.toolkit == "wx": - log.debug("Binding the exit function...") - widgetUtils.connectExitFunction(self.exit_) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.edit_keystrokes, menuitem=self.view.keystroke_editor) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_tweet, self.view.compose) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_reply, self.view.reply) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_retweet, self.view.retweet) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_favourites, self.view.fav) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_favourites, self.view.unfav) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_item, self.view.view) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.reverse_geocode, menuitem=self.view.view_coordinates) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.delete, self.view.delete) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.follow, menuitem=self.view.follow) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.send_dm, self.view.dm) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_user_lists, menuitem=self.view.viewLists) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_more_items, menuitem=self.view.load_previous_items) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_user_lists, menuitem=self.view.viewLists) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.clear_buffer, menuitem=self.view.clear) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_buffer, self.view.deleteTl) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.check_for_updates, self.view.check_for_updates) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.about, menuitem=self.view.about) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.visit_website, menuitem=self.view.visit_website) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_soundpacks, menuitem=self.view.get_soundpacks) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_accounts, self.view.manage_accounts) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_profile, menuitem=self.view.updateProfile) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.user_details, menuitem=self.view.details) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.toggle_autoread, menuitem=self.view.autoread) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.toggle_buffer_mute, self.view.mute_buffer) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_timeline, self.view.timeline) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_favs_timeline, self.view.favs) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_conversation, menuitem=self.view.view_conversation) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.seekLeft, menuitem=self.view.seekLeft) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.seekRight, menuitem=self.view.seekRight) - if widgetUtils.toolkit == "wx": - widgetUtils.connect_event(self.view.nb, widgetUtils.NOTEBOOK_PAGE_CHANGED, self.buffer_changed) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_documentation, self.view.doc) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_changelog, self.view.changelog) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_list, self.view.addToList) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_list, self.view.removeFromList) - widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_buffer, self.view.update_buffer) + def bind_other_events(self): + """ Binds the local application events with their functions.""" + log.debug("Binding other application events...") + pub.subscribe(self.buffer_title_changed, "buffer-title-changed") + pub.subscribe(self.manage_sent_dm, "sent-dm") + widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit_) + pub.subscribe(self.logout_account, "logout") + pub.subscribe(self.login_account, "login") + pub.subscribe(self.create_new_buffer, "create-new-buffer") + pub.subscribe(self.execute_action, "execute-action") + pub.subscribe(self.search_topic, "search") + pub.subscribe(self.update_sent_dms, "sent-dms-updated") + pub.subscribe(self.more_dms, "more-sent-dms") + pub.subscribe(self.manage_sent_tweets, "sent-tweet") + pub.subscribe(self.manage_friend, "friend") + pub.subscribe(self.manage_unfollowing, "unfollowing") + pub.subscribe(self.manage_favourite, "favourite") + pub.subscribe(self.manage_unfavourite, "unfavourite") + pub.subscribe(self.manage_blocked_user, "blocked-user") + pub.subscribe(self.manage_unblocked_user, "unblocked-user") + if system == "Windows": + pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed") + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.search, menuitem=self.view.menuitem_search) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.list_manager, menuitem=self.view.lists) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_trending_topics, menuitem=self.view.trends) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.filter, menuitem=self.view.filter) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_filters, menuitem=self.view.manage_filters) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.find, menuitem=self.view.find) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.accountConfiguration, menuitem=self.view.account_settings) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.ocr_image, menuitem=self.view.ocr) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.learn_sounds, menuitem=self.view.sounds_tutorial) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.exit, menuitem=self.view.close) + widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit) + if widgetUtils.toolkit == "wx": + log.debug("Binding the exit function...") + widgetUtils.connectExitFunction(self.exit_) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.edit_keystrokes, menuitem=self.view.keystroke_editor) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_tweet, self.view.compose) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_reply, self.view.reply) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_retweet, self.view.retweet) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_favourites, self.view.fav) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_favourites, self.view.unfav) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_item, self.view.view) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.reverse_geocode, menuitem=self.view.view_coordinates) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.delete, self.view.delete) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.follow, menuitem=self.view.follow) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.send_dm, self.view.dm) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_user_lists, menuitem=self.view.viewLists) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_more_items, menuitem=self.view.load_previous_items) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_user_lists, menuitem=self.view.viewLists) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.clear_buffer, menuitem=self.view.clear) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_buffer, self.view.deleteTl) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.check_for_updates, self.view.check_for_updates) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.about, menuitem=self.view.about) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.visit_website, menuitem=self.view.visit_website) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_soundpacks, menuitem=self.view.get_soundpacks) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_accounts, self.view.manage_accounts) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_profile, menuitem=self.view.updateProfile) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.user_details, menuitem=self.view.details) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.toggle_autoread, menuitem=self.view.autoread) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.toggle_buffer_mute, self.view.mute_buffer) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_timeline, self.view.timeline) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_favs_timeline, self.view.favs) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.open_conversation, menuitem=self.view.view_conversation) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.seekLeft, menuitem=self.view.seekLeft) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.seekRight, menuitem=self.view.seekRight) + if widgetUtils.toolkit == "wx": + widgetUtils.connect_event(self.view.nb, widgetUtils.NOTEBOOK_PAGE_CHANGED, self.buffer_changed) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_documentation, self.view.doc) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_changelog, self.view.changelog) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_list, self.view.addToList) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_list, self.view.removeFromList) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_buffer, self.view.update_buffer) - def set_systray_icon(self): - self.systrayIcon = sysTrayIcon.SysTrayIcon() - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.post_tweet, menuitem=self.systrayIcon.tweet) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.configuration, menuitem=self.systrayIcon.global_settings) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.accountConfiguration, menuitem=self.systrayIcon.account_settings) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.update_profile, menuitem=self.systrayIcon.update_profile) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.show_hide, menuitem=self.systrayIcon.show_hide) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.check_for_updates, menuitem=self.systrayIcon.check_for_updates) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.view_documentation, menuitem=self.systrayIcon.doc) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.exit, menuitem=self.systrayIcon.exit) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.TASKBAR_LEFT_CLICK, self.taskbar_left_click) - widgetUtils.connect_event(self.systrayIcon, widgetUtils.TASKBAR_RIGHT_CLICK, self.taskbar_right_click) + def set_systray_icon(self): + self.systrayIcon = sysTrayIcon.SysTrayIcon() + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.post_tweet, menuitem=self.systrayIcon.tweet) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.configuration, menuitem=self.systrayIcon.global_settings) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.accountConfiguration, menuitem=self.systrayIcon.account_settings) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.update_profile, menuitem=self.systrayIcon.update_profile) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.show_hide, menuitem=self.systrayIcon.show_hide) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.check_for_updates, menuitem=self.systrayIcon.check_for_updates) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.view_documentation, menuitem=self.systrayIcon.doc) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.MENU, self.exit, menuitem=self.systrayIcon.exit) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.TASKBAR_LEFT_CLICK, self.taskbar_left_click) + widgetUtils.connect_event(self.systrayIcon, widgetUtils.TASKBAR_RIGHT_CLICK, self.taskbar_right_click) - def taskbar_left_click(self, *args, **kwargs): - if self.showing == True: - self.view.set_focus() - else: - self.show_hide() + def taskbar_left_click(self, *args, **kwargs): + if self.showing == True: + self.view.set_focus() + else: + self.show_hide() - def taskbar_right_click(self, *args, **kwargs): - self.systrayIcon.show_menu() + def taskbar_right_click(self, *args, **kwargs): + self.systrayIcon.show_menu() - def __init__(self): - super(Controller, self).__init__() - # Visibility state. - self.showing = True - # main window - self.view = view.mainFrame() - # buffers list. - self.buffers = [] - self.started = False - # accounts list. - self.accounts = [] - # This saves the current account (important in invisible mode) - self.current_account = "" - self.view.prepare() - self.bind_other_events() - if system == "Windows": - self.set_systray_icon() + def __init__(self): + super(Controller, self).__init__() + # Visibility state. + self.showing = True + # main window + self.view = view.mainFrame() + # buffers list. + self.buffers = [] + self.started = False + # accounts list. + self.accounts = [] + # This saves the current account (important in invisible mode) + self.current_account = "" + self.view.prepare() + self.bind_other_events() + if system == "Windows": + self.set_systray_icon() - def check_invisible_at_startup(self): - # Visibility check. It does only work for windows. - if system != "Windows": return - if config.app["app-settings"]["hide_gui"] == True: - self.show_hide() - self.view.Show() - self.view.Hide() - # Invisible keyboard Shorcuts check. - if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == True: - km = self.create_invisible_keyboard_shorcuts() - self.register_invisible_keyboard_shorcuts(km) + def check_invisible_at_startup(self): + # Visibility check. It does only work for windows. + if system != "Windows": return + if config.app["app-settings"]["hide_gui"] == True: + self.show_hide() + self.view.Show() + self.view.Hide() + # Invisible keyboard Shorcuts check. + if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == True: + km = self.create_invisible_keyboard_shorcuts() + self.register_invisible_keyboard_shorcuts(km) - def do_work(self): - """ Creates the buffer objects for all accounts. This does not starts the buffer streams, only creates the objects.""" - log.debug("Creating buffers for all sessions...") - for i in sessions.sessions: - log.debug("Working on session %s" % (i,)) - if sessions.sessions[i].is_logged == False: - self.create_ignored_session_buffer(sessions.sessions[i]) - continue - self.create_buffers(sessions.sessions[i]) + def do_work(self): + """ Creates the buffer objects for all accounts. This does not starts the buffer streams, only creates the objects.""" + log.debug("Creating buffers for all sessions...") + for i in sessions.sessions: + log.debug("Working on session %s" % (i,)) + if sessions.sessions[i].is_logged == False: + self.create_ignored_session_buffer(sessions.sessions[i]) + continue + self.create_buffers(sessions.sessions[i]) - # Connection checker executed each minute. - self.checker_function = RepeatingTimer(60, self.check_connection) + # Connection checker executed each minute. + self.checker_function = RepeatingTimer(60, self.check_connection) # self.checker_function.start() - self.save_db = RepeatingTimer(300, self.save_data_in_db) - self.save_db.start() - log.debug("Setting updates to buffers every %d seconds..." % (60*config.app["app-settings"]["update_period"],)) - self.update_buffers_function = RepeatingTimer(60*config.app["app-settings"]["update_period"], self.update_buffers) - self.update_buffers_function.start() - - def start(self): - """ Starts all buffer objects. Loads their items.""" - for i in sessions.sessions: - if sessions.sessions[i].is_logged == False: continue - self.start_buffers(sessions.sessions[i]) - self.set_buffer_positions(sessions.sessions[i]) - if config.app["app-settings"]["play_ready_sound"] == True: - sessions.sessions[list(sessions.sessions.keys())[0]].sound.play("ready.ogg") - if config.app["app-settings"]["speak_ready_msg"] == True: - output.speak(_(u"Ready")) - self.started = True - - def create_ignored_session_buffer(self, session): - self.accounts.append(session.settings["twitter"]["user_name"]) - account = baseBuffers.accountPanel(self.view.nb, session.settings["twitter"]["user_name"], session.settings["twitter"]["user_name"], session.session_id) - account.logged = False - account.setup_account() - self.buffers.append(account) - self.view.add_buffer(account.buffer , name=session.settings["twitter"]["user_name"]) - - def login_account(self, session_id): - for i in sessions.sessions: - if sessions.sessions[i].session_id == session_id: session = sessions.sessions[i] - session.login() - session.db = dict() - self.create_buffers(session, False) - self.start_buffers(session) - - def create_buffers(self, session, createAccounts=True): - """ Generates buffer objects for an user account. - session SessionObject: a sessionmanager.session.Session Object""" - session.get_user_info() - if createAccounts == True: - self.accounts.append(session.db["user_name"]) - account = baseBuffers.accountPanel(self.view.nb, session.db["user_name"], session.db["user_name"], session.session_id) - account.setup_account() - self.buffers.append(account) - self.view.add_buffer(account.buffer , name=session.db["user_name"]) - for i in session.settings['general']['buffer_order']: - if i == 'home': - home = twitterBuffers.baseBufferController(self.view.nb, "home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended") - self.buffers.append(home) - self.view.insert_buffer(home.buffer, name=_(u"Home"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'mentions': - mentions = twitterBuffers.baseBufferController(self.view.nb, "mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended") - self.buffers.append(mentions) - self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'dm': - dm = twitterBuffers.directMessagesController(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg") - self.buffers.append(dm) - self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'sent_dm': - sent_dm = twitterBuffers.sentDirectMessagesController(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message") - self.buffers.append(sent_dm) - self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'sent_tweets': - sent_tweets = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended") - self.buffers.append(sent_tweets) - self.view.insert_buffer(sent_tweets.buffer, name=_(u"Sent tweets"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'favorites': - favourites = twitterBuffers.baseBufferController(self.view.nb, "favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended") - self.buffers.append(favourites) - self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'followers': - followers = twitterBuffers.peopleBufferController(self.view.nb, "followers", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"]) - self.buffers.append(followers) - self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'friends': - friends = twitterBuffers.peopleBufferController(self.view.nb, "friends", "friends", session, session.db["user_name"], screen_name=session.db["user_name"]) - self.buffers.append(friends) - self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'blocks': - blocks = twitterBuffers.peopleBufferController(self.view.nb, "blocks", "blocked", session, session.db["user_name"]) - self.buffers.append(blocks) - self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - elif i == 'muted': - muted = twitterBuffers.peopleBufferController(self.view.nb, "mutes", "muted", session, session.db["user_name"]) - self.buffers.append(muted) - self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - timelines = baseBuffers.emptyPanel(self.view.nb, "timelines", session.db["user_name"]) - self.buffers.append(timelines) - self.view.insert_buffer(timelines.buffer , name=_(u"Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - for i in session.settings["other_buffers"]["timelines"]: - tl = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended") - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(i,), pos=self.view.search("timelines", session.db["user_name"])) - favs_timelines = baseBuffers.emptyPanel(self.view.nb, "favs_timelines", session.db["user_name"]) - self.buffers.append(favs_timelines) - self.view.insert_buffer(favs_timelines.buffer , name=_(u"Likes timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - for i in session.settings["other_buffers"]["favourites_timelines"]: - tl = twitterBuffers.baseBufferController(self.view.nb, "favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended") - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Likes for {}").format(i,), pos=self.view.search("favs_timelines", session.db["user_name"])) - followers_timelines = baseBuffers.emptyPanel(self.view.nb, "followers_timelines", session.db["user_name"]) - self.buffers.append(followers_timelines) - self.view.insert_buffer(followers_timelines.buffer , name=_(u"Followers' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - for i in session.settings["other_buffers"]["followers_timelines"]: - tl = twitterBuffers.peopleBufferController(self.view.nb, "followers", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Followers for {}").format(i,), pos=self.view.search("followers_timelines", session.db["user_name"])) - friends_timelines = baseBuffers.emptyPanel(self.view.nb, "friends_timelines", session.db["user_name"]) - self.buffers.append(friends_timelines) - self.view.insert_buffer(friends_timelines.buffer , name=_(u"Friends' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - for i in session.settings["other_buffers"]["friends_timelines"]: - tl = twitterBuffers.peopleBufferController(self.view.nb, "friends", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Friends for {}").format(i,), pos=self.view.search("friends_timelines", session.db["user_name"])) - lists = baseBuffers.emptyPanel(self.view.nb, "lists", session.db["user_name"]) - self.buffers.append(lists) - self.view.insert_buffer(lists.buffer , name=_(u"Lists"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - for i in session.settings["other_buffers"]["lists"]: - tl = twitterBuffers.listBufferController(self.view.nb, "list_timeline", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended") - session.lists.append(tl) - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(i), pos=self.view.search("lists", session.db["user_name"])) - searches = baseBuffers.emptyPanel(self.view.nb, "searches", session.db["user_name"]) - self.buffers.append(searches) - self.view.insert_buffer(searches.buffer , name=_(u"Searches"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - for i in session.settings["other_buffers"]["tweet_searches"]: - tl = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended") - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Search for {}").format(i), pos=self.view.search("searches", session.db["user_name"])) - for i in session.settings["other_buffers"]["trending_topic_buffers"]: - buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg") - buffer.start_stream(play_sound=False) - buffer.searchfunction = self.search - self.buffers.append(buffer) - self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (buffer.name_), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - - def set_buffer_positions(self, session): - "Sets positions for buffers if values exist in the database." - for i in self.buffers: - if i.account == session.db["user_name"] and i.name+"_pos" in session.db and hasattr(i.buffer,'list'): - i.buffer.list.select_item(session.db[str(i.name+"_pos")]) - - def logout_account(self, session_id): - for i in sessions.sessions: - if sessions.sessions[i].session_id == session_id: session = sessions.sessions[i] - user = session.db["user_name"] - delete_buffers = [] - for i in self.buffers: - if i.account == user and i.name != user: - delete_buffers.append(i.name) - for i in delete_buffers: - self.destroy_buffer(i, user) - session.db = None - - def destroy_buffer(self, buffer_name, account): - buffer = self.search_buffer(buffer_name, account) - if buffer == None: return - buff = self.view.search(buffer.name, buffer.account) - if buff == None: return - self.view.delete_buffer(buff) - self.buffers.remove(buffer) - del buffer - - def search_topic(self, term): - self.search(value=term) - - def search(self, event=None, value="", *args, **kwargs): - """ Searches words or users in twitter. This creates a new buffer containing the search results.""" - log.debug("Creating a new search...") - dlg = dialogs.search.searchDialog(value) - if dlg.get_response() == widgetUtils.OK and dlg.get("term") != "": - term = dlg.get("term") - buffer = self.get_best_buffer() - if dlg.get("tweets") == True: - if term not in buffer.session.settings["other_buffers"]["tweet_searches"]: - buffer.session.settings["other_buffers"]["tweet_searches"].append(term) - buffer.session.settings.write() - args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()} - search = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args) - else: - log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) - return - elif dlg.get("users") == True: - search = twitterBuffers.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) - search.start_stream(mandatory=True) - pos=self.view.search("searches", buffer.session.db["user_name"]) - self.insert_buffer(search, pos) - self.view.insert_buffer(search.buffer, name=_(u"Search for {}").format(term), pos=pos) - dlg.Destroy() - - def find(self, *args, **kwargs): - if 'string' in kwargs: - string=kwargs['string'] - else: - string='' - dlg = dialogs.find.findDialog(string) - if dlg.get_response() == widgetUtils.OK and dlg.get("string") != "": - string = dlg.get("string") - #If we still have an empty string for some reason (I.E. user clicked cancel, etc), return here. - if string == '': - log.debug("Find canceled.") - return - page = self.get_current_buffer() - if not hasattr(page.buffer, "list"): - output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) - return - count = page.buffer.list.get_count() - if count < 1: - output.speak(_(u"Empty buffer."), True) - return - start = page.buffer.list.get_selected() - for i in range(start, count): - if string.lower() in page.buffer.list.get_text_column(i, 1).lower(): - page.buffer.list.select_item(i) - return output.speak(page.get_message(), True) - output.speak(_(u"{0} not found.").format(string,), True) - - def filter(self, *args, **kwargs): - page = self.get_current_buffer() - if not hasattr(page.buffer, "list"): - output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) - return - # Let's prevent filtering of some buffers (people buffers, direct messages, events and sent items). - # ToDo: Remove events from here after August 16. - if (page.name == "direct_messages" or page.name == "sent_tweets" or page.name == "events") or page.type == "people": - output.speak(_(u"Filters cannot be applied on this buffer")) - return - new_filter = filterController.filter(page) - - def manage_filters(self, *args, **kwargs): - page = self.get_best_buffer() - manage_filters = filterController.filterManager(page.session) - - def seekLeft(self, *args, **kwargs): - try: - sound.URLPlayer.seek(-5000) - except: - output.speak("Unable to seek.",True) - - def seekRight(self, *args, **kwargs): - try: - sound.URLPlayer.seek(5000) - except: - output.speak("Unable to seek.",True) - - def edit_keystrokes(self, *args, **kwargs): - editor = keystrokeEditor.KeystrokeEditor() - if editor.changed == True: - config.keymap.write() - register = False - # determines if we need to reassign the keymap. - if self.showing == False: - register = True - elif config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == True: - register = True - # If there is a keyboard handler instance we need unregister all old keystrokes before register the new ones. - if hasattr(self, "keyboard_handler"): - keymap = {} - for i in editor.hold_map: - if hasattr(self, i): keymap[editor.hold_map[i]] = getattr(self, i) - self.unregister_invisible_keyboard_shorcuts(keymap) - self.invisible_shorcuts_changed(registered=register) - - def learn_sounds(self, *args, **kwargs): - """ Opens the sounds tutorial for the current account.""" - buffer = self.get_best_buffer() - SoundsTutorial.soundsTutorial(buffer.session) - - def view_user_lists(self, *args, **kwargs): - buff = self.get_best_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) - if dlg.get_response() == widgetUtils.OK: - user = dlg.get_user() - else: - return - l = listsController.listsController(buff.session, user=user) - - def add_to_list(self, *args, **kwargs): - buff = self.get_best_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) - if dlg.get_response() == widgetUtils.OK: - user = dlg.get_user() - else: - return - dlg = dialogs.lists.addUserListDialog() - dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]]) - if dlg.get_response() == widgetUtils.OK: - try: - list = buff.session.twitter.add_list_member(list_id=buff.session.db["lists"][dlg.get_item()].id, screen_name=user) - older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()].id, buff.session.db["lists"]) - listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()].name.lower()), buff.session.db["user_name"]) - if listBuffer != None: listBuffer.get_user_ids() - buff.session.db["lists"].pop(older_list) - buff.session.db["lists"].append(list) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) - - def remove_from_list(self, *args, **kwargs): - buff = self.get_best_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) - if dlg.get_response() == widgetUtils.OK: - user = dlg.get_user() - else: - return - dlg = dialogs.lists.removeUserListDialog() - dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]]) - if dlg.get_response() == widgetUtils.OK: - try: - list = buff.session.twitter.remove_list_member(list_id=buff.session.db["lists"][dlg.get_item()].id, screen_name=user) - older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()].id, buff.session.db["lists"]) - listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()].name.lower()), buff.session.db["user_name"]) - if listBuffer != None: listBuffer.get_user_ids() - buff.session.db["lists"].pop(older_list) - buff.session.db["lists"].append(list) - except TweepError as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) - - def list_manager(self, *args, **kwargs): - s = self.get_best_buffer().session - l = listsController.listsController(s) - - def configuration(self, *args, **kwargs): - """ Opens the global settings dialogue.""" - d = settings.globalSettingsController() - if d.response == widgetUtils.OK: - d.save_configuration() - if d.needs_restart == True: - commonMessageDialogs.needs_restart() - restart.restart_program() - - def accountConfiguration(self, *args, **kwargs): - """ Opens the account settings dialogue for the current account.""" - buff = self.get_best_buffer() - manager.manager.set_current_session(buff.session.session_id) - d = settings.accountSettingsController(buff, self) - if d.response == widgetUtils.OK: - d.save_configuration() - if d.needs_restart == True: - commonMessageDialogs.needs_restart() - buff.session.settings.write() - restart.restart_program() - - def report_error(self, *args, **kwargs): - r = issueReporter.reportBug(self.get_best_buffer().session.db["user_name"]) - - def check_for_updates(self, *args, **kwargs): - update = updater.do_update() - if update == False: - view.no_update_available() - - def delete(self, *args, **kwargs): - """ Deletes an item in the current buffer. - Users can only remove their tweets and direct messages, other users' tweets and people (followers, friends, blocked, etc) can not be removed using this method.""" - buffer = self.view.get_current_buffer() - if hasattr(buffer, "account"): - buffer = self.search_buffer(buffer.name, buffer.account) - buffer.destroy_status() - - def exit(self, *args, **kwargs): - if config.app["app-settings"]["ask_at_exit"] == True: - answer = commonMessageDialogs.exit_dialog(self.view) - if answer == widgetUtils.YES: - self.exit_() - else: - self.exit_() - - def exit_(self, *args, **kwargs): - for i in self.buffers: i.save_positions() - log.debug("Exiting...") - log.debug("Saving global configuration...") - for item in sessions.sessions: - if sessions.sessions[item].logged == False: continue - log.debug("Disconnecting streams for %s session" % (sessions.sessions[item].session_id,)) - sessions.sessions[item].sound.cleaner.cancel() - log.debug("Shelving database for " + sessions.sessions[item].session_id) - sessions.sessions[item].shelve() - if system == "Windows": - self.systrayIcon.RemoveIcon() - pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) - if os.path.exists(pidpath): - os.remove(pidpath) - widgetUtils.exit_application() - - def follow(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users) - - def unfollow(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users, "unfollow") - - def mute(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users, "mute") - - def unmute(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users, "unmute") - - def block(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users, "block") - - def unblock(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users, "unblock") - - def report(self, *args, **kwargs): - buff = self.get_current_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - u = userActionsController.userActionsController(buff, users, "report") - - def post_tweet(self, event=None): - buffer = self.get_best_buffer() - buffer.post_status() - - def post_reply(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.name == "direct_messages": - buffer.send_message() - else: - buffer.reply() - - def send_dm(self, *args, **kwargs): - buffer = self.get_current_buffer() - buffer.send_message() - - def post_retweet(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": - return - else: - buffer.share_item() - - def add_to_favourites(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": - return - else: - id = buffer.get_tweet().id - call_threaded(buffer.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id) - - def remove_from_favourites(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": - return - else: - id = buffer.get_tweet().id - call_threaded(buffer.session.api_call, call_name="destroy_favorite", id=id) - - def toggle_like(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": - return - else: - id = buffer.get_tweet().id - tweet = buffer.session.twitter.get_status(id=id, include_ext_alt_text=True, tweet_mode="extended") - if tweet.favorited == False: - call_threaded(buffer.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id) - else: - call_threaded(buffer.session.api_call, call_name="destroy_favorite", id=id) - - def view_item(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.type == "account" or buffer.type == "empty": - return - elif buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search": - tweet, tweetsList = buffer.get_full_tweet() - msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"]) - elif buffer.type == "dm": - non_tweet = buffer.get_formatted_message() - item = buffer.get_right_tweet() - original_date = arrow.get(int(item.created_timestamp)) - date = original_date.shift(seconds=buffer.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage()) - msg = messages.viewTweet(non_tweet, [], False, date=date) - else: - non_tweet = buffer.get_formatted_message() - msg = messages.viewTweet(non_tweet, [], False) - - def open_in_browser(self, *args, **kwargs): - buffer = self.get_current_buffer() - if hasattr(buffer, "open_in_browser"): - buffer.open_in_browser() - - def open_favs_timeline(self, *args, **kwargs): - self.open_timeline(default="favourites") - - def open_timeline(self, default="tweets", *args, **kwargs): - buff = self.get_best_buffer() - if not hasattr(buff, "get_right_tweet"): return - tweet = buff.get_right_tweet() - if buff.type == "people": - users = [tweet.screen_name] - elif buff.type == "dm": - users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] - else: - users = utils.get_all_users(tweet, buff.session.db) - dlg = dialogs.userSelection.selectUserDialog(users=users, default=default) - if dlg.get_response() == widgetUtils.OK: - usr = utils.if_user_exists(buff.session.twitter, dlg.get_user()) - if usr != None: - if usr == dlg.get_user(): - commonMessageDialogs.suspended_user() - return - if usr.protected == True: - if usr.following == False: - commonMessageDialogs.no_following() - return - tl_type = dlg.get_action() - if tl_type == "tweets": - if usr.statuses_count == 0: - commonMessageDialogs.no_tweets() - return - if usr.id_str in buff.session.settings["other_buffers"]["timelines"]: - commonMessageDialogs.timeline_exist() - return - tl = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "%s-timeline" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="tweet_timeline.ogg", user_id=usr.id_str, tweet_mode="extended") - try: - tl.start_stream(play_sound=False) - except ValueError: - commonMessageDialogs.unauthorized() - return - pos=self.view.search("timelines", buff.session.db["user_name"]) - self.insert_buffer(tl, pos+1) - self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(dlg.get_user()), pos=pos) - buff.session.settings["other_buffers"]["timelines"].append(usr.id_str) - pub.sendMessage("buffer-title-changed", buffer=tl) - buff.session.sound.play("create_timeline.ogg") - elif tl_type == "favourites": - if usr.favourites_count == 0: - commonMessageDialogs.no_favs() - return - if usr.id_str in buff.session.settings["other_buffers"]["favourites_timelines"]: - commonMessageDialogs.timeline_exist() - return - tl = twitterBuffers.baseBufferController(self.view.nb, "favorites", "%s-favorite" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, tweet_mode="extended") - try: - tl.start_stream(play_sound=False) - except ValueError: - commonMessageDialogs.unauthorized() - return - pos=self.view.search("favs_timelines", buff.session.db["user_name"]) - self.insert_buffer(tl, pos+1) - self.view.insert_buffer(buffer=tl.buffer, name=_(u"Likes for {}").format(dlg.get_user()), pos=pos) - buff.session.settings["other_buffers"]["favourites_timelines"].append(usr.id_str) - pub.sendMessage("buffer-title-changed", buffer=buff) - buff.session.sound.play("create_timeline.ogg") - elif tl_type == "followers": - if usr.followers_count == 0: - commonMessageDialogs.no_followers() - return - if usr.id_str in buff.session.settings["other_buffers"]["followers_timelines"]: - commonMessageDialogs.timeline_exist() - return - tl = twitterBuffers.peopleBufferController(self.view.nb, "followers", "%s-followers" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) - try: - tl.start_stream(play_sound=False) - except ValueError: - commonMessageDialogs.unauthorized() - return - pos=self.view.search("followers_timelines", buff.session.db["user_name"]) - self.insert_buffer(tl, pos+1) - self.view.insert_buffer(buffer=tl.buffer, name=_(u"Followers for {}").format(dlg.get_user()), pos=pos) - buff.session.settings["other_buffers"]["followers_timelines"].append(usr.id_str) - buff.session.sound.play("create_timeline.ogg") - pub.sendMessage("buffer-title-changed", buffer=i) - elif tl_type == "friends": - if usr.friends_count == 0: - commonMessageDialogs.no_friends() - return - if usr.id_str in buff.session.settings["other_buffers"]["friends_timelines"]: - commonMessageDialogs.timeline_exist() - return - tl = twitterBuffers.peopleBufferController(self.view.nb, "friends", "%s-friends" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) - try: - tl.start_stream(play_sound=False) - except ValueError: - commonMessageDialogs.unauthorized() - return - pos=self.view.search("friends_timelines", buff.session.db["user_name"]) - self.insert_buffer(tl, pos+1) - self.view.insert_buffer(buffer=tl.buffer, name=_(u"Friends for {}").format(dlg.get_user()), pos=pos) - buff.session.settings["other_buffers"]["friends_timelines"].append(usr.id_str) - buff.session.sound.play("create_timeline.ogg") - pub.sendMessage("buffer-title-changed", buffer=i) - else: - commonMessageDialogs.user_not_exist() - buff.session.settings.write() - - def open_conversation(self, *args, **kwargs): - buffer = self.get_current_buffer() - id = buffer.get_right_tweet().id_str - user = buffer.get_right_tweet().user.screen_name - search = twitterBuffers.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) - search.tweet = buffer.get_right_tweet() - search.start_stream(start=True) - pos=self.view.search("searches", buffer.session.db["user_name"]) - self.insert_buffer(search, pos) - self.view.insert_buffer(search.buffer, name=_(u"Conversation with {0}").format(user), pos=pos) - - def show_hide(self, *args, **kwargs): - km = self.create_invisible_keyboard_shorcuts() - if self.showing == True: - if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == False: - self.register_invisible_keyboard_shorcuts(km) - self.view.Hide() - self.fix_wrong_buffer() - self.showing = False - else: - if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == False: - self.unregister_invisible_keyboard_shorcuts(km) - self.view.Show() - self.showing = True - - def get_trending_topics(self, *args, **kwargs): - buff = self.get_best_buffer() - trends = trendingTopics.trendingTopicsController(buff.session) - if trends.dialog.get_response() == widgetUtils.OK: - woeid = trends.get_woeid() - if woeid in buff.session.settings["other_buffers"]["trending_topic_buffers"]: return - buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (woeid,), buff.session, buff.account, woeid, sound="trends_updated.ogg") - buffer.searchfunction = self.search - pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]) - self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (trends.get_string()), pos=pos) - self.buffers.append(buffer) - buffer.start_stream() - buffer.session.settings["other_buffers"]["trending_topic_buffers"].append(woeid) - buffer.session.settings.write() - - def reverse_geocode(self, event=None): - try: - tweet = self.get_current_buffer().get_tweet() - if tweet.coordinates != None: - x = tweet.coordinates["coordinates"][0] - y = tweet.coordinates["coordinates"][1] - address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang) - if event == None: output.speak(address[0].__str__()) - else: self.view.show_address(address[0].__str__()) - else: - output.speak(_(u"There are no coordinates in this tweet")) - except GeocoderError: - output.speak(_(u"There are no results for the coordinates in this tweet")) - except ValueError: - output.speak(_(u"Error decoding coordinates. Try again later.")) - except KeyError: - pass - except AttributeError: - pass - - def view_reverse_geocode(self, event=None): - try: - tweet = self.get_current_buffer().get_right_tweet() - if tweet.coordinates != None: - x = tweet.coordinates["coordinates"][0] - y = tweet.coordinates["coordinates"][1] - address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang) - dlg = commonMessageDialogs.view_geodata(address[0].__str__()) - else: - output.speak(_(u"There are no coordinates in this tweet")) - except GeocoderError: - output.speak(_(u"There are no results for the coordinates in this tweet")) - except ValueError: - output.speak(_(u"Error decoding coordinates. Try again later.")) - except KeyError: - pass - except AttributeError: - pass - - def get_more_items(self, *args, **kwargs): - self.get_current_buffer().get_more_items() - - def clear_buffer(self, *args, **kwargs): - self.get_current_buffer().clear_list() - - def remove_buffer(self, *args, **kwargs): - buffer = self.get_current_buffer() - if not hasattr(buffer, "account"): return - buff = self.view.search(buffer.name, buffer.account) - answer = buffer.remove_buffer() - if answer == False: return - log.debug("destroying buffer...") - if hasattr(buffer, "timer"): - log.debug("Stopping timer...") - buffer.timer.cancel() - log.debug("Timer cancelled.") - self.right() - self.view.delete_buffer(buff) - buffer.session.sound.play("delete_timeline.ogg") - self.buffers.remove(buffer) - del buffer - - def skip_buffer(self, forward=True): - buff = self.get_current_buffer() - if buff.invisible == False: - self.view.advance_selection(forward) - - def buffer_changed(self, *args, **kwargs): - buffer = self.get_current_buffer() - if buffer.account != self.current_account: - self.current_account = buffer.account - if not hasattr(buffer, "session") or buffer.session == None: return - muted = autoread = False - if buffer.name in buffer.session.settings["other_buffers"]["muted_buffers"]: - muted = True - elif buffer.name in buffer.session.settings["other_buffers"]["autoread_buffers"]: - autoread = True - self.view.check_menuitem("mute_buffer", muted) - self.view.check_menuitem("autoread", autoread) - - def fix_wrong_buffer(self): - buf = self.get_best_buffer() - if buf == None: - for i in self.accounts: - buffer = self.view.search("home_timeline", i) - if buffer != None: break - else: - buffer = self.view.search("home_timeline", buf.session.db["user_name"]) - if buffer!=None: - self.view.change_buffer(buffer) - - def up(self, *args, **kwargs): - page = self.get_current_buffer() - if not hasattr(page.buffer, "list"): - output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) - return - position = page.buffer.list.get_selected() - index = position-1 - try: - page.buffer.list.select_item(index) - except: - pass - if position == page.buffer.list.get_selected(): - page.session.sound.play("limit.ogg") - - try: - output.speak(page.get_message(), True) - except: - pass - - def down(self, *args, **kwargs): - page = self.get_current_buffer() - if not hasattr(page.buffer, "list"): - output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) - return - position = page.buffer.list.get_selected() - index = position+1 - try: - page.buffer.list.select_item(index) - except: - pass - if position == page.buffer.list.get_selected(): - page.session.sound.play("limit.ogg") - try: - output.speak(page.get_message(), True) - except: - pass - - def left(self, *args, **kwargs): - buff = self.view.get_current_buffer_pos() - buffer = self.get_current_buffer() - if not hasattr(buffer.buffer, "list"): - output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) - return - if buff == self.get_first_buffer_index(buffer.account) or buff == 0: - self.view.change_buffer(self.get_last_buffer_index(buffer.account)) - else: - self.view.change_buffer(buff-1) - while self.get_current_buffer().invisible == False: self.skip_buffer(False) - buffer = self.get_current_buffer() - if self.showing == True: buffer.buffer.set_focus_in_list() - try: - msg = _(u"%s, %s of %s") % (self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) - except: - msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) - output.speak(msg, True) - - def right(self, *args, **kwargs): - buff = self.view.get_current_buffer_pos() - buffer = self.get_current_buffer() - if not hasattr(buffer.buffer, "list"): - output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) - return - if buff == self.get_last_buffer_index(buffer.account) or buff+1 == self.view.get_buffer_count(): - self.view.change_buffer(self.get_first_buffer_index(buffer.account)) - else: - self.view.change_buffer(buff+1) - while self.get_current_buffer().invisible == False: self.skip_buffer(True) - buffer = self.get_current_buffer() - if self.showing == True: buffer.buffer.set_focus_in_list() - try: - msg = _(u"%s, %s of %s") % (self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) - except: - msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) - output.speak(msg, True) - - def next_account(self, *args, **kwargs): - index = self.accounts.index(self.current_account) - if index+1 == len(self.accounts): - index = 0 - else: - index = index+1 - account = self.accounts[index] - self.current_account = account - buffer_object = self.get_first_buffer(account) - if buffer_object == None: - output.speak(_(u"{0}: This account is not logged into Twitter.").format(account), True) - return - buff = self.view.search(buffer_object.name, account) - if buff == None: - output.speak(_(u"{0}: This account is not logged into Twitter.").format(account), True) - return - self.view.change_buffer(buff) - buffer = self.get_current_buffer() - if self.showing == True: buffer.buffer.set_focus_in_list() - try: - msg = _(u"%s. %s, %s of %s") % (buffer.account, self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) - except: - msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) - output.speak(msg, True) - - def previous_account(self, *args, **kwargs): - index = self.accounts.index(self.current_account) - if index-1 < 0: - index = len(self.accounts)-1 - else: - index = index-1 - account = self.accounts[index] - self.current_account = account - buffer_object = self.get_first_buffer(account) - if buffer_object == None: - output.speak(_(u"{0}: This account is not logged into Twitter.").format(account), True) - return - buff = self.view.search(buffer_object.name, account) - if buff == None: - output.speak(_(u"{0}: This account is not logged into twitter.").format(account), True) - return - self.view.change_buffer(buff) - buffer = self.get_current_buffer() - if self.showing == True: buffer.buffer.set_focus_in_list() - try: - msg = _(u"%s. %s, %s of %s") % (buffer.account, self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) - except: - msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) - output.speak(msg, True) - - def go_home(self): - buffer = self.get_current_buffer() - buffer.buffer.list.select_item(0) - try: - output.speak(buffer.get_message(), True) - except: - pass - - def go_end(self): - buffer = self.get_current_buffer() - buffer.buffer.list.select_item(buffer.buffer.list.get_count()-1) - try: - output.speak(buffer.get_message(), True) - except: - pass - - def go_page_up(self): - buffer = self.get_current_buffer() - if buffer.buffer.list.get_selected() <= 20: - index = 0 - else: - index = buffer.buffer.list.get_selected() - 20 - buffer.buffer.list.select_item(index) - try: - output.speak(buffer.get_message(), True) - except: - pass - - def go_page_down(self): - buffer = self.get_current_buffer() - if buffer.buffer.list.get_selected() >= buffer.buffer.list.get_count() - 20: - index = buffer.buffer.list.get_count()-1 - else: - index = buffer.buffer.list.get_selected() + 20 - buffer.buffer.list.select_item(index) - try: - output.speak(buffer.get_message(), True) - except: - pass - - def url(self, *args, **kwargs): - buffer = self.get_current_buffer() - buffer.url() - - def audio(self, *args, **kwargs): - self.get_current_buffer().audio() - - def volume_down(self, *args, **kwargs): - self.get_current_buffer().volume_down() - - def volume_up(self, *args, **kwargs): - self.get_current_buffer().volume_up() - - def create_invisible_keyboard_shorcuts(self): - keymap = {} - for i in config.keymap["keymap"]: - if hasattr(self, i): - keymap[config.keymap["keymap"][i]] = getattr(self, i) - return keymap - - def register_invisible_keyboard_shorcuts(self, keymap): - if config.changed_keymap: - commonMessageDialogs.changed_keymap() - self.keyboard_handler = WXKeyboardHandler(self.view) - self.keyboard_handler.register_keys(keymap) - - def unregister_invisible_keyboard_shorcuts(self, keymap): - try: - self.keyboard_handler.unregister_keys(keymap) - del self.keyboard_handler - except AttributeError: - pass - - def notify(self, session, play_sound=None, message=None, notification=False): - if session.settings["sound"]["session_mute"] == True: return - if play_sound != None: - session.sound.play(play_sound) - if message != None: - output.speak(message, speech=session.settings["reporting"]["speech_reporting"], braille=session.settings["reporting"]["braille_reporting"]) - - def manage_sent_dm(self, data, user): - buffer = self.search_buffer("sent_direct_messages", user) - if buffer == None: return - play_sound = "dm_sent.ogg" - if "sent_direct_messages" not in buffer.session.settings["other_buffers"]["muted_buffers"]: - self.notify(buffer.session, play_sound=play_sound) - buffer.add_new_item(data) - - def manage_sent_tweets(self, data, user): - buffer = self.search_buffer("sent_tweets", user) - if buffer == None: return + self.save_db = RepeatingTimer(300, self.save_data_in_db) + self.save_db.start() + log.debug("Setting updates to buffers every %d seconds..." % (60*config.app["app-settings"]["update_period"],)) + self.update_buffers_function = RepeatingTimer(60*config.app["app-settings"]["update_period"], self.update_buffers) + self.update_buffers_function.start() + + def start(self): + """ Starts all buffer objects. Loads their items.""" + for i in sessions.sessions: + if sessions.sessions[i].is_logged == False: continue + self.start_buffers(sessions.sessions[i]) + self.set_buffer_positions(sessions.sessions[i]) + if config.app["app-settings"]["play_ready_sound"] == True: + sessions.sessions[list(sessions.sessions.keys())[0]].sound.play("ready.ogg") + if config.app["app-settings"]["speak_ready_msg"] == True: + output.speak(_(u"Ready")) + self.started = True + + def create_ignored_session_buffer(self, session): + self.accounts.append(session.settings["twitter"]["user_name"]) + account = baseBuffers.accountPanel(self.view.nb, session.settings["twitter"]["user_name"], session.settings["twitter"]["user_name"], session.session_id) + account.logged = False + account.setup_account() + self.buffers.append(account) + self.view.add_buffer(account.buffer , name=session.settings["twitter"]["user_name"]) + + def login_account(self, session_id): + for i in sessions.sessions: + if sessions.sessions[i].session_id == session_id: session = sessions.sessions[i] + session.login() + session.db = dict() + self.create_buffers(session, False) + self.start_buffers(session) + + def create_buffers(self, session, createAccounts=True): + """ Generates buffer objects for an user account. + session SessionObject: a sessionmanager.session.Session Object""" + session.get_user_info() + if createAccounts == True: + self.accounts.append(session.db["user_name"]) + account = baseBuffers.accountPanel(self.view.nb, session.db["user_name"], session.db["user_name"], session.session_id) + account.setup_account() + self.buffers.append(account) + self.view.add_buffer(account.buffer , name=session.db["user_name"]) + for i in session.settings['general']['buffer_order']: + if i == 'home': + home = twitterBuffers.baseBufferController(self.view.nb, "home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended") + self.buffers.append(home) + self.view.insert_buffer(home.buffer, name=_(u"Home"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'mentions': + mentions = twitterBuffers.baseBufferController(self.view.nb, "mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended") + self.buffers.append(mentions) + self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'dm': + dm = twitterBuffers.directMessagesController(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg") + self.buffers.append(dm) + self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'sent_dm': + sent_dm = twitterBuffers.sentDirectMessagesController(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message") + self.buffers.append(sent_dm) + self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'sent_tweets': + sent_tweets = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended") + self.buffers.append(sent_tweets) + self.view.insert_buffer(sent_tweets.buffer, name=_(u"Sent tweets"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'favorites': + favourites = twitterBuffers.baseBufferController(self.view.nb, "favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended") + self.buffers.append(favourites) + self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'followers': + followers = twitterBuffers.peopleBufferController(self.view.nb, "followers", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"]) + self.buffers.append(followers) + self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'friends': + friends = twitterBuffers.peopleBufferController(self.view.nb, "friends", "friends", session, session.db["user_name"], screen_name=session.db["user_name"]) + self.buffers.append(friends) + self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'blocks': + blocks = twitterBuffers.peopleBufferController(self.view.nb, "blocks", "blocked", session, session.db["user_name"]) + self.buffers.append(blocks) + self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + elif i == 'muted': + muted = twitterBuffers.peopleBufferController(self.view.nb, "mutes", "muted", session, session.db["user_name"]) + self.buffers.append(muted) + self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + timelines = baseBuffers.emptyPanel(self.view.nb, "timelines", session.db["user_name"]) + self.buffers.append(timelines) + self.view.insert_buffer(timelines.buffer , name=_(u"Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["timelines"]: + tl = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended") + self.buffers.append(tl) + self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(i,), pos=self.view.search("timelines", session.db["user_name"])) + favs_timelines = baseBuffers.emptyPanel(self.view.nb, "favs_timelines", session.db["user_name"]) + self.buffers.append(favs_timelines) + self.view.insert_buffer(favs_timelines.buffer , name=_(u"Likes timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["favourites_timelines"]: + tl = twitterBuffers.baseBufferController(self.view.nb, "favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended") + self.buffers.append(tl) + self.view.insert_buffer(tl.buffer, name=_(u"Likes for {}").format(i,), pos=self.view.search("favs_timelines", session.db["user_name"])) + followers_timelines = baseBuffers.emptyPanel(self.view.nb, "followers_timelines", session.db["user_name"]) + self.buffers.append(followers_timelines) + self.view.insert_buffer(followers_timelines.buffer , name=_(u"Followers' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["followers_timelines"]: + tl = twitterBuffers.peopleBufferController(self.view.nb, "followers", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) + self.buffers.append(tl) + self.view.insert_buffer(tl.buffer, name=_(u"Followers for {}").format(i,), pos=self.view.search("followers_timelines", session.db["user_name"])) + friends_timelines = baseBuffers.emptyPanel(self.view.nb, "friends_timelines", session.db["user_name"]) + self.buffers.append(friends_timelines) + self.view.insert_buffer(friends_timelines.buffer , name=_(u"Friends' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["friends_timelines"]: + tl = twitterBuffers.peopleBufferController(self.view.nb, "friends", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) + self.buffers.append(tl) + self.view.insert_buffer(tl.buffer, name=_(u"Friends for {}").format(i,), pos=self.view.search("friends_timelines", session.db["user_name"])) + lists = baseBuffers.emptyPanel(self.view.nb, "lists", session.db["user_name"]) + self.buffers.append(lists) + self.view.insert_buffer(lists.buffer , name=_(u"Lists"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["lists"]: + tl = twitterBuffers.listBufferController(self.view.nb, "list_timeline", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended") + session.lists.append(tl) + self.buffers.append(tl) + self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(i), pos=self.view.search("lists", session.db["user_name"])) + searches = baseBuffers.emptyPanel(self.view.nb, "searches", session.db["user_name"]) + self.buffers.append(searches) + self.view.insert_buffer(searches.buffer , name=_(u"Searches"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + for i in session.settings["other_buffers"]["tweet_searches"]: + tl = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended") + self.buffers.append(tl) + self.view.insert_buffer(tl.buffer, name=_(u"Search for {}").format(i), pos=self.view.search("searches", session.db["user_name"])) + for i in session.settings["other_buffers"]["trending_topic_buffers"]: + buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg") + buffer.start_stream(play_sound=False) + buffer.searchfunction = self.search + self.buffers.append(buffer) + self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (buffer.name_), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + + def set_buffer_positions(self, session): + "Sets positions for buffers if values exist in the database." + for i in self.buffers: + if i.account == session.db["user_name"] and i.name+"_pos" in session.db and hasattr(i.buffer,'list'): + i.buffer.list.select_item(session.db[str(i.name+"_pos")]) + + def logout_account(self, session_id): + for i in sessions.sessions: + if sessions.sessions[i].session_id == session_id: session = sessions.sessions[i] + user = session.db["user_name"] + delete_buffers = [] + for i in self.buffers: + if i.account == user and i.name != user: + delete_buffers.append(i.name) + for i in delete_buffers: + self.destroy_buffer(i, user) + session.db = None + + def destroy_buffer(self, buffer_name, account): + buffer = self.search_buffer(buffer_name, account) + if buffer == None: return + buff = self.view.search(buffer.name, buffer.account) + if buff == None: return + self.view.delete_buffer(buff) + self.buffers.remove(buffer) + del buffer + + def search_topic(self, term): + self.search(value=term) + + def search(self, event=None, value="", *args, **kwargs): + """ Searches words or users in twitter. This creates a new buffer containing the search results.""" + log.debug("Creating a new search...") + dlg = dialogs.search.searchDialog(value) + if dlg.get_response() == widgetUtils.OK and dlg.get("term") != "": + term = dlg.get("term") + buffer = self.get_best_buffer() + if dlg.get("tweets") == True: + if term not in buffer.session.settings["other_buffers"]["tweet_searches"]: + buffer.session.settings["other_buffers"]["tweet_searches"].append(term) + buffer.session.settings.write() + args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()} + search = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args) + else: + log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) + return + elif dlg.get("users") == True: + search = twitterBuffers.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) + search.start_stream(mandatory=True) + pos=self.view.search("searches", buffer.session.db["user_name"]) + self.insert_buffer(search, pos) + self.view.insert_buffer(search.buffer, name=_(u"Search for {}").format(term), pos=pos) + dlg.Destroy() + + def find(self, *args, **kwargs): + if 'string' in kwargs: + string=kwargs['string'] + else: + string='' + dlg = dialogs.find.findDialog(string) + if dlg.get_response() == widgetUtils.OK and dlg.get("string") != "": + string = dlg.get("string") + #If we still have an empty string for some reason (I.E. user clicked cancel, etc), return here. + if string == '': + log.debug("Find canceled.") + return + page = self.get_current_buffer() + if not hasattr(page.buffer, "list"): + output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) + return + count = page.buffer.list.get_count() + if count < 1: + output.speak(_(u"Empty buffer."), True) + return + start = page.buffer.list.get_selected() + for i in range(start, count): + if string.lower() in page.buffer.list.get_text_column(i, 1).lower(): + page.buffer.list.select_item(i) + return output.speak(page.get_message(), True) + output.speak(_(u"{0} not found.").format(string,), True) + + def filter(self, *args, **kwargs): + page = self.get_current_buffer() + if not hasattr(page.buffer, "list"): + output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) + return + # Let's prevent filtering of some buffers (people buffers, direct messages, events and sent items). + # ToDo: Remove events from here after August 16. + if (page.name == "direct_messages" or page.name == "sent_tweets" or page.name == "events") or page.type == "people": + output.speak(_(u"Filters cannot be applied on this buffer")) + return + new_filter = filterController.filter(page) + + def manage_filters(self, *args, **kwargs): + page = self.get_best_buffer() + manage_filters = filterController.filterManager(page.session) + + def seekLeft(self, *args, **kwargs): + try: + sound.URLPlayer.seek(-5000) + except: + output.speak("Unable to seek.",True) + + def seekRight(self, *args, **kwargs): + try: + sound.URLPlayer.seek(5000) + except: + output.speak("Unable to seek.",True) + + def edit_keystrokes(self, *args, **kwargs): + editor = keystrokeEditor.KeystrokeEditor() + if editor.changed == True: + config.keymap.write() + register = False + # determines if we need to reassign the keymap. + if self.showing == False: + register = True + elif config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == True: + register = True + # If there is a keyboard handler instance we need unregister all old keystrokes before register the new ones. + if hasattr(self, "keyboard_handler"): + keymap = {} + for i in editor.hold_map: + if hasattr(self, i): keymap[editor.hold_map[i]] = getattr(self, i) + self.unregister_invisible_keyboard_shorcuts(keymap) + self.invisible_shorcuts_changed(registered=register) + + def learn_sounds(self, *args, **kwargs): + """ Opens the sounds tutorial for the current account.""" + buffer = self.get_best_buffer() + SoundsTutorial.soundsTutorial(buffer.session) + + def view_user_lists(self, *args, **kwargs): + buff = self.get_best_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) + if dlg.get_response() == widgetUtils.OK: + user = dlg.get_user() + else: + return + l = listsController.listsController(buff.session, user=user) + + def add_to_list(self, *args, **kwargs): + buff = self.get_best_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) + if dlg.get_response() == widgetUtils.OK: + user = dlg.get_user() + else: + return + dlg = dialogs.lists.addUserListDialog() + dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]]) + if dlg.get_response() == widgetUtils.OK: + try: + list = buff.session.twitter.add_list_member(list_id=buff.session.db["lists"][dlg.get_item()].id, screen_name=user) + older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()].id, buff.session.db["lists"]) + listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()].name.lower()), buff.session.db["user_name"]) + if listBuffer != None: listBuffer.get_user_ids() + buff.session.db["lists"].pop(older_list) + buff.session.db["lists"].append(list) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) + + def remove_from_list(self, *args, **kwargs): + buff = self.get_best_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) + if dlg.get_response() == widgetUtils.OK: + user = dlg.get_user() + else: + return + dlg = dialogs.lists.removeUserListDialog() + dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]]) + if dlg.get_response() == widgetUtils.OK: + try: + list = buff.session.twitter.remove_list_member(list_id=buff.session.db["lists"][dlg.get_item()].id, screen_name=user) + older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()].id, buff.session.db["lists"]) + listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()].name.lower()), buff.session.db["user_name"]) + if listBuffer != None: listBuffer.get_user_ids() + buff.session.db["lists"].pop(older_list) + buff.session.db["lists"].append(list) + except TweepError as e: + output.speak("error %s: %s" % (e.api_code, e.reason)) + + def list_manager(self, *args, **kwargs): + s = self.get_best_buffer().session + l = listsController.listsController(s) + + def configuration(self, *args, **kwargs): + """ Opens the global settings dialogue.""" + d = settings.globalSettingsController() + if d.response == widgetUtils.OK: + d.save_configuration() + if d.needs_restart == True: + commonMessageDialogs.needs_restart() + restart.restart_program() + + def accountConfiguration(self, *args, **kwargs): + """ Opens the account settings dialogue for the current account.""" + buff = self.get_best_buffer() + manager.manager.set_current_session(buff.session.session_id) + d = settings.accountSettingsController(buff, self) + if d.response == widgetUtils.OK: + d.save_configuration() + if d.needs_restart == True: + commonMessageDialogs.needs_restart() + buff.session.settings.write() + restart.restart_program() + + def report_error(self, *args, **kwargs): + r = issueReporter.reportBug(self.get_best_buffer().session.db["user_name"]) + + def check_for_updates(self, *args, **kwargs): + update = updater.do_update() + if update == False: + view.no_update_available() + + def delete(self, *args, **kwargs): + """ Deletes an item in the current buffer. + Users can only remove their tweets and direct messages, other users' tweets and people (followers, friends, blocked, etc) can not be removed using this method.""" + buffer = self.view.get_current_buffer() + if hasattr(buffer, "account"): + buffer = self.search_buffer(buffer.name, buffer.account) + buffer.destroy_status() + + def exit(self, *args, **kwargs): + if config.app["app-settings"]["ask_at_exit"] == True: + answer = commonMessageDialogs.exit_dialog(self.view) + if answer == widgetUtils.YES: + self.exit_() + else: + self.exit_() + + def exit_(self, *args, **kwargs): + for i in self.buffers: i.save_positions() + log.debug("Exiting...") + log.debug("Saving global configuration...") + for item in sessions.sessions: + if sessions.sessions[item].logged == False: continue + log.debug("Disconnecting streams for %s session" % (sessions.sessions[item].session_id,)) + sessions.sessions[item].sound.cleaner.cancel() + log.debug("Shelving database for " + sessions.sessions[item].session_id) + sessions.sessions[item].shelve() + if system == "Windows": + self.systrayIcon.RemoveIcon() + pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) + if os.path.exists(pidpath): + os.remove(pidpath) + widgetUtils.exit_application() + + def follow(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users) + + def unfollow(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users, "unfollow") + + def mute(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users, "mute") + + def unmute(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users, "unmute") + + def block(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users, "block") + + def unblock(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users, "unblock") + + def report(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + u = userActionsController.userActionsController(buff, users, "report") + + def post_tweet(self, event=None): + buffer = self.get_best_buffer() + buffer.post_status() + + def post_reply(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.name == "direct_messages": + buffer.send_message() + else: + buffer.reply() + + def send_dm(self, *args, **kwargs): + buffer = self.get_current_buffer() + buffer.send_message() + + def post_retweet(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": + return + else: + buffer.share_item() + + def add_to_favourites(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": + return + else: + id = buffer.get_tweet().id + call_threaded(buffer.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id) + + def remove_from_favourites(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": + return + else: + id = buffer.get_tweet().id + call_threaded(buffer.session.api_call, call_name="destroy_favorite", id=id) + + def toggle_like(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events": + return + else: + id = buffer.get_tweet().id + tweet = buffer.session.twitter.get_status(id=id, include_ext_alt_text=True, tweet_mode="extended") + if tweet.favorited == False: + call_threaded(buffer.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id) + else: + call_threaded(buffer.session.api_call, call_name="destroy_favorite", id=id) + + def view_item(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.type == "account" or buffer.type == "empty": + return + elif buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search": + tweet, tweetsList = buffer.get_full_tweet() + msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"]) + elif buffer.type == "dm": + non_tweet = buffer.get_formatted_message() + item = buffer.get_right_tweet() + original_date = arrow.get(int(item.created_timestamp)) + date = original_date.shift(seconds=buffer.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage()) + msg = messages.viewTweet(non_tweet, [], False, date=date) + else: + non_tweet = buffer.get_formatted_message() + msg = messages.viewTweet(non_tweet, [], False) + + def open_in_browser(self, *args, **kwargs): + buffer = self.get_current_buffer() + if hasattr(buffer, "open_in_browser"): + buffer.open_in_browser() + + def open_favs_timeline(self, *args, **kwargs): + self.open_timeline(default="favourites") + + def open_timeline(self, default="tweets", *args, **kwargs): + buff = self.get_best_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session.db) + dlg = dialogs.userSelection.selectUserDialog(users=users, default=default) + if dlg.get_response() == widgetUtils.OK: + usr = utils.if_user_exists(buff.session.twitter, dlg.get_user()) + if usr != None: + if usr == dlg.get_user(): + commonMessageDialogs.suspended_user() + return + if usr.protected == True: + if usr.following == False: + commonMessageDialogs.no_following() + return + tl_type = dlg.get_action() + if tl_type == "tweets": + if usr.statuses_count == 0: + commonMessageDialogs.no_tweets() + return + if usr.id_str in buff.session.settings["other_buffers"]["timelines"]: + commonMessageDialogs.timeline_exist() + return + tl = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "%s-timeline" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="tweet_timeline.ogg", user_id=usr.id_str, tweet_mode="extended") + try: + tl.start_stream(play_sound=False) + except ValueError: + commonMessageDialogs.unauthorized() + return + pos=self.view.search("timelines", buff.session.db["user_name"]) + self.insert_buffer(tl, pos+1) + self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(dlg.get_user()), pos=pos) + buff.session.settings["other_buffers"]["timelines"].append(usr.id_str) + pub.sendMessage("buffer-title-changed", buffer=tl) + buff.session.sound.play("create_timeline.ogg") + elif tl_type == "favourites": + if usr.favourites_count == 0: + commonMessageDialogs.no_favs() + return + if usr.id_str in buff.session.settings["other_buffers"]["favourites_timelines"]: + commonMessageDialogs.timeline_exist() + return + tl = twitterBuffers.baseBufferController(self.view.nb, "favorites", "%s-favorite" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, tweet_mode="extended") + try: + tl.start_stream(play_sound=False) + except ValueError: + commonMessageDialogs.unauthorized() + return + pos=self.view.search("favs_timelines", buff.session.db["user_name"]) + self.insert_buffer(tl, pos+1) + self.view.insert_buffer(buffer=tl.buffer, name=_(u"Likes for {}").format(dlg.get_user()), pos=pos) + buff.session.settings["other_buffers"]["favourites_timelines"].append(usr.id_str) + pub.sendMessage("buffer-title-changed", buffer=buff) + buff.session.sound.play("create_timeline.ogg") + elif tl_type == "followers": + if usr.followers_count == 0: + commonMessageDialogs.no_followers() + return + if usr.id_str in buff.session.settings["other_buffers"]["followers_timelines"]: + commonMessageDialogs.timeline_exist() + return + tl = twitterBuffers.peopleBufferController(self.view.nb, "followers", "%s-followers" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) + try: + tl.start_stream(play_sound=False) + except ValueError: + commonMessageDialogs.unauthorized() + return + pos=self.view.search("followers_timelines", buff.session.db["user_name"]) + self.insert_buffer(tl, pos+1) + self.view.insert_buffer(buffer=tl.buffer, name=_(u"Followers for {}").format(dlg.get_user()), pos=pos) + buff.session.settings["other_buffers"]["followers_timelines"].append(usr.id_str) + buff.session.sound.play("create_timeline.ogg") + pub.sendMessage("buffer-title-changed", buffer=i) + elif tl_type == "friends": + if usr.friends_count == 0: + commonMessageDialogs.no_friends() + return + if usr.id_str in buff.session.settings["other_buffers"]["friends_timelines"]: + commonMessageDialogs.timeline_exist() + return + tl = twitterBuffers.peopleBufferController(self.view.nb, "friends", "%s-friends" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) + try: + tl.start_stream(play_sound=False) + except ValueError: + commonMessageDialogs.unauthorized() + return + pos=self.view.search("friends_timelines", buff.session.db["user_name"]) + self.insert_buffer(tl, pos+1) + self.view.insert_buffer(buffer=tl.buffer, name=_(u"Friends for {}").format(dlg.get_user()), pos=pos) + buff.session.settings["other_buffers"]["friends_timelines"].append(usr.id_str) + buff.session.sound.play("create_timeline.ogg") + pub.sendMessage("buffer-title-changed", buffer=i) + else: + commonMessageDialogs.user_not_exist() + buff.session.settings.write() + + def open_conversation(self, *args, **kwargs): + buffer = self.get_current_buffer() + id = buffer.get_right_tweet().id_str + user = buffer.get_right_tweet().user.screen_name + search = twitterBuffers.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) + search.tweet = buffer.get_right_tweet() + search.start_stream(start=True) + pos=self.view.search("searches", buffer.session.db["user_name"]) + self.insert_buffer(search, pos) + self.view.insert_buffer(search.buffer, name=_(u"Conversation with {0}").format(user), pos=pos) + + def show_hide(self, *args, **kwargs): + km = self.create_invisible_keyboard_shorcuts() + if self.showing == True: + if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == False: + self.register_invisible_keyboard_shorcuts(km) + self.view.Hide() + self.fix_wrong_buffer() + self.showing = False + else: + if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] == False: + self.unregister_invisible_keyboard_shorcuts(km) + self.view.Show() + self.showing = True + + def get_trending_topics(self, *args, **kwargs): + buff = self.get_best_buffer() + trends = trendingTopics.trendingTopicsController(buff.session) + if trends.dialog.get_response() == widgetUtils.OK: + woeid = trends.get_woeid() + if woeid in buff.session.settings["other_buffers"]["trending_topic_buffers"]: return + buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (woeid,), buff.session, buff.account, woeid, sound="trends_updated.ogg") + buffer.searchfunction = self.search + pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]) + self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (trends.get_string()), pos=pos) + self.buffers.append(buffer) + buffer.start_stream() + buffer.session.settings["other_buffers"]["trending_topic_buffers"].append(woeid) + buffer.session.settings.write() + + def reverse_geocode(self, event=None): + try: + tweet = self.get_current_buffer().get_tweet() + if tweet.coordinates != None: + x = tweet.coordinates["coordinates"][0] + y = tweet.coordinates["coordinates"][1] + address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang) + if event == None: output.speak(address[0].__str__()) + else: self.view.show_address(address[0].__str__()) + else: + output.speak(_(u"There are no coordinates in this tweet")) + except GeocoderError: + output.speak(_(u"There are no results for the coordinates in this tweet")) + except ValueError: + output.speak(_(u"Error decoding coordinates. Try again later.")) + except KeyError: + pass + except AttributeError: + pass + + def view_reverse_geocode(self, event=None): + try: + tweet = self.get_current_buffer().get_right_tweet() + if tweet.coordinates != None: + x = tweet.coordinates["coordinates"][0] + y = tweet.coordinates["coordinates"][1] + address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang) + dlg = commonMessageDialogs.view_geodata(address[0].__str__()) + else: + output.speak(_(u"There are no coordinates in this tweet")) + except GeocoderError: + output.speak(_(u"There are no results for the coordinates in this tweet")) + except ValueError: + output.speak(_(u"Error decoding coordinates. Try again later.")) + except KeyError: + pass + except AttributeError: + pass + + def get_more_items(self, *args, **kwargs): + self.get_current_buffer().get_more_items() + + def clear_buffer(self, *args, **kwargs): + self.get_current_buffer().clear_list() + + def remove_buffer(self, *args, **kwargs): + buffer = self.get_current_buffer() + if not hasattr(buffer, "account"): return + buff = self.view.search(buffer.name, buffer.account) + answer = buffer.remove_buffer() + if answer == False: return + log.debug("destroying buffer...") + if hasattr(buffer, "timer"): + log.debug("Stopping timer...") + buffer.timer.cancel() + log.debug("Timer cancelled.") + self.right() + self.view.delete_buffer(buff) + buffer.session.sound.play("delete_timeline.ogg") + self.buffers.remove(buffer) + del buffer + + def skip_buffer(self, forward=True): + buff = self.get_current_buffer() + if buff.invisible == False: + self.view.advance_selection(forward) + + def buffer_changed(self, *args, **kwargs): + buffer = self.get_current_buffer() + if buffer.account != self.current_account: + self.current_account = buffer.account + if not hasattr(buffer, "session") or buffer.session == None: return + muted = autoread = False + if buffer.name in buffer.session.settings["other_buffers"]["muted_buffers"]: + muted = True + elif buffer.name in buffer.session.settings["other_buffers"]["autoread_buffers"]: + autoread = True + self.view.check_menuitem("mute_buffer", muted) + self.view.check_menuitem("autoread", autoread) + + def fix_wrong_buffer(self): + buf = self.get_best_buffer() + if buf == None: + for i in self.accounts: + buffer = self.view.search("home_timeline", i) + if buffer != None: break + else: + buffer = self.view.search("home_timeline", buf.session.db["user_name"]) + if buffer!=None: + self.view.change_buffer(buffer) + + def up(self, *args, **kwargs): + page = self.get_current_buffer() + if not hasattr(page.buffer, "list"): + output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) + return + position = page.buffer.list.get_selected() + index = position-1 + try: + page.buffer.list.select_item(index) + except: + pass + if position == page.buffer.list.get_selected(): + page.session.sound.play("limit.ogg") + + try: + output.speak(page.get_message(), True) + except: + pass + + def down(self, *args, **kwargs): + page = self.get_current_buffer() + if not hasattr(page.buffer, "list"): + output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) + return + position = page.buffer.list.get_selected() + index = position+1 + try: + page.buffer.list.select_item(index) + except: + pass + if position == page.buffer.list.get_selected(): + page.session.sound.play("limit.ogg") + try: + output.speak(page.get_message(), True) + except: + pass + + def left(self, *args, **kwargs): + buff = self.view.get_current_buffer_pos() + buffer = self.get_current_buffer() + if not hasattr(buffer.buffer, "list"): + output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) + return + if buff == self.get_first_buffer_index(buffer.account) or buff == 0: + self.view.change_buffer(self.get_last_buffer_index(buffer.account)) + else: + self.view.change_buffer(buff-1) + while self.get_current_buffer().invisible == False: self.skip_buffer(False) + buffer = self.get_current_buffer() + if self.showing == True: buffer.buffer.set_focus_in_list() + try: + msg = _(u"%s, %s of %s") % (self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) + except: + msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) + output.speak(msg, True) + + def right(self, *args, **kwargs): + buff = self.view.get_current_buffer_pos() + buffer = self.get_current_buffer() + if not hasattr(buffer.buffer, "list"): + output.speak(_(u"No session is currently in focus. Focus a session with the next or previous session shortcut."), True) + return + if buff == self.get_last_buffer_index(buffer.account) or buff+1 == self.view.get_buffer_count(): + self.view.change_buffer(self.get_first_buffer_index(buffer.account)) + else: + self.view.change_buffer(buff+1) + while self.get_current_buffer().invisible == False: self.skip_buffer(True) + buffer = self.get_current_buffer() + if self.showing == True: buffer.buffer.set_focus_in_list() + try: + msg = _(u"%s, %s of %s") % (self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) + except: + msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) + output.speak(msg, True) + + def next_account(self, *args, **kwargs): + index = self.accounts.index(self.current_account) + if index+1 == len(self.accounts): + index = 0 + else: + index = index+1 + account = self.accounts[index] + self.current_account = account + buffer_object = self.get_first_buffer(account) + if buffer_object == None: + output.speak(_(u"{0}: This account is not logged into Twitter.").format(account), True) + return + buff = self.view.search(buffer_object.name, account) + if buff == None: + output.speak(_(u"{0}: This account is not logged into Twitter.").format(account), True) + return + self.view.change_buffer(buff) + buffer = self.get_current_buffer() + if self.showing == True: buffer.buffer.set_focus_in_list() + try: + msg = _(u"%s. %s, %s of %s") % (buffer.account, self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) + except: + msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) + output.speak(msg, True) + + def previous_account(self, *args, **kwargs): + index = self.accounts.index(self.current_account) + if index-1 < 0: + index = len(self.accounts)-1 + else: + index = index-1 + account = self.accounts[index] + self.current_account = account + buffer_object = self.get_first_buffer(account) + if buffer_object == None: + output.speak(_(u"{0}: This account is not logged into Twitter.").format(account), True) + return + buff = self.view.search(buffer_object.name, account) + if buff == None: + output.speak(_(u"{0}: This account is not logged into twitter.").format(account), True) + return + self.view.change_buffer(buff) + buffer = self.get_current_buffer() + if self.showing == True: buffer.buffer.set_focus_in_list() + try: + msg = _(u"%s. %s, %s of %s") % (buffer.account, self.view.get_buffer_text(), buffer.buffer.list.get_selected()+1, buffer.buffer.list.get_count()) + except: + msg = _(u"%s. Empty") % (self.view.get_buffer_text(),) + output.speak(msg, True) + + def go_home(self): + buffer = self.get_current_buffer() + buffer.buffer.list.select_item(0) + try: + output.speak(buffer.get_message(), True) + except: + pass + + def go_end(self): + buffer = self.get_current_buffer() + buffer.buffer.list.select_item(buffer.buffer.list.get_count()-1) + try: + output.speak(buffer.get_message(), True) + except: + pass + + def go_page_up(self): + buffer = self.get_current_buffer() + if buffer.buffer.list.get_selected() <= 20: + index = 0 + else: + index = buffer.buffer.list.get_selected() - 20 + buffer.buffer.list.select_item(index) + try: + output.speak(buffer.get_message(), True) + except: + pass + + def go_page_down(self): + buffer = self.get_current_buffer() + if buffer.buffer.list.get_selected() >= buffer.buffer.list.get_count() - 20: + index = buffer.buffer.list.get_count()-1 + else: + index = buffer.buffer.list.get_selected() + 20 + buffer.buffer.list.select_item(index) + try: + output.speak(buffer.get_message(), True) + except: + pass + + def url(self, *args, **kwargs): + buffer = self.get_current_buffer() + buffer.url() + + def audio(self, *args, **kwargs): + self.get_current_buffer().audio() + + def volume_down(self, *args, **kwargs): + self.get_current_buffer().volume_down() + + def volume_up(self, *args, **kwargs): + self.get_current_buffer().volume_up() + + def create_invisible_keyboard_shorcuts(self): + keymap = {} + for i in config.keymap["keymap"]: + if hasattr(self, i): + keymap[config.keymap["keymap"][i]] = getattr(self, i) + return keymap + + def register_invisible_keyboard_shorcuts(self, keymap): + if config.changed_keymap: + commonMessageDialogs.changed_keymap() + self.keyboard_handler = WXKeyboardHandler(self.view) + self.keyboard_handler.register_keys(keymap) + + def unregister_invisible_keyboard_shorcuts(self, keymap): + try: + self.keyboard_handler.unregister_keys(keymap) + del self.keyboard_handler + except AttributeError: + pass + + def notify(self, session, play_sound=None, message=None, notification=False): + if session.settings["sound"]["session_mute"] == True: return + if play_sound != None: + session.sound.play(play_sound) + if message != None: + output.speak(message, speech=session.settings["reporting"]["speech_reporting"], braille=session.settings["reporting"]["braille_reporting"]) + + def manage_sent_dm(self, data, user): + buffer = self.search_buffer("sent_direct_messages", user) + if buffer == None: return + play_sound = "dm_sent.ogg" + if "sent_direct_messages" not in buffer.session.settings["other_buffers"]["muted_buffers"]: + self.notify(buffer.session, play_sound=play_sound) + buffer.add_new_item(data) + + def manage_sent_tweets(self, data, user): + buffer = self.search_buffer("sent_tweets", user) + if buffer == None: return # if "sent_tweets" not in buffer.session.settings["other_buffers"]["muted_buffers"]: # self.notify(buffer.session, play_sound=play_sound) - data = buffer.session.check_quoted_status(data) - data = buffer.session.check_long_tweet(data) - if data == False: # Long tweet deleted from twishort. - return - if buffer.session.settings["general"]["reverse_timelines"] == False: - buffer.session.db[buffer.name].append(data) - else: - buffer.session.db[buffer.name].insert(0, data) - buffer.add_new_item(data) + data = buffer.session.check_quoted_status(data) + data = buffer.session.check_long_tweet(data) + if data == False: # Long tweet deleted from twishort. + return + if buffer.session.settings["general"]["reverse_timelines"] == False: + buffer.session.db[buffer.name].append(data) + else: + buffer.session.db[buffer.name].insert(0, data) + buffer.add_new_item(data) - def manage_friend(self, data, user): - buffer = self.search_buffer("friends", user) - if buffer == None: return - buffer.add_new_item(data) + def manage_friend(self, data, user): + buffer = self.search_buffer("friends", user) + if buffer == None: return + buffer.add_new_item(data) - def manage_unfollowing(self, item, user): - buffer = self.search_buffer("friends", user) - if buffer == None: return - buffer.remove_item(item) + def manage_unfollowing(self, item, user): + buffer = self.search_buffer("friends", user) + if buffer == None: return + buffer.remove_item(item) - def manage_favourite(self, data, user): - buffer = self.search_buffer("favourites", user) - if buffer == None: return - play_sound = "favourite.ogg" - if "favourites" not in buffer.session.settings["other_buffers"]["muted_buffers"]: - self.notify(buffer.session, play_sound=play_sound) - buffer.add_new_item(data) + def manage_favourite(self, data, user): + buffer = self.search_buffer("favourites", user) + if buffer == None: return + play_sound = "favourite.ogg" + if "favourites" not in buffer.session.settings["other_buffers"]["muted_buffers"]: + self.notify(buffer.session, play_sound=play_sound) + buffer.add_new_item(data) - def manage_unfavourite(self, item, user): - buffer = self.search_buffer("favourites", user) - if buffer == None: return - buffer.remove_item(item) + def manage_unfavourite(self, item, user): + buffer = self.search_buffer("favourites", user) + if buffer == None: return + buffer.remove_item(item) - def manage_blocked_user(self, data, user): - buffer = self.search_buffer("blocked", user) - if buffer == None: return - buffer.add_new_item(data) + def manage_blocked_user(self, data, user): + buffer = self.search_buffer("blocked", user) + if buffer == None: return + buffer.add_new_item(data) - def manage_unblocked_user(self, item, user): - buffer = self.search_buffer("blocked", user) - if buffer == None: return - buffer.remove_item(item) + def manage_unblocked_user(self, item, user): + buffer = self.search_buffer("blocked", user) + if buffer == None: return + buffer.remove_item(item) - def start_buffers(self, session): - log.debug("starting buffers... Session %s" % (session.session_id,)) - for i in self.buffers: - if i.session == session and i.needs_init == True: - if hasattr(i, "finished_timeline") and i.finished_timeline == False: - change_title = True - else: - change_title = False - try: - if "mentions" in i.name or "direct_messages" in i.name: - i.start_stream() - else: - i.start_stream(play_sound=False) - except TweepError as err: - log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) - # Determine if this error was caused by a block applied to the current user (IE permission errors). - errors_allowed = [130] - if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. - buff = self.view.search(i.name, i.account) - i.remove_buffer(force=True) - commonMessageDialogs.blocked_timeline() - if self.get_current_buffer() == i: - self.right() - self.view.delete_buffer(buff) - self.buffers.remove(i) - del i - continue - if change_title: - pub.sendMessage("buffer-title-changed", buffer=i) + def start_buffers(self, session): + log.debug("starting buffers... Session %s" % (session.session_id,)) + for i in self.buffers: + if i.session == session and i.needs_init == True: + if hasattr(i, "finished_timeline") and i.finished_timeline == False: + change_title = True + else: + change_title = False + try: + if "mentions" in i.name or "direct_messages" in i.name: + i.start_stream() + else: + i.start_stream(play_sound=False) + except TweepError as err: + log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) + # Determine if this error was caused by a block applied to the current user (IE permission errors). + errors_allowed = [130] + if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. + buff = self.view.search(i.name, i.account) + i.remove_buffer(force=True) + commonMessageDialogs.blocked_timeline() + if self.get_current_buffer() == i: + self.right() + self.view.delete_buffer(buff) + self.buffers.remove(i) + del i + continue + if change_title: + pub.sendMessage("buffer-title-changed", buffer=i) - def set_positions(self): - for i in sessions.sessions: - self.set_buffer_positions(i) + def set_positions(self): + for i in sessions.sessions: + self.set_buffer_positions(i) - def check_connection(self): - if self.started == False: - return - for i in sessions.sessions: - try: - if sessions.sessions[i].is_logged == False: continue - sessions.sessions[i].check_connection() - except TweepError: # We shouldn't allow this function to die. - pass + def check_connection(self): + if self.started == False: + return + for i in sessions.sessions: + try: + if sessions.sessions[i].is_logged == False: continue + sessions.sessions[i].check_connection() + except TweepError: # We shouldn't allow this function to die. + pass - def create_new_buffer(self, buffer, account, create): - buff = self.search_buffer("home_timeline", account) - if create == True: - if buffer == "favourites": - favourites = twitterBuffers.baseBufferController(self.view.nb, "favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended") - self.buffers.append(favourites) - self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) - favourites.start_stream(play_sound=False) - if buffer == "followers": - followers = twitterBuffers.peopleBufferController(self.view.nb, "followers", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) - self.buffers.append(followers) - self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) - followers.start_stream(play_sound=False) - elif buffer == "friends": - friends = twitterBuffers.peopleBufferController(self.view.nb, "friends", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) - self.buffers.append(friends) - self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) - friends.start_stream(play_sound=False) - elif buffer == "blocked": - blocks = twitterBuffers.peopleBufferController(self.view.nb, "blocks", "blocked", buff.session, buff.session.db["user_name"]) - self.buffers.append(blocks) - self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) - blocks.start_stream(play_sound=False) - elif buffer == "muted": - muted = twitterBuffers.peopleBufferController(self.view.nb, "mutes", "muted", buff.session, buff.session.db["user_name"]) - self.buffers.append(muted) - self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) - muted.start_stream(play_sound=False) - elif buffer == "events": - events = twitterBuffers.eventsBufferController(self.view.nb, "events", buff.session, buff.session.db["user_name"], bufferType="dmPanel", screen_name=buff.session.db["user_name"]) - self.buffers.append(events) - self.view.insert_buffer(events.buffer, name=_(u"Events"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) - elif create == False: - self.destroy_buffer(buffer, buff.session.db["user_name"]) - elif buffer == "list": - if create in buff.session.settings["other_buffers"]["lists"]: - output.speak(_(u"This list is already opened"), True) - return - tl = twitterBuffers.listBufferController(self.view.nb, "list_timeline", create+"-list", buff.session, buff.session.db["user_name"], bufferType=None, list_id=utils.find_list(create, buff.session.db["lists"]), tweet_mode="extended") - buff.session.lists.append(tl) - pos=self.view.search("lists", buff.session.db["user_name"]) - self.insert_buffer(tl, pos) - self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(create), pos=self.view.search("lists", buff.session.db["user_name"])) - tl.start_stream(play_sound=False) - buff.session.settings["other_buffers"]["lists"].append(create) - buff.session.settings.write() + def create_new_buffer(self, buffer, account, create): + buff = self.search_buffer("home_timeline", account) + if create == True: + if buffer == "favourites": + favourites = twitterBuffers.baseBufferController(self.view.nb, "favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended") + self.buffers.append(favourites) + self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) + favourites.start_stream(play_sound=False) + if buffer == "followers": + followers = twitterBuffers.peopleBufferController(self.view.nb, "followers", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) + self.buffers.append(followers) + self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) + followers.start_stream(play_sound=False) + elif buffer == "friends": + friends = twitterBuffers.peopleBufferController(self.view.nb, "friends", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) + self.buffers.append(friends) + self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) + friends.start_stream(play_sound=False) + elif buffer == "blocked": + blocks = twitterBuffers.peopleBufferController(self.view.nb, "blocks", "blocked", buff.session, buff.session.db["user_name"]) + self.buffers.append(blocks) + self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) + blocks.start_stream(play_sound=False) + elif buffer == "muted": + muted = twitterBuffers.peopleBufferController(self.view.nb, "mutes", "muted", buff.session, buff.session.db["user_name"]) + self.buffers.append(muted) + self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) + muted.start_stream(play_sound=False) + elif buffer == "events": + events = twitterBuffers.eventsBufferController(self.view.nb, "events", buff.session, buff.session.db["user_name"], bufferType="dmPanel", screen_name=buff.session.db["user_name"]) + self.buffers.append(events) + self.view.insert_buffer(events.buffer, name=_(u"Events"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) + elif create == False: + self.destroy_buffer(buffer, buff.session.db["user_name"]) + elif buffer == "list": + if create in buff.session.settings["other_buffers"]["lists"]: + output.speak(_(u"This list is already opened"), True) + return + tl = twitterBuffers.listBufferController(self.view.nb, "list_timeline", create+"-list", buff.session, buff.session.db["user_name"], bufferType=None, list_id=utils.find_list(create, buff.session.db["lists"]), tweet_mode="extended") + buff.session.lists.append(tl) + pos=self.view.search("lists", buff.session.db["user_name"]) + self.insert_buffer(tl, pos) + self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(create), pos=self.view.search("lists", buff.session.db["user_name"])) + tl.start_stream(play_sound=False) + buff.session.settings["other_buffers"]["lists"].append(create) + buff.session.settings.write() - def invisible_shorcuts_changed(self, registered): - if registered == True: - km = self.create_invisible_keyboard_shorcuts() - self.register_invisible_keyboard_shorcuts(km) - elif registered == False: - km = self.create_invisible_keyboard_shorcuts() - self.unregister_invisible_keyboard_shorcuts(km) + def invisible_shorcuts_changed(self, registered): + if registered == True: + km = self.create_invisible_keyboard_shorcuts() + self.register_invisible_keyboard_shorcuts(km) + elif registered == False: + km = self.create_invisible_keyboard_shorcuts() + self.unregister_invisible_keyboard_shorcuts(km) - def about(self, *args, **kwargs): - self.view.about_dialog() + def about(self, *args, **kwargs): + self.view.about_dialog() - def get_soundpacks(self, *args, **kwargs): - # This should redirect users of other languages to the right version of the TWBlue website. - lang = languageHandler.curLang[:2] - url = application.url - final_url = "{0}/{1}/soundpacks".format(url, lang) - try: - response = requests.get(final_url) - except: - output.speak(_(u"An error happened while trying to connect to the server. Please try later.")) - return - # There is no twblue.es/en, so if English is the language used this should be False anyway. - if response.status_code == 200 and lang != "en": - webbrowser.open_new_tab(final_url) - else: - webbrowser.open_new_tab(application.url+"/soundpacks") + def get_soundpacks(self, *args, **kwargs): + # This should redirect users of other languages to the right version of the TWBlue website. + lang = languageHandler.curLang[:2] + url = application.url + final_url = "{0}/{1}/soundpacks".format(url, lang) + try: + response = requests.get(final_url) + except: + output.speak(_(u"An error happened while trying to connect to the server. Please try later.")) + return + # There is no twblue.es/en, so if English is the language used this should be False anyway. + if response.status_code == 200 and lang != "en": + webbrowser.open_new_tab(final_url) + else: + webbrowser.open_new_tab(application.url+"/soundpacks") - def visit_website(self, *args, **kwargs): - # This should redirect users of other languages to the right version of the TWBlue website. - lang = languageHandler.curLang[:2] - url = application.url - final_url = "{0}/{1}".format(url, lang) - try: - response = requests.get(final_url) - except: - output.speak(_(u"An error happened while trying to connect to the server. Please try later.")) - return - # There is no twblue.es/en, so if English is the language used this should be False anyway. - if response.status_code == 200 and lang != "en": - webbrowser.open_new_tab(final_url) - else: - webbrowser.open_new_tab(application.url) + def visit_website(self, *args, **kwargs): + # This should redirect users of other languages to the right version of the TWBlue website. + lang = languageHandler.curLang[:2] + url = application.url + final_url = "{0}/{1}".format(url, lang) + try: + response = requests.get(final_url) + except: + output.speak(_(u"An error happened while trying to connect to the server. Please try later.")) + return + # There is no twblue.es/en, so if English is the language used this should be False anyway. + if response.status_code == 200 and lang != "en": + webbrowser.open_new_tab(final_url) + else: + webbrowser.open_new_tab(application.url) - def manage_accounts(self, *args, **kwargs): - sm = sessionManager.sessionManagerController(started=True) - sm.fill_list() - sm.show() - for i in sm.new_sessions: - self.create_buffers(sessions.sessions[i]) - call_threaded(self.start_buffers, sessions.sessions[i]) - for i in sm.removed_sessions: - if sessions.sessions[i].logged == True: - self.logout_account(sessions.sessions[i].session_id) - self.destroy_buffer(sessions.sessions[i].settings["twitter"]["user_name"], sessions.sessions[i].settings["twitter"]["user_name"]) - self.accounts.remove(sessions.sessions[i].settings["twitter"]["user_name"]) - sessions.sessions.pop(i) + def manage_accounts(self, *args, **kwargs): + sm = sessionManager.sessionManagerController(started=True) + sm.fill_list() + sm.show() + for i in sm.new_sessions: + self.create_buffers(sessions.sessions[i]) + call_threaded(self.start_buffers, sessions.sessions[i]) + for i in sm.removed_sessions: + if sessions.sessions[i].logged == True: + self.logout_account(sessions.sessions[i].session_id) + self.destroy_buffer(sessions.sessions[i].settings["twitter"]["user_name"], sessions.sessions[i].settings["twitter"]["user_name"]) + self.accounts.remove(sessions.sessions[i].settings["twitter"]["user_name"]) + sessions.sessions.pop(i) - def update_profile(self, *args, **kwargs): - r = user.profileController(self.get_best_buffer().session) + def update_profile(self, *args, **kwargs): + r = user.profileController(self.get_best_buffer().session) - def user_details(self, *args, **kwargs): - buffer = self.get_current_buffer() - if not hasattr(buffer, "session") or buffer.session == None: return - if hasattr(buffer, "user_details"): - buffer.user_details() + def user_details(self, *args, **kwargs): + buffer = self.get_current_buffer() + if not hasattr(buffer, "session") or buffer.session == None: return + if hasattr(buffer, "user_details"): + buffer.user_details() - def toggle_autoread(self, *args, **kwargs): - buffer = self.get_current_buffer() - if hasattr(buffer, "session") and buffer.session == None: return - if buffer.name not in buffer.session.settings["other_buffers"]["autoread_buffers"]: - buffer.session.settings["other_buffers"]["autoread_buffers"].append(buffer.name) - output.speak(_(u"The auto-reading of new tweets is enabled for this buffer"), True) - elif buffer.name in buffer.session.settings["other_buffers"]["autoread_buffers"]: - buffer.session.settings["other_buffers"]["autoread_buffers"].remove(buffer.name) - output.speak(_(u"The auto-reading of new tweets is disabled for this buffer"), True) - buffer.session.settings.write() + def toggle_autoread(self, *args, **kwargs): + buffer = self.get_current_buffer() + if hasattr(buffer, "session") and buffer.session == None: return + if buffer.name not in buffer.session.settings["other_buffers"]["autoread_buffers"]: + buffer.session.settings["other_buffers"]["autoread_buffers"].append(buffer.name) + output.speak(_(u"The auto-reading of new tweets is enabled for this buffer"), True) + elif buffer.name in buffer.session.settings["other_buffers"]["autoread_buffers"]: + buffer.session.settings["other_buffers"]["autoread_buffers"].remove(buffer.name) + output.speak(_(u"The auto-reading of new tweets is disabled for this buffer"), True) + buffer.session.settings.write() - def toggle_session_mute(self, *args, **kwargs): - buffer = self.get_best_buffer() - if buffer.session.settings["sound"]["session_mute"] == False: - buffer.session.settings["sound"]["session_mute"] = True - output.speak(_(u"Session mute on"), True) - elif buffer.session.settings["sound"]["session_mute"] == True: - buffer.session.settings["sound"]["session_mute"] = False - output.speak(_(u"Session mute off"), True) - buffer.session.settings.write() + def toggle_session_mute(self, *args, **kwargs): + buffer = self.get_best_buffer() + if buffer.session.settings["sound"]["session_mute"] == False: + buffer.session.settings["sound"]["session_mute"] = True + output.speak(_(u"Session mute on"), True) + elif buffer.session.settings["sound"]["session_mute"] == True: + buffer.session.settings["sound"]["session_mute"] = False + output.speak(_(u"Session mute off"), True) + buffer.session.settings.write() - def toggle_buffer_mute(self, *args, **kwargs): - buffer = self.get_current_buffer() - if hasattr(buffer, "session") and buffer.session == None: return - if buffer.name not in buffer.session.settings["other_buffers"]["muted_buffers"]: - buffer.session.settings["other_buffers"]["muted_buffers"].append(buffer.name) - output.speak(_(u"Buffer mute on"), True) - elif buffer.name in buffer.session.settings["other_buffers"]["muted_buffers"]: - buffer.session.settings["other_buffers"]["muted_buffers"].remove(buffer.name) - output.speak(_(u"Buffer mute off"), True) - buffer.session.settings.write() + def toggle_buffer_mute(self, *args, **kwargs): + buffer = self.get_current_buffer() + if hasattr(buffer, "session") and buffer.session == None: return + if buffer.name not in buffer.session.settings["other_buffers"]["muted_buffers"]: + buffer.session.settings["other_buffers"]["muted_buffers"].append(buffer.name) + output.speak(_(u"Buffer mute on"), True) + elif buffer.name in buffer.session.settings["other_buffers"]["muted_buffers"]: + buffer.session.settings["other_buffers"]["muted_buffers"].remove(buffer.name) + output.speak(_(u"Buffer mute off"), True) + buffer.session.settings.write() - def view_documentation(self, *args, **kwargs): - lang = localization.get("documentation") - os.chdir("documentation/%s" % (lang,)) - webbrowser.open("manual.html") - os.chdir("../../") + def view_documentation(self, *args, **kwargs): + lang = localization.get("documentation") + os.chdir("documentation/%s" % (lang,)) + webbrowser.open("manual.html") + os.chdir("../../") - def view_changelog(self, *args, **kwargs): - if application.snapshot == True: - webbrowser.open("https://github.com/manuelcortez/twblue/blob/next-gen/doc/changelog.md") - else: - lang = localization.get("documentation") - os.chdir("documentation/%s" % (lang,)) - webbrowser.open("changelog.html") - os.chdir("../../") + def view_changelog(self, *args, **kwargs): + if application.snapshot == True: + webbrowser.open("https://github.com/manuelcortez/twblue/blob/next-gen/doc/changelog.md") + else: + lang = localization.get("documentation") + os.chdir("documentation/%s" % (lang,)) + webbrowser.open("changelog.html") + os.chdir("../../") - def insert_buffer(self, buffer, position): - self.buffers.insert(position, buffer) + def insert_buffer(self, buffer, position): + self.buffers.insert(position, buffer) - def copy_to_clipboard(self, *args, **kwargs): - output.copy(self.get_current_buffer().get_message()) - output.speak(_(u"Copied")) + def copy_to_clipboard(self, *args, **kwargs): + output.copy(self.get_current_buffer().get_message()) + output.speak(_(u"Copied")) - def repeat_item(self, *args, **kwargs): - output.speak(self.get_current_buffer().get_message()) + def repeat_item(self, *args, **kwargs): + output.speak(self.get_current_buffer().get_message()) - def execute_action(self, action): - if hasattr(self, action): - getattr(self, action)() + def execute_action(self, action): + if hasattr(self, action): + getattr(self, action)() - def update_buffers(self): - for i in self.buffers[:]: - if i.session != None and i.session.is_logged == True: - try: - i.start_stream(mandatory=True) - except TweepError as err: - log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) - # Determine if this error was caused by a block applied to the current user (IE permission errors). - errors_allowed = [130] - if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. - buff = self.view.search(i.name, i.account) - i.remove_buffer(force=True) - commonMessageDialogs.blocked_timeline() - if self.get_current_buffer() == i: - self.right() - self.view.delete_buffer(buff) - self.buffers.remove(i) - del i + def update_buffers(self): + for i in self.buffers[:]: + if i.session != None and i.session.is_logged == True: + try: + i.start_stream(mandatory=True) + except TweepError as err: + log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) + # Determine if this error was caused by a block applied to the current user (IE permission errors). + errors_allowed = [130] + if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. + buff = self.view.search(i.name, i.account) + i.remove_buffer(force=True) + commonMessageDialogs.blocked_timeline() + if self.get_current_buffer() == i: + self.right() + self.view.delete_buffer(buff) + self.buffers.remove(i) + del i - def update_buffer(self, *args, **kwargs): - bf = self.get_current_buffer() - if not hasattr(bf, "start_stream"): - output.speak(_(u"Unable to update this buffer.")) - return - else: - output.speak(_(u"Updating buffer...")) - n = bf.start_stream(mandatory=True, avoid_autoreading=True) - if n != None: - output.speak(_(u"{0} items retrieved").format(n,)) + def update_buffer(self, *args, **kwargs): + bf = self.get_current_buffer() + if not hasattr(bf, "start_stream"): + output.speak(_(u"Unable to update this buffer.")) + return + else: + output.speak(_(u"Updating buffer...")) + n = bf.start_stream(mandatory=True, avoid_autoreading=True) + if n != None: + output.speak(_(u"{0} items retrieved").format(n,)) - def buffer_title_changed(self, buffer): - if "-timeline" in buffer.name: - title = _(u"Timeline for {}").format(buffer.username,) - elif "-favorite" in buffer.name: - title = _(u"Likes for {}").format(buffer.username,) - elif "-followers" in buffer.name: - title = _(u"Followers for {}").format(buffer.username,) - elif "-friends" in buffer.name: - title = _(u"Friends for {}").format(buffer.username,) - buffer_index = self.view.search(buffer.name, buffer.account) - self.view.set_page_title(buffer_index, title) + def buffer_title_changed(self, buffer): + if "-timeline" in buffer.name: + title = _(u"Timeline for {}").format(buffer.username,) + elif "-favorite" in buffer.name: + title = _(u"Likes for {}").format(buffer.username,) + elif "-followers" in buffer.name: + title = _(u"Followers for {}").format(buffer.username,) + elif "-friends" in buffer.name: + title = _(u"Friends for {}").format(buffer.username,) + buffer_index = self.view.search(buffer.name, buffer.account) + self.view.set_page_title(buffer_index, title) - def ocr_image(self, *args, **kwargs): - buffer = self.get_current_buffer() - if hasattr(buffer, "get_right_tweet") == False: - output.speak(_(u"Invalid buffer")) - return - tweet = buffer.get_tweet() - media_list = [] - if hasattr(tweet, "entities") and tweet.entities.get("media") != None: - [media_list.append(i) for i in tweet.entities["media"] if i not in media_list] - elif hasattr(tweet, "retweeted_status") and tweet.retweeted_status.get("media") != None: - [media_list.append(i) for i in tweet.retweeted_status.entities["media"] if i not in media_list] - elif hasattr(tweet, "quoted_status") and tweet.quoted_status.entities.get("media") != None: - [media_list.append(i) for i in tweet.quoted_status.entities["media"] if i not in media_list] - if len(media_list) > 1: - image_list = [_(u"Picture {0}").format(i,) for i in range(0, len(media_list))] - dialog = dialogs.urlList.urlList(title=_(u"Select the picture")) - if dialog.get_response() == widgetUtils.OK: - img = media_list[dialog.get_item()] - else: - return - elif len(media_list) == 1: - img = media_list[0] - else: - output.speak(_(u"Invalid buffer")) - return - if buffer.session.settings["mysc"]["ocr_language"] != "": - ocr_lang = buffer.session.settings["mysc"]["ocr_language"] - else: - ocr_lang = ocr.OCRSpace.short_langs.index(tweet.lang) - ocr_lang = ocr.OCRSpace.OcrLangs[ocr_lang] - api = ocr.OCRSpace.OCRSpaceAPI() - try: - text = api.OCR_URL(img["media_url"], lang=ocr_lang) - except ocr.OCRSpace.APIError as er: - output.speak(_(u"Unable to extract text")) - return - msg = messages.viewTweet(text["ParsedText"], [], False) + def ocr_image(self, *args, **kwargs): + buffer = self.get_current_buffer() + if hasattr(buffer, "get_right_tweet") == False: + output.speak(_(u"Invalid buffer")) + return + tweet = buffer.get_tweet() + media_list = [] + if hasattr(tweet, "entities") and tweet.entities.get("media") != None: + [media_list.append(i) for i in tweet.entities["media"] if i not in media_list] + elif hasattr(tweet, "retweeted_status") and tweet.retweeted_status.get("media") != None: + [media_list.append(i) for i in tweet.retweeted_status.entities["media"] if i not in media_list] + elif hasattr(tweet, "quoted_status") and tweet.quoted_status.entities.get("media") != None: + [media_list.append(i) for i in tweet.quoted_status.entities["media"] if i not in media_list] + if len(media_list) > 1: + image_list = [_(u"Picture {0}").format(i,) for i in range(0, len(media_list))] + dialog = dialogs.urlList.urlList(title=_(u"Select the picture")) + if dialog.get_response() == widgetUtils.OK: + img = media_list[dialog.get_item()] + else: + return + elif len(media_list) == 1: + img = media_list[0] + else: + output.speak(_(u"Invalid buffer")) + return + if buffer.session.settings["mysc"]["ocr_language"] != "": + ocr_lang = buffer.session.settings["mysc"]["ocr_language"] + else: + ocr_lang = ocr.OCRSpace.short_langs.index(tweet.lang) + ocr_lang = ocr.OCRSpace.OcrLangs[ocr_lang] + api = ocr.OCRSpace.OCRSpaceAPI() + try: + text = api.OCR_URL(img["media_url"], lang=ocr_lang) + except ocr.OCRSpace.APIError as er: + output.speak(_(u"Unable to extract text")) + return + msg = messages.viewTweet(text["ParsedText"], [], False) - def update_sent_dms(self, total, account): - sent_dms = self.search_buffer("sent_direct_messages", account) - if sent_dms != None: - sent_dms.put_items_on_list(total) + def update_sent_dms(self, total, account): + sent_dms = self.search_buffer("sent_direct_messages", account) + if sent_dms != None: + sent_dms.put_items_on_list(total) - def more_dms(self, data, account): - sent_dms = self.search_buffer("sent_direct_messages", account) - if sent_dms != None: - sent_dms.put_more_items(data) + def more_dms(self, data, account): + sent_dms = self.search_buffer("sent_direct_messages", account) + if sent_dms != None: + sent_dms.put_more_items(data) - def save_data_in_db(self): - for i in sessions.sessions: - sessions.sessions[i].shelve() + def save_data_in_db(self): + for i in sessions.sessions: + sessions.sessions[i].shelve() diff --git a/src/controller/messages.py b/src/controller/messages.py index 5eac4e13..e4a7747c 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -12,281 +12,281 @@ import config from pubsub import pub from twitter_text import parse_tweet if system == "Windows": - from wxUI.dialogs import message, urlList - from wxUI import commonMessageDialogs - from extra import translator, SpellChecker, autocompletionUsers - from extra.AudioUploader import audioUploader + from wxUI.dialogs import message, urlList + from wxUI import commonMessageDialogs + from extra import translator, SpellChecker, autocompletionUsers + from extra.AudioUploader import audioUploader elif system == "Linux": - from gtkUI.dialogs import message + from gtkUI.dialogs import message from sessions.twitter import utils from . import attach class basicTweet(object): - """ This class handles the tweet main features. Other classes should derive from this class.""" - def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs): - super(basicTweet, self).__init__() - self.max = max - self.title = title - self.session = session - self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs) - widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) - widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach) - widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor) - widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten) - widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) - widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - if hasattr(self.message, "long_tweet"): - widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor) - if config.app["app-settings"]["remember_mention_and_longtweet"]: - self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"]) - self.attachments = [] + """ This class handles the tweet main features. Other classes should derive from this class.""" + def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs): + super(basicTweet, self).__init__() + self.max = max + self.title = title + self.session = session + self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs) + widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) + widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach) + widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor) + widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten) + widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) + widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) + if hasattr(self.message, "long_tweet"): + widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor) + if config.app["app-settings"]["remember_mention_and_longtweet"]: + self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"]) + self.attachments = [] - def translate(self, event=None): - dlg = translator.gui.translateDialog() - if dlg.get_response() == widgetUtils.OK: - text_to_translate = self.message.get_text() - language_dict = translator.translator.available_languages() - for k in language_dict: - if language_dict[k] == dlg.dest_lang.GetStringSelection(): - dst = k - msg = translator.translator.translate(text=text_to_translate, target=dst) - self.message.set_text(msg) - self.text_processor() - self.message.text_focus() - output.speak(_(u"Translated")) - else: - return + def translate(self, event=None): + dlg = translator.gui.translateDialog() + if dlg.get_response() == widgetUtils.OK: + text_to_translate = self.message.get_text() + language_dict = translator.translator.available_languages() + for k in language_dict: + if language_dict[k] == dlg.dest_lang.GetStringSelection(): + dst = k + msg = translator.translator.translate(text=text_to_translate, target=dst) + self.message.set_text(msg) + self.text_processor() + self.message.text_focus() + output.speak(_(u"Translated")) + else: + return - def shorten(self, event=None): - urls = utils.find_urls_in_text(self.message.get_text()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be shortened")) - self.message.text_focus() - elif len(urls) == 1: - self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0]))) - output.speak(_(u"URL shortened")) - self.text_processor() - self.message.text_focus() - elif len(urls) > 1: - list_urls = urlList.urlList() - list_urls.populate_list(urls) - if list_urls.get_response() == widgetUtils.OK: - self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.shorten(list_urls.get_string()))) - output.speak(_(u"URL shortened")) - self.text_processor() - self.message.text_focus() + def shorten(self, event=None): + urls = utils.find_urls_in_text(self.message.get_text()) + if len(urls) == 0: + output.speak(_(u"There's no URL to be shortened")) + self.message.text_focus() + elif len(urls) == 1: + self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0]))) + output.speak(_(u"URL shortened")) + self.text_processor() + self.message.text_focus() + elif len(urls) > 1: + list_urls = urlList.urlList() + list_urls.populate_list(urls) + if list_urls.get_response() == widgetUtils.OK: + self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.shorten(list_urls.get_string()))) + output.speak(_(u"URL shortened")) + self.text_processor() + self.message.text_focus() - def unshorten(self, event=None): - urls = utils.find_urls_in_text(self.message.get_text()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be expanded")) - self.message.text_focus() - elif len(urls) == 1: - self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0]))) - output.speak(_(u"URL expanded")) - self.text_processor() - self.message.text_focus() - elif len(urls) > 1: - list_urls = urlList.urlList() - list_urls.populate_list(urls) - if list_urls.get_response() == widgetUtils.OK: - self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.unshorten(list_urls.get_string()))) - output.speak(_(u"URL expanded")) - self.text_processor() - self.message.text_focus() + def unshorten(self, event=None): + urls = utils.find_urls_in_text(self.message.get_text()) + if len(urls) == 0: + output.speak(_(u"There's no URL to be expanded")) + self.message.text_focus() + elif len(urls) == 1: + self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0]))) + output.speak(_(u"URL expanded")) + self.text_processor() + self.message.text_focus() + elif len(urls) > 1: + list_urls = urlList.urlList() + list_urls.populate_list(urls) + if list_urls.get_response() == widgetUtils.OK: + self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.unshorten(list_urls.get_string()))) + output.speak(_(u"URL expanded")) + self.text_processor() + self.message.text_focus() - def text_processor(self, *args, **kwargs): - if len(self.message.get_text()) > 1: - self.message.enable_button("shortenButton") - self.message.enable_button("unshortenButton") - else: - self.message.disable_button("shortenButton") - self.message.disable_button("unshortenButton") - if self.message.get("long_tweet") == False: - text = self.message.get_text() - results = parse_tweet(text) - self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) - if results.weightedLength > self.max: - self.session.sound.play("max_length.ogg") - else: - self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text()))) + def text_processor(self, *args, **kwargs): + if len(self.message.get_text()) > 1: + self.message.enable_button("shortenButton") + self.message.enable_button("unshortenButton") + else: + self.message.disable_button("shortenButton") + self.message.disable_button("unshortenButton") + if self.message.get("long_tweet") == False: + text = self.message.get_text() + results = parse_tweet(text) + self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) + if results.weightedLength > self.max: + self.session.sound.play("max_length.ogg") + else: + self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text()))) - def spellcheck(self, event=None): - text = self.message.get_text() - checker = SpellChecker.spellchecker.spellChecker(text, "") - if hasattr(checker, "fixed_text"): - self.message.set_text(checker.fixed_text) - self.text_processor() - self.message.text_focus() + def spellcheck(self, event=None): + text = self.message.get_text() + checker = SpellChecker.spellchecker.spellChecker(text, "") + if hasattr(checker, "fixed_text"): + self.message.set_text(checker.fixed_text) + self.text_processor() + self.message.text_focus() - def attach(self, *args, **kwargs): - def completed_callback(dlg): - url = dlg.uploaderFunction.get_url() - pub.unsubscribe(dlg.uploaderDialog.update, "uploading") - dlg.uploaderDialog.destroy() - if "sndup.net/" in url: - self.message.set_text(self.message.get_text()+url+" #audio") - self.text_processor() - else: - commonMessageDialogs.common_error(url) + def attach(self, *args, **kwargs): + def completed_callback(dlg): + url = dlg.uploaderFunction.get_url() + pub.unsubscribe(dlg.uploaderDialog.update, "uploading") + dlg.uploaderDialog.destroy() + if "sndup.net/" in url: + self.message.set_text(self.message.get_text()+url+" #audio") + self.text_processor() + else: + commonMessageDialogs.common_error(url) - dlg.cleanup() - dlg = audioUploader.audioUploader(self.session.settings, completed_callback) - self.message.text_focus() + dlg.cleanup() + dlg = audioUploader.audioUploader(self.session.settings, completed_callback) + self.message.text_focus() class tweet(basicTweet): - def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs): - super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) - self.image = None - widgetUtils.connect_event(self.message.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) - widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) - self.text_processor() + def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs): + super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) + self.image = None + widgetUtils.connect_event(self.message.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) + widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + self.text_processor() - def upload_image(self, *args, **kwargs): - a = attach.attach() - if len(a.attachments) != 0: - self.attachments = a.attachments + def upload_image(self, *args, **kwargs): + a = attach.attach() + if len(a.attachments) != 0: + self.attachments = a.attachments - def autocomplete_users(self, *args, **kwargs): - c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) - c.show_menu() + def autocomplete_users(self, *args, **kwargs): + c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) + c.show_menu() class reply(tweet): - def __init__(self, session, title, caption, text, users=[], ids=[]): - super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users) - self.ids = ids - self.users = users - if len(users) > 0: - widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all) - self.message.enable_button("mentionAll") - if config.app["app-settings"]["remember_mention_and_longtweet"]: - self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"]) - self.mention_all() - self.message.set_cursor_at_end() - self.text_processor() + def __init__(self, session, title, caption, text, users=[], ids=[]): + super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users) + self.ids = ids + self.users = users + if len(users) > 0: + widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all) + self.message.enable_button("mentionAll") + if config.app["app-settings"]["remember_mention_and_longtweet"]: + self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"]) + self.mention_all() + self.message.set_cursor_at_end() + self.text_processor() - def mention_all(self, *args, **kwargs): - if self.message.mentionAll.GetValue() == True: - for i in self.message.checkboxes: - i.SetValue(True) - i.Hide() - else: - for i in self.message.checkboxes: - i.SetValue(False) - i.Show() + def mention_all(self, *args, **kwargs): + if self.message.mentionAll.GetValue() == True: + for i in self.message.checkboxes: + i.SetValue(True) + i.Hide() + else: + for i in self.message.checkboxes: + i.SetValue(False) + i.Show() - def get_ids(self): - excluded_ids = "" - for i in range(0, len(self.message.checkboxes)): - if self.message.checkboxes[i].GetValue() == False: - excluded_ids = excluded_ids + "{0},".format(self.ids[i],) - return excluded_ids + def get_ids(self): + excluded_ids = "" + for i in range(0, len(self.message.checkboxes)): + if self.message.checkboxes[i].GetValue() == False: + excluded_ids = excluded_ids + "{0},".format(self.ids[i],) + return excluded_ids - def get_people(self): - people = "" - for i in range(0, len(self.message.checkboxes)): - if self.message.checkboxes[i].GetValue() == True: - people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),) - return people + def get_people(self): + people = "" + for i in range(0, len(self.message.checkboxes)): + if self.message.checkboxes[i].GetValue() == True: + people = people + "{0} ".format(self.message.checkboxes[i].GetLabel(),) + return people class dm(basicTweet): - def __init__(self, session, title, caption, text): - super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000) - widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) - self.text_processor() - widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed) + def __init__(self, session, title, caption, text): + super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000) + widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + self.text_processor() + widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed) - def user_changed(self, *args, **kwargs): - self.title = _("Direct message to %s") % (self.message.get_user()) - self.text_processor() + def user_changed(self, *args, **kwargs): + self.title = _("Direct message to %s") % (self.message.get_user()) + self.text_processor() - def autocomplete_users(self, *args, **kwargs): - c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) - c.show_menu("dm") + def autocomplete_users(self, *args, **kwargs): + c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) + c.show_menu("dm") class viewTweet(basicTweet): - def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date=""): - """ This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event. - param tweet: A dictionary that represents a full tweet or a string for non-tweets. - param tweetList: If is_tweet is set to True, this could be a list of quoted tweets. - param is_tweet: True or false, depending wether the passed object is a tweet or not.""" - if is_tweet == True: - self.title = _(u"Tweet") - image_description = [] - text = "" - for i in range(0, len(tweetList)): - # tweets with message keys are longer tweets, the message value is the full messaje taken from twishort. - if hasattr(tweetList[i], "message") and tweetList[i].is_quote_status == False: - value = "message" - else: - value = "full_text" - if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False: - if not hasattr(tweetList[i], "message"): - text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, tweetList[i].retweeted_status.full_text) - else: - text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value)) - else: - text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value)) - # tweets with extended_entities could include image descriptions. - if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities: - for z in tweetList[i].extended_entities["media"]: - if "ext_alt_text" in z and z["ext_alt_text"] != None: - image_description.append(z["ext_alt_text"]) - if hasattr(tweetList[i], "retweeted_status") and hasattr(tweetList[i].retweeted_status, "extended_entities") and "media" in tweetList[i].retweeted_status["extended_entities"]: - for z in tweetList[i].retweeted_status.extended_entities["media"]: - if "ext_alt_text" in z and z["ext_alt_text"] != None: - image_description.append(z["ext_alt_text"]) - # set rt and likes counters. - rt_count = str(tweet.retweet_count) - favs_count = str(tweet.favorite_count) - # Gets the client from where this tweet was made. - source = tweet.source - original_date = arrow.get(tweet.created_at, locale="en") - date = original_date.shift(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage()) - if text == "": - if hasattr(tweet, "message"): - value = "message" - else: - value = "full_text" - if hasattr(tweet, "retweeted_status"): - if not hasattr(tweet, "message"): - text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text) - else: - text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value)) - else: - text = getattr(tweet, value) - text = self.clear_text(text) - if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities: - for z in tweet.extended_entities["media"]: - if "ext_alt_text" in z and z["ext_alt_text"] != None: - image_description.append(z["ext_alt_text"]) - if hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "extended_entities") and "media" in tweet.retweeted_status.extended_entities: - for z in tweet.retweeted_status.extended_entities["media"]: - if "ext_alt_text" in z and z["ext_alt_text"] != None: - image_description.append(z["ext_alt_text"]) - self.message = message.viewTweet(text, rt_count, favs_count, source, date) - results = parse_tweet(text) - self.message.set_title(results.weightedLength) - [self.message.set_image_description(i) for i in image_description] - else: - self.title = _(u"View item") - text = tweet - self.message = message.viewNonTweet(text, date) - widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) - widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - if self.contain_urls() == True: - self.message.enable_button("unshortenButton") - widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) - self.message.get_response() + def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date=""): + """ This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event. + param tweet: A dictionary that represents a full tweet or a string for non-tweets. + param tweetList: If is_tweet is set to True, this could be a list of quoted tweets. + param is_tweet: True or false, depending wether the passed object is a tweet or not.""" + if is_tweet == True: + self.title = _(u"Tweet") + image_description = [] + text = "" + for i in range(0, len(tweetList)): + # tweets with message keys are longer tweets, the message value is the full messaje taken from twishort. + if hasattr(tweetList[i], "message") and tweetList[i].is_quote_status == False: + value = "message" + else: + value = "full_text" + if hasattr(tweetList[i], "retweeted_status") and tweetList[i].is_quote_status == False: + if not hasattr(tweetList[i], "message"): + text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, tweetList[i].retweeted_status.full_text) + else: + text = text + "rt @%s: %s\n" % (tweetList[i].retweeted_status.user.screen_name, getattr(tweetList[i], value)) + else: + text = text + " @%s: %s\n" % (tweetList[i].user.screen_name, getattr(tweetList[i], value)) + # tweets with extended_entities could include image descriptions. + if hasattr(tweetList[i], "extended_entities") and "media" in tweetList[i].extended_entities: + for z in tweetList[i].extended_entities["media"]: + if "ext_alt_text" in z and z["ext_alt_text"] != None: + image_description.append(z["ext_alt_text"]) + if hasattr(tweetList[i], "retweeted_status") and hasattr(tweetList[i].retweeted_status, "extended_entities") and "media" in tweetList[i].retweeted_status["extended_entities"]: + for z in tweetList[i].retweeted_status.extended_entities["media"]: + if "ext_alt_text" in z and z["ext_alt_text"] != None: + image_description.append(z["ext_alt_text"]) + # set rt and likes counters. + rt_count = str(tweet.retweet_count) + favs_count = str(tweet.favorite_count) + # Gets the client from where this tweet was made. + source = tweet.source + original_date = arrow.get(tweet.created_at, locale="en") + date = original_date.shift(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage()) + if text == "": + if hasattr(tweet, "message"): + value = "message" + else: + value = "full_text" + if hasattr(tweet, "retweeted_status"): + if not hasattr(tweet, "message"): + text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, tweet.retweeted_status.full_text) + else: + text = "rt @%s: %s" % (tweet.retweeted_status.user.screen_name, getattr(tweet, value)) + else: + text = getattr(tweet, value) + text = self.clear_text(text) + if hasattr(tweet, "extended_entities") and "media" in tweet.extended_entities: + for z in tweet.extended_entities["media"]: + if "ext_alt_text" in z and z["ext_alt_text"] != None: + image_description.append(z["ext_alt_text"]) + if hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "extended_entities") and "media" in tweet.retweeted_status.extended_entities: + for z in tweet.retweeted_status.extended_entities["media"]: + if "ext_alt_text" in z and z["ext_alt_text"] != None: + image_description.append(z["ext_alt_text"]) + self.message = message.viewTweet(text, rt_count, favs_count, source, date) + results = parse_tweet(text) + self.message.set_title(results.weightedLength) + [self.message.set_image_description(i) for i in image_description] + else: + self.title = _(u"View item") + text = tweet + self.message = message.viewNonTweet(text, date) + widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) + widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) + if self.contain_urls() == True: + self.message.enable_button("unshortenButton") + widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) + self.message.get_response() - def contain_urls(self): - if len(utils.find_urls_in_text(self.message.get_text())) > 0: - return True - return False + def contain_urls(self): + if len(utils.find_urls_in_text(self.message.get_text())) > 0: + return True + return False - def clear_text(self, text): - urls = utils.find_urls_in_text(text) - for i in urls: - if "https://twitter.com/" in i: - text = text.replace(i, "\n") - return text + def clear_text(self, text): + urls = utils.find_urls_in_text(text) + for i in urls: + if "https://twitter.com/" in i: + text = text.replace(i, "\n") + return text diff --git a/src/controller/settings.py b/src/controller/settings.py index f1a3e728..b0c1efd3 100644 --- a/src/controller/settings.py +++ b/src/controller/settings.py @@ -24,202 +24,202 @@ from collections import OrderedDict from mysc import autostart as autostart_windows class globalSettingsController(object): - def __init__(self): - super(globalSettingsController, self).__init__() - self.dialog = configuration.configurationDialog() - self.create_config() - self.needs_restart = False - self.is_started = True + def __init__(self): + super(globalSettingsController, self).__init__() + self.dialog = configuration.configurationDialog() + self.create_config() + self.needs_restart = False + self.is_started = True - def make_kmmap(self): - res={} - for i in os.listdir(os.path.join(paths.app_path(), 'keymaps')): - if ".keymap" not in i: - continue - try: - res[i[:-7]] =i - except: - log.exception("Exception while loading keymap " + i) - return res + def make_kmmap(self): + res={} + for i in os.listdir(os.path.join(paths.app_path(), 'keymaps')): + if ".keymap" not in i: + continue + try: + res[i[:-7]] =i + except: + log.exception("Exception while loading keymap " + i) + return res - def create_config(self): - self.kmmap=self.make_kmmap() - self.langs = languageHandler.getAvailableLanguages() - langs = [] - [langs.append(i[1]) for i in self.langs] - self.codes = [] - [self.codes.append(i[0]) for i in self.langs] - id = self.codes.index(config.app["app-settings"]["language"]) - self.kmfriendlies=[] - self.kmnames=[] - for k,v in list(self.kmmap.items()): - self.kmfriendlies.append(k) - self.kmnames.append(v) - self.kmid=self.kmnames.index(config.app['app-settings']['load_keymap']) - self.dialog.create_general(langs,self.kmfriendlies) - self.dialog.general.language.SetSelection(id) - self.dialog.general.km.SetSelection(self.kmid) - if paths.mode == "installed": - self.dialog.set_value("general", "autostart", config.app["app-settings"]["autostart"]) - else: - self.dialog.general.autostart.Enable(False) - self.dialog.set_value("general", "ask_at_exit", config.app["app-settings"]["ask_at_exit"]) - self.dialog.set_value("general", "no_streaming", config.app["app-settings"]["no_streaming"]) - self.dialog.set_value("general", "play_ready_sound", config.app["app-settings"]["play_ready_sound"]) - self.dialog.set_value("general", "speak_ready_msg", config.app["app-settings"]["speak_ready_msg"]) - self.dialog.set_value("general", "handle_longtweets", config.app["app-settings"]["handle_longtweets"]) - self.dialog.set_value("general", "use_invisible_shorcuts", config.app["app-settings"]["use_invisible_keyboard_shorcuts"]) - self.dialog.set_value("general", "disable_sapi5", config.app["app-settings"]["voice_enabled"]) - self.dialog.set_value("general", "hide_gui", config.app["app-settings"]["hide_gui"]) - self.dialog.set_value("general", "update_period", config.app["app-settings"]["update_period"]) - self.dialog.set_value("general", "check_for_updates", config.app["app-settings"]["check_for_updates"]) - self.dialog.set_value("general", "remember_mention_and_longtweet", config.app["app-settings"]["remember_mention_and_longtweet"]) - proxyTypes = [_("System default"), _("HTTP"), _("SOCKS v4"), _("SOCKS v4 with DNS support"), _("SOCKS v5"), _("SOCKS v5 with DNS support")] - self.dialog.create_proxy(proxyTypes) - try: - self.dialog.proxy.type.SetSelection(config.app["proxy"]["type"]) - except: - self.dialog.proxy.type.SetSelection(0) - self.dialog.set_value("proxy", "server", config.app["proxy"]["server"]) - self.dialog.set_value("proxy", "port", config.app["proxy"]["port"]) - self.dialog.set_value("proxy", "user", config.app["proxy"]["user"]) - self.dialog.set_value("proxy", "password", config.app["proxy"]["password"]) + def create_config(self): + self.kmmap=self.make_kmmap() + self.langs = languageHandler.getAvailableLanguages() + langs = [] + [langs.append(i[1]) for i in self.langs] + self.codes = [] + [self.codes.append(i[0]) for i in self.langs] + id = self.codes.index(config.app["app-settings"]["language"]) + self.kmfriendlies=[] + self.kmnames=[] + for k,v in list(self.kmmap.items()): + self.kmfriendlies.append(k) + self.kmnames.append(v) + self.kmid=self.kmnames.index(config.app['app-settings']['load_keymap']) + self.dialog.create_general(langs,self.kmfriendlies) + self.dialog.general.language.SetSelection(id) + self.dialog.general.km.SetSelection(self.kmid) + if paths.mode == "installed": + self.dialog.set_value("general", "autostart", config.app["app-settings"]["autostart"]) + else: + self.dialog.general.autostart.Enable(False) + self.dialog.set_value("general", "ask_at_exit", config.app["app-settings"]["ask_at_exit"]) + self.dialog.set_value("general", "no_streaming", config.app["app-settings"]["no_streaming"]) + self.dialog.set_value("general", "play_ready_sound", config.app["app-settings"]["play_ready_sound"]) + self.dialog.set_value("general", "speak_ready_msg", config.app["app-settings"]["speak_ready_msg"]) + self.dialog.set_value("general", "handle_longtweets", config.app["app-settings"]["handle_longtweets"]) + self.dialog.set_value("general", "use_invisible_shorcuts", config.app["app-settings"]["use_invisible_keyboard_shorcuts"]) + self.dialog.set_value("general", "disable_sapi5", config.app["app-settings"]["voice_enabled"]) + self.dialog.set_value("general", "hide_gui", config.app["app-settings"]["hide_gui"]) + self.dialog.set_value("general", "update_period", config.app["app-settings"]["update_period"]) + self.dialog.set_value("general", "check_for_updates", config.app["app-settings"]["check_for_updates"]) + self.dialog.set_value("general", "remember_mention_and_longtweet", config.app["app-settings"]["remember_mention_and_longtweet"]) + proxyTypes = [_("System default"), _("HTTP"), _("SOCKS v4"), _("SOCKS v4 with DNS support"), _("SOCKS v5"), _("SOCKS v5 with DNS support")] + self.dialog.create_proxy(proxyTypes) + try: + self.dialog.proxy.type.SetSelection(config.app["proxy"]["type"]) + except: + self.dialog.proxy.type.SetSelection(0) + self.dialog.set_value("proxy", "server", config.app["proxy"]["server"]) + self.dialog.set_value("proxy", "port", config.app["proxy"]["port"]) + self.dialog.set_value("proxy", "user", config.app["proxy"]["user"]) + self.dialog.set_value("proxy", "password", config.app["proxy"]["password"]) - self.dialog.realize() - self.response = self.dialog.get_response() + self.dialog.realize() + self.response = self.dialog.get_response() - def save_configuration(self): - if self.codes[self.dialog.general.language.GetSelection()] != config.app["app-settings"]["language"]: - config.app["app-settings"]["language"] = self.codes[self.dialog.general.language.GetSelection()] - languageHandler.setLanguage(config.app["app-settings"]["language"]) - self.needs_restart = True - if self.kmnames[self.dialog.general.km.GetSelection()] != config.app["app-settings"]["load_keymap"]: - config.app["app-settings"]["load_keymap"] =self.kmnames[self.dialog.general.km.GetSelection()] - kmFile = open(os.path.join(paths.config_path(), "keymap.keymap"), "w") - kmFile.close() - self.needs_restart = True - if config.app["app-settings"]["autostart"] != self.dialog.get_value("general", "autostart") and paths.mode == "installed": - config.app["app-settings"]["autostart"] = self.dialog.get_value("general", "autostart") - autostart_windows.setAutoStart(application.name, enable=self.dialog.get_value("general", "autostart")) - if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] != self.dialog.get_value("general", "use_invisible_shorcuts"): - config.app["app-settings"]["use_invisible_keyboard_shorcuts"] = self.dialog.get_value("general", "use_invisible_shorcuts") - pub.sendMessage("invisible-shorcuts-changed", registered=self.dialog.get_value("general", "use_invisible_shorcuts")) - if config.app["app-settings"]["no_streaming"] != self.dialog.get_value("general", "no_streaming"): - config.app["app-settings"]["no_streaming"] = self.dialog.get_value("general", "no_streaming") - self.needs_restart = True - if config.app["app-settings"]["update_period"] != self.dialog.get_value("general", "update_period"): - config.app["app-settings"]["update_period"] = self.dialog.get_value("general", "update_period") - self.needs_restart = True - config.app["app-settings"]["voice_enabled"] = self.dialog.get_value("general", "disable_sapi5") - config.app["app-settings"]["hide_gui"] = self.dialog.get_value("general", "hide_gui") - config.app["app-settings"]["ask_at_exit"] = self.dialog.get_value("general", "ask_at_exit") - config.app["app-settings"]["handle_longtweets"] = self.dialog.get_value("general", "handle_longtweets") - config.app["app-settings"]["play_ready_sound"] = self.dialog.get_value("general", "play_ready_sound") - config.app["app-settings"]["speak_ready_msg"] = self.dialog.get_value("general", "speak_ready_msg") - config.app["app-settings"]["check_for_updates"] = self.dialog.get_value("general", "check_for_updates") - config.app["app-settings"]["remember_mention_and_longtweet"] = self.dialog.get_value("general", "remember_mention_and_longtweet") - if config.app["proxy"]["type"]!=self.dialog.get_value("proxy", "type") or config.app["proxy"]["server"] != self.dialog.get_value("proxy", "server") or config.app["proxy"]["port"] != self.dialog.get_value("proxy", "port") or config.app["proxy"]["user"] != self.dialog.get_value("proxy", "user") or config.app["proxy"]["password"] != self.dialog.get_value("proxy", "password"): - if self.is_started == True: - self.needs_restart = True - config.app["proxy"]["type"] = self.dialog.proxy.type.Selection - config.app["proxy"]["server"] = self.dialog.get_value("proxy", "server") - config.app["proxy"]["port"] = self.dialog.get_value("proxy", "port") - config.app["proxy"]["user"] = self.dialog.get_value("proxy", "user") - config.app["proxy"]["password"] = self.dialog.get_value("proxy", "password") - config.app.write() + def save_configuration(self): + if self.codes[self.dialog.general.language.GetSelection()] != config.app["app-settings"]["language"]: + config.app["app-settings"]["language"] = self.codes[self.dialog.general.language.GetSelection()] + languageHandler.setLanguage(config.app["app-settings"]["language"]) + self.needs_restart = True + if self.kmnames[self.dialog.general.km.GetSelection()] != config.app["app-settings"]["load_keymap"]: + config.app["app-settings"]["load_keymap"] =self.kmnames[self.dialog.general.km.GetSelection()] + kmFile = open(os.path.join(paths.config_path(), "keymap.keymap"), "w") + kmFile.close() + self.needs_restart = True + if config.app["app-settings"]["autostart"] != self.dialog.get_value("general", "autostart") and paths.mode == "installed": + config.app["app-settings"]["autostart"] = self.dialog.get_value("general", "autostart") + autostart_windows.setAutoStart(application.name, enable=self.dialog.get_value("general", "autostart")) + if config.app["app-settings"]["use_invisible_keyboard_shorcuts"] != self.dialog.get_value("general", "use_invisible_shorcuts"): + config.app["app-settings"]["use_invisible_keyboard_shorcuts"] = self.dialog.get_value("general", "use_invisible_shorcuts") + pub.sendMessage("invisible-shorcuts-changed", registered=self.dialog.get_value("general", "use_invisible_shorcuts")) + if config.app["app-settings"]["no_streaming"] != self.dialog.get_value("general", "no_streaming"): + config.app["app-settings"]["no_streaming"] = self.dialog.get_value("general", "no_streaming") + self.needs_restart = True + if config.app["app-settings"]["update_period"] != self.dialog.get_value("general", "update_period"): + config.app["app-settings"]["update_period"] = self.dialog.get_value("general", "update_period") + self.needs_restart = True + config.app["app-settings"]["voice_enabled"] = self.dialog.get_value("general", "disable_sapi5") + config.app["app-settings"]["hide_gui"] = self.dialog.get_value("general", "hide_gui") + config.app["app-settings"]["ask_at_exit"] = self.dialog.get_value("general", "ask_at_exit") + config.app["app-settings"]["handle_longtweets"] = self.dialog.get_value("general", "handle_longtweets") + config.app["app-settings"]["play_ready_sound"] = self.dialog.get_value("general", "play_ready_sound") + config.app["app-settings"]["speak_ready_msg"] = self.dialog.get_value("general", "speak_ready_msg") + config.app["app-settings"]["check_for_updates"] = self.dialog.get_value("general", "check_for_updates") + config.app["app-settings"]["remember_mention_and_longtweet"] = self.dialog.get_value("general", "remember_mention_and_longtweet") + if config.app["proxy"]["type"]!=self.dialog.get_value("proxy", "type") or config.app["proxy"]["server"] != self.dialog.get_value("proxy", "server") or config.app["proxy"]["port"] != self.dialog.get_value("proxy", "port") or config.app["proxy"]["user"] != self.dialog.get_value("proxy", "user") or config.app["proxy"]["password"] != self.dialog.get_value("proxy", "password"): + if self.is_started == True: + self.needs_restart = True + config.app["proxy"]["type"] = self.dialog.proxy.type.Selection + config.app["proxy"]["server"] = self.dialog.get_value("proxy", "server") + config.app["proxy"]["port"] = self.dialog.get_value("proxy", "port") + config.app["proxy"]["user"] = self.dialog.get_value("proxy", "user") + config.app["proxy"]["password"] = self.dialog.get_value("proxy", "password") + config.app.write() class accountSettingsController(globalSettingsController): - def __init__(self, buffer, window): - self.user = buffer.session.db["user_name"] - self.buffer = buffer - self.window = window - self.config = buffer.session.settings - super(accountSettingsController, self).__init__() + def __init__(self, buffer, window): + self.user = buffer.session.db["user_name"] + self.buffer = buffer + self.window = window + self.config = buffer.session.settings + super(accountSettingsController, self).__init__() - def create_config(self): - self.dialog.create_general_account() - widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete) - self.dialog.set_value("general", "relative_time", self.config["general"]["relative_times"]) - self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"]) - self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_tweets_per_call"]) - self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"]) - rt = self.config["general"]["retweet_mode"] - if rt == "ask": - self.dialog.set_value("general", "retweet_mode", _(u"Ask")) - elif rt == "direct": - self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments")) - else: - self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments")) - self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"])) - self.dialog.create_reporting() - self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"]) - self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"]) - self.dialog.create_other_buffers() - buffer_values = self.get_buffers_list() - self.dialog.buffers.insert_buffers(buffer_values) - self.dialog.buffers.connect_hook_func(self.toggle_buffer_active) - widgetUtils.connect_event(self.dialog.buffers.toggle_state, widgetUtils.BUTTON_PRESSED, self.toggle_state) - widgetUtils.connect_event(self.dialog.buffers.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up) - widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down) + def create_config(self): + self.dialog.create_general_account() + widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete) + self.dialog.set_value("general", "relative_time", self.config["general"]["relative_times"]) + self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"]) + self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_tweets_per_call"]) + self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"]) + rt = self.config["general"]["retweet_mode"] + if rt == "ask": + self.dialog.set_value("general", "retweet_mode", _(u"Ask")) + elif rt == "direct": + self.dialog.set_value("general", "retweet_mode", _(u"Retweet without comments")) + else: + self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments")) + self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"])) + self.dialog.create_reporting() + self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"]) + self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"]) + self.dialog.create_other_buffers() + buffer_values = self.get_buffers_list() + self.dialog.buffers.insert_buffers(buffer_values) + self.dialog.buffers.connect_hook_func(self.toggle_buffer_active) + widgetUtils.connect_event(self.dialog.buffers.toggle_state, widgetUtils.BUTTON_PRESSED, self.toggle_state) + widgetUtils.connect_event(self.dialog.buffers.up, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_up) + widgetUtils.connect_event(self.dialog.buffers.down, widgetUtils.BUTTON_PRESSED, self.dialog.buffers.move_down) - self.dialog.create_ignored_clients(self.config["twitter"]["ignored_clients"]) - widgetUtils.connect_event(self.dialog.ignored_clients.add, widgetUtils.BUTTON_PRESSED, self.add_ignored_client) - widgetUtils.connect_event(self.dialog.ignored_clients.remove, widgetUtils.BUTTON_PRESSED, self.remove_ignored_client) - self.input_devices = sound_lib.input.Input.get_device_names() - self.output_devices = sound_lib.output.Output.get_device_names() - self.soundpacks = [] - [self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(os.path.join(paths.sound_path(), i)) == True ] - self.dialog.create_sound(self.input_devices, self.output_devices, self.soundpacks) - self.dialog.set_value("sound", "volumeCtrl", self.config["sound"]["volume"]*100) - self.dialog.set_value("sound", "input", self.config["sound"]["input_device"]) - self.dialog.set_value("sound", "output", self.config["sound"]["output_device"]) - self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"]) - self.dialog.set_value("sound", "soundpack", self.config["sound"]["current_soundpack"]) - self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"]) - self.dialog.set_value("sound", "indicate_geo", self.config["sound"]["indicate_geo"]) - self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"]) - self.dialog.create_extras(OCRSpace.translatable_langs) - self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"]) - language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"]) - self.dialog.extras.ocr_lang.SetSelection(language_index) - self.dialog.realize() - self.dialog.set_title(_(u"Account settings for %s") % (self.user,)) - self.response = self.dialog.get_response() + self.dialog.create_ignored_clients(self.config["twitter"]["ignored_clients"]) + widgetUtils.connect_event(self.dialog.ignored_clients.add, widgetUtils.BUTTON_PRESSED, self.add_ignored_client) + widgetUtils.connect_event(self.dialog.ignored_clients.remove, widgetUtils.BUTTON_PRESSED, self.remove_ignored_client) + self.input_devices = sound_lib.input.Input.get_device_names() + self.output_devices = sound_lib.output.Output.get_device_names() + self.soundpacks = [] + [self.soundpacks.append(i) for i in os.listdir(paths.sound_path()) if os.path.isdir(os.path.join(paths.sound_path(), i)) == True ] + self.dialog.create_sound(self.input_devices, self.output_devices, self.soundpacks) + self.dialog.set_value("sound", "volumeCtrl", self.config["sound"]["volume"]*100) + self.dialog.set_value("sound", "input", self.config["sound"]["input_device"]) + self.dialog.set_value("sound", "output", self.config["sound"]["output_device"]) + self.dialog.set_value("sound", "session_mute", self.config["sound"]["session_mute"]) + self.dialog.set_value("sound", "soundpack", self.config["sound"]["current_soundpack"]) + self.dialog.set_value("sound", "indicate_audio", self.config["sound"]["indicate_audio"]) + self.dialog.set_value("sound", "indicate_geo", self.config["sound"]["indicate_geo"]) + self.dialog.set_value("sound", "indicate_img", self.config["sound"]["indicate_img"]) + self.dialog.create_extras(OCRSpace.translatable_langs) + self.dialog.set_value("extras", "sndup_apiKey", self.config["sound"]["sndup_api_key"]) + language_index = OCRSpace.OcrLangs.index(self.config["mysc"]["ocr_language"]) + self.dialog.extras.ocr_lang.SetSelection(language_index) + self.dialog.realize() + self.dialog.set_title(_(u"Account settings for %s") % (self.user,)) + self.response = self.dialog.get_response() - def save_configuration(self): - if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"): - self.needs_restart = True - self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time") - self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names") - self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall") - if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"): - if self.dialog.get_value("general", "persist_size") == '': - self.config["general"]["persist_size"] =-1 - else: - try: - self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size")) - except ValueError: - output.speak("Invalid cache size, setting to default.",True) - self.config["general"]["persist_size"] =1764 + def save_configuration(self): + if self.config["general"]["relative_times"] != self.dialog.get_value("general", "relative_time"): + self.needs_restart = True + self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time") + self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names") + self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall") + if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"): + if self.dialog.get_value("general", "persist_size") == '': + self.config["general"]["persist_size"] =-1 + else: + try: + self.config["general"]["persist_size"] = int(self.dialog.get_value("general", "persist_size")) + except ValueError: + output.speak("Invalid cache size, setting to default.",True) + self.config["general"]["persist_size"] =1764 - if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"): - self.needs_restart = True - self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines") - rt = self.dialog.get_value("general", "retweet_mode") - if rt == _(u"Ask"): - self.config["general"]["retweet_mode"] = "ask" - elif rt == _(u"Retweet without comments"): - self.config["general"]["retweet_mode"] = "direct" - else: - self.config["general"]["retweet_mode"] = "comment" - buffers_list = self.dialog.buffers.get_list() - if buffers_list != self.config["general"]["buffer_order"]: - self.needs_restart = True - self.config["general"]["buffer_order"] = buffers_list - self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting") - self.config["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting") - self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()] + if self.config["general"]["reverse_timelines"] != self.dialog.get_value("general", "reverse_timelines"): + self.needs_restart = True + self.config["general"]["reverse_timelines"] = self.dialog.get_value("general", "reverse_timelines") + rt = self.dialog.get_value("general", "retweet_mode") + if rt == _(u"Ask"): + self.config["general"]["retweet_mode"] = "ask" + elif rt == _(u"Retweet without comments"): + self.config["general"]["retweet_mode"] = "direct" + else: + self.config["general"]["retweet_mode"] = "comment" + buffers_list = self.dialog.buffers.get_list() + if buffers_list != self.config["general"]["buffer_order"]: + self.needs_restart = True + self.config["general"]["buffer_order"] = buffers_list + self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting") + self.config["reporting"]["braille_reporting"] = self.dialog.get_value("reporting", "braille_reporting") + self.config["mysc"]["ocr_language"] = OCRSpace.OcrLangs[self.dialog.extras.ocr_lang.GetSelection()] # if self.config["other_buffers"]["show_followers"] != self.dialog.get_value("buffers", "followers"): # self.config["other_buffers"]["show_followers"] = self.dialog.get_value("buffers", "followers") # pub.sendMessage("create-new-buffer", buffer="followers", account=self.user, create=self.config["other_buffers"]["show_followers"]) @@ -238,75 +238,75 @@ class accountSettingsController(globalSettingsController): # if self.config["other_buffers"]["show_events"] != self.dialog.get_value("buffers", "events"): # self.config["other_buffers"]["show_events"] = self.dialog.get_value("buffers", "events") # pub.sendMessage("create-new-buffer", buffer="events", account=self.user, create=self.config["other_buffers"]["show_events"]) - if self.config["sound"]["input_device"] != self.dialog.sound.get("input"): - self.config["sound"]["input_device"] = self.dialog.sound.get("input") - try: - self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"])) - except: - self.config["sound"]["input_device"] = "default" - if self.config["sound"]["output_device"] != self.dialog.sound.get("output"): - self.config["sound"]["output_device"] = self.dialog.sound.get("output") - try: - self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"])) - except: - self.config["sound"]["output_device"] = "default" - self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0 - self.config["sound"]["session_mute"] = self.dialog.get_value("sound", "session_mute") - self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack") - self.config["sound"]["indicate_audio"] = self.dialog.get_value("sound", "indicate_audio") - self.config["sound"]["indicate_geo"] = self.dialog.get_value("sound", "indicate_geo") - self.config["sound"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img") - self.config["sound"]["sndup_api_key"] = self.dialog.get_value("extras", "sndup_apiKey") - self.buffer.session.sound.config = self.config["sound"] - self.buffer.session.sound.check_soundpack() - self.config.write() + if self.config["sound"]["input_device"] != self.dialog.sound.get("input"): + self.config["sound"]["input_device"] = self.dialog.sound.get("input") + try: + self.buffer.session.sound.input.set_device(self.buffer.session.sound.input.find_device_by_name(self.config["sound"]["input_device"])) + except: + self.config["sound"]["input_device"] = "default" + if self.config["sound"]["output_device"] != self.dialog.sound.get("output"): + self.config["sound"]["output_device"] = self.dialog.sound.get("output") + try: + self.buffer.session.sound.output.set_device(self.buffer.session.sound.output.find_device_by_name(self.config["sound"]["output_device"])) + except: + self.config["sound"]["output_device"] = "default" + self.config["sound"]["volume"] = self.dialog.get_value("sound", "volumeCtrl")/100.0 + self.config["sound"]["session_mute"] = self.dialog.get_value("sound", "session_mute") + self.config["sound"]["current_soundpack"] = self.dialog.sound.get("soundpack") + self.config["sound"]["indicate_audio"] = self.dialog.get_value("sound", "indicate_audio") + self.config["sound"]["indicate_geo"] = self.dialog.get_value("sound", "indicate_geo") + self.config["sound"]["indicate_img"] = self.dialog.get_value("sound", "indicate_img") + self.config["sound"]["sndup_api_key"] = self.dialog.get_value("extras", "sndup_apiKey") + self.buffer.session.sound.config = self.config["sound"] + self.buffer.session.sound.check_soundpack() + self.config.write() - def toggle_state(self,*args,**kwargs): - return self.dialog.buffers.change_selected_item() + def toggle_state(self,*args,**kwargs): + return self.dialog.buffers.change_selected_item() - def manage_autocomplete(self, *args, **kwargs): - configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window) + def manage_autocomplete(self, *args, **kwargs): + configuration = settings.autocompletionSettings(self.buffer.session.settings, self.buffer, self.window) - def add_ignored_client(self, *args, **kwargs): - client = commonMessageDialogs.get_ignored_client() - if client == None: return - if client not in self.config["twitter"]["ignored_clients"]: - self.config["twitter"]["ignored_clients"].append(client) - self.dialog.ignored_clients.append(client) + def add_ignored_client(self, *args, **kwargs): + client = commonMessageDialogs.get_ignored_client() + if client == None: return + if client not in self.config["twitter"]["ignored_clients"]: + self.config["twitter"]["ignored_clients"].append(client) + self.dialog.ignored_clients.append(client) - def remove_ignored_client(self, *args, **kwargs): - if self.dialog.ignored_clients.get_clients() == 0: return - id = self.dialog.ignored_clients.get_client_id() - self.config["twitter"]["ignored_clients"].pop(id) - self.dialog.ignored_clients.remove_(id) + def remove_ignored_client(self, *args, **kwargs): + if self.dialog.ignored_clients.get_clients() == 0: return + id = self.dialog.ignored_clients.get_client_id() + self.config["twitter"]["ignored_clients"].pop(id) + self.dialog.ignored_clients.remove_(id) - def get_buffers_list(self): - all_buffers=OrderedDict() - all_buffers['home']=_(u"Home") - all_buffers['mentions']=_(u"Mentions") - all_buffers['dm']=_(u"Direct Messages") - all_buffers['sent_dm']=_(u"Sent direct messages") - all_buffers['sent_tweets']=_(u"Sent tweets") - all_buffers['favorites']=_(u"Likes") - all_buffers['followers']=_(u"Followers") - all_buffers['friends']=_(u"Friends") - all_buffers['blocks']=_(u"Blocked users") - all_buffers['muted']=_(u"Muted users") - list_buffers = [] - hidden_buffers=[] - all_buffers_keys = list(all_buffers.keys()) - # Check buffers shown first. - for i in self.config["general"]["buffer_order"]: - if i in all_buffers_keys: - list_buffers.append((i, all_buffers[i], True)) - # This second pass will retrieve all hidden buffers. - for i in all_buffers_keys: - if i not in self.config["general"]["buffer_order"]: - hidden_buffers.append((i, all_buffers[i], False)) - list_buffers.extend(hidden_buffers) - return list_buffers + def get_buffers_list(self): + all_buffers=OrderedDict() + all_buffers['home']=_(u"Home") + all_buffers['mentions']=_(u"Mentions") + all_buffers['dm']=_(u"Direct Messages") + all_buffers['sent_dm']=_(u"Sent direct messages") + all_buffers['sent_tweets']=_(u"Sent tweets") + all_buffers['favorites']=_(u"Likes") + all_buffers['followers']=_(u"Followers") + all_buffers['friends']=_(u"Friends") + all_buffers['blocks']=_(u"Blocked users") + all_buffers['muted']=_(u"Muted users") + list_buffers = [] + hidden_buffers=[] + all_buffers_keys = list(all_buffers.keys()) + # Check buffers shown first. + for i in self.config["general"]["buffer_order"]: + if i in all_buffers_keys: + list_buffers.append((i, all_buffers[i], True)) + # This second pass will retrieve all hidden buffers. + for i in all_buffers_keys: + if i not in self.config["general"]["buffer_order"]: + hidden_buffers.append((i, all_buffers[i], False)) + list_buffers.extend(hidden_buffers) + return list_buffers - def toggle_buffer_active(self, ev): - change = self.dialog.buffers.get_event(ev) - if change == True: - self.dialog.buffers.change_selected_item() \ No newline at end of file + def toggle_buffer_active(self, ev): + change = self.dialog.buffers.get_event(ev) + if change == True: + self.dialog.buffers.change_selected_item() diff --git a/src/controller/trendingTopics.py b/src/controller/trendingTopics.py index 5b6bd270..58234204 100644 --- a/src/controller/trendingTopics.py +++ b/src/controller/trendingTopics.py @@ -3,43 +3,43 @@ from wxUI.dialogs import trends import widgetUtils class trendingTopicsController(object): - def __init__(self, session): - super(trendingTopicsController, self).__init__() - self.countries = {} - self.cities = {} - self.dialog = trends.trendingTopicsDialog() - self.information = session.twitter.trends_available() - self.split_information() - widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places) - widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places) - self.get_places() + def __init__(self, session): + super(trendingTopicsController, self).__init__() + self.countries = {} + self.cities = {} + self.dialog = trends.trendingTopicsDialog() + self.information = session.twitter.trends_available() + self.split_information() + widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places) + widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places) + self.get_places() - def split_information(self): - for i in self.information: - if i["placeType"]["name"] == "Country": - self.countries[i["name"]] = i["woeid"] - else: - self.cities[i["name"]] = i["woeid"] + def split_information(self): + for i in self.information: + if i["placeType"]["name"] == "Country": + self.countries[i["name"]] = i["woeid"] + else: + self.cities[i["name"]] = i["woeid"] - def get_places(self, event=None): - values = [] - if self.dialog.get_active() == "country": - for i in self.information: - if i["placeType"]["name"] == "Country": - values.append(i["name"]) - elif self.dialog.get_active() == "city": - for i in self.information: - if i["placeType"]["name"] != "Country": - values.append(i["name"]) - self.dialog.set(values) + def get_places(self, event=None): + values = [] + if self.dialog.get_active() == "country": + for i in self.information: + if i["placeType"]["name"] == "Country": + values.append(i["name"]) + elif self.dialog.get_active() == "city": + for i in self.information: + if i["placeType"]["name"] != "Country": + values.append(i["name"]) + self.dialog.set(values) - def get_woeid(self): - selected = self.dialog.get_item() - if self.dialog.get_active() == "country": - woeid = self.countries[selected] - else: - woeid = self.cities[selected] - return woeid + def get_woeid(self): + selected = self.dialog.get_item() + if self.dialog.get_active() == "country": + woeid = self.countries[selected] + else: + woeid = self.cities[selected] + return woeid - def get_string(self): - return self.dialog.get_item() \ No newline at end of file + def get_string(self): + return self.dialog.get_item() diff --git a/src/controller/user.py b/src/controller/user.py index 9293b5c7..755b21ba 100644 --- a/src/controller/user.py +++ b/src/controller/user.py @@ -10,119 +10,119 @@ from tweepy.error import TweepError from sessions.twitter import utils class profileController(object): - def __init__(self, session, user=None): - super(profileController, self).__init__() - self.file = None - self.session = session - self.user = user - if user == None: - self.get_data(screen_name=self.session.db["user_name"]) - self.dialog = update_profile.updateProfileDialog() - self.fill_profile_fields() - self.uploaded = False - widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) - else: - try: - self.get_data(screen_name=self.user) - except TweepError as err: - if err.api_code == 50: - wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() - if err.api_code == 403: - wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal() - log.error("error %d: %s" % (err.api_code, err.reason)) - return - self.dialog = show_user.showUserProfile() - string = self.get_user_info() - self.dialog.set("text", string) - self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name)) - if self.data.url != None: - self.dialog.enable_url() - widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url) - if self.dialog.get_response() == widgetUtils.OK and self.user == None: - self.do_update() + def __init__(self, session, user=None): + super(profileController, self).__init__() + self.file = None + self.session = session + self.user = user + if user == None: + self.get_data(screen_name=self.session.db["user_name"]) + self.dialog = update_profile.updateProfileDialog() + self.fill_profile_fields() + self.uploaded = False + widgetUtils.connect_event(self.dialog.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) + else: + try: + self.get_data(screen_name=self.user) + except TweepError as err: + if err.api_code == 50: + wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() + if err.api_code == 403: + wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal() + log.error("error %d: %s" % (err.api_code, err.reason)) + return + self.dialog = show_user.showUserProfile() + string = self.get_user_info() + self.dialog.set("text", string) + self.dialog.set_title(_(u"Information for %s") % (self.data.screen_name)) + if self.data.url != None: + self.dialog.enable_url() + widgetUtils.connect_event(self.dialog.url, widgetUtils.BUTTON_PRESSED, self.visit_url) + if self.dialog.get_response() == widgetUtils.OK and self.user == None: + self.do_update() - def get_data(self, screen_name): - self.data = self.session.twitter.get_user(screen_name=screen_name) - if screen_name != self.session.db["user_name"]: - self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name) + def get_data(self, screen_name): + self.data = self.session.twitter.get_user(screen_name=screen_name) + if screen_name != self.session.db["user_name"]: + self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name) - def fill_profile_fields(self): - self.dialog.set_name(self.data.name) - if self.data.url != None: - self.dialog.set_url(self.data.url) - if len(self.data.location) > 0: - self.dialog.set_location(self.data.location) - if len(self.data.description) > 0: - self.dialog.set_description(self.data.description) + def fill_profile_fields(self): + self.dialog.set_name(self.data.name) + if self.data.url != None: + self.dialog.set_url(self.data.url) + if len(self.data.location) > 0: + self.dialog.set_location(self.data.location) + if len(self.data.description) > 0: + self.dialog.set_description(self.data.description) - def get_image(self): - file = self.dialog.upload_picture() - if file != None: - self.file = open(file, "rb") - self.uploaded = True - self.dialog.change_upload_button(self.uploaded) + def get_image(self): + file = self.dialog.upload_picture() + if file != None: + self.file = open(file, "rb") + self.uploaded = True + self.dialog.change_upload_button(self.uploaded) - def discard_image(self): - self.file = None - output.speak(_(u"Discarded")) - self.uploaded = False - self.dialog.change_upload_button(self.uploaded) + def discard_image(self): + self.file = None + output.speak(_(u"Discarded")) + self.uploaded = False + self.dialog.change_upload_button(self.uploaded) - def upload_image(self, *args, **kwargs): - if self.uploaded == False: - self.get_image() - elif self.uploaded == True: - self.discard_image() + def upload_image(self, *args, **kwargs): + if self.uploaded == False: + self.get_image() + elif self.uploaded == True: + self.discard_image() - def do_update(self): - if self.user != None: return - name = self.dialog.get("name") - description = self.dialog.get("description") - location = self.dialog.get("location") - url = self.dialog.get("url") - if self.file != None: - try: - self.session.twitter.update_profile_image(image=self.file) - except TweepError as e: - output.speak(u"Error %s. %s" % (e.api_code, e.reason)) - try: - self.session.twitter.update_profile(name=name, description=description, location=location, url=url) - except TweepError as e: - output.speak(u"Error %s. %s" % (e.api_code, e.reason)) + def do_update(self): + if self.user != None: return + name = self.dialog.get("name") + description = self.dialog.get("description") + location = self.dialog.get("location") + url = self.dialog.get("url") + if self.file != None: + try: + self.session.twitter.update_profile_image(image=self.file) + except TweepError as e: + output.speak(u"Error %s. %s" % (e.api_code, e.reason)) + try: + self.session.twitter.update_profile(name=name, description=description, location=location, url=url) + except TweepError as e: + output.speak(u"Error %s. %s" % (e.api_code, e.reason)) - def get_user_info(self): - string = u"" - string = string + _(u"Username: @%s\n") % (self.data.screen_name) - string = string + _(u"Name: %s\n") % (self.data.name) - if self.data.location != "": - string = string + _(u"Location: %s\n") % (self.data.location) - if self.data.url != None: - string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"]) - if self.data.description != "": - if self.data.entities.get("description") != None and self.data.entities["description"].get("urls"): - self.data.description = utils.expand_urls(self.data.description, self.data.entities["description"]) - string = string+ _(u"Bio: %s\n") % (self.data.description) - if self.data.protected == True: protected = _(u"Yes") - else: protected = _(u"No") - string = string+ _(u"Protected: %s\n") % (protected) - if hasattr(self, "friendship_status"): - relation = False - friendship = "Relationship: " - if self.friendship_status[0].following: - friendship += _(u"You follow {0}. ").format(self.data.name,) - relation = True - if self.friendship_status[1].following: - friendship += _(u"{0} is following you.").format(self.data.name,) - relation = True - if relation == True: - string = string+friendship+"\n" - string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data.followers_count, self.data.friends_count) - if self.data.verified == True: verified = _(u"Yes") - else: verified = _(u"No") - string = string+ _(u"Verified: %s\n") % (verified) - string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count) - string = string+ _(u"Likes: %s") % (self.data.favourites_count) - return string + def get_user_info(self): + string = u"" + string = string + _(u"Username: @%s\n") % (self.data.screen_name) + string = string + _(u"Name: %s\n") % (self.data.name) + if self.data.location != "": + string = string + _(u"Location: %s\n") % (self.data.location) + if self.data.url != None: + string = string+ _(u"URL: %s\n") % (self.data.entities["url"]["urls"][0]["expanded_url"]) + if self.data.description != "": + if self.data.entities.get("description") != None and self.data.entities["description"].get("urls"): + self.data.description = utils.expand_urls(self.data.description, self.data.entities["description"]) + string = string+ _(u"Bio: %s\n") % (self.data.description) + if self.data.protected == True: protected = _(u"Yes") + else: protected = _(u"No") + string = string+ _(u"Protected: %s\n") % (protected) + if hasattr(self, "friendship_status"): + relation = False + friendship = "Relationship: " + if self.friendship_status[0].following: + friendship += _(u"You follow {0}. ").format(self.data.name,) + relation = True + if self.friendship_status[1].following: + friendship += _(u"{0} is following you.").format(self.data.name,) + relation = True + if relation == True: + string = string+friendship+"\n" + string = string+_(u"Followers: %s\n Friends: %s\n") % (self.data.followers_count, self.data.friends_count) + if self.data.verified == True: verified = _(u"Yes") + else: verified = _(u"No") + string = string+ _(u"Verified: %s\n") % (verified) + string = string+ _(u"Tweets: %s\n") % (self.data.statuses_count) + string = string+ _(u"Likes: %s") % (self.data.favourites_count) + return string - def visit_url(self, *args, **kwargs): - webbrowser.open_new_tab(self.data.url) \ No newline at end of file + def visit_url(self, *args, **kwargs): + webbrowser.open_new_tab(self.data.url) diff --git a/src/controller/userActionsController.py b/src/controller/userActionsController.py index 54f4ba16..623dc818 100644 --- a/src/controller/userActionsController.py +++ b/src/controller/userActionsController.py @@ -7,73 +7,73 @@ from tweepy.error import TweepError from extra import autocompletionUsers class userActionsController(object): - def __init__(self, buffer, users=[], default="follow"): - super(userActionsController, self).__init__() - self.buffer = buffer - self.session = buffer.session - self.dialog = userActions.UserActionsDialog(users, default) - widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) - if self.dialog.get_response() == widgetUtils.OK: - self.process_action() + def __init__(self, buffer, users=[], default="follow"): + super(userActionsController, self).__init__() + self.buffer = buffer + self.session = buffer.session + self.dialog = userActions.UserActionsDialog(users, default) + widgetUtils.connect_event(self.dialog.autocompletion, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + if self.dialog.get_response() == widgetUtils.OK: + self.process_action() - def autocomplete_users(self, *args, **kwargs): - c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id) - c.show_menu("dm") + def autocomplete_users(self, *args, **kwargs): + c = autocompletionUsers.completion.autocompletionUsers(self.dialog, self.session.session_id) + c.show_menu("dm") - def process_action(self): - action = self.dialog.get_action() - user = self.dialog.get_user() - if user == "": return - getattr(self, action)(user) + def process_action(self): + action = self.dialog.get_action() + user = self.dialog.get_user() + if user == "": return + getattr(self, action)(user) - def follow(self, user): - try: - self.session.twitter.create_friendship(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def follow(self, user): + try: + self.session.twitter.create_friendship(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def unfollow(self, user): - try: - id = self.session.twitter.destroy_friendship(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def unfollow(self, user): + try: + id = self.session.twitter.destroy_friendship(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def mute(self, user): - try: - id = self.session.twitter.create_mute(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def mute(self, user): + try: + id = self.session.twitter.create_mute(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def unmute(self, user): - try: - id = self.session.twitter.destroy_mute(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def unmute(self, user): + try: + id = self.session.twitter.destroy_mute(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def report(self, user): - try: - id = self.session.twitter.report_spam(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def report(self, user): + try: + id = self.session.twitter.report_spam(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def block(self, user): - try: - id = self.session.twitter.create_block(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def block(self, user): + try: + id = self.session.twitter.create_block(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def unblock(self, user): - try: - id = self.session.twitter.destroy_block(screen_name=user ) - except TweepError as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + def unblock(self, user): + try: + id = self.session.twitter.destroy_block(screen_name=user ) + except TweepError as err: + output.speak("Error %s: %s" % (err.api_code, err.reason), True) - def ignore_client(self, user): - tweet = self.buffer.get_right_tweet() - if hasattr(tweet, "sender"): - output.speak(_(u"You can't ignore direct messages")) - return - client = tweet.source - if client not in self.session.settings["twitter"]["ignored_clients"]: - self.session.settings["twitter"]["ignored_clients"].append(client) - self.session.settings.write() \ No newline at end of file + def ignore_client(self, user): + tweet = self.buffer.get_right_tweet() + if hasattr(tweet, "sender"): + output.speak(_(u"You can't ignore direct messages")) + return + client = tweet.source + if client not in self.session.settings["twitter"]["ignored_clients"]: + self.session.settings["twitter"]["ignored_clients"].append(client) + self.session.settings.write() diff --git a/src/extra/AudioUploader/audioUploader.py b/src/extra/AudioUploader/audioUploader.py index 7f23fbbd..0ba6f82e 100644 --- a/src/extra/AudioUploader/audioUploader.py +++ b/src/extra/AudioUploader/audioUploader.py @@ -37,146 +37,146 @@ import logging log = logging.getLogger("extra.AudioUploader.audioUploader") class audioUploader(object): - def __init__(self, configFile, completed_callback): - self.config = configFile - super(audioUploader, self).__init__() - self.dialog = wx_ui.audioDialog(services=self.get_available_services()) - self.file = None - self.recorded = False - self.recording = None - self.playing = None - widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) - widgetUtils.connect_event(self.dialog.pause, widgetUtils.BUTTON_PRESSED, self.on_pause) - widgetUtils.connect_event(self.dialog.record, widgetUtils.BUTTON_PRESSED, self.on_record) - widgetUtils.connect_event(self.dialog.attach_exists, widgetUtils.BUTTON_PRESSED, self.on_attach_exists) - widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard) - if self.dialog.get_response() == widgetUtils.OK: - self.postprocess() - log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services"))) - self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file) - output.speak(_(u"Attaching...")) - if self.dialog.get("services") == "SNDUp": - base_url = "https://sndup.net/post.php" - if len(self.config["sound"]["sndup_api_key"]) > 0: - url = base_url + '?apikey=' + self.config['sound']['sndup_api_key'] - else: - url = base_url - self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback) - pub.subscribe(self.uploaderDialog.update, "uploading") - self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded) + def __init__(self, configFile, completed_callback): + self.config = configFile + super(audioUploader, self).__init__() + self.dialog = wx_ui.audioDialog(services=self.get_available_services()) + self.file = None + self.recorded = False + self.recording = None + self.playing = None + widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) + widgetUtils.connect_event(self.dialog.pause, widgetUtils.BUTTON_PRESSED, self.on_pause) + widgetUtils.connect_event(self.dialog.record, widgetUtils.BUTTON_PRESSED, self.on_record) + widgetUtils.connect_event(self.dialog.attach_exists, widgetUtils.BUTTON_PRESSED, self.on_attach_exists) + widgetUtils.connect_event(self.dialog.discard, widgetUtils.BUTTON_PRESSED, self.on_discard) + if self.dialog.get_response() == widgetUtils.OK: + self.postprocess() + log.debug("Uploading file %s to %s..." % (self.file, self.dialog.get("services"))) + self.uploaderDialog = wx_transfer_dialogs.UploadDialog(self.file) + output.speak(_(u"Attaching...")) + if self.dialog.get("services") == "SNDUp": + base_url = "https://sndup.net/post.php" + if len(self.config["sound"]["sndup_api_key"]) > 0: + url = base_url + '?apikey=' + self.config['sound']['sndup_api_key'] + else: + url = base_url + self.uploaderFunction = transfer.Upload(obj=self, field='file', url=url, filename=self.file, completed_callback=completed_callback) + pub.subscribe(self.uploaderDialog.update, "uploading") + self.uploaderDialog.get_response(self.uploaderFunction.perform_threaded) - def get_available_services(self): - services = [] - services.append("SNDUp") - return services + def get_available_services(self): + services = [] + services.append("SNDUp") + return services - def on_pause(self, *args, **kwargs): - if self.dialog.get("pause") == _(u"Pause"): - self.recording.pause() - self.dialog.set("pause", _(u"&Resume")) - elif self.dialog.get("pause") == _(u"Resume"): - self.recording.play() - self.dialog.set("pause", _(U"&Pause")) + def on_pause(self, *args, **kwargs): + if self.dialog.get("pause") == _(u"Pause"): + self.recording.pause() + self.dialog.set("pause", _(u"&Resume")) + elif self.dialog.get("pause") == _(u"Resume"): + self.recording.play() + self.dialog.set("pause", _(U"&Pause")) - def on_record(self, *args, **kwargs): - if self.recording != None: - self.stop_recording() - self.dialog.disable_control("pause") - else: - self.start_recording() - self.dialog.enable_control("pause") + def on_record(self, *args, **kwargs): + if self.recording != None: + self.stop_recording() + self.dialog.disable_control("pause") + else: + self.start_recording() + self.dialog.enable_control("pause") - def start_recording(self): - self.dialog.disable_control("attach_exists") - self.file = tempfile.mktemp(suffix='.wav') - self.recording = sound.recording(self.file) - self.recording.play() - self.dialog.set("record", _(u"&Stop")) - output.speak(_(u"Recording")) + def start_recording(self): + self.dialog.disable_control("attach_exists") + self.file = tempfile.mktemp(suffix='.wav') + self.recording = sound.recording(self.file) + self.recording.play() + self.dialog.set("record", _(u"&Stop")) + output.speak(_(u"Recording")) - def stop_recording(self): - self.recording.stop() - self.recording.free() - output.speak(_(u"Stopped")) - self.recorded = True - self.dialog.set("record", _(u"&Record")) - self.file_attached() + def stop_recording(self): + self.recording.stop() + self.recording.free() + output.speak(_(u"Stopped")) + self.recorded = True + self.dialog.set("record", _(u"&Record")) + self.file_attached() - def file_attached(self): - self.dialog.set("pause", _(u"&Pause")) - self.dialog.disable_control("record") - self.dialog.enable_control("play") - self.dialog.enable_control("discard") - self.dialog.disable_control("attach_exists") - self.dialog.enable_control("attach") - self.dialog.play.SetFocus() + def file_attached(self): + self.dialog.set("pause", _(u"&Pause")) + self.dialog.disable_control("record") + self.dialog.enable_control("play") + self.dialog.enable_control("discard") + self.dialog.disable_control("attach_exists") + self.dialog.enable_control("attach") + self.dialog.play.SetFocus() - def on_discard(self, *args, **kwargs): - if self.playing: - self._stop() - if self.recording != None: - self.cleanup() - self.dialog.disable_control("attach") - self.dialog.disable_control("play") - self.file = None - self.dialog.enable_control("record") - self.dialog.enable_control("attach_exists") - self.dialog.record.SetFocus() - self.dialog.disable_control("discard") - self.recording = None - output.speak(_(u"Discarded")) + def on_discard(self, *args, **kwargs): + if self.playing: + self._stop() + if self.recording != None: + self.cleanup() + self.dialog.disable_control("attach") + self.dialog.disable_control("play") + self.file = None + self.dialog.enable_control("record") + self.dialog.enable_control("attach_exists") + self.dialog.record.SetFocus() + self.dialog.disable_control("discard") + self.recording = None + output.speak(_(u"Discarded")) - def on_play(self, *args, **kwargs): - if not self.playing: - call_threaded(self._play) - else: - self._stop() + def on_play(self, *args, **kwargs): + if not self.playing: + call_threaded(self._play) + else: + self._stop() - def _play(self): - output.speak(_(u"Playing...")) + def _play(self): + output.speak(_(u"Playing...")) # try: - self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE) - self.playing.play() - self.dialog.set("play", _(u"&Stop")) - try: - while self.playing.is_playing: - pass - self.dialog.set("play", _(u"&Play")) - self.playing.free() - self.playing = None - except: - pass + self.playing = sound_lib.stream.FileStream(file=str(self.file), flags=sound_lib.stream.BASS_UNICODE) + self.playing.play() + self.dialog.set("play", _(u"&Stop")) + try: + while self.playing.is_playing: + pass + self.dialog.set("play", _(u"&Play")) + self.playing.free() + self.playing = None + except: + pass - def _stop(self): - output.speak(_(u"Stopped")) - self.playing.stop() - self.playing.free() - self.dialog.set("play", _(u"&Play")) - self.playing = None + def _stop(self): + output.speak(_(u"Stopped")) + self.playing.stop() + self.playing.free() + self.dialog.set("play", _(u"&Play")) + self.playing = None - def postprocess(self): - if self.file.lower().endswith('.wav'): - output.speak(_(u"Recoding audio...")) - sound.recode_audio(self.file) - self.wav_file = self.file - self.file = '%s.ogg' % self.file[:-4] + def postprocess(self): + if self.file.lower().endswith('.wav'): + output.speak(_(u"Recoding audio...")) + sound.recode_audio(self.file) + self.wav_file = self.file + self.file = '%s.ogg' % self.file[:-4] - def cleanup(self): - if self.playing and self.playing.is_playing: - self.playing.stop() - if self.recording != None: - if self.recording.is_playing: - self.recording.stop() - try: - self.recording.free() - except: - pass - os.remove(self.file) - if hasattr(self, 'wav_file'): - os.remove(self.wav_file) + def cleanup(self): + if self.playing and self.playing.is_playing: + self.playing.stop() + if self.recording != None: + if self.recording.is_playing: + self.recording.stop() + try: + self.recording.free() + except: + pass + os.remove(self.file) + if hasattr(self, 'wav_file'): + os.remove(self.wav_file) - def on_attach_exists(self, *args, **kwargs): - self.file = self.dialog.get_file() - if self.file != False: - self.file_attached() + def on_attach_exists(self, *args, **kwargs): + self.file = self.dialog.get_file() + if self.file != False: + self.file_attached() diff --git a/src/extra/AudioUploader/transfer.py b/src/extra/AudioUploader/transfer.py index a567f753..8c6bc670 100644 --- a/src/extra/AudioUploader/transfer.py +++ b/src/extra/AudioUploader/transfer.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from __future__ import division -from __future__ import unicode_literals -from builtins import object -from past.utils import old_div +from __future__ import division +from __future__ import unicode_literals +from builtins import object +from past.utils import old_div import sys import threading import time @@ -15,74 +15,74 @@ from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncod import requests import os class Upload(object): - def __init__(self, field=None, obj=None, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs): - super(Upload, self).__init__(*args, **kwargs) - self.url=url - self.filename=filename - log.debug("Uploading audio to %s, filename %s" % (url, filename)) - self.start_time = None - self.completed_callback = completed_callback - self.background_thread = None - self.transfer_rate = 0 - self.local_filename=os.path.basename(self.filename) - if isinstance(self.local_filename, str): - self.local_filename=self.local_filename.encode(sys.getfilesystemencoding()) - self.fin=open(self.filename, 'rb') - self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")}) - self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback) - self.response=None - self.obj=obj - self.follow_location=follow_location - #the verbose parameter is deprecated and will be removed soon + def __init__(self, field=None, obj=None, url=None, filename=None, follow_location=True, completed_callback=None, verbose=False, *args, **kwargs): + super(Upload, self).__init__(*args, **kwargs) + self.url=url + self.filename=filename + log.debug("Uploading audio to %s, filename %s" % (url, filename)) + self.start_time = None + self.completed_callback = completed_callback + self.background_thread = None + self.transfer_rate = 0 + self.local_filename=os.path.basename(self.filename) + if isinstance(self.local_filename, str): + self.local_filename=self.local_filename.encode(sys.getfilesystemencoding()) + self.fin=open(self.filename, 'rb') + self.m = MultipartEncoder(fields={field:(self.local_filename, self.fin, "application/octet-stream")}) + self.monitor = MultipartEncoderMonitor(self.m, self.progress_callback) + self.response=None + self.obj=obj + self.follow_location=follow_location + #the verbose parameter is deprecated and will be removed soon - def elapsed_time(self): - if not self.start_time: - return 0 - return time.time() - self.start_time + def elapsed_time(self): + if not self.start_time: + return 0 + return time.time() - self.start_time - def progress_callback(self, monitor): - progress = {} - progress["total"] = monitor.len - progress["current"] = monitor.bytes_read - if progress["current"] == 0: - progress["percent"] = 0 - self.transfer_rate = 0 - else: - progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100) - self.transfer_rate = old_div(progress["current"], self.elapsed_time()) - progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate) - if self.transfer_rate: - progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate) - else: - progress["eta"] = 0 - pub.sendMessage("uploading", data=progress) + def progress_callback(self, monitor): + progress = {} + progress["total"] = monitor.len + progress["current"] = monitor.bytes_read + if progress["current"] == 0: + progress["percent"] = 0 + self.transfer_rate = 0 + else: + progress["percent"] = int((float(progress["current"]) / progress["total"]) * 100) + self.transfer_rate = old_div(progress["current"], self.elapsed_time()) + progress["speed"] = '%s/s' % convert_bytes(self.transfer_rate) + if self.transfer_rate: + progress["eta"] = old_div((progress["total"] - progress["current"]), self.transfer_rate) + else: + progress["eta"] = 0 + pub.sendMessage("uploading", data=progress) - def perform_transfer(self): - log.debug("starting upload...") - self.start_time = time.time() - self.response=requests.post(url=self.url, data=self.monitor, headers={"Content-Type":self.m.content_type}, allow_redirects=self.follow_location, stream=True) - log.debug("Upload finished.") - self.complete_transfer() + def perform_transfer(self): + log.debug("starting upload...") + self.start_time = time.time() + self.response=requests.post(url=self.url, data=self.monitor, headers={"Content-Type":self.m.content_type}, allow_redirects=self.follow_location, stream=True) + log.debug("Upload finished.") + self.complete_transfer() - def perform_threaded(self, *args, **kwargs): - self.background_thread = threading.Thread(target=self.perform_transfer) - self.background_thread.daemon = True - self.background_thread.start() + def perform_threaded(self, *args, **kwargs): + self.background_thread = threading.Thread(target=self.perform_transfer) + self.background_thread.daemon = True + self.background_thread.start() - def complete_transfer(self): - if callable(self.completed_callback): - self.completed_callback(self.obj) - if hasattr(self,'fin') and callable(self.fin.close): - self.fin.close() + def complete_transfer(self): + if callable(self.completed_callback): + self.completed_callback(self.obj) + if hasattr(self,'fin') and callable(self.fin.close): + self.fin.close() - def get_url(self): - try: - data = self.response.json() - except: - return _("Error in file upload: {0}").format(self.data.content,) - if "url" in data and data["url"] != "0": - return data["url"] - elif "error" in data and data["error"] != "0": - return data["error"] - else: - return _("Error in file upload: {0}").format(self.data.content,) \ No newline at end of file + def get_url(self): + try: + data = self.response.json() + except: + return _("Error in file upload: {0}").format(self.data.content,) + if "url" in data and data["url"] != "0": + return data["url"] + elif "error" in data and data["error"] != "0": + return data["error"] + else: + return _("Error in file upload: {0}").format(self.data.content,) diff --git a/src/extra/AudioUploader/utils.py b/src/extra/AudioUploader/utils.py index 9ec89156..c9bbdc9a 100644 --- a/src/extra/AudioUploader/utils.py +++ b/src/extra/AudioUploader/utils.py @@ -3,42 +3,42 @@ from __future__ import unicode_literals from builtins import str def convert_bytes(n): - K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 - if n >= P: - return '%.2fPb' % (float(n) / T) - elif n >= T: - return '%.2fTb' % (float(n) / T) - elif n >= G: - return '%.2fGb' % (float(n) / G) - elif n >= M: - return '%.2fMb' % (float(n) / M) - elif n >= K: - return '%.2fKb' % (float(n) / K) - else: - return '%d' % n + K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 + if n >= P: + return '%.2fPb' % (float(n) / T) + elif n >= T: + return '%.2fTb' % (float(n) / T) + elif n >= G: + return '%.2fGb' % (float(n) / G) + elif n >= M: + return '%.2fMb' % (float(n) / M) + elif n >= K: + return '%.2fKb' % (float(n) / K) + else: + return '%d' % n def seconds_to_string(seconds, precision=0): - day = seconds // 86400 - hour = seconds // 3600 - min = (seconds // 60) % 60 - sec = seconds - (hour * 3600) - (min * 60) - sec_spec = "." + str(precision) + "f" - sec_string = sec.__format__(sec_spec) - string = "" - if day == 1: - string += _(u"%d day, ") % day - elif day >= 2: - string += _(u"%d days, ") % day - if (hour == 1): - string += _(u"%d hour, ") % hour - elif (hour >= 2): - string += _("%d hours, ") % hour - if (min == 1): - string += _(u"%d minute, ") % min - elif (min >= 2): - string += _(u"%d minutes, ") % min - if sec >= 0 and sec <= 2: - string += _(u"%s second") % sec_string - else: - string += _(u"%s seconds") % sec_string - return string \ No newline at end of file + day = seconds // 86400 + hour = seconds // 3600 + min = (seconds // 60) % 60 + sec = seconds - (hour * 3600) - (min * 60) + sec_spec = "." + str(precision) + "f" + sec_string = sec.__format__(sec_spec) + string = "" + if day == 1: + string += _(u"%d day, ") % day + elif day >= 2: + string += _(u"%d days, ") % day + if (hour == 1): + string += _(u"%d hour, ") % hour + elif (hour >= 2): + string += _("%d hours, ") % hour + if (min == 1): + string += _(u"%d minute, ") % min + elif (min >= 2): + string += _(u"%d minutes, ") % min + if sec >= 0 and sec <= 2: + string += _(u"%s second") % sec_string + else: + string += _(u"%s seconds") % sec_string + return string diff --git a/src/extra/AudioUploader/wx_transfer_dialogs.py b/src/extra/AudioUploader/wx_transfer_dialogs.py index b70d343e..fc14b201 100644 --- a/src/extra/AudioUploader/wx_transfer_dialogs.py +++ b/src/extra/AudioUploader/wx_transfer_dialogs.py @@ -7,57 +7,57 @@ import widgetUtils class UploadDialog(widgetUtils.BaseDialog): - def __init__(self, filename, *args, **kwargs): - super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs) - self.pane = wx.Panel(self) - self.progress_bar = wx.Gauge(parent=self.pane) - fileBox = wx.BoxSizer(wx.HORIZONTAL) - fileLabel = wx.StaticText(self.pane, -1, _(u"File")) - self.file = wx.TextCtrl(self.pane, -1, value=filename, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(200, 100)) - self.file.SetFocus() - fileBox.Add(fileLabel) - fileBox.Add(self.file) - currentAmountBox = wx.BoxSizer(wx.HORIZONTAL) - current_amount_label = wx.StaticText(self.pane, -1, _(u"Transferred")) - self.current_amount = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE) - currentAmountBox.Add(current_amount_label) - currentAmountBox.Add(self.current_amount) - totalSizeBox = wx.BoxSizer(wx.HORIZONTAL) - total_size_label = wx.StaticText(self.pane, -1, _(u"Total file size")) - self.total_size = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE) - totalSizeBox.Add(total_size_label) - totalSizeBox.Add(self.total_size) - speedBox = wx.BoxSizer(wx.HORIZONTAL) - speedLabel = wx.StaticText(self.pane, -1, _(u"Transfer rate")) - self.speed = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="0 Kb/s") - speedBox.Add(speedLabel) - speedBox.Add(self.speed) - etaBox = wx.BoxSizer(wx.HORIZONTAL) - etaLabel = wx.StaticText(self.pane, -1, _(u"Time left")) - self.eta = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="Unknown", size=(200, 100)) - etaBox.Add(etaLabel) - etaBox.Add(self.eta) - self.create_buttons() - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(fileBox) - sizer.Add(currentAmountBox) - sizer.Add(totalSizeBox) - sizer.Add(speedBox) - sizer.Add(etaBox) - sizer.Add(self.progress_bar) - self.pane.SetSizerAndFit(sizer) + def __init__(self, filename, *args, **kwargs): + super(UploadDialog, self).__init__(parent=None, id=wx.ID_ANY, *args, **kwargs) + self.pane = wx.Panel(self) + self.progress_bar = wx.Gauge(parent=self.pane) + fileBox = wx.BoxSizer(wx.HORIZONTAL) + fileLabel = wx.StaticText(self.pane, -1, _(u"File")) + self.file = wx.TextCtrl(self.pane, -1, value=filename, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(200, 100)) + self.file.SetFocus() + fileBox.Add(fileLabel) + fileBox.Add(self.file) + currentAmountBox = wx.BoxSizer(wx.HORIZONTAL) + current_amount_label = wx.StaticText(self.pane, -1, _(u"Transferred")) + self.current_amount = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE) + currentAmountBox.Add(current_amount_label) + currentAmountBox.Add(self.current_amount) + totalSizeBox = wx.BoxSizer(wx.HORIZONTAL) + total_size_label = wx.StaticText(self.pane, -1, _(u"Total file size")) + self.total_size = wx.TextCtrl(self.pane, -1, value='0', style=wx.TE_READONLY|wx.TE_MULTILINE) + totalSizeBox.Add(total_size_label) + totalSizeBox.Add(self.total_size) + speedBox = wx.BoxSizer(wx.HORIZONTAL) + speedLabel = wx.StaticText(self.pane, -1, _(u"Transfer rate")) + self.speed = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="0 Kb/s") + speedBox.Add(speedLabel) + speedBox.Add(self.speed) + etaBox = wx.BoxSizer(wx.HORIZONTAL) + etaLabel = wx.StaticText(self.pane, -1, _(u"Time left")) + self.eta = wx.TextCtrl(self.pane, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, value="Unknown", size=(200, 100)) + etaBox.Add(etaLabel) + etaBox.Add(self.eta) + self.create_buttons() + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(fileBox) + sizer.Add(currentAmountBox) + sizer.Add(totalSizeBox) + sizer.Add(speedBox) + sizer.Add(etaBox) + sizer.Add(self.progress_bar) + self.pane.SetSizerAndFit(sizer) - def update(self, data): - wx.CallAfter(self.progress_bar.SetValue, data["percent"]) - wx.CallAfter(self.current_amount.SetValue, '%s (%d%%)' % (convert_bytes(data["current"]), data["percent"])) - wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"])) - wx.CallAfter(self.speed.SetValue, data["speed"]) - if data["eta"]: - wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"])) + def update(self, data): + wx.CallAfter(self.progress_bar.SetValue, data["percent"]) + wx.CallAfter(self.current_amount.SetValue, '%s (%d%%)' % (convert_bytes(data["current"]), data["percent"])) + wx.CallAfter(self.total_size.SetValue, convert_bytes(data["total"])) + wx.CallAfter(self.speed.SetValue, data["speed"]) + if data["eta"]: + wx.CallAfter(self.eta.SetValue, seconds_to_string(data["eta"])) - def create_buttons(self): - self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL) + def create_buttons(self): + self.cancel_button = wx.Button(parent=self.pane, id=wx.ID_CANCEL) - def get_response(self, fn): - wx.CallAfter(fn, 0.01) - self.ShowModal() + def get_response(self, fn): + wx.CallAfter(fn, 0.01) + self.ShowModal() diff --git a/src/extra/AudioUploader/wx_ui.py b/src/extra/AudioUploader/wx_ui.py index 05fdbcc7..dc64dab4 100644 --- a/src/extra/AudioUploader/wx_ui.py +++ b/src/extra/AudioUploader/wx_ui.py @@ -24,56 +24,56 @@ import logging log = logging.getLogger("extra.AudioUploader.wx_UI") class audioDialog(widgetUtils.BaseDialog): - def __init__(self, services): - log.debug("creating audio dialog.") - super(audioDialog, self).__init__(None, -1, _(u"Attach audio")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer2 = wx.BoxSizer(wx.HORIZONTAL) + def __init__(self, services): + log.debug("creating audio dialog.") + super(audioDialog, self).__init__(None, -1, _(u"Attach audio")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer2 = wx.BoxSizer(wx.HORIZONTAL) - self.play = wx.Button(panel, -1, _(u"&Play")) - self.play.Disable() - self.pause = wx.Button(panel, -1, _(u"&Pause")) - self.pause.Disable() - self.record = wx.Button(panel, -1, _(u"&Record")) - self.record.SetFocus() - self.attach_exists = wx.Button(panel, -1, _(u"&Add an existing file")) - self.discard = wx.Button(panel, -1, _(u"&Discard")) - self.discard.Disable() - label = wx.StaticText(panel, -1, _(u"Upload to")) - self.services = wx.ComboBox(panel, -1, choices=services, value=services[0], style=wx.CB_READONLY) - servicesBox = wx.BoxSizer(wx.HORIZONTAL) - servicesBox.Add(label, 0, wx.ALL, 5) - servicesBox.Add(self.services, 0, wx.ALL, 5) - self.attach = wx.Button(panel, wx.ID_OK, _(u"Attach")) - self.attach.Disable() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Cancel")) - btnSizer.Add(self.play, 0, wx.ALL, 5) - btnSizer.Add(self.pause, 0, wx.ALL, 5) - btnSizer.Add(self.record, 0, wx.ALL, 5) - btnSizer2.Add(self.attach_exists, 0, wx.ALL, 5) - btnSizer2.Add(self.discard, 0, wx.ALL, 5) - btnSizer2.Add(self.attach, 0, wx.ALL, 5) - btnSizer2.Add(cancel, 0, wx.ALL, 5) - sizer.Add(servicesBox, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - sizer.Add(btnSizer2, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + self.play = wx.Button(panel, -1, _(u"&Play")) + self.play.Disable() + self.pause = wx.Button(panel, -1, _(u"&Pause")) + self.pause.Disable() + self.record = wx.Button(panel, -1, _(u"&Record")) + self.record.SetFocus() + self.attach_exists = wx.Button(panel, -1, _(u"&Add an existing file")) + self.discard = wx.Button(panel, -1, _(u"&Discard")) + self.discard.Disable() + label = wx.StaticText(panel, -1, _(u"Upload to")) + self.services = wx.ComboBox(panel, -1, choices=services, value=services[0], style=wx.CB_READONLY) + servicesBox = wx.BoxSizer(wx.HORIZONTAL) + servicesBox.Add(label, 0, wx.ALL, 5) + servicesBox.Add(self.services, 0, wx.ALL, 5) + self.attach = wx.Button(panel, wx.ID_OK, _(u"Attach")) + self.attach.Disable() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Cancel")) + btnSizer.Add(self.play, 0, wx.ALL, 5) + btnSizer.Add(self.pause, 0, wx.ALL, 5) + btnSizer.Add(self.record, 0, wx.ALL, 5) + btnSizer2.Add(self.attach_exists, 0, wx.ALL, 5) + btnSizer2.Add(self.discard, 0, wx.ALL, 5) + btnSizer2.Add(self.attach, 0, wx.ALL, 5) + btnSizer2.Add(cancel, 0, wx.ALL, 5) + sizer.Add(servicesBox, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + sizer.Add(btnSizer2, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def enable_control(self, control): - log.debug("Enabling control %s" % (control,)) - if hasattr(self, control): - getattr(self, control).Enable() + def enable_control(self, control): + log.debug("Enabling control %s" % (control,)) + if hasattr(self, control): + getattr(self, control).Enable() - def disable_control(self, control): - log.debug("Disabling control %s" % (control,)) - if hasattr(self, control): - getattr(self, control).Disable() + def disable_control(self, control): + log.debug("Disabling control %s" % (control,)) + if hasattr(self, control): + getattr(self, control).Disable() - def get_file(self): - openFileDialog = wx.FileDialog(self, _(u"Select the audio file to be uploaded"), "", "", _("Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return False - return openFileDialog.GetPath() + def get_file(self): + openFileDialog = wx.FileDialog(self, _(u"Select the audio file to be uploaded"), "", "", _("Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return False + return openFileDialog.GetPath() diff --git a/src/extra/SoundsTutorial/gtk_ui.py b/src/extra/SoundsTutorial/gtk_ui.py index 450498a5..a5ffab02 100644 --- a/src/extra/SoundsTutorial/gtk_ui.py +++ b/src/extra/SoundsTutorial/gtk_ui.py @@ -4,23 +4,23 @@ from gi.repository import Gtk import widgetUtils class soundsTutorialDialog(Gtk.Dialog): - def __init__(self, actions): - super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) - box = self.get_content_area() - label = Gtk.Label("Press enter for listen the sound") - self.list = widgetUtils.list("Action") - self.populate_actions(actions) - lBox = Gtk.Box(spacing=6) - lBox.add(label) - lBox.add(self.list.list) - box.add(lBox) - self.play = Gtk.Button("Play") - box.add(self.play) - self.show_all() + def __init__(self, actions): + super(soundsTutorialDialog, self).__init__("Sounds tutorial", None, 0, (Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) + box = self.get_content_area() + label = Gtk.Label("Press enter for listen the sound") + self.list = widgetUtils.list("Action") + self.populate_actions(actions) + lBox = Gtk.Box(spacing=6) + lBox.add(label) + lBox.add(self.list.list) + box.add(lBox) + self.play = Gtk.Button("Play") + box.add(self.play) + self.show_all() - def populate_actions(self, actions): - for i in actions: - self.list.insert_item(i) + def populate_actions(self, actions): + for i in actions: + self.list.insert_item(i) - def get_selected(self): - return self.list.get_selected() \ No newline at end of file + def get_selected(self): + return self.list.get_selected() diff --git a/src/extra/SoundsTutorial/reverse_sort.py b/src/extra/SoundsTutorial/reverse_sort.py index 1094113e..27711174 100644 --- a/src/extra/SoundsTutorial/reverse_sort.py +++ b/src/extra/SoundsTutorial/reverse_sort.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals +from __future__ import unicode_literals #Reverse sort, by Bill Dengler for use in TWBlue http://twblue.es def invert_tuples(t): "Invert a list of tuples, so that the 0th element becomes the -1th, and the -1th becomes the 0th." @@ -9,4 +9,4 @@ def invert_tuples(t): def reverse_sort(t): "Sorts a list of tuples/lists by their last elements, not their first." - return invert_tuples(sorted(invert_tuples(t))) \ No newline at end of file + return invert_tuples(sorted(invert_tuples(t))) diff --git a/src/extra/SoundsTutorial/soundsTutorial.py b/src/extra/SoundsTutorial/soundsTutorial.py index 58b23590..4e679b1c 100644 --- a/src/extra/SoundsTutorial/soundsTutorial.py +++ b/src/extra/SoundsTutorial/soundsTutorial.py @@ -10,28 +10,28 @@ import logging log = logging.getLogger("extra.SoundsTutorial.soundsTutorial") from . import soundsTutorial_constants if platform.system() == "Windows": - from . import wx_ui as UI + from . import wx_ui as UI elif platform.system() == "Linux": - from . import gtk_ui as UI + from . import gtk_ui as UI class soundsTutorial(object): - def __init__(self, sessionObject): - log.debug("Creating sounds tutorial object...") - super(soundsTutorial, self).__init__() - self.session = sessionObject - self.actions = [] - log.debug("Loading actions for sounds tutorial...") - [self.actions.append(i[1]) for i in soundsTutorial_constants.actions] - self.files = [] - log.debug("Searching sound files...") - [self.files.append(i[0]) for i in soundsTutorial_constants.actions] - log.debug("Creating dialog...") - self.dialog = UI.soundsTutorialDialog(self.actions) - widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) - self.dialog.get_response() + def __init__(self, sessionObject): + log.debug("Creating sounds tutorial object...") + super(soundsTutorial, self).__init__() + self.session = sessionObject + self.actions = [] + log.debug("Loading actions for sounds tutorial...") + [self.actions.append(i[1]) for i in soundsTutorial_constants.actions] + self.files = [] + log.debug("Searching sound files...") + [self.files.append(i[0]) for i in soundsTutorial_constants.actions] + log.debug("Creating dialog...") + self.dialog = UI.soundsTutorialDialog(self.actions) + widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.on_play) + self.dialog.get_response() - def on_play(self, *args, **kwargs): - try: - self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg") - except: - log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],)) \ No newline at end of file + def on_play(self, *args, **kwargs): + try: + self.session.sound.play(self.files[self.dialog.get_selection()]+".ogg") + except: + log.exception("Error playing the %s sound" % (self.files[self.dialog.items.GetSelection()],)) diff --git a/src/extra/SoundsTutorial/soundsTutorial_constants.py b/src/extra/SoundsTutorial/soundsTutorial_constants.py index e28612dc..536add4d 100644 --- a/src/extra/SoundsTutorial/soundsTutorial_constants.py +++ b/src/extra/SoundsTutorial/soundsTutorial_constants.py @@ -5,27 +5,27 @@ from __future__ import unicode_literals from . import reverse_sort import application actions = reverse_sort.reverse_sort([ ("audio", _(u"Audio tweet.")), - ("create_timeline", _(u"User timeline buffer created.")), - ("delete_timeline", _(u"Buffer destroied.")), - ("dm_received", _(u"Direct message received.")), - ("dm_sent", _(u"Direct message sent.")), - ("error", _(u"Error.")), - ("favourite", _(u"Tweet liked.")), - ("favourites_timeline_updated", _(u"Likes buffer updated.")), - ("geo", _(u"Geotweet.")), -("image", _("Tweet contains one or more images")), -("limit", _(u"Boundary reached.")), - ("list_tweet", _(u"List updated.")), - ("max_length", _(u"Too many characters.")), - ("mention_received", _(u"Mention received.")), - ("new_event", _(u"New event.")), - ("ready", _(u"{0} is ready.").format(application.name,)), - ("reply_send", _(u"Mention sent.")), - ("retweet_send", _(u"Tweet retweeted.")), - ("search_updated", _(u"Search buffer updated.")), - ("tweet_received", _(u"Tweet received.")), - ("tweet_send", _(u"Tweet sent.")), - ("trends_updated", _(u"Trending topics buffer updated.")), - ("tweet_timeline", _(u"New tweet in user timeline buffer.")), - ("update_followers", _(u"New follower.")), - ("volume_changed", _(u"Volume changed."))]) + ("create_timeline", _(u"User timeline buffer created.")), + ("delete_timeline", _(u"Buffer destroied.")), + ("dm_received", _(u"Direct message received.")), + ("dm_sent", _(u"Direct message sent.")), + ("error", _(u"Error.")), + ("favourite", _(u"Tweet liked.")), + ("favourites_timeline_updated", _(u"Likes buffer updated.")), + ("geo", _(u"Geotweet.")), + ("image", _("Tweet contains one or more images")), + ("limit", _(u"Boundary reached.")), + ("list_tweet", _(u"List updated.")), + ("max_length", _(u"Too many characters.")), + ("mention_received", _(u"Mention received.")), + ("new_event", _(u"New event.")), + ("ready", _(u"{0} is ready.").format(application.name,)), + ("reply_send", _(u"Mention sent.")), + ("retweet_send", _(u"Tweet retweeted.")), + ("search_updated", _(u"Search buffer updated.")), + ("tweet_received", _(u"Tweet received.")), + ("tweet_send", _(u"Tweet sent.")), + ("trends_updated", _(u"Trending topics buffer updated.")), + ("tweet_timeline", _(u"New tweet in user timeline buffer.")), + ("update_followers", _(u"New follower.")), + ("volume_changed", _(u"Volume changed."))]) diff --git a/src/extra/SoundsTutorial/wx_ui.py b/src/extra/SoundsTutorial/wx_ui.py index ac2b0373..ebb6caf9 100644 --- a/src/extra/SoundsTutorial/wx_ui.py +++ b/src/extra/SoundsTutorial/wx_ui.py @@ -4,27 +4,27 @@ import wx import widgetUtils class soundsTutorialDialog(widgetUtils.BaseDialog): - def __init__(self, actions): - super(soundsTutorialDialog, self).__init__(None, -1) - self.SetTitle(_(u"Sounds tutorial")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(panel, -1, _(u"Press enter to listen to the sound for the selected event")) - self.items = wx.ListBox(panel, 1, choices=actions, style=wx.LB_SINGLE) - self.items.SetSelection(0) - listBox = wx.BoxSizer(wx.HORIZONTAL) - listBox.Add(label) - listBox.Add(self.items) - self.play = wx.Button(panel, 1, (u"Play")) - self.play.SetDefault() - close = wx.Button(panel, wx.ID_CANCEL) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(self.play) - btnBox.Add(close) - sizer.Add(listBox) - sizer.Add(btnBox) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self, actions): + super(soundsTutorialDialog, self).__init__(None, -1) + self.SetTitle(_(u"Sounds tutorial")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(panel, -1, _(u"Press enter to listen to the sound for the selected event")) + self.items = wx.ListBox(panel, 1, choices=actions, style=wx.LB_SINGLE) + self.items.SetSelection(0) + listBox = wx.BoxSizer(wx.HORIZONTAL) + listBox.Add(label) + listBox.Add(self.items) + self.play = wx.Button(panel, 1, (u"Play")) + self.play.SetDefault() + close = wx.Button(panel, wx.ID_CANCEL) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.play) + btnBox.Add(close) + sizer.Add(listBox) + sizer.Add(btnBox) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def get_selection(self): - return self.items.GetSelection() \ No newline at end of file + def get_selection(self): + return self.items.GetSelection() diff --git a/src/extra/SpellChecker/__init__.py b/src/extra/SpellChecker/__init__.py index f1eb69de..cf120537 100644 --- a/src/extra/SpellChecker/__init__.py +++ b/src/extra/SpellChecker/__init__.py @@ -3,4 +3,4 @@ from __future__ import unicode_literals from . import spellchecker import platform if platform.system() == "Windows": - from .wx_ui import * \ No newline at end of file + from .wx_ui import * diff --git a/src/extra/SpellChecker/spellchecker.py b/src/extra/SpellChecker/spellchecker.py index f8b1bec4..29bf2512 100644 --- a/src/extra/SpellChecker/spellchecker.py +++ b/src/extra/SpellChecker/spellchecker.py @@ -19,69 +19,69 @@ from enchant import tokenize log = logging.getLogger("extra.SpellChecker.spellChecker") class spellChecker(object): - def __init__(self, text, dictionary): - super(spellChecker, self).__init__() - # Set Dictionary path if not set in a previous call to this method. - # Dictionary path will be located in user config, see https://github.com/manuelcortez/twblue/issues/208 + def __init__(self, text, dictionary): + super(spellChecker, self).__init__() + # Set Dictionary path if not set in a previous call to this method. + # Dictionary path will be located in user config, see https://github.com/manuelcortez/twblue/issues/208 # dict_path = enchant.get_param("enchant.myspell.dictionary.path") # if dict_path == None: # enchant.set_param("enchant.myspell.dictionary.path", os.path.join(paths.config_path(), "dicts")) # log.debug("Dictionary path set to %s" % (os.path.join(paths.config_path(), "dicts"),)) - log.debug("Creating the SpellChecker object. Dictionary: %s" % (dictionary,)) - self.active = True - try: - if config.app["app-settings"]["language"] == "system": - log.debug("Using the system language") - self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict")) - else: - log.debug("Using language: %s" % (languageHandler.getLanguage(),)) - self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict")) - except DictNotFoundError: - log.exception("Dictionary for language %s not found." % (dictionary,)) - wx_ui.dict_not_found_error() - self.active = False - self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter]) - self.checker.set_text(text) - if self.active == True: - log.debug("Creating dialog...") - self.dialog = wx_ui.spellCheckerDialog() - widgetUtils.connect_event(self.dialog.ignore, widgetUtils.BUTTON_PRESSED, self.ignore) - widgetUtils.connect_event(self.dialog.ignoreAll, widgetUtils.BUTTON_PRESSED, self.ignoreAll) - widgetUtils.connect_event(self.dialog.replace, widgetUtils.BUTTON_PRESSED, self.replace) - widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll) - widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add) - self.check() - self.dialog.get_response() - self.fixed_text = self.checker.get_text() + log.debug("Creating the SpellChecker object. Dictionary: %s" % (dictionary,)) + self.active = True + try: + if config.app["app-settings"]["language"] == "system": + log.debug("Using the system language") + self.dict = enchant.DictWithPWL(languageHandler.curLang[:2], os.path.join(paths.config_path(), "wordlist.dict")) + else: + log.debug("Using language: %s" % (languageHandler.getLanguage(),)) + self.dict = enchant.DictWithPWL(languageHandler.getLanguage()[:2], os.path.join(paths.config_path(), "wordlist.dict")) + except DictNotFoundError: + log.exception("Dictionary for language %s not found." % (dictionary,)) + wx_ui.dict_not_found_error() + self.active = False + self.checker = SpellChecker(self.dict, filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter]) + self.checker.set_text(text) + if self.active == True: + log.debug("Creating dialog...") + self.dialog = wx_ui.spellCheckerDialog() + widgetUtils.connect_event(self.dialog.ignore, widgetUtils.BUTTON_PRESSED, self.ignore) + widgetUtils.connect_event(self.dialog.ignoreAll, widgetUtils.BUTTON_PRESSED, self.ignoreAll) + widgetUtils.connect_event(self.dialog.replace, widgetUtils.BUTTON_PRESSED, self.replace) + widgetUtils.connect_event(self.dialog.replaceAll, widgetUtils.BUTTON_PRESSED, self.replaceAll) + widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add) + self.check() + self.dialog.get_response() + self.fixed_text = self.checker.get_text() - def check(self): - try: - next(self.checker) - textToSay = _(u"Misspelled word: %s") % (self.checker.word,) - context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10)) - self.dialog.set_title(textToSay) - output.speak(textToSay) - self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest()) - except StopIteration: - log.debug("Process finished.") - wx_ui.finished() - self.dialog.Destroy() + def check(self): + try: + next(self.checker) + textToSay = _(u"Misspelled word: %s") % (self.checker.word,) + context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10)) + self.dialog.set_title(textToSay) + output.speak(textToSay) + self.dialog.set_word_and_suggestions(word=self.checker.word, context=context, suggestions=self.checker.suggest()) + except StopIteration: + log.debug("Process finished.") + wx_ui.finished() + self.dialog.Destroy() - def ignore(self, ev): - self.check() + def ignore(self, ev): + self.check() - def ignoreAll(self, ev): - self.checker.ignore_always(word=self.checker.word) - self.check() + def ignoreAll(self, ev): + self.checker.ignore_always(word=self.checker.word) + self.check() - def replace(self, ev): - self.checker.replace(self.dialog.get_selected_suggestion()) - self.check() + def replace(self, ev): + self.checker.replace(self.dialog.get_selected_suggestion()) + self.check() - def replaceAll(self, ev): - self.checker.replace_always(self.dialog.get_selected_suggestion()) - self.check() + def replaceAll(self, ev): + self.checker.replace_always(self.dialog.get_selected_suggestion()) + self.check() - def add(self, ev): - self.checker.add() - self.check() + def add(self, ev): + self.checker.add() + self.check() diff --git a/src/extra/SpellChecker/wx_ui.py b/src/extra/SpellChecker/wx_ui.py index 3a13e9f1..9c7159fd 100644 --- a/src/extra/SpellChecker/wx_ui.py +++ b/src/extra/SpellChecker/wx_ui.py @@ -21,63 +21,63 @@ import wx import application class spellCheckerDialog(wx.Dialog): - def __init__(self): - super(spellCheckerDialog, self).__init__(None, 1) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - word = wx.StaticText(panel, -1, _(u"Misspelled word")) - self.word = wx.TextCtrl(panel, -1) - wordBox = wx.BoxSizer(wx.HORIZONTAL) - wordBox.Add(word, 0, wx.ALL, 5) - wordBox.Add(self.word, 0, wx.ALL, 5) - context = wx.StaticText(panel, -1, _(u"Context")) - self.context = wx.TextCtrl(panel, -1) - contextBox = wx.BoxSizer(wx.HORIZONTAL) - contextBox.Add(context, 0, wx.ALL, 5) - contextBox.Add(self.context, 0, wx.ALL, 5) - suggest = wx.StaticText(panel, -1, _(u"Suggestions")) - self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE) - suggestionsBox = wx.BoxSizer(wx.HORIZONTAL) - suggestionsBox.Add(suggest, 0, wx.ALL, 5) - suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5) - self.ignore = wx.Button(panel, -1, _(u"&Ignore")) - self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all")) - self.replace = wx.Button(panel, -1, _(u"&Replace")) - self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all")) - self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary")) - close = wx.Button(panel, wx.ID_CANCEL) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(self.ignore, 0, wx.ALL, 5) - btnBox.Add(self.ignoreAll, 0, wx.ALL, 5) - btnBox.Add(self.replace, 0, wx.ALL, 5) - btnBox.Add(self.replaceAll, 0, wx.ALL, 5) - btnBox.Add(self.add, 0, wx.ALL, 5) - btnBox.Add(close, 0, wx.ALL, 5) - sizer.Add(wordBox, 0, wx.ALL, 5) - sizer.Add(contextBox, 0, wx.ALL, 5) - sizer.Add(suggestionsBox, 0, wx.ALL, 5) - sizer.Add(btnBox, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(spellCheckerDialog, self).__init__(None, 1) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + word = wx.StaticText(panel, -1, _(u"Misspelled word")) + self.word = wx.TextCtrl(panel, -1) + wordBox = wx.BoxSizer(wx.HORIZONTAL) + wordBox.Add(word, 0, wx.ALL, 5) + wordBox.Add(self.word, 0, wx.ALL, 5) + context = wx.StaticText(panel, -1, _(u"Context")) + self.context = wx.TextCtrl(panel, -1) + contextBox = wx.BoxSizer(wx.HORIZONTAL) + contextBox.Add(context, 0, wx.ALL, 5) + contextBox.Add(self.context, 0, wx.ALL, 5) + suggest = wx.StaticText(panel, -1, _(u"Suggestions")) + self.suggestions = wx.ListBox(panel, -1, choices=[], style=wx.LB_SINGLE) + suggestionsBox = wx.BoxSizer(wx.HORIZONTAL) + suggestionsBox.Add(suggest, 0, wx.ALL, 5) + suggestionsBox.Add(self.suggestions, 0, wx.ALL, 5) + self.ignore = wx.Button(panel, -1, _(u"&Ignore")) + self.ignoreAll = wx.Button(panel, -1, _(u"I&gnore all")) + self.replace = wx.Button(panel, -1, _(u"&Replace")) + self.replaceAll = wx.Button(panel, -1, _(u"R&eplace all")) + self.add = wx.Button(panel, -1, _(u"&Add to personal dictionary")) + close = wx.Button(panel, wx.ID_CANCEL) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.ignore, 0, wx.ALL, 5) + btnBox.Add(self.ignoreAll, 0, wx.ALL, 5) + btnBox.Add(self.replace, 0, wx.ALL, 5) + btnBox.Add(self.replaceAll, 0, wx.ALL, 5) + btnBox.Add(self.add, 0, wx.ALL, 5) + btnBox.Add(close, 0, wx.ALL, 5) + sizer.Add(wordBox, 0, wx.ALL, 5) + sizer.Add(contextBox, 0, wx.ALL, 5) + sizer.Add(suggestionsBox, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def get_response(self): - return self.ShowModal() + def get_response(self): + return self.ShowModal() - def set_title(self, title): - return self.SetTitle(title) + def set_title(self, title): + return self.SetTitle(title) - def set_word_and_suggestions(self, word, context, suggestions): - self.word.SetValue(word) - self.context.ChangeValue(context) - self.suggestions.Set(suggestions) - self.suggestions.SetFocus() + def set_word_and_suggestions(self, word, context, suggestions): + self.word.SetValue(word) + self.context.ChangeValue(context) + self.suggestions.Set(suggestions) + self.suggestions.SetFocus() - def get_selected_suggestion(self): - return self.suggestions.GetStringSelection() + def get_selected_suggestion(self): + return self.suggestions.GetStringSelection() def dict_not_found_error(): - wx.MessageDialog(None, _(u"An error has occurred. There are no dictionaries available for the selected language in {0}").format(application.name,), _(u"Error"), wx.ICON_ERROR).ShowModal() + wx.MessageDialog(None, _(u"An error has occurred. There are no dictionaries available for the selected language in {0}").format(application.name,), _(u"Error"), wx.ICON_ERROR).ShowModal() def finished(): - wx.MessageDialog(None, _(u"Spell check complete."), application.name, style=wx.OK).ShowModal() + wx.MessageDialog(None, _(u"Spell check complete."), application.name, style=wx.OK).ShowModal() diff --git a/src/extra/autocompletionUsers/__init__.py b/src/extra/autocompletionUsers/__init__.py index cceb68cc..7a307a5e 100644 --- a/src/extra/autocompletionUsers/__init__.py +++ b/src/extra/autocompletionUsers/__init__.py @@ -2,4 +2,4 @@ from __future__ import absolute_import from __future__ import unicode_literals # -*- coding: utf-8 -*- -from . import completion, settings \ No newline at end of file +from . import completion, settings diff --git a/src/extra/autocompletionUsers/completion.py b/src/extra/autocompletionUsers/completion.py index 25875d8c..826dc699 100644 --- a/src/extra/autocompletionUsers/completion.py +++ b/src/extra/autocompletionUsers/completion.py @@ -4,44 +4,44 @@ from . import storage from . import wx_menu class autocompletionUsers(object): - def __init__(self, window, session_id): - super(autocompletionUsers, self).__init__() - self.window = window - self.db = storage.storage(session_id) + def __init__(self, window, session_id): + super(autocompletionUsers, self).__init__() + self.window = window + self.db = storage.storage(session_id) - def show_menu(self, mode="tweet"): - position = self.window.get_position() - if mode == "tweet": - text = self.window.get_text() - text = text[:position] - try: - pattern = text.split()[-1] - except IndexError: - output.speak(_(u"You have to start writing")) - return - if pattern.startswith("@") == True: - menu = wx_menu.menu(self.window.text, pattern[1:], mode=mode) - users = self.db.get_users(pattern[1:]) - if len(users) > 0: - menu.append_options(users) - self.window.popup_menu(menu) - menu.destroy() - else: - output.speak(_(u"There are no results in your users database")) - else: - output.speak(_(u"Autocompletion only works for users.")) - elif mode == "dm": - text = self.window.get_user() - try: - pattern = text.split()[-1] - except IndexError: - output.speak(_(u"You have to start writing")) - return - menu = wx_menu.menu(self.window.cb, pattern, mode=mode) - users = self.db.get_users(pattern) - if len(users) > 0: - menu.append_options(users) - self.window.popup_menu(menu) - menu.destroy() - else: - output.speak(_(u"There are no results in your users database")) \ No newline at end of file + def show_menu(self, mode="tweet"): + position = self.window.get_position() + if mode == "tweet": + text = self.window.get_text() + text = text[:position] + try: + pattern = text.split()[-1] + except IndexError: + output.speak(_(u"You have to start writing")) + return + if pattern.startswith("@") == True: + menu = wx_menu.menu(self.window.text, pattern[1:], mode=mode) + users = self.db.get_users(pattern[1:]) + if len(users) > 0: + menu.append_options(users) + self.window.popup_menu(menu) + menu.destroy() + else: + output.speak(_(u"There are no results in your users database")) + else: + output.speak(_(u"Autocompletion only works for users.")) + elif mode == "dm": + text = self.window.get_user() + try: + pattern = text.split()[-1] + except IndexError: + output.speak(_(u"You have to start writing")) + return + menu = wx_menu.menu(self.window.cb, pattern, mode=mode) + users = self.db.get_users(pattern) + if len(users) > 0: + menu.append_options(users) + self.window.popup_menu(menu) + menu.destroy() + else: + output.speak(_(u"There are no results in your users database")) diff --git a/src/extra/autocompletionUsers/manage.py b/src/extra/autocompletionUsers/manage.py index ae7dd957..1d724e4f 100644 --- a/src/extra/autocompletionUsers/manage.py +++ b/src/extra/autocompletionUsers/manage.py @@ -4,39 +4,39 @@ from . import storage, wx_manage from wxUI import commonMessageDialogs class autocompletionManage(object): - def __init__(self, session): - super(autocompletionManage, self).__init__() - self.session = session - self.dialog = wx_manage.autocompletionManageDialog() - self.database = storage.storage(self.session.session_id) - self.users = self.database.get_all_users() - self.dialog.put_users(self.users) - widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user) - widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_user) - self.dialog.get_response() + def __init__(self, session): + super(autocompletionManage, self).__init__() + self.session = session + self.dialog = wx_manage.autocompletionManageDialog() + self.database = storage.storage(self.session.session_id) + self.users = self.database.get_all_users() + self.dialog.put_users(self.users) + widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_user) + widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_user) + self.dialog.get_response() - def update_list(self): - item = self.dialog.users.get_selected() - self.dialog.users.clear() - self.users = self.database.get_all_users() - self.dialog.put_users(self.users) - self.dialog.users.select_item(item) + def update_list(self): + item = self.dialog.users.get_selected() + self.dialog.users.clear() + self.users = self.database.get_all_users() + self.dialog.put_users(self.users) + self.dialog.users.select_item(item) - def add_user(self, *args, **kwargs): - usr = self.dialog.get_user() - if usr == False: - return - try: - data = self.session.twitter.twitter.get_user(screen_name=usr) - except: - self.dialog.show_invalid_user_error() - return - self.database.set_user(data.screen_name, data.name, 0) - self.update_list() + def add_user(self, *args, **kwargs): + usr = self.dialog.get_user() + if usr == False: + return + try: + data = self.session.twitter.twitter.get_user(screen_name=usr) + except: + self.dialog.show_invalid_user_error() + return + self.database.set_user(data.screen_name, data.name, 0) + self.update_list() - def remove_user(self, ev): - if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES: - item = self.dialog.users.get_selected() - user = self.users[item] - self.database.remove_user(user[0]) - self.update_list() \ No newline at end of file + def remove_user(self, ev): + if commonMessageDialogs.delete_user_from_db() == widgetUtils.YES: + item = self.dialog.users.get_selected() + user = self.users[item] + self.database.remove_user(user[0]) + self.update_list() diff --git a/src/extra/autocompletionUsers/settings.py b/src/extra/autocompletionUsers/settings.py index 283c217c..d875fb0d 100644 --- a/src/extra/autocompletionUsers/settings.py +++ b/src/extra/autocompletionUsers/settings.py @@ -7,53 +7,53 @@ from . import storage from mysc.thread_utils import call_threaded class autocompletionSettings(object): - def __init__(self, config, buffer, window): - super(autocompletionSettings, self).__init__() - self.config = config - self.buffer = buffer - self.window = window - self.dialog = wx_settings.autocompletionSettingsDialog() - self.dialog.set("friends_buffer", self.config["mysc"]["save_friends_in_autocompletion_db"]) - self.dialog.set("followers_buffer", self.config["mysc"]["save_followers_in_autocompletion_db"]) - widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list) - if self.dialog.get_response() == widgetUtils.OK: - call_threaded(self.add_users_to_database) + def __init__(self, config, buffer, window): + super(autocompletionSettings, self).__init__() + self.config = config + self.buffer = buffer + self.window = window + self.dialog = wx_settings.autocompletionSettingsDialog() + self.dialog.set("friends_buffer", self.config["mysc"]["save_friends_in_autocompletion_db"]) + self.dialog.set("followers_buffer", self.config["mysc"]["save_followers_in_autocompletion_db"]) + widgetUtils.connect_event(self.dialog.viewList, widgetUtils.BUTTON_PRESSED, self.view_list) + if self.dialog.get_response() == widgetUtils.OK: + call_threaded(self.add_users_to_database) - def add_users_to_database(self): - self.config["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.get("friends_buffer") - self.config["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.get("followers_buffer") - output.speak(_(u"Updating database... You can close this window now. A message will tell you when the process finishes.")) - database = storage.storage(self.buffer.session.session_id) - if self.dialog.get("followers_buffer") == True: - buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"]) - for i in buffer.session.db[buffer.name]: - database.set_user(i.screen_name, i.name, 1) - else: - database.remove_by_buffer(1) - if self.dialog.get("friends_buffer") == True: - buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"]) - for i in buffer.session.db[buffer.name]: - database.set_user(i.screen_name, i.name, 2) - else: - database.remove_by_buffer(2) - wx_settings.show_success_dialog() - self.dialog.destroy() - - def view_list(self, ev): - q = manage.autocompletionManage(self.buffer.session) + def add_users_to_database(self): + self.config["mysc"]["save_friends_in_autocompletion_db"] = self.dialog.get("friends_buffer") + self.config["mysc"]["save_followers_in_autocompletion_db"] = self.dialog.get("followers_buffer") + output.speak(_(u"Updating database... You can close this window now. A message will tell you when the process finishes.")) + database = storage.storage(self.buffer.session.session_id) + if self.dialog.get("followers_buffer") == True: + buffer = self.window.search_buffer("followers", self.config["twitter"]["user_name"]) + for i in buffer.session.db[buffer.name]: + database.set_user(i.screen_name, i.name, 1) + else: + database.remove_by_buffer(1) + if self.dialog.get("friends_buffer") == True: + buffer = self.window.search_buffer("friends", self.config["twitter"]["user_name"]) + for i in buffer.session.db[buffer.name]: + database.set_user(i.screen_name, i.name, 2) + else: + database.remove_by_buffer(2) + wx_settings.show_success_dialog() + self.dialog.destroy() + + def view_list(self, ev): + q = manage.autocompletionManage(self.buffer.session) def execute_at_startup(window, buffer, config): - database = storage.storage(buffer.session.session_id) - if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True: - buffer = window.search_buffer("followers", config["twitter"]["user_name"]) - for i in buffer.session.db[buffer.name]: - database.set_user(i.screen_name, i.name, 1) - else: - database.remove_by_buffer(1) - if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True: - buffer = window.search_buffer("friends", config["twitter"]["user_name"]) - for i in buffer.session.db[buffer.name]: - database.set_user(i.screen_name, i.name, 2) - else: - database.remove_by_buffer(2) \ No newline at end of file + database = storage.storage(buffer.session.session_id) + if config["mysc"]["save_followers_in_autocompletion_db"] == True and config["other_buffers"]["show_followers"] == True: + buffer = window.search_buffer("followers", config["twitter"]["user_name"]) + for i in buffer.session.db[buffer.name]: + database.set_user(i.screen_name, i.name, 1) + else: + database.remove_by_buffer(1) + if config["mysc"]["save_friends_in_autocompletion_db"] == True and config["other_buffers"]["show_friends"] == True: + buffer = window.search_buffer("friends", config["twitter"]["user_name"]) + for i in buffer.session.db[buffer.name]: + database.set_user(i.screen_name, i.name, 2) + else: + database.remove_by_buffer(2) diff --git a/src/extra/autocompletionUsers/storage.py b/src/extra/autocompletionUsers/storage.py index 4d5df88f..0b56781e 100644 --- a/src/extra/autocompletionUsers/storage.py +++ b/src/extra/autocompletionUsers/storage.py @@ -2,51 +2,51 @@ import os, sqlite3, paths class storage(object): - def __init__(self, session_id): - self.connection = sqlite3.connect(os.path.join(paths.config_path(), "%s/autocompletionUsers.dat" % (session_id))) - self.cursor = self.connection.cursor() - if self.table_exist("users") == False: - self.create_table() + def __init__(self, session_id): + self.connection = sqlite3.connect(os.path.join(paths.config_path(), "%s/autocompletionUsers.dat" % (session_id))) + self.cursor = self.connection.cursor() + if self.table_exist("users") == False: + self.create_table() - def table_exist(self, table): - ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table)) - answer = ask.fetchone() - if answer == None: - return False - else: - return True + def table_exist(self, table): + ask = self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % (table)) + answer = ask.fetchone() + if answer == None: + return False + else: + return True - def get_all_users(self): - self.cursor.execute("""select * from users""") - return self.cursor.fetchall() + def get_all_users(self): + self.cursor.execute("""select * from users""") + return self.cursor.fetchall() - def get_users(self, term): - self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),)) - return self.cursor.fetchall() + def get_users(self, term): + self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),)) + return self.cursor.fetchall() - def set_user(self, screen_name, user_name, from_a_buffer): - self.cursor.execute("""insert or ignore into users values(?, ?, ?)""", (screen_name, user_name, from_a_buffer)) - self.connection.commit() + def set_user(self, screen_name, user_name, from_a_buffer): + self.cursor.execute("""insert or ignore into users values(?, ?, ?)""", (screen_name, user_name, from_a_buffer)) + self.connection.commit() - def remove_user(self, user): - self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,)) - self.connection.commit() - return self.cursor.fetchone() + def remove_user(self, user): + self.cursor.execute("""DELETE FROM users WHERE user = ?""", (user,)) + self.connection.commit() + return self.cursor.fetchone() - def remove_by_buffer(self, bufferType): - """ Removes all users saved on a buffer. BufferType is 0 for no buffer, 1 for friends and 2 for followers""" - self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,)) - self.connection.commit() - return self.cursor.fetchone() + def remove_by_buffer(self, bufferType): + """ Removes all users saved on a buffer. BufferType is 0 for no buffer, 1 for friends and 2 for followers""" + self.cursor.execute("""DELETE FROM users WHERE from_a_buffer = ?""", (bufferType,)) + self.connection.commit() + return self.cursor.fetchone() - def create_table(self): - self.cursor.execute(""" + def create_table(self): + self.cursor.execute(""" create table users( user TEXT UNIQUE, name TEXT, from_a_buffer INTEGER )""") - def __del__(self): - self.cursor.close() - self.connection.close() \ No newline at end of file + def __del__(self): + self.cursor.close() + self.connection.close() diff --git a/src/extra/autocompletionUsers/wx_manage.py b/src/extra/autocompletionUsers/wx_manage.py index 3db4de67..6f34a681 100644 --- a/src/extra/autocompletionUsers/wx_manage.py +++ b/src/extra/autocompletionUsers/wx_manage.py @@ -5,40 +5,40 @@ from multiplatform_widgets import widgets import application class autocompletionManageDialog(widgetUtils.BaseDialog): - def __init__(self): - super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(panel, -1, _(u"Editing {0} users database").format(application.name,)) - self.users = widgets.list(panel, _(u"Username"), _(u"Name"), style=wx.LC_REPORT) - sizer.Add(label, 0, wx.ALL, 5) - sizer.Add(self.users.list, 0, wx.ALL, 5) - self.add = wx.Button(panel, -1, _(u"Add user")) - self.remove = wx.Button(panel, -1, _(u"Remove user")) - optionsBox = wx.BoxSizer(wx.HORIZONTAL) - optionsBox.Add(self.add, 0, wx.ALL, 5) - optionsBox.Add(self.remove, 0, wx.ALL, 5) - sizer.Add(optionsBox, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK) - cancel = wx.Button(panel, wx.ID_CANCEL) - sizerBtn = wx.BoxSizer(wx.HORIZONTAL) - sizerBtn.Add(ok, 0, wx.ALL, 5) - sizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(sizerBtn, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(autocompletionManageDialog, self).__init__(parent=None, id=-1, title=_(u"Manage Autocompletion database")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(panel, -1, _(u"Editing {0} users database").format(application.name,)) + self.users = widgets.list(panel, _(u"Username"), _(u"Name"), style=wx.LC_REPORT) + sizer.Add(label, 0, wx.ALL, 5) + sizer.Add(self.users.list, 0, wx.ALL, 5) + self.add = wx.Button(panel, -1, _(u"Add user")) + self.remove = wx.Button(panel, -1, _(u"Remove user")) + optionsBox = wx.BoxSizer(wx.HORIZONTAL) + optionsBox.Add(self.add, 0, wx.ALL, 5) + optionsBox.Add(self.remove, 0, wx.ALL, 5) + sizer.Add(optionsBox, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK) + cancel = wx.Button(panel, wx.ID_CANCEL) + sizerBtn = wx.BoxSizer(wx.HORIZONTAL) + sizerBtn.Add(ok, 0, wx.ALL, 5) + sizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(sizerBtn, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def put_users(self, users): - for i in users: - j = [i[0], i[1]] - self.users.insert_item(False, *j) + def put_users(self, users): + for i in users: + j = [i[0], i[1]] + self.users.insert_item(False, *j) - def get_user(self): - usr = False - userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database")) - if userDlg.ShowModal() == wx.ID_OK: - usr = userDlg.GetValue() - return usr + def get_user(self): + usr = False + userDlg = wx.TextEntryDialog(None, _(u"Twitter username"), _(u"Add user to database")) + if userDlg.ShowModal() == wx.ID_OK: + usr = userDlg.GetValue() + return usr - def show_invalid_user_error(self): - wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal() \ No newline at end of file + def show_invalid_user_error(self): + wx.MessageDialog(None, _(u"The user does not exist"), _(u"Error!"), wx.ICON_ERROR).ShowModal() diff --git a/src/extra/autocompletionUsers/wx_menu.py b/src/extra/autocompletionUsers/wx_menu.py index 55d81458..065ff2a1 100644 --- a/src/extra/autocompletionUsers/wx_menu.py +++ b/src/extra/autocompletionUsers/wx_menu.py @@ -2,24 +2,24 @@ import wx class menu(wx.Menu): - def __init__(self, window, pattern, mode): - super(menu, self).__init__() - self.window = window - self.pattern = pattern - self.mode = mode + def __init__(self, window, pattern, mode): + super(menu, self).__init__() + self.window = window + self.pattern = pattern + self.mode = mode - def append_options(self, options): - for i in options: - item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0])) - self.AppendItem(item) - self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item) + def append_options(self, options): + for i in options: + item = wx.MenuItem(self, wx.ID_ANY, "%s (@%s)" % (i[1], i[0])) + self.AppendItem(item) + self.Bind(wx.EVT_MENU, lambda evt, temp=i[0]: self.select_text(evt, temp), item) - def select_text(self, ev, text): - if self.mode == "tweet": - self.window.ChangeValue(self.window.GetValue().replace("@"+self.pattern, "@"+text+" ")) - elif self.mode == "dm": - self.window.SetValue(self.window.GetValue().replace(self.pattern, text)) - self.window.SetInsertionPointEnd() + def select_text(self, ev, text): + if self.mode == "tweet": + self.window.ChangeValue(self.window.GetValue().replace("@"+self.pattern, "@"+text+" ")) + elif self.mode == "dm": + self.window.SetValue(self.window.GetValue().replace(self.pattern, text)) + self.window.SetInsertionPointEnd() - def destroy(self): - self.Destroy() \ No newline at end of file + def destroy(self): + self.Destroy() diff --git a/src/extra/autocompletionUsers/wx_settings.py b/src/extra/autocompletionUsers/wx_settings.py index 068decf6..3d635935 100644 --- a/src/extra/autocompletionUsers/wx_settings.py +++ b/src/extra/autocompletionUsers/wx_settings.py @@ -4,24 +4,24 @@ import widgetUtils import application class autocompletionSettingsDialog(widgetUtils.BaseDialog): - def __init__(self): - super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.followers_buffer = wx.CheckBox(panel, -1, _(u"Add users from followers buffer")) - self.friends_buffer = wx.CheckBox(panel, -1, _(u"Add users from friends buffer")) - sizer.Add(self.followers_buffer, 0, wx.ALL, 5) - sizer.Add(self.friends_buffer, 0, wx.ALL, 5) - self.viewList = wx.Button(panel, -1, _(u"Manage database...")) - sizer.Add(self.viewList, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK) - cancel = wx.Button(panel, wx.ID_CANCEL) - sizerBtn = wx.BoxSizer(wx.HORIZONTAL) - sizerBtn.Add(ok, 0, wx.ALL, 5) - sizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(sizerBtn, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(autocompletionSettingsDialog, self).__init__(parent=None, id=-1, title=_(u"Autocomplete users' settings")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.followers_buffer = wx.CheckBox(panel, -1, _(u"Add users from followers buffer")) + self.friends_buffer = wx.CheckBox(panel, -1, _(u"Add users from friends buffer")) + sizer.Add(self.followers_buffer, 0, wx.ALL, 5) + sizer.Add(self.friends_buffer, 0, wx.ALL, 5) + self.viewList = wx.Button(panel, -1, _(u"Manage database...")) + sizer.Add(self.viewList, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK) + cancel = wx.Button(panel, wx.ID_CANCEL) + sizerBtn = wx.BoxSizer(wx.HORIZONTAL) + sizerBtn.Add(ok, 0, wx.ALL, 5) + sizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(sizerBtn, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) def show_success_dialog(): - wx.MessageDialog(None, _(u"{0}'s database of users has been updated.").format(application.name,), _(u"Done"), wx.OK).ShowModal() \ No newline at end of file + wx.MessageDialog(None, _(u"{0}'s database of users has been updated.").format(application.name,), _(u"Done"), wx.OK).ShowModal() diff --git a/src/extra/ocr/OCRSpace.py b/src/extra/ocr/OCRSpace.py index ec7e21a1..cee5e7c3 100644 --- a/src/extra/ocr/OCRSpace.py +++ b/src/extra/ocr/OCRSpace.py @@ -9,37 +9,37 @@ short_langs = ["", "da", "du", "en", "fi", "fr", "de", "hu", "ko", "it", "ja", " OcrLangs = ["", "dan", "dut", "eng", "fin", "fre", "ger", "hun", "kor", "ita", "jpn", "pol", "por", "rus", "spa", "tur"] class APIError(Exception): - pass + pass class OCRSpaceAPI(object): - def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'): - self.key = key - self.url = url + def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'): + self.key = key + self.url = url - def OCR_URL(self, url, overlay=False, lang=None): - payload = { - 'url': url, - 'isOverlayRequired': overlay, - 'apikey': self.key, - } - if lang != None: - payload.update(language=lang) - r = requests.post(self.url, data=payload) - result = r.json()['ParsedResults'][0] - if result['ErrorMessage']: - raise APIError(result['ErrorMessage']) - return result + def OCR_URL(self, url, overlay=False, lang=None): + payload = { + 'url': url, + 'isOverlayRequired': overlay, + 'apikey': self.key, + } + if lang != None: + payload.update(language=lang) + r = requests.post(self.url, data=payload) + result = r.json()['ParsedResults'][0] + if result['ErrorMessage']: + raise APIError(result['ErrorMessage']) + return result - def OCR_file(self, fileobj, overlay=False): - payload = { - 'isOverlayRequired': overlay, - 'apikey': self.key, - 'lang': 'es', - } - r = requests.post(self.url, data=payload, files={'file': fileobj}) - results = r.json()['ParsedResults'] - if results[0]['ErrorMessage']: - raise APIError(results[0]['ErrorMessage']) - return results + def OCR_file(self, fileobj, overlay=False): + payload = { + 'isOverlayRequired': overlay, + 'apikey': self.key, + 'lang': 'es', + } + r = requests.post(self.url, data=payload, files={'file': fileobj}) + results = r.json()['ParsedResults'] + if results[0]['ErrorMessage']: + raise APIError(results[0]['ErrorMessage']) + return results diff --git a/src/extra/ocr/__init__.py b/src/extra/ocr/__init__.py index 48e76b1a..5617235f 100644 --- a/src/extra/ocr/__init__.py +++ b/src/extra/ocr/__init__.py @@ -2,4 +2,4 @@ from __future__ import absolute_import from __future__ import unicode_literals # -*- coding: utf-8 -*- -from . import OCRSpace \ No newline at end of file +from . import OCRSpace diff --git a/src/extra/translator/__init__.py b/src/extra/translator/__init__.py index 4b1845ea..07b41a1e 100644 --- a/src/extra/translator/__init__.py +++ b/src/extra/translator/__init__.py @@ -4,5 +4,5 @@ from __future__ import unicode_literals from . import translator import platform if platform.system() == "Windows": - from . import wx_ui as gui - \ No newline at end of file + from . import wx_ui as gui + diff --git a/src/extra/translator/translator.py b/src/extra/translator/translator.py index ae08a4e8..d9bc99dc 100644 --- a/src/extra/translator/translator.py +++ b/src/extra/translator/translator.py @@ -9,108 +9,108 @@ log = logging.getLogger("extras.translator") t = None def translate(text="", target="en"): - global t - log.debug("Received translation request for language %s, text=%s" % (target, text)) - if t == None: - t = Translator() - vars = dict(text=text, dest=target) - return t.translate(**vars).text + global t + log.debug("Received translation request for language %s, text=%s" % (target, text)) + if t == None: + t = Translator() + vars = dict(text=text, dest=target) + return t.translate(**vars).text supported_langs = None languages = { - "af": _(u"Afrikaans"), - "sq": _(u"Albanian"), - "am": _(u"Amharic"), - "ar": _(u"Arabic"), - "hy": _(u"Armenian"), - "az": _(u"Azerbaijani"), - "eu": _(u"Basque"), - "be": _(u"Belarusian"), - "bn": _(u"Bengali"), - "bh": _(u"Bihari"), - "bg": _(u"Bulgarian"), - "my": _(u"Burmese"), - "ca": _(u"Catalan"), - "chr": _(u"Cherokee"), - "zh": _(u"Chinese"), - "zh-CN": _(u"Chinese_simplified"), - "zh-TW": _(u"Chinese_traditional"), - "hr": _(u"Croatian"), - "cs": _(u"Czech"), - "da": _(u"Danish"), - "dv": _(u"Dhivehi"), - "nl": _(u"Dutch"), - "en": _(u"English"), - "eo": _(u"Esperanto"), - "et": _(u"Estonian"), - "tl": _(u"Filipino"), - "fi": _(u"Finnish"), - "fr": _(u"French"), - "gl": _(u"Galician"), - "ka": _(u"Georgian"), - "de": _(u"German"), - "el": _(u"Greek"), - "gn": _(u"Guarani"), - "gu": _(u"Gujarati"), - "iw": _(u"Hebrew"), - "hi": _(u"Hindi"), - "hu": _(u"Hungarian"), - "is": _(u"Icelandic"), - "id": _(u"Indonesian"), - "iu": _(u"Inuktitut"), - "ga": _(u"Irish"), - "it": _(u"Italian"), - "ja": _(u"Japanese"), - "kn": _(u"Kannada"), - "kk": _(u"Kazakh"), - "km": _(u"Khmer"), - "ko": _(u"Korean"), - "ku": _(u"Kurdish"), - "ky": _(u"Kyrgyz"), - "lo": _(u"Laothian"), - "lv": _(u"Latvian"), - "lt": _(u"Lithuanian"), - "mk": _(u"Macedonian"), - "ms": _(u"Malay"), - "ml": _(u"Malayalam"), - "mt": _(u"Maltese"), - "mr": _(u"Marathi"), - "mn": _(u"Mongolian"), - "ne": _(u"Nepali"), - "no": _(u"Norwegian"), - "or": _(u"Oriya"), - "ps": _(u"Pashto"), - "fa": _(u"Persian"), - "pl": _(u"Polish"), - "pt": _(u"Portuguese"), - "pa": _(u"Punjabi"), - "ro": _(u"Romanian"), - "ru": _(u"Russian"), - "sa": _(u"Sanskrit"), - "sr": _(u"Serbian"), - "sd": _(u"Sindhi"), - "si": _(u"Sinhalese"), - "sk": _(u"Slovak"), - "sl": _(u"Slovenian"), - "es": _(u"Spanish"), - "sw": _(u"Swahili"), - "sv": _(u"Swedish"), - "tg": _(u"Tajik"), - "ta": _(u"Tamil"), - "tl": _(u"Tagalog"), - "te": _(u"Telugu"), - "th": _(u"Thai"), - "bo": _(u"Tibetan"), - "tr": _(u"Turkish"), - "uk": _(u"Ukrainian"), - "ur": _(u"Urdu"), - "uz": _(u"Uzbek"), - "ug": _(u"Uighur"), - "vi": _(u"Vietnamese"), - "cy": _(u"Welsh"), - "yi": _(u"Yiddish") + "af": _(u"Afrikaans"), + "sq": _(u"Albanian"), + "am": _(u"Amharic"), + "ar": _(u"Arabic"), + "hy": _(u"Armenian"), + "az": _(u"Azerbaijani"), + "eu": _(u"Basque"), + "be": _(u"Belarusian"), + "bn": _(u"Bengali"), + "bh": _(u"Bihari"), + "bg": _(u"Bulgarian"), + "my": _(u"Burmese"), + "ca": _(u"Catalan"), + "chr": _(u"Cherokee"), + "zh": _(u"Chinese"), + "zh-CN": _(u"Chinese_simplified"), + "zh-TW": _(u"Chinese_traditional"), + "hr": _(u"Croatian"), + "cs": _(u"Czech"), + "da": _(u"Danish"), + "dv": _(u"Dhivehi"), + "nl": _(u"Dutch"), + "en": _(u"English"), + "eo": _(u"Esperanto"), + "et": _(u"Estonian"), + "tl": _(u"Filipino"), + "fi": _(u"Finnish"), + "fr": _(u"French"), + "gl": _(u"Galician"), + "ka": _(u"Georgian"), + "de": _(u"German"), + "el": _(u"Greek"), + "gn": _(u"Guarani"), + "gu": _(u"Gujarati"), + "iw": _(u"Hebrew"), + "hi": _(u"Hindi"), + "hu": _(u"Hungarian"), + "is": _(u"Icelandic"), + "id": _(u"Indonesian"), + "iu": _(u"Inuktitut"), + "ga": _(u"Irish"), + "it": _(u"Italian"), + "ja": _(u"Japanese"), + "kn": _(u"Kannada"), + "kk": _(u"Kazakh"), + "km": _(u"Khmer"), + "ko": _(u"Korean"), + "ku": _(u"Kurdish"), + "ky": _(u"Kyrgyz"), + "lo": _(u"Laothian"), + "lv": _(u"Latvian"), + "lt": _(u"Lithuanian"), + "mk": _(u"Macedonian"), + "ms": _(u"Malay"), + "ml": _(u"Malayalam"), + "mt": _(u"Maltese"), + "mr": _(u"Marathi"), + "mn": _(u"Mongolian"), + "ne": _(u"Nepali"), + "no": _(u"Norwegian"), + "or": _(u"Oriya"), + "ps": _(u"Pashto"), + "fa": _(u"Persian"), + "pl": _(u"Polish"), + "pt": _(u"Portuguese"), + "pa": _(u"Punjabi"), + "ro": _(u"Romanian"), + "ru": _(u"Russian"), + "sa": _(u"Sanskrit"), + "sr": _(u"Serbian"), + "sd": _(u"Sindhi"), + "si": _(u"Sinhalese"), + "sk": _(u"Slovak"), + "sl": _(u"Slovenian"), + "es": _(u"Spanish"), + "sw": _(u"Swahili"), + "sv": _(u"Swedish"), + "tg": _(u"Tajik"), + "ta": _(u"Tamil"), + "tl": _(u"Tagalog"), + "te": _(u"Telugu"), + "th": _(u"Thai"), + "bo": _(u"Tibetan"), + "tr": _(u"Turkish"), + "uk": _(u"Ukrainian"), + "ur": _(u"Urdu"), + "uz": _(u"Uzbek"), + "ug": _(u"Uighur"), + "vi": _(u"Vietnamese"), + "cy": _(u"Welsh"), + "yi": _(u"Yiddish") } def available_languages(): - return dict(sorted(languages.items(), key=lambda x: x[1])) + return dict(sorted(languages.items(), key=lambda x: x[1])) diff --git a/src/extra/translator/wx_ui.py b/src/extra/translator/wx_ui.py index 8b9672e3..e05af488 100644 --- a/src/extra/translator/wx_ui.py +++ b/src/extra/translator/wx_ui.py @@ -21,25 +21,25 @@ import wx from wxUI.dialogs import baseDialog class translateDialog(baseDialog.BaseWXDialog): - def __init__(self): - languages = [] - language_dict = translator.available_languages() - for k in language_dict: - languages.append(language_dict[k]) - super(translateDialog, self).__init__(None, -1, title=_(u"Translate message")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - staticDest = wx.StaticText(panel, -1, _(u"Target language")) - self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY) - self.dest_lang.SetFocus() - self.dest_lang.SetSelection(0) - listSizer = wx.BoxSizer(wx.HORIZONTAL) - listSizer.Add(staticDest) - listSizer.Add(self.dest_lang) - ok = wx.Button(panel, wx.ID_OK) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL) - self.SetEscapeId(wx.ID_CANCEL) + def __init__(self): + languages = [] + language_dict = translator.available_languages() + for k in language_dict: + languages.append(language_dict[k]) + super(translateDialog, self).__init__(None, -1, title=_(u"Translate message")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + staticDest = wx.StaticText(panel, -1, _(u"Target language")) + self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY) + self.dest_lang.SetFocus() + self.dest_lang.SetSelection(0) + listSizer = wx.BoxSizer(wx.HORIZONTAL) + listSizer.Add(staticDest) + listSizer.Add(self.dest_lang) + ok = wx.Button(panel, wx.ID_OK) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL) + self.SetEscapeId(wx.ID_CANCEL) - def get(self, control): - return getattr(self, control).GetSelection() \ No newline at end of file + def get(self, control): + return getattr(self, control).GetSelection() diff --git a/src/fixes/__init__.py b/src/fixes/__init__.py index 70834b1a..6f256431 100644 --- a/src/fixes/__init__.py +++ b/src/fixes/__init__.py @@ -9,11 +9,11 @@ from . import fix_urllib3_warnings # Avoiding some SSL warnings related to Twyth from . import fix_win32com #from . import fix_requests #fix cacert.pem location for TWBlue binary copies def setup(): - fix_arrow.fix() - if hasattr(sys, "frozen"): - fix_libloader.fix() - fix_win32com.fix() + fix_arrow.fix() + if hasattr(sys, "frozen"): + fix_libloader.fix() + fix_win32com.fix() # fix_requests.fix() # else: # fix_requests.fix(False) - fix_urllib3_warnings.fix() \ No newline at end of file + fix_urllib3_warnings.fix() diff --git a/src/fixes/fix_libloader.py b/src/fixes/fix_libloader.py index db214ed4..064440f7 100644 --- a/src/fixes/fix_libloader.py +++ b/src/fixes/fix_libloader.py @@ -16,27 +16,27 @@ log = logging.getLogger("fixes.fix_libloader") fixed=False def patched_getmodule(modname): - mod=__import__(modname) - return sys.modules[modname] + mod=__import__(modname) + return sys.modules[modname] def load_com(*names): - global fixed - if fixed==False: - gencache._GetModule=patched_getmodule - com.prepare_gencache() - fixed=True - result = None - for name in names: - try: - result = gencache.EnsureDispatch(name) - break - except com_error: - continue - if result is None: - raise com_error("Unable to load any of the provided com objects.") - return result + global fixed + if fixed==False: + gencache._GetModule=patched_getmodule + com.prepare_gencache() + fixed=True + result = None + for name in names: + try: + result = gencache.EnsureDispatch(name) + break + except com_error: + continue + if result is None: + raise com_error("Unable to load any of the provided com objects.") + return result def fix(): - log.debug("Applying fix for Libloader...") - com.load_com = load_com - log.debug("Load_com has been mapped correctly.") \ No newline at end of file + log.debug("Applying fix for Libloader...") + com.load_com = load_com + log.debug("Load_com has been mapped correctly.") diff --git a/src/fixes/fix_requests.py b/src/fixes/fix_requests.py index 49ff12e3..a1d88585 100644 --- a/src/fixes/fix_requests.py +++ b/src/fixes/fix_requests.py @@ -7,6 +7,6 @@ import logging log = logging.getLogger("fixes.fix_requests") def fix(): - log.debug("Applying fix for requests...") - os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "certifi", "cacert.pem")#.encode(paths.fsencoding) -# log.debug("Changed CA path to %s" % (os.environ["REQUESTS_CA_BUNDLE"]))#.decode(paths.fsencoding))) \ No newline at end of file + log.debug("Applying fix for requests...") + os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(paths.app_path(), "certifi", "cacert.pem")#.encode(paths.fsencoding) +# log.debug("Changed CA path to %s" % (os.environ["REQUESTS_CA_BUNDLE"]))#.decode(paths.fsencoding))) diff --git a/src/fixes/fix_urllib3_warnings.py b/src/fixes/fix_urllib3_warnings.py index 63ca2615..67c6d9ad 100644 --- a/src/fixes/fix_urllib3_warnings.py +++ b/src/fixes/fix_urllib3_warnings.py @@ -8,8 +8,8 @@ import six import urllib.request, urllib.parse, urllib.error def fix(): - urllib3.disable_warnings() - fields.format_header_param=patched_format_header_param + urllib3.disable_warnings() + fields.format_header_param=patched_format_header_param def patched_format_header_param(name, value): if not any(ch in value for ch in '"\\\r\n'): diff --git a/src/fixes/fix_win32com.py b/src/fixes/fix_win32com.py index a135c90a..bce06112 100644 --- a/src/fixes/fix_win32com.py +++ b/src/fixes/fix_win32com.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals import win32com.client def fix(): - if win32com.client.gencache.is_readonly == True: - win32com.client.gencache.is_readonly = False - win32com.client.gencache.Rebuild() \ No newline at end of file + if win32com.client.gencache.is_readonly == True: + win32com.client.gencache.is_readonly = False + win32com.client.gencache.Rebuild() diff --git a/src/issueReporter/issueReporter.py b/src/issueReporter/issueReporter.py index a4d074eb..db261b5e 100644 --- a/src/issueReporter/issueReporter.py +++ b/src/issueReporter/issueReporter.py @@ -27,40 +27,40 @@ from suds.client import Client import constants class reportBug(object): - def __init__(self, user_name): - self.user_name = user_name - self.categories = [_(u"General")] - self.reproducibilities = [_(u"always"), _(u"sometimes"), _(u"random"), _(u"have not tried"), _(u"unable to duplicate")] - self.severities = [_(u"block"), _(u"crash"), _(u"major"), _(u"minor"), _(u"tweak"), _(u"text"), _(u"trivial"), _(u"feature")] - self.dialog = wx_ui.reportBugDialog(self.categories, self.reproducibilities, self.severities) - widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send) - self.dialog.get_response() + def __init__(self, user_name): + self.user_name = user_name + self.categories = [_(u"General")] + self.reproducibilities = [_(u"always"), _(u"sometimes"), _(u"random"), _(u"have not tried"), _(u"unable to duplicate")] + self.severities = [_(u"block"), _(u"crash"), _(u"major"), _(u"minor"), _(u"tweak"), _(u"text"), _(u"trivial"), _(u"feature")] + self.dialog = wx_ui.reportBugDialog(self.categories, self.reproducibilities, self.severities) + widgetUtils.connect_event(self.dialog.ok, widgetUtils.BUTTON_PRESSED, self.send) + self.dialog.get_response() - def send(self, *args, **kwargs): - if self.dialog.get("summary") == "" or self.dialog.get("description") == "": - self.dialog.no_filled() - return - if self.dialog.get("agree") == False: - self.dialog.no_checkbox() - return - try: - client = Client(application.report_bugs_url) - issue = client.factory.create('IssueData') - issue.project.name = application.name - issue.project.id = 0 - issue.summary = self.dialog.get("summary"), - issue.description = "Reported by @%s on version %s (snapshot = %s)\n\n" % (self.user_name, application.version, application.snapshot) + self.dialog.get("description") - # to do: Create getters for category, severity and reproducibility in wx_UI. - issue.category = constants.categories[self.dialog.category.GetSelection()] - issue.reproducibility.name = constants.reproducibilities[self.dialog.reproducibility.GetSelection()] - issue.severity.name = constants.severities[self.dialog.severity.GetSelection()] - issue.priority.name = "normal" - issue.view_state.name = "public" - issue.resolution.name = "open" - issue.projection.name = "none" - issue.eta.name = "eta" - issue.status.name = "new" - id = client.service.mc_issue_add(keys.keyring.get("bts_user"), keys.keyring.get("bts_password"), issue) - self.dialog.success(id) - except: - self.dialog.error() + def send(self, *args, **kwargs): + if self.dialog.get("summary") == "" or self.dialog.get("description") == "": + self.dialog.no_filled() + return + if self.dialog.get("agree") == False: + self.dialog.no_checkbox() + return + try: + client = Client(application.report_bugs_url) + issue = client.factory.create('IssueData') + issue.project.name = application.name + issue.project.id = 0 + issue.summary = self.dialog.get("summary"), + issue.description = "Reported by @%s on version %s (snapshot = %s)\n\n" % (self.user_name, application.version, application.snapshot) + self.dialog.get("description") + # to do: Create getters for category, severity and reproducibility in wx_UI. + issue.category = constants.categories[self.dialog.category.GetSelection()] + issue.reproducibility.name = constants.reproducibilities[self.dialog.reproducibility.GetSelection()] + issue.severity.name = constants.severities[self.dialog.severity.GetSelection()] + issue.priority.name = "normal" + issue.view_state.name = "public" + issue.resolution.name = "open" + issue.projection.name = "none" + issue.eta.name = "eta" + issue.status.name = "new" + id = client.service.mc_issue_add(keys.keyring.get("bts_user"), keys.keyring.get("bts_password"), issue) + self.dialog.success(id) + except: + self.dialog.error() diff --git a/src/issueReporter/wx_ui.py b/src/issueReporter/wx_ui.py index 46ee715c..82d0c51c 100644 --- a/src/issueReporter/wx_ui.py +++ b/src/issueReporter/wx_ui.py @@ -21,75 +21,75 @@ import wx import widgetUtils import application class reportBugDialog(widgetUtils.BaseDialog): - def __init__(self, categories, reproducibilities, severities): - super(reportBugDialog, self).__init__(parent=None, id=wx.NewId()) - self.SetTitle(_(u"Report an error")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - categoryLabel = wx.StaticText(panel, -1, _(u"Select a category"), size=wx.DefaultSize) - self.category = wx.ComboBox(panel, -1, choices=categories, style=wx.CB_READONLY) - self.category.SetSelection(0) - categoryB = wx.BoxSizer(wx.HORIZONTAL) - categoryB.Add(categoryLabel, 0, wx.ALL, 5) - categoryB.Add(self.category, 0, wx.ALL, 5) - self.category.SetFocus() - sizer.Add(categoryB, 0, wx.ALL, 5) - summaryLabel = wx.StaticText(panel, -1, _(u"Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize) - self.summary = wx.TextCtrl(panel, -1) - dc = wx.WindowDC(self.summary) - dc.SetFont(self.summary.GetFont()) - self.summary.SetSize(dc.GetTextExtent("a"*80)) - summaryB = wx.BoxSizer(wx.HORIZONTAL) - summaryB.Add(summaryLabel, 0, wx.ALL, 5) - summaryB.Add(self.summary, 0, wx.ALL, 5) - sizer.Add(summaryB, 0, wx.ALL, 5) - descriptionLabel = wx.StaticText(panel, -1, _(u"Here, you can describe the bug in detail"), size=wx.DefaultSize) - self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) - dc = wx.WindowDC(self.description) - dc.SetFont(self.description.GetFont()) - (x, y, z) = dc.GetMultiLineTextExtent("0"*2000) - self.description.SetSize((x, y)) - descBox = wx.BoxSizer(wx.HORIZONTAL) - descBox.Add(descriptionLabel, 0, wx.ALL, 5) - descBox.Add(self.description, 0, wx.ALL, 5) - sizer.Add(descBox, 0, wx.ALL, 5) - reproducibilityLabel = wx.StaticText(panel, -1, _(u"how often does this bug happen?"), size=wx.DefaultSize) - self.reproducibility = wx.ComboBox(panel, -1, choices=reproducibilities, style=wx.CB_READONLY) - self.reproducibility.SetSelection(3) - reprB = wx.BoxSizer(wx.HORIZONTAL) - reprB.Add(reproducibilityLabel, 0, wx.ALL, 5) - reprB.Add(self.reproducibility, 0, wx.ALL, 5) - sizer.Add(reprB, 0, wx.ALL, 5) - severityLabel = wx.StaticText(panel, -1, _(u"Select the importance that you think this bug has")) - self.severity = wx.ComboBox(panel, -1, choices=severities, style=wx.CB_READONLY) - self.severity.SetSelection(3) - severityB = wx.BoxSizer(wx.HORIZONTAL) - severityB.Add(severityLabel, 0, wx.ALL, 5) - severityB.Add(self.severity, 0, wx.ALL, 5) - sizer.Add(severityB, 0, wx.ALL, 5) - self.agree = wx.CheckBox(panel, -1, _(u"I know that the {0} bug system will get my Twitter username to contact me and fix the bug quickly").format(application.name,)) - self.agree.SetValue(False) - sizer.Add(self.agree, 0, wx.ALL, 5) - self.ok = wx.Button(panel, wx.ID_OK, _(u"Send report")) - self.ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(self.ok, 0, wx.ALL, 5) - btnBox.Add(cancel, 0, wx.ALL, 5) - sizer.Add(btnBox, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self, categories, reproducibilities, severities): + super(reportBugDialog, self).__init__(parent=None, id=wx.NewId()) + self.SetTitle(_(u"Report an error")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + categoryLabel = wx.StaticText(panel, -1, _(u"Select a category"), size=wx.DefaultSize) + self.category = wx.ComboBox(panel, -1, choices=categories, style=wx.CB_READONLY) + self.category.SetSelection(0) + categoryB = wx.BoxSizer(wx.HORIZONTAL) + categoryB.Add(categoryLabel, 0, wx.ALL, 5) + categoryB.Add(self.category, 0, wx.ALL, 5) + self.category.SetFocus() + sizer.Add(categoryB, 0, wx.ALL, 5) + summaryLabel = wx.StaticText(panel, -1, _(u"Briefly describe what happened. You will be able to thoroughly explain it later"), size=wx.DefaultSize) + self.summary = wx.TextCtrl(panel, -1) + dc = wx.WindowDC(self.summary) + dc.SetFont(self.summary.GetFont()) + self.summary.SetSize(dc.GetTextExtent("a"*80)) + summaryB = wx.BoxSizer(wx.HORIZONTAL) + summaryB.Add(summaryLabel, 0, wx.ALL, 5) + summaryB.Add(self.summary, 0, wx.ALL, 5) + sizer.Add(summaryB, 0, wx.ALL, 5) + descriptionLabel = wx.StaticText(panel, -1, _(u"Here, you can describe the bug in detail"), size=wx.DefaultSize) + self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) + dc = wx.WindowDC(self.description) + dc.SetFont(self.description.GetFont()) + (x, y, z) = dc.GetMultiLineTextExtent("0"*2000) + self.description.SetSize((x, y)) + descBox = wx.BoxSizer(wx.HORIZONTAL) + descBox.Add(descriptionLabel, 0, wx.ALL, 5) + descBox.Add(self.description, 0, wx.ALL, 5) + sizer.Add(descBox, 0, wx.ALL, 5) + reproducibilityLabel = wx.StaticText(panel, -1, _(u"how often does this bug happen?"), size=wx.DefaultSize) + self.reproducibility = wx.ComboBox(panel, -1, choices=reproducibilities, style=wx.CB_READONLY) + self.reproducibility.SetSelection(3) + reprB = wx.BoxSizer(wx.HORIZONTAL) + reprB.Add(reproducibilityLabel, 0, wx.ALL, 5) + reprB.Add(self.reproducibility, 0, wx.ALL, 5) + sizer.Add(reprB, 0, wx.ALL, 5) + severityLabel = wx.StaticText(panel, -1, _(u"Select the importance that you think this bug has")) + self.severity = wx.ComboBox(panel, -1, choices=severities, style=wx.CB_READONLY) + self.severity.SetSelection(3) + severityB = wx.BoxSizer(wx.HORIZONTAL) + severityB.Add(severityLabel, 0, wx.ALL, 5) + severityB.Add(self.severity, 0, wx.ALL, 5) + sizer.Add(severityB, 0, wx.ALL, 5) + self.agree = wx.CheckBox(panel, -1, _(u"I know that the {0} bug system will get my Twitter username to contact me and fix the bug quickly").format(application.name,)) + self.agree.SetValue(False) + sizer.Add(self.agree, 0, wx.ALL, 5) + self.ok = wx.Button(panel, wx.ID_OK, _(u"Send report")) + self.ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.ok, 0, wx.ALL, 5) + btnBox.Add(cancel, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def no_filled(self): - wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal() + def no_filled(self): + wx.MessageDialog(self, _(u"You must fill out both fields"), _(u"Error"), wx.OK|wx.ICON_ERROR).ShowModal() - def no_checkbox(self): - wx.MessageDialog(self, _(u"You need to mark the checkbox to provide us your twitter username to contact you if it is necessary."), _(u"Error"), wx.ICON_ERROR).ShowModal() + def no_checkbox(self): + wx.MessageDialog(self, _(u"You need to mark the checkbox to provide us your twitter username to contact you if it is necessary."), _(u"Error"), wx.ICON_ERROR).ShowModal() - def success(self, id): - wx.MessageDialog(self, _(u"Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You've reported the bug number %i") % (id), _(u"reported"), wx.OK).ShowModal() - self.EndModal(wx.ID_OK) + def success(self, id): + wx.MessageDialog(self, _(u"Thanks for reporting this bug! In future versions, you may be able to find it in the changes list. You've reported the bug number %i") % (id), _(u"reported"), wx.OK).ShowModal() + self.EndModal(wx.ID_OK) - def error(self): - wx.MessageDialog(self, _(u"Something unexpected occurred while trying to report the bug. Please, try again later"), _(u"Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal() - self.EndModal(wx.ID_CANCEL) \ No newline at end of file + def error(self): + wx.MessageDialog(self, _(u"Something unexpected occurred while trying to report the bug. Please, try again later"), _(u"Error while reporting"), wx.ICON_ERROR|wx.OK).ShowModal() + self.EndModal(wx.ID_CANCEL) diff --git a/src/keyboard_handler/global_handler.py b/src/keyboard_handler/global_handler.py index d07062ac..b50e082e 100644 --- a/src/keyboard_handler/global_handler.py +++ b/src/keyboard_handler/global_handler.py @@ -1,8 +1,8 @@ from __future__ import absolute_import import platform if platform.system() == 'Linux': - from .linux import LinuxKeyboardHandler as GlobalKeyboardHandler + from .linux import LinuxKeyboardHandler as GlobalKeyboardHandler else: - from .wx_handler import WXKeyboardHandler as GlobalKeyboardHandler + from .wx_handler import WXKeyboardHandler as GlobalKeyboardHandler #elif platform.system() == 'Darwin': - #from osx import OSXKeyboardHandler as GlobalKeyboardHandler + #from osx import OSXKeyboardHandler as GlobalKeyboardHandler diff --git a/src/keyboard_handler/key_constants.py b/src/keyboard_handler/key_constants.py index c40491d4..6d88ffe9 100644 --- a/src/keyboard_handler/key_constants.py +++ b/src/keyboard_handler/key_constants.py @@ -1,127 +1,127 @@ keys = { - 'accept': 30, - 'add': 107, - 'apps': 93, - 'attn': 246, - 'back': 8, - 'browser_back': 166, - 'browser_forward': 167, - 'cancel': 3, - 'capital': 20, - 'clear': 12, - 'control': 17, - 'convert': 28, - 'crsel': 247, - 'decimal': 110, - 'delete': 46, - 'divide': 111, - 'down': 40, - 'end': 35, - 'ereof': 249, - 'escape': 27, - 'execute': 43, - 'exsel': 248, - 'f1': 112, - 'f10': 121, - 'f11': 122, - 'f12': 123, - 'f13': 124, - 'f14': 125, - 'f15': 126, - 'f16': 127, - 'f17': 128, - 'f18': 129, - 'f19': 130, - 'f2': 113, - 'f20': 131, - 'f21': 132, - 'f22': 133, - 'f23': 134, - 'f24': 135, - 'f3': 114, - 'f4': 115, - 'f5': 116, - 'f6': 117, - 'f7': 118, - 'f8': 119, - 'f9': 120, - 'final': 24, - 'hangeul': 21, - 'hangul': 21, - 'hanja': 25, - 'help': 47, - 'home': 36, - 'insert': 45, - 'junja': 23, - 'kana': 21, - 'kanji': 25, - 'lbutton': 1, - 'lcontrol': 162, - 'left': 37, - 'lmenu': 164, - 'lshift': 160, - 'lwin': 91, - 'mbutton': 4, - 'media_next_track': 176, - 'media_play_pause': 179, - 'media_prev_track': 177, - 'menu': 18, - 'modechange': 31, - 'multiply': 106, - 'next': 34, - 'noname': 252, - 'nonconvert': 29, - 'numlock': 144, - 'numpad0': 96, - 'numpad1': 97, - 'numpad2': 98, - 'numpad3': 99, - 'numpad4': 100, - 'numpad5': 101, - 'numpad6': 102, - 'numpad7': 103, - 'numpad8': 104, - 'numpad9': 105, - 'oem_clear': 254, - 'pa1': 253, - 'pagedown': 34, - 'pageup': 33, - 'pause': 19, - 'play': 250, - 'print': 42, - 'prior': 33, - 'processkey': 229, - 'rbutton': 2, - 'rcontrol': 163, - 'return': 13, - 'right': 39, - 'rmenu': 165, - 'rshift': 161, - 'rwin': 92, - 'scroll': 145, - 'select': 41, - 'separator': 108, - 'shift': 16, - 'snapshot': 44, - 'space': 32, - 'subtract': 109, - 'tab': 9, - 'up': 38, - 'volume_down': 174, - 'volume_mute': 173, - 'volume_up': 175, - 'xbutton1': 5, - 'xbutton2': 6, - 'zoom': 251, - '/': 191, - ';': 218, - '[': 219, - '\\': 220, - ']': 221, - '\'': 222, - '=': 187, - '-': 189, - ';': 186, + 'accept': 30, + 'add': 107, + 'apps': 93, + 'attn': 246, + 'back': 8, + 'browser_back': 166, + 'browser_forward': 167, + 'cancel': 3, + 'capital': 20, + 'clear': 12, + 'control': 17, + 'convert': 28, + 'crsel': 247, + 'decimal': 110, + 'delete': 46, + 'divide': 111, + 'down': 40, + 'end': 35, + 'ereof': 249, + 'escape': 27, + 'execute': 43, + 'exsel': 248, + 'f1': 112, + 'f10': 121, + 'f11': 122, + 'f12': 123, + 'f13': 124, + 'f14': 125, + 'f15': 126, + 'f16': 127, + 'f17': 128, + 'f18': 129, + 'f19': 130, + 'f2': 113, + 'f20': 131, + 'f21': 132, + 'f22': 133, + 'f23': 134, + 'f24': 135, + 'f3': 114, + 'f4': 115, + 'f5': 116, + 'f6': 117, + 'f7': 118, + 'f8': 119, + 'f9': 120, + 'final': 24, + 'hangeul': 21, + 'hangul': 21, + 'hanja': 25, + 'help': 47, + 'home': 36, + 'insert': 45, + 'junja': 23, + 'kana': 21, + 'kanji': 25, + 'lbutton': 1, + 'lcontrol': 162, + 'left': 37, + 'lmenu': 164, + 'lshift': 160, + 'lwin': 91, + 'mbutton': 4, + 'media_next_track': 176, + 'media_play_pause': 179, + 'media_prev_track': 177, + 'menu': 18, + 'modechange': 31, + 'multiply': 106, + 'next': 34, + 'noname': 252, + 'nonconvert': 29, + 'numlock': 144, + 'numpad0': 96, + 'numpad1': 97, + 'numpad2': 98, + 'numpad3': 99, + 'numpad4': 100, + 'numpad5': 101, + 'numpad6': 102, + 'numpad7': 103, + 'numpad8': 104, + 'numpad9': 105, + 'oem_clear': 254, + 'pa1': 253, + 'pagedown': 34, + 'pageup': 33, + 'pause': 19, + 'play': 250, + 'print': 42, + 'prior': 33, + 'processkey': 229, + 'rbutton': 2, + 'rcontrol': 163, + 'return': 13, + 'right': 39, + 'rmenu': 165, + 'rshift': 161, + 'rwin': 92, + 'scroll': 145, + 'select': 41, + 'separator': 108, + 'shift': 16, + 'snapshot': 44, + 'space': 32, + 'subtract': 109, + 'tab': 9, + 'up': 38, + 'volume_down': 174, + 'volume_mute': 173, + 'volume_up': 175, + 'xbutton1': 5, + 'xbutton2': 6, + 'zoom': 251, + '/': 191, + ';': 218, + '[': 219, + '\\': 220, + ']': 221, + '\'': 222, + '=': 187, + '-': 189, + ';': 186, } modifiers = {'alt': 1, 'control': 2, 'shift': 4, 'win': 8} diff --git a/src/keyboard_handler/linux.py b/src/keyboard_handler/linux.py index ba69d7ff..15f6ff7b 100644 --- a/src/keyboard_handler/linux.py +++ b/src/keyboard_handler/linux.py @@ -3,56 +3,56 @@ import threading import thread import pyatspi def parse(s): - """parse a string like control+f into (modifier, key). -Unknown modifiers will return ValueError.""" - m = 0 - lst = s.split('+') - if not len(lst): return (0, s) + """parse a string like control+f into (modifier, key). + Unknown modifiers will return ValueError.""" + m = 0 + lst = s.split('+') + if not len(lst): return (0, s) #Are these right? - d = { - "shift": 1< 1: #more than one key, parse error - raise ValueError, 'unknown modifier %s' % lst[0] - return (m, lst[0].lower()) + if len(lst) > 1: #more than one key, parse error + raise ValueError, 'unknown modifier %s' % lst[0] + return (m, lst[0].lower()) class AtspiThread(threading.Thread): - def run(self): - pyatspi.Registry.registerKeystrokeListener(handler, kind=(pyatspi.KEY_PRESSED_EVENT,), - mask=pyatspi.allModifiers()) - pyatspi.Registry.start() + def run(self): + pyatspi.Registry.registerKeystrokeListener(handler, kind=(pyatspi.KEY_PRESSED_EVENT,), + mask=pyatspi.allModifiers()) + pyatspi.Registry.start() #the keys we registered keys = {} def handler(e): - m,k = e.modifiers,e.event_string.lower() + m,k = e.modifiers,e.event_string.lower() #not sure why we can't catch control+f. Try to fix it. - if (not e.is_text) and e.id >= 97 <= 126: - k = chr(e.id) - if (m,k) not in keys: return False - thread.start_new(keys[(m,k)], ()) - return True #don't pass it on + if (not e.is_text) and e.id >= 97 <= 126: + k = chr(e.id) + if (m,k) not in keys: return False + thread.start_new(keys[(m,k)], ()) + return True #don't pass it on class LinuxKeyboardHandler(KeyboardHandler): - def __init__(self, *args, **kwargs): - KeyboardHandler.__init__(self, *args, **kwargs) - t = AtspiThread() - t.start() - def register_key(self, key, function): - """key will be a string, such as control+shift+f. -We need to convert that, using parse_key, -into modifier and key to put into our dictionary.""" + def __init__(self, *args, **kwargs): + KeyboardHandler.__init__(self, *args, **kwargs) + t = AtspiThread() + t.start() + def register_key(self, key, function): + """key will be a string, such as control+shift+f. + We need to convert that, using parse_key, + into modifier and key to put into our dictionary.""" #register key so we know if we have it on event receive. - t = parse(key) - keys[t] = function + t = parse(key) + keys[t] = function #if we got this far, the key is valid. - KeyboardHandler.register_key(self, key, function) + KeyboardHandler.register_key(self, key, function) - def unregister_key (self, key, function): - KeyboardHandler.unregister_key(self, key, function) - del keys[parse(key)] + def unregister_key (self, key, function): + KeyboardHandler.unregister_key(self, key, function) + del keys[parse(key)] diff --git a/src/keyboard_handler/main.py b/src/keyboard_handler/main.py index 000ee65d..0020bf7d 100644 --- a/src/keyboard_handler/main.py +++ b/src/keyboard_handler/main.py @@ -5,84 +5,84 @@ class KeyboardHandlerError (Exception): pass class KeyboardHandler(object): - def __init__(self, repeat_rate=0.0, *args, **kwargs): - self.repeat_rate = repeat_rate #How long between accepting the same keystroke? - self._last_key = None - self._last_keypress_time = 0 - super(KeyboardHandler, self).__init__(*args, **kwargs) - self.active_keys = {} - if not hasattr(self, 'replacement_mods'): - self.replacement_mods = {} - if not hasattr(self, 'replacement_keys'): - self.replacement_keys = {} + def __init__(self, repeat_rate=0.0, *args, **kwargs): + self.repeat_rate = repeat_rate #How long between accepting the same keystroke? + self._last_key = None + self._last_keypress_time = 0 + super(KeyboardHandler, self).__init__(*args, **kwargs) + self.active_keys = {} + if not hasattr(self, 'replacement_mods'): + self.replacement_mods = {} + if not hasattr(self, 'replacement_keys'): + self.replacement_keys = {} - def register_key (self, key, function): - if key in self.active_keys: - raise KeyboardHandlerError("Key %s is already registered to a function" % key) - if not callable(function): - raise TypeError("Must provide a callable to be invoked upon keypress") - self.active_keys[key] = function + def register_key (self, key, function): + if key in self.active_keys: + raise KeyboardHandlerError("Key %s is already registered to a function" % key) + if not callable(function): + raise TypeError("Must provide a callable to be invoked upon keypress") + self.active_keys[key] = function - def unregister_key (self, key, function): - try: - if self.active_keys[key] != function: - raise KeyboardHandlerError("key %s is not registered to that function" % key) - except KeyError: - raise KeyboardHandlerError("Key %s not currently registered" % key) - del(self.active_keys[key]) + def unregister_key (self, key, function): + try: + if self.active_keys[key] != function: + raise KeyboardHandlerError("key %s is not registered to that function" % key) + except KeyError: + raise KeyboardHandlerError("Key %s not currently registered" % key) + del(self.active_keys[key]) - def unregister_all_keys(self): - for key in list(self.active_keys): - self.unregister_key(key, self.active_keys[key]) + def unregister_all_keys(self): + for key in list(self.active_keys): + self.unregister_key(key, self.active_keys[key]) - def handle_key (self, key): - if self.repeat_rate and key == self._last_key and time.time() - self._last_keypress_time < self.repeat_rate: - return - try: - function = self.active_keys[key] - except KeyError: - return - self._last_key = key - self._last_keypress_time = time.time() - return function() + def handle_key (self, key): + if self.repeat_rate and key == self._last_key and time.time() - self._last_keypress_time < self.repeat_rate: + return + try: + function = self.active_keys[key] + except KeyError: + return + self._last_key = key + self._last_keypress_time = time.time() + return function() - def register_keys(self, keys): - """Given a mapping of keystrokes to functions, registers all keystrokes""" - for k in keys: - self.register_key(k, keys[k]) + def register_keys(self, keys): + """Given a mapping of keystrokes to functions, registers all keystrokes""" + for k in keys: + self.register_key(k, keys[k]) - def unregister_keys(self, keys): - """Given a mapping of keys to their functions, unregisters all provided keys.""" - for k in keys: - self.unregister_key(k, keys[k]) + def unregister_keys(self, keys): + """Given a mapping of keys to their functions, unregisters all provided keys.""" + for k in keys: + self.unregister_key(k, keys[k]) - def standardize_key(self, key): - """Takes a keystroke and places it in a standard case and order in a list.""" - working = key.split('+') - working = [i.lower() for i in working] - answer = [] - if "control" in working: - answer.append("control") - if "win" in working: - answer.append("win") - if "alt" in working: - answer.append("alt") - if "shift" in working: - answer.append("shift") - if working[-1] not in answer: - answer.append(working[-1]) - return answer + def standardize_key(self, key): + """Takes a keystroke and places it in a standard case and order in a list.""" + working = key.split('+') + working = [i.lower() for i in working] + answer = [] + if "control" in working: + answer.append("control") + if "win" in working: + answer.append("win") + if "alt" in working: + answer.append("alt") + if "shift" in working: + answer.append("shift") + if working[-1] not in answer: + answer.append(working[-1]) + return answer - def standardize_keymap(self, keymap): - """Given a keymap, returns the keymap standardized.""" - full = {} - for i in keymap: - answer = "" - new = self.standardize_key(keymap[i]) - for (c, j) in enumerate(new): - if c < len(new)-1: - answer = "%s%s+" % (answer, j) - else: - answer = "%s%s" % (answer, j) - full[i] = answer - return full + def standardize_keymap(self, keymap): + """Given a keymap, returns the keymap standardized.""" + full = {} + for i in keymap: + answer = "" + new = self.standardize_key(keymap[i]) + for (c, j) in enumerate(new): + if c < len(new)-1: + answer = "%s%s+" % (answer, j) + else: + answer = "%s%s" % (answer, j) + full[i] = answer + return full diff --git a/src/keyboard_handler/osx.py b/src/keyboard_handler/osx.py index 12884859..f63e85ad 100644 --- a/src/keyboard_handler/osx.py +++ b/src/keyboard_handler/osx.py @@ -12,45 +12,45 @@ kEventHotKeyReleasedSubtype = 9 class OSXKeyboardHandler(KeyboardHandler): - def __init__(self): - super(OSXKeyboardHandler, self).__init__() - self.replacement_keys = dict() - self.app = KeyboardCapturingNSApplication.alloc().init() - self._event_thread = Thread(target=AppHelper.runEventLoop) - self._event_thread.start() + def __init__(self): + super(OSXKeyboardHandler, self).__init__() + self.replacement_keys = dict() + self.app = KeyboardCapturingNSApplication.alloc().init() + self._event_thread = Thread(target=AppHelper.runEventLoop) + self._event_thread.start() - def register_key (self, key, function): - super(OSXKeyboardHandler, self).register_key(key, function) - k, m = self.parse_key(key) - key_id = RegisterEventHotKey(k, m, (0, 0), GetApplicationEventTarget(), 0) - self.key_ids[key] = key_id + def register_key (self, key, function): + super(OSXKeyboardHandler, self).register_key(key, function) + k, m = self.parse_key(key) + key_id = RegisterEventHotKey(k, m, (0, 0), GetApplicationEventTarget(), 0) + self.key_ids[key] = key_id - def unregister_key (self, key, function): - super(OSXKeyboardHandler, self).unregister_key(key, function) - key_id = self.key_ids[key] - raise NotImplementedError + def unregister_key (self, key, function): + super(OSXKeyboardHandler, self).unregister_key(key, function) + key_id = self.key_ids[key] + raise NotImplementedError - def parse_key (self, key): - key=key.split("+") - #replacements - #Modifier keys: - for index, item in enumerate(key[0:-1]): - if self.replacement_mods.has_key(item): - key[index] = self.replacement_mods[item] - if self.replacement_keys.has_key(key[-1]): - key[-1] = self.replacement_keys[key[-1]] - elif len(key[-1])==1: - key[-1] = ord(str(key[-1]))-36 - mods = 0 - for i in key[:-1]: - mods = mods|i - return [key[-1], mods] + def parse_key (self, key): + key=key.split("+") + #replacements + #Modifier keys: + for index, item in enumerate(key[0:-1]): + if self.replacement_mods.has_key(item): + key[index] = self.replacement_mods[item] + if self.replacement_keys.has_key(key[-1]): + key[-1] = self.replacement_keys[key[-1]] + elif len(key[-1])==1: + key[-1] = ord(str(key[-1]))-36 + mods = 0 + for i in key[:-1]: + mods = mods|i + return [key[-1], mods] class KeyboardCapturingNSApplication(NSApplication): - def sendEvent_(self, theEvent): - if theEvent.type() == NSSystemDefined and theEvent.subtype() == kEventHotKeyPressedSubtype: - self.activateIgnoringOtherApps_(True) - NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed', None, None, None) - super(NSApplication, self).sendEvent_(theEvent) + def sendEvent_(self, theEvent): + if theEvent.type() == NSSystemDefined and theEvent.subtype() == kEventHotKeyPressedSubtype: + self.activateIgnoringOtherApps_(True) + NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed', None, None, None) + super(NSApplication, self).sendEvent_(theEvent) diff --git a/src/keyboard_handler/windows.py b/src/keyboard_handler/windows.py index 4197400b..2411c38c 100644 --- a/src/keyboard_handler/windows.py +++ b/src/keyboard_handler/windows.py @@ -5,36 +5,36 @@ from main import KeyboardHandler class WindowsKeyboardHandler(KeyboardHandler): - def __init__ (self, *args, **kwargs): - super(WindowsKeyboardHandler, self).__init__(*args, **kwargs) - #Setup the replacement dictionaries. - for i in dir(win32con): - if i.startswith("VK_"): - key = i[3:].lower() - self.replacement_keys[key] = getattr(win32con, i) - elif i.startswith("MOD_"): - key = i[4:].lower() - self.replacement_mods[key] = getattr(win32con, i) - self.replacement_keys .update(dict(pageup=win32con.VK_PRIOR, pagedown=win32con.VK_NEXT)) + def __init__ (self, *args, **kwargs): + super(WindowsKeyboardHandler, self).__init__(*args, **kwargs) + #Setup the replacement dictionaries. + for i in dir(win32con): + if i.startswith("VK_"): + key = i[3:].lower() + self.replacement_keys[key] = getattr(win32con, i) + elif i.startswith("MOD_"): + key = i[4:].lower() + self.replacement_mods[key] = getattr(win32con, i) + self.replacement_keys .update(dict(pageup=win32con.VK_PRIOR, pagedown=win32con.VK_NEXT)) - def parse_key (self, keystroke, separator="+"): - keystroke = str(keystroke) #We don't want unicode - keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] - mods = 0 - for i in keystroke[:-1]: - mods = mods | i #or everything together - return (mods, keystroke[-1]) + def parse_key (self, keystroke, separator="+"): + keystroke = str(keystroke) #We don't want unicode + keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] + mods = 0 + for i in keystroke[:-1]: + mods = mods | i #or everything together + return (mods, keystroke[-1]) - def keycode_from_key(self, key): - if key in self.replacement_mods: - return self.replacement_mods[key] - if key in self.replacement_keys: - return self.replacement_keys[key] - if len(key) == 1: - return win32api.VkKeyScanEx(key, win32api.GetKeyboardLayout()) + def keycode_from_key(self, key): + if key in self.replacement_mods: + return self.replacement_mods[key] + if key in self.replacement_keys: + return self.replacement_keys[key] + if len(key) == 1: + return win32api.VkKeyScanEx(key, win32api.GetKeyboardLayout()) - def is_key_pressed(self, key): - """Returns if the given key was pressed. Requires an active message loop or will simply give if the key was pressed recently.""" - key = self.keycode_from_key(key) - return win32api.GetAsyncKeyState(key) + def is_key_pressed(self, key): + """Returns if the given key was pressed. Requires an active message loop or will simply give if the key was pressed recently.""" + key = self.keycode_from_key(key) + return win32api.GetAsyncKeyState(key) diff --git a/src/keyboard_handler/wx_handler.py b/src/keyboard_handler/wx_handler.py index 80609116..ff16db3d 100644 --- a/src/keyboard_handler/wx_handler.py +++ b/src/keyboard_handler/wx_handler.py @@ -10,121 +10,121 @@ from . import key_constants __all__ = ['WXKeyboardHandler', 'WXControlKeyboardHandler'] def call_after(func): - def wrapper(*args, **kwargs): - wx.CallAfter(func, *args, **kwargs) - functools.update_wrapper(wrapper, func) - return wrapper + def wrapper(*args, **kwargs): + wx.CallAfter(func, *args, **kwargs) + functools.update_wrapper(wrapper, func) + return wrapper class BaseWXKeyboardHandler(KeyboardHandler): - def __init__(self, *args, **kwargs): - super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs) - #Setup the replacement dictionaries. - for i in dir(wx): - if i.startswith('WXK_'): - key = i[4:].lower() - self.replacement_keys[key] = getattr(wx, i) - elif i.startswith('MOD_'): - key = i[4:].lower() - self.replacement_mods[key] = getattr(wx, i) + def __init__(self, *args, **kwargs): + super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs) + #Setup the replacement dictionaries. + for i in dir(wx): + if i.startswith('WXK_'): + key = i[4:].lower() + self.replacement_keys[key] = getattr(wx, i) + elif i.startswith('MOD_'): + key = i[4:].lower() + self.replacement_mods[key] = getattr(wx, i) - def parse_key (self, keystroke, separator="+"): - keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] - mods = 0 - for i in keystroke[:-1]: - mods = mods | i #or everything together - return (mods, keystroke[-1]) + def parse_key (self, keystroke, separator="+"): + keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] + mods = 0 + for i in keystroke[:-1]: + mods = mods | i #or everything together + return (mods, keystroke[-1]) + + def keycode_from_key(self, key): + result = None + if key in self.replacement_mods: + result = self.replacement_mods[key] + elif key in self.replacement_keys: + result = self.replacement_keys[key] + if result >= 277: + result -= 277 + elif len(key) == 1: + result = ord(key.upper()) + if result is None: + raise KeyboardHandlerError("Could not translate key %r into a valid keycode." % key) + return result - def keycode_from_key(self, key): - result = None - if key in self.replacement_mods: - result = self.replacement_mods[key] - elif key in self.replacement_keys: - result = self.replacement_keys[key] - if result >= 277: - result -= 277 - elif len(key) == 1: - result = ord(key.upper()) - if result is None: - raise KeyboardHandlerError("Could not translate key %r into a valid keycode." % key) - return result - class WXKeyboardHandler(BaseWXKeyboardHandler): - def __init__ (self, parent, *args, **kwargs): - super(WXKeyboardHandler, self).__init__(*args, **kwargs) - self.parent = parent - self.key_ids = {} - self.replacement_keys = key_constants.keys - self.replacement_mods = key_constants.modifiers + def __init__ (self, parent, *args, **kwargs): + super(WXKeyboardHandler, self).__init__(*args, **kwargs) + self.parent = parent + self.key_ids = {} + self.replacement_keys = key_constants.keys + self.replacement_mods = key_constants.modifiers - @call_after - def register_key(self, key, function): - super(WXKeyboardHandler, self).register_key(key, function) - key_id = wx.NewId() - parsed = self.parse_key(key) - res = self.parent.RegisterHotKey(key_id, *parsed) - if not res: - logger.warn("Failed to register hotkey: %s for function %r", key, function) - self.parent.Bind(wx.EVT_HOTKEY, lambda evt: self.process_key(evt, key_id), id=key_id) - self.key_ids[key] = key_id - return res + @call_after + def register_key(self, key, function): + super(WXKeyboardHandler, self).register_key(key, function) + key_id = wx.NewId() + parsed = self.parse_key(key) + res = self.parent.RegisterHotKey(key_id, *parsed) + if not res: + logger.warn("Failed to register hotkey: %s for function %r", key, function) + self.parent.Bind(wx.EVT_HOTKEY, lambda evt: self.process_key(evt, key_id), id=key_id) + self.key_ids[key] = key_id + return res - def parse_key (self, keystroke, separator="+"): - keystroke = str(keystroke) #We don't want unicode - keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] - mods = 0 - for i in keystroke[:-1]: - mods = mods | i #or everything together - return (mods, keystroke[-1]) + def parse_key (self, keystroke, separator="+"): + keystroke = str(keystroke) #We don't want unicode + keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)] + mods = 0 + for i in keystroke[:-1]: + mods = mods | i #or everything together + return (mods, keystroke[-1]) - @call_after - def unregister_key (self, key, function): - super(WXKeyboardHandler, self).unregister_key(key, function) - if key not in self.key_ids: - return #there's nothing we can do. - key_id = self.key_ids[key] - self.parent.UnregisterHotKey(key_id) - self.parent.Unbind( wx.EVT_HOTKEY, id=key_id) - self.key_ids.pop(key) + @call_after + def unregister_key (self, key, function): + super(WXKeyboardHandler, self).unregister_key(key, function) + if key not in self.key_ids: + return #there's nothing we can do. + key_id = self.key_ids[key] + self.parent.UnregisterHotKey(key_id) + self.parent.Unbind( wx.EVT_HOTKEY, id=key_id) + self.key_ids.pop(key) - def process_key (self, evt, id): - evt.Skip() - key_ids = self.key_ids.keys() - for i in key_ids: - if self.key_ids.get(i) == id: - self.handle_key(i) + def process_key (self, evt, id): + evt.Skip() + key_ids = self.key_ids.keys() + for i in key_ids: + if self.key_ids.get(i) == id: + self.handle_key(i) class WXControlKeyboardHandler(wx.StaticText, KeyboardHandler): - def __init__(self, parent=None, *a, **k): - wx.StaticText.__init__(self, parent=parent) - KeyboardHandler.__init__(self, *a, **k) - self.wx_replacements = {} - for i in [d for d in dir(wx) if d.startswith('WXK_')]: - self.wx_replacements[getattr(wx, i)] = i[4:].lower() - self.Bind(wx.EVT_KEY_DOWN, self.process_key, self) - self.SetFocus() + def __init__(self, parent=None, *a, **k): + wx.StaticText.__init__(self, parent=parent) + KeyboardHandler.__init__(self, *a, **k) + self.wx_replacements = {} + for i in [d for d in dir(wx) if d.startswith('WXK_')]: + self.wx_replacements[getattr(wx, i)] = i[4:].lower() + self.Bind(wx.EVT_KEY_DOWN, self.process_key, self) + self.SetFocus() - def process_key(self, evt): - keycode = evt.GetKeyCode() - keyname = self.wx_replacements.get(keycode, None) - modifiers = "" - replacements = ( (evt.ControlDown(), 'control+'), - (evt.AltDown(), 'alt+'), - (evt.ShiftDown(), 'shift+'), - (evt.MetaDown(), 'win+') - ) - for mod, ch in (replacements): - if mod: - modifiers += ch - if keyname is None: - if 27 < keycode < 256: - keyname = chr(keycode).lower() - else: - keyname = "(%s)unknown" % keycode - key = modifiers + keyname - self.handle_key(key) + def process_key(self, evt): + keycode = evt.GetKeyCode() + keyname = self.wx_replacements.get(keycode, None) + modifiers = "" + replacements = ( (evt.ControlDown(), 'control+'), + (evt.AltDown(), 'alt+'), + (evt.ShiftDown(), 'shift+'), + (evt.MetaDown(), 'win+') + ) + for mod, ch in (replacements): + if mod: + modifiers += ch + if keyname is None: + if 27 < keycode < 256: + keyname = chr(keycode).lower() + else: + keyname = "(%s)unknown" % keycode + key = modifiers + keyname + self.handle_key(key) diff --git a/src/keys/__init__.py b/src/keys/__init__.py index aa08bfc8..6c0a4990 100644 --- a/src/keys/__init__.py +++ b/src/keys/__init__.py @@ -14,9 +14,9 @@ import paths # lib = load_library("snapshot_api_keys64", x64_path=paths.app_path("keys/lib")) #else: if platform.architecture()[0][:2] == "32": - lib = load_library("stable_api_keys32", x86_path=os.path.join(paths.app_path(), "keys", "lib")) + lib = load_library("stable_api_keys32", x86_path=os.path.join(paths.app_path(), "keys", "lib")) else: - lib = load_library("stable_api_keys64", x64_path=os.path.join(paths.app_path(), "keys", "lib")) + lib = load_library("stable_api_keys64", x64_path=os.path.join(paths.app_path(), "keys", "lib")) # import linuxKeys # lib = linuxKeys @@ -24,20 +24,20 @@ else: keyring = None def setup(): - global keyring - if keyring == None: - keyring = Keyring() + global keyring + if keyring == None: + keyring = Keyring() class Keyring(object): - def __init__(self): - super(Keyring, self).__init__() + def __init__(self): + super(Keyring, self).__init__() - def _call_method(self, function): - result = getattr(lib, function) - result = c_char_p(result.__call__()) - return result.value + def _call_method(self, function): + result = getattr(lib, function) + result = c_char_p(result.__call__()) + return result.value - def get(self, func): - if hasattr(application,func+"_override"): - return getattr(application,func+'_override') - return getattr(self, "_call_method")("get_"+func) + def get(self, func): + if hasattr(application,func+"_override"): + return getattr(application,func+'_override') + return getattr(self, "_call_method")("get_"+func) diff --git a/src/keys/linuxKeys.py b/src/keys/linuxKeys.py index 0baef390..4b6bb8d4 100644 --- a/src/keys/linuxKeys.py +++ b/src/keys/linuxKeys.py @@ -1,9 +1,9 @@ from __future__ import unicode_literals def get_api_key(): - return "8pDLbyOW3saYnvSZ4uLFg\0" + return "8pDLbyOW3saYnvSZ4uLFg\0" def get_api_secret(): - return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0"; + return "YsgdrzY9B4yyYvYsyee78rKI3GshjHpenVS9LnFJXY\0"; #char *get_dropbox_api_key(){ #return "key\0"; diff --git a/src/keystrokeEditor/__init__.py b/src/keystrokeEditor/__init__.py index b8cf7680..10ba64c2 100644 --- a/src/keystrokeEditor/__init__.py +++ b/src/keystrokeEditor/__init__.py @@ -1,3 +1,3 @@ from __future__ import absolute_import from __future__ import unicode_literals -from .keystrokeEditor import KeystrokeEditor \ No newline at end of file +from .keystrokeEditor import KeystrokeEditor diff --git a/src/keystrokeEditor/constants.py b/src/keystrokeEditor/constants.py index 47cc0e97..b14616bc 100644 --- a/src/keystrokeEditor/constants.py +++ b/src/keystrokeEditor/constants.py @@ -1,60 +1,60 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals actions = { -"up": _(u"Go up in the current buffer"), -"down": _(u"Go down in the current buffer"), -"left": _(u"Go to the previous buffer"), -"right": _(u"Go to the next buffer"), -"next_account": _(u"Focus the next session"), -"previous_account": _(u"Focus the previous session"), -"show_hide": _(u"Show or hide the GUI"), -"post_tweet": _(u"New tweet"), -"post_reply": _(u"Reply"), -"post_retweet": _(u"Retweet"), -"send_dm": _(u"Send direct message"), -"add_to_favourites": _(u"Like a tweet"), -"toggle_like": _(u"Like/unlike a tweet"), -"remove_from_favourites": _(u"Unlike a tweet"), -"follow": _(u"Open the user actions dialogue"), -"user_details": _(u"See user details"), -"view_item": _(u"Show tweet"), -"exit": _(u"Quit"), -"open_timeline": _(u"Open user timeline"), -"remove_buffer": _(u"Destroy buffer"), -"interact": _(u"Interact with the currently focused tweet."), -"url": _(u"Open URL"), -"open_in_browser": _(u"View in Twitter"), -"volume_up": _(u"Increase volume by 5%"), -"volume_down": _(u"Decrease volume by 5%"), -"go_home": _(u"Jump to the first element of a buffer"), -"go_end": _(u"Jump to the last element of the current buffer"), -"go_page_up": _(u"Jump 20 elements up in the current buffer"), -"go_page_down": _(u"Jump 20 elements down in the current buffer"), -"update_profile": _(u"Edit profile"), -"delete": _(u"Delete a tweet or direct message"), -"clear_buffer": _(u"Empty the current buffer"), -"repeat_item": _(u"Repeat last item"), -"copy_to_clipboard": _(u"Copy to clipboard"), -"add_to_list": _(u"Add to list"), -"remove_from_list": _(u"Remove from list"), -"toggle_buffer_mute": _(u"Mute/unmute the active buffer"), -"toggle_session_mute": _(u"Mute/unmute the current session"), -"toggle_autoread": _(u"toggle the automatic reading of incoming tweets in the active buffer"), -"search": _(u"Search on twitter"), -"find": _(u"Find a string in the currently focused buffer"), -"edit_keystrokes": _(u"Show the keystroke editor"), -"view_user_lists": _(u"Show lists for a specified user"), -"get_more_items": _(u"load previous items"), -"reverse_geocode": _(u"Get geolocation"), -"view_reverse_geocode": _(u"Display the tweet's geolocation in a dialog"), -"get_trending_topics": _(u"Create a trending topics buffer"), -"open_conversation": _(u"View conversation"), -"check_for_updates": _(u"Check and download updates"), -"lists_manager": _(u"Opens the list manager, which allows you to create, edit, delete and open lists in buffers."), -"configuration": _(u"Opens the global settings dialogue"), -"list_manager": _(u"Opens the list manager"), -"accountConfiguration": _(u"Opens the account settings dialogue"), -"audio": _(u"Try to play an audio file"), -"update_buffer": _(u"Updates the buffer and retrieves possible lost items there."), -"ocr_image": _(u"Extracts the text from a picture and displays the result in a dialog."), -} \ No newline at end of file + "up": _(u"Go up in the current buffer"), + "down": _(u"Go down in the current buffer"), + "left": _(u"Go to the previous buffer"), + "right": _(u"Go to the next buffer"), + "next_account": _(u"Focus the next session"), + "previous_account": _(u"Focus the previous session"), + "show_hide": _(u"Show or hide the GUI"), + "post_tweet": _(u"New tweet"), + "post_reply": _(u"Reply"), + "post_retweet": _(u"Retweet"), + "send_dm": _(u"Send direct message"), + "add_to_favourites": _(u"Like a tweet"), + "toggle_like": _(u"Like/unlike a tweet"), + "remove_from_favourites": _(u"Unlike a tweet"), + "follow": _(u"Open the user actions dialogue"), + "user_details": _(u"See user details"), + "view_item": _(u"Show tweet"), + "exit": _(u"Quit"), + "open_timeline": _(u"Open user timeline"), + "remove_buffer": _(u"Destroy buffer"), + "interact": _(u"Interact with the currently focused tweet."), + "url": _(u"Open URL"), + "open_in_browser": _(u"View in Twitter"), + "volume_up": _(u"Increase volume by 5%"), + "volume_down": _(u"Decrease volume by 5%"), + "go_home": _(u"Jump to the first element of a buffer"), + "go_end": _(u"Jump to the last element of the current buffer"), + "go_page_up": _(u"Jump 20 elements up in the current buffer"), + "go_page_down": _(u"Jump 20 elements down in the current buffer"), + "update_profile": _(u"Edit profile"), + "delete": _(u"Delete a tweet or direct message"), + "clear_buffer": _(u"Empty the current buffer"), + "repeat_item": _(u"Repeat last item"), + "copy_to_clipboard": _(u"Copy to clipboard"), + "add_to_list": _(u"Add to list"), + "remove_from_list": _(u"Remove from list"), + "toggle_buffer_mute": _(u"Mute/unmute the active buffer"), + "toggle_session_mute": _(u"Mute/unmute the current session"), + "toggle_autoread": _(u"toggle the automatic reading of incoming tweets in the active buffer"), + "search": _(u"Search on twitter"), + "find": _(u"Find a string in the currently focused buffer"), + "edit_keystrokes": _(u"Show the keystroke editor"), + "view_user_lists": _(u"Show lists for a specified user"), + "get_more_items": _(u"load previous items"), + "reverse_geocode": _(u"Get geolocation"), + "view_reverse_geocode": _(u"Display the tweet's geolocation in a dialog"), + "get_trending_topics": _(u"Create a trending topics buffer"), + "open_conversation": _(u"View conversation"), + "check_for_updates": _(u"Check and download updates"), + "lists_manager": _(u"Opens the list manager, which allows you to create, edit, delete and open lists in buffers."), + "configuration": _(u"Opens the global settings dialogue"), + "list_manager": _(u"Opens the list manager"), + "accountConfiguration": _(u"Opens the account settings dialogue"), + "audio": _(u"Try to play an audio file"), + "update_buffer": _(u"Updates the buffer and retrieves possible lost items there."), + "ocr_image": _(u"Extracts the text from a picture and displays the result in a dialog."), +} diff --git a/src/keystrokeEditor/keystrokeEditor.py b/src/keystrokeEditor/keystrokeEditor.py index 215ed404..720e1b1b 100644 --- a/src/keystrokeEditor/keystrokeEditor.py +++ b/src/keystrokeEditor/keystrokeEditor.py @@ -9,53 +9,53 @@ from . import constants from pubsub import pub class KeystrokeEditor(object): - def __init__(self): - super(KeystrokeEditor, self).__init__() - self.changed = False # Change it if the keyboard shorcuts are reassigned. - self.dialog = wx_ui.keystrokeEditorDialog() - self.map = config.keymap["keymap"] - # we need to copy the keymap before modify it, for unregistering the old keystrokes if is needed. - self.hold_map = self.map.copy() - self.dialog.put_keystrokes(constants.actions, self.map) - widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_keystroke) - widgetUtils.connect_event(self.dialog.execute, widgetUtils.BUTTON_PRESSED, self.execute_action) - self.dialog.get_response() + def __init__(self): + super(KeystrokeEditor, self).__init__() + self.changed = False # Change it if the keyboard shorcuts are reassigned. + self.dialog = wx_ui.keystrokeEditorDialog() + self.map = config.keymap["keymap"] + # we need to copy the keymap before modify it, for unregistering the old keystrokes if is needed. + self.hold_map = self.map.copy() + self.dialog.put_keystrokes(constants.actions, self.map) + widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_keystroke) + widgetUtils.connect_event(self.dialog.execute, widgetUtils.BUTTON_PRESSED, self.execute_action) + self.dialog.get_response() - def edit_keystroke(self, *args, **kwargs): - action = self.dialog.actions[self.dialog.get_action()] - edit_dialog = wx_ui.editKeystrokeDialog() - self.set_keystroke(self.map[action], edit_dialog) - answer = edit_dialog.get_response() - if answer == widgetUtils.OK: - new_keystroke = self.get_edited_keystroke(edit_dialog) - if new_keystroke != self.map[action]: - self.changed = True - self.map[action] = new_keystroke - self.dialog.put_keystrokes(constants.actions, self.map) + def edit_keystroke(self, *args, **kwargs): + action = self.dialog.actions[self.dialog.get_action()] + edit_dialog = wx_ui.editKeystrokeDialog() + self.set_keystroke(self.map[action], edit_dialog) + answer = edit_dialog.get_response() + if answer == widgetUtils.OK: + new_keystroke = self.get_edited_keystroke(edit_dialog) + if new_keystroke != self.map[action]: + self.changed = True + self.map[action] = new_keystroke + self.dialog.put_keystrokes(constants.actions, self.map) - def set_keystroke(self, keystroke, dialog): - for i in keystroke.split("+"): - if hasattr(dialog, i): - dialog.set(i, True) - dialog.set("key", keystroke.split("+")[-1]) + def set_keystroke(self, keystroke, dialog): + for i in keystroke.split("+"): + if hasattr(dialog, i): + dialog.set(i, True) + dialog.set("key", keystroke.split("+")[-1]) - def get_edited_keystroke(self, dialog): - keys = [] - if dialog.get("control") == True: - keys.append("control") - if dialog.get("win") == True: - keys.append("win") - if dialog.get("alt") == True: - keys.append("alt") - if dialog.get("shift") == True: - keys.append("shift") - if dialog.get("key") != "": - keys.append(dialog.get("key")) - else: - wx_ui.no_key() - return - return "+".join(keys) + def get_edited_keystroke(self, dialog): + keys = [] + if dialog.get("control") == True: + keys.append("control") + if dialog.get("win") == True: + keys.append("win") + if dialog.get("alt") == True: + keys.append("alt") + if dialog.get("shift") == True: + keys.append("shift") + if dialog.get("key") != "": + keys.append(dialog.get("key")) + else: + wx_ui.no_key() + return + return "+".join(keys) - def execute_action(self, *args, **kwargs): - action = self.dialog.actions[self.dialog.get_action()] - pub.sendMessage("execute-action", action=action) \ No newline at end of file + def execute_action(self, *args, **kwargs): + action = self.dialog.actions[self.dialog.get_action()] + pub.sendMessage("execute-action", action=action) diff --git a/src/keystrokeEditor/wx_ui.py b/src/keystrokeEditor/wx_ui.py index 7fd7c5c0..51c03e69 100644 --- a/src/keystrokeEditor/wx_ui.py +++ b/src/keystrokeEditor/wx_ui.py @@ -5,78 +5,78 @@ from multiplatform_widgets import widgets from wxUI.dialogs import baseDialog class keystrokeEditorDialog(baseDialog.BaseWXDialog): - def __init__(self): - super(keystrokeEditorDialog, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor")) - panel = wx.Panel(self) - self.actions = [] - sizer = wx.BoxSizer(wx.VERTICAL) - keysText = wx.StaticText(panel, -1, _(u"Select a keystroke to edit")) - self.keys = widgets.list(self, _(u"Action"), _(u"Keystroke"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(400, 450)) - self.keys.list.SetFocus() - firstSizer = wx.BoxSizer(wx.HORIZONTAL) - firstSizer.Add(keysText, 0, wx.ALL, 5) - firstSizer.Add(self.keys.list, 0, wx.ALL, 5) - self.edit = wx.Button(panel, -1, _(u"Edit")) - self.edit.SetDefault() - self.execute = wx.Button(panel, -1, _(u"Execute action")) - close = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - secondSizer = wx.BoxSizer(wx.HORIZONTAL) - secondSizer.Add(self.edit, 0, wx.ALL, 5) - secondSizer.Add(self.execute, 0, wx.ALL, 5) - secondSizer.Add(close, 0, wx.ALL, 5) - sizer.Add(firstSizer, 0, wx.ALL, 5) - sizer.Add(secondSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(keystrokeEditorDialog, self).__init__(parent=None, id=-1, title=_(u"Keystroke editor")) + panel = wx.Panel(self) + self.actions = [] + sizer = wx.BoxSizer(wx.VERTICAL) + keysText = wx.StaticText(panel, -1, _(u"Select a keystroke to edit")) + self.keys = widgets.list(self, _(u"Action"), _(u"Keystroke"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(400, 450)) + self.keys.list.SetFocus() + firstSizer = wx.BoxSizer(wx.HORIZONTAL) + firstSizer.Add(keysText, 0, wx.ALL, 5) + firstSizer.Add(self.keys.list, 0, wx.ALL, 5) + self.edit = wx.Button(panel, -1, _(u"Edit")) + self.edit.SetDefault() + self.execute = wx.Button(panel, -1, _(u"Execute action")) + close = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + secondSizer = wx.BoxSizer(wx.HORIZONTAL) + secondSizer.Add(self.edit, 0, wx.ALL, 5) + secondSizer.Add(self.execute, 0, wx.ALL, 5) + secondSizer.Add(close, 0, wx.ALL, 5) + sizer.Add(firstSizer, 0, wx.ALL, 5) + sizer.Add(secondSizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def put_keystrokes(self, actions, keystrokes): - selection = self.keys.get_selected() - self.keys.clear() - for i in keystrokes: - if (i in actions) == False: - continue - action = actions[i] - self.actions.append(i) - keystroke = keystrokes[i] - self.keys.insert_item(False, *[action, keystroke]) - self.keys.select_item(selection) + def put_keystrokes(self, actions, keystrokes): + selection = self.keys.get_selected() + self.keys.clear() + for i in keystrokes: + if (i in actions) == False: + continue + action = actions[i] + self.actions.append(i) + keystroke = keystrokes[i] + self.keys.insert_item(False, *[action, keystroke]) + self.keys.select_item(selection) - def get_action(self): - return self.keys.get_selected() + def get_action(self): + return self.keys.get_selected() class editKeystrokeDialog(baseDialog.BaseWXDialog): - def __init__(self): - super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.control = wx.CheckBox(panel, -1, _(u"Control")) - self.alt = wx.CheckBox(panel, -1, _(u"Alt")) - self.shift = wx.CheckBox(panel, -1, _(u"Shift")) - self.win = wx.CheckBox(panel, -1, _(u"Windows")) - sizer1 = wx.BoxSizer(wx.HORIZONTAL) - sizer1.Add(self.control) - sizer1.Add(self.alt) - sizer1.Add(self.shift) - sizer1.Add(self.win) - charLabel = wx.StaticText(panel, -1, _(u"Key")) - self.key = wx.TextCtrl(panel, -1) - sizer2 = wx.BoxSizer(wx.HORIZONTAL) - sizer2.Add(charLabel) - sizer2.Add(self.key) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL) - sizer3 = wx.BoxSizer(wx.HORIZONTAL) - sizer3.Add(ok) - sizer3.Add(cancel) - sizer.Add(sizer1) - sizer.Add(sizer2) - sizer.Add(sizer3) - panel.SetSizerAndFit(sizer) + def __init__(self): + super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.control = wx.CheckBox(panel, -1, _(u"Control")) + self.alt = wx.CheckBox(panel, -1, _(u"Alt")) + self.shift = wx.CheckBox(panel, -1, _(u"Shift")) + self.win = wx.CheckBox(panel, -1, _(u"Windows")) + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + sizer1.Add(self.control) + sizer1.Add(self.alt) + sizer1.Add(self.shift) + sizer1.Add(self.win) + charLabel = wx.StaticText(panel, -1, _(u"Key")) + self.key = wx.TextCtrl(panel, -1) + sizer2 = wx.BoxSizer(wx.HORIZONTAL) + sizer2.Add(charLabel) + sizer2.Add(self.key) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL) + sizer3 = wx.BoxSizer(wx.HORIZONTAL) + sizer3.Add(ok) + sizer3.Add(cancel) + sizer.Add(sizer1) + sizer.Add(sizer2) + sizer.Add(sizer3) + panel.SetSizerAndFit(sizer) def no_win_message(): - return wx.MessageDialog(None, _(u"You need to use the Windows key"), _(u"Invalid keystroke"), wx.OK|wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"You need to use the Windows key"), _(u"Invalid keystroke"), wx.OK|wx.ICON_ERROR).ShowModal() def no_key(): - return wx.MessageDialog(None, _(u"You must provide a character for the keystroke"), _(u"Invalid keystroke"), wx.ICON_ERROR).ShowModal() \ No newline at end of file + return wx.MessageDialog(None, _(u"You must provide a character for the keystroke"), _(u"Invalid keystroke"), wx.ICON_ERROR).ShowModal() diff --git a/src/languageHandler.py b/src/languageHandler.py index d17aa61b..b0ea7fb5 100644 --- a/src/languageHandler.py +++ b/src/languageHandler.py @@ -12,7 +12,7 @@ import gettext import paths import platform import application - + #a few Windows locale constants LOCALE_SLANGUAGE=0x2 LOCALE_SLANGDISPLAYNAME=0x6f @@ -20,195 +20,195 @@ LOCALE_SLANGDISPLAYNAME=0x6f curLang="en" def localeNameToWindowsLCID(localeName): - """Retreave the Windows locale identifier (LCID) for the given locale name - @param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage - @type localeName: string - @returns: a Windows LCID - @rtype: integer - """ - #Windows Vista is able to convert locale names to LCIDs - func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None) - if func_LocaleNameToLCID is not None: - localeName=localeName.replace('_','-') - LCID=func_LocaleNameToLCID(str(localeName),0) - else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID - localeName=locale.normalize(localeName) - if '.' in localeName: - localeName=localeName.split('.')[0] - LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName] - if len(LCList)>0: - LCID=LCList[0] - else: - LCID=0 - return LCID + """Retreave the Windows locale identifier (LCID) for the given locale name + @param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage + @type localeName: string + @returns: a Windows LCID + @rtype: integer + """ + #Windows Vista is able to convert locale names to LCIDs + func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None) + if func_LocaleNameToLCID is not None: + localeName=localeName.replace('_','-') + LCID=func_LocaleNameToLCID(str(localeName),0) + else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID + localeName=locale.normalize(localeName) + if '.' in localeName: + localeName=localeName.split('.')[0] + LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName] + if len(LCList)>0: + LCID=LCList[0] + else: + LCID=0 + return LCID def getLanguageDescription(language): - """Finds out the description (localized full name) of a given local name""" - desc=None - if platform.system() == "Windows": - LCID=localeNameToWindowsLCID(language) - if LCID!=0: - buf=ctypes.create_unicode_buffer(1024) - if '_' not in language: - res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024) - else: - res=0 - if res==0: - res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024) - desc=buf.value - elif platform.system() == "Linux" or not desc: - desc={ - "am":pgettext("languageName","Amharic"), - "an":pgettext("languageName","Aragonese"), - "es":pgettext("languageName","Spanish"), - "pt":pgettext("languageName","Portuguese"), - "ru":pgettext("languageName","Russian"), - "it":pgettext("languageName","italian"), - "tr":pgettext("languageName","Turkey"), - "gl":pgettext("languageName","Galician"), - "ca":pgettext("languageName","Catala"), - "eu":pgettext("languageName","Vasque"), - "pl":pgettext("languageName","polish"), - "ar":pgettext("languageName","Arabic"), - "ne":pgettext("languageName","Nepali"), - "sr":pgettext("languageName","Serbian (Latin)"), - "ja":pgettext("languageName","Japanese"), - }.get(language,None) - return desc + """Finds out the description (localized full name) of a given local name""" + desc=None + if platform.system() == "Windows": + LCID=localeNameToWindowsLCID(language) + if LCID!=0: + buf=ctypes.create_unicode_buffer(1024) + if '_' not in language: + res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024) + else: + res=0 + if res==0: + res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024) + desc=buf.value + elif platform.system() == "Linux" or not desc: + desc={ + "am":pgettext("languageName","Amharic"), + "an":pgettext("languageName","Aragonese"), + "es":pgettext("languageName","Spanish"), + "pt":pgettext("languageName","Portuguese"), + "ru":pgettext("languageName","Russian"), + "it":pgettext("languageName","italian"), + "tr":pgettext("languageName","Turkey"), + "gl":pgettext("languageName","Galician"), + "ca":pgettext("languageName","Catala"), + "eu":pgettext("languageName","Vasque"), + "pl":pgettext("languageName","polish"), + "ar":pgettext("languageName","Arabic"), + "ne":pgettext("languageName","Nepali"), + "sr":pgettext("languageName","Serbian (Latin)"), + "ja":pgettext("languageName","Japanese"), + }.get(language,None) + return desc def getAvailableLanguages(): - """generates a list of locale names, plus their full localized language and country names. - @rtype: list of tuples - """ - #Make a list of all the locales found in NVDA's locale dir - l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')] - l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))] - #Make sure that en (english) is in the list as it may not have any locale files, but is default - if 'en' not in l: - l.append('en') - l.sort() - #For each locale, ask Windows for its human readable display name - d=[] - for i in l: - desc=getLanguageDescription(i) - label="%s, %s"%(desc,i) if desc else i - d.append(label) - #include a 'user default, windows' language, which just represents the default language for this user account - l.append("system") - # Translators: the label for the Windows default NVDA interface language. - d.append(_("User default")) - #return a zipped up version of both the lists (a list with tuples of locale,label) - return list(zip(l,d)) + """generates a list of locale names, plus their full localized language and country names. + @rtype: list of tuples + """ + #Make a list of all the locales found in NVDA's locale dir + l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')] + l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))] + #Make sure that en (english) is in the list as it may not have any locale files, but is default + if 'en' not in l: + l.append('en') + l.sort() + #For each locale, ask Windows for its human readable display name + d=[] + for i in l: + desc=getLanguageDescription(i) + label="%s, %s"%(desc,i) if desc else i + d.append(label) + #include a 'user default, windows' language, which just represents the default language for this user account + l.append("system") + # Translators: the label for the Windows default NVDA interface language. + d.append(_("User default")) + #return a zipped up version of both the lists (a list with tuples of locale,label) + return list(zip(l,d)) def makePgettext(translations): - """Obtaina pgettext function for use with a gettext translations instance. - pgettext is used to support message contexts, - but Python 2.7's gettext module doesn't support this, - so NVDA must provide its own implementation. - """ - if isinstance(translations, gettext.GNUTranslations): - def pgettext(context, message): - message = str(message) - try: - # Look up the message with its context. - return translations._catalog["%s\x04%s" % (context, message)] - except KeyError: - return message - else: - def pgettext(context, message): - return str(message) - return pgettext + """Obtaina pgettext function for use with a gettext translations instance. + pgettext is used to support message contexts, + but Python 2.7's gettext module doesn't support this, + so NVDA must provide its own implementation. + """ + if isinstance(translations, gettext.GNUTranslations): + def pgettext(context, message): + message = str(message) + try: + # Look up the message with its context. + return translations._catalog["%s\x04%s" % (context, message)] + except KeyError: + return message + else: + def pgettext(context, message): + return str(message) + return pgettext def setLanguage(lang): - system = platform.system() - global curLang - try: - if lang=="system": - if system == "Windows": - windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage() - localeName=locale.windows_locale[windowsLCID] - elif system == "Darwin": - import Foundation - localeName = Foundation.NSLocale.currentLocale().identifier() - elif system == "Linux": - localeName = locale.getdefaultlocale()[0] - trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName]) - curLang=localeName + system = platform.system() + global curLang + try: + if lang=="system": + if system == "Windows": + windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage() + localeName=locale.windows_locale[windowsLCID] + elif system == "Darwin": + import Foundation + localeName = Foundation.NSLocale.currentLocale().identifier() + elif system == "Linux": + localeName = locale.getdefaultlocale()[0] + trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName]) + curLang=localeName # else: # localeName=locale.getdefaultlocale()[0] # trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName]) # curLang=localeName - else: - trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang]) - curLang=lang - localeChanged=False - #Try setting Python's locale to lang + else: + trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang]) + curLang=lang + localeChanged=False + #Try setting Python's locale to lang # try: - if system == "Windows": - locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang)) - localeChanged=True - else: - locale.setlocale(locale.LC_ALL, lang) - localeChanged=True + if system == "Windows": + locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang)) + localeChanged=True + else: + locale.setlocale(locale.LC_ALL, lang) + localeChanged=True # except: # pass - if not localeChanged and '_' in lang: - #Python couldn'tsupport the language_country locale, just try language. - try: - locale.setlocale(locale.LC_ALL, lang.split('_')[0]) - except: - pass - #Set the windows locale for this thread (NVDA core) to this locale. - if system == "Windows": - LCID=localeNameToWindowsLCID(lang) - ctypes.windll.kernel32.SetThreadLocale(LCID) - except IOError: - trans=gettext.translation(application.short_name, fallback=True) - curLang="en" - if sys.version[0] == "3": - trans.install() - else: - trans.install(unicode=True) - # Install our pgettext function. + if not localeChanged and '_' in lang: + #Python couldn'tsupport the language_country locale, just try language. + try: + locale.setlocale(locale.LC_ALL, lang.split('_')[0]) + except: + pass + #Set the windows locale for this thread (NVDA core) to this locale. + if system == "Windows": + LCID=localeNameToWindowsLCID(lang) + ctypes.windll.kernel32.SetThreadLocale(LCID) + except IOError: + trans=gettext.translation(application.short_name, fallback=True) + curLang="en" + if sys.version[0] == "3": + trans.install() + else: + trans.install(unicode=True) + # Install our pgettext function. # __builtin__.__dict__["pgettext"] = makePgettext(trans) def getLanguage(): - return curLang + return curLang def normalizeLanguage(lang): - """ - Normalizes a language-dialect string in to a standard form we can deal with. - Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase. - """ - lang=lang.replace('-','_') - ld=lang.split('_') - ld[0]=ld[0].lower() - #Filter out meta languages such as x-western - if ld[0]=='x': - return None - if len(ld)>=2: - ld[1]=ld[1].upper() - return "_".join(ld) + """ + Normalizes a language-dialect string in to a standard form we can deal with. + Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase. + """ + lang=lang.replace('-','_') + ld=lang.split('_') + ld[0]=ld[0].lower() + #Filter out meta languages such as x-western + if ld[0]=='x': + return None + if len(ld)>=2: + ld[1]=ld[1].upper() + return "_".join(ld) def langToWindowsLocale(lang): - languages = {"en": "eng", - "ar": "ara", - "ca": "cat", -"de": "deu", - "es": "esp", - "fi": "fin", - "fr": "fre_FRA", - "gl": "glc", - "eu": "euq", - "hu": "hun", - "hr": "hrv", - "it": "ita", - "ja": "jpn", - "pl": "plk", - "pt": "ptb", - "ru": "rus", - "tr": "trk", - "sr": "eng", - } - return languages[lang] + languages = {"en": "eng", + "ar": "ara", + "ca": "cat", + "de": "deu", + "es": "esp", + "fi": "fin", + "fr": "fre_FRA", + "gl": "glc", + "eu": "euq", + "hu": "hun", + "hr": "hrv", + "it": "ita", + "ja": "jpn", + "pl": "plk", + "pt": "ptb", + "ru": "rus", + "tr": "trk", + "sr": "eng", + } + return languages[lang] diff --git a/src/logger.py b/src/logger.py index 89895b34..0e8293aa 100644 --- a/src/logger.py +++ b/src/logger.py @@ -37,9 +37,9 @@ error_handler.setLevel(logging.ERROR) logger.addHandler(error_handler) def handle_exception(exc_type, exc_value, exc_traceback): - if issubclass(exc_type, KeyboardInterrupt): - sys.__excepthook__(exc_type, exc_value, exc_traceback) - return - logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) + if issubclass(exc_type, KeyboardInterrupt): + sys.__excepthook__(exc_type, exc_value, exc_traceback) + return + logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) sys.excepthook = handle_exception diff --git a/src/main.py b/src/main.py index 0bb3c802..147155c9 100644 --- a/src/main.py +++ b/src/main.py @@ -7,19 +7,19 @@ from win32com.client import GetObject system = platform.system() if system == "Windows": - import sys - import os - #redirect the original stdout and stderr - stdout=sys.stdout - stderr=sys.stderr - sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w") - sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w") + import sys + import os + #redirect the original stdout and stderr + stdout=sys.stdout + stderr=sys.stderr + sys.stdout = open(os.path.join(os.getenv("temp"), "stdout.log"), "w") + sys.stderr = open(os.path.join(os.getenv("temp"), "stderr.log"), "w") import languageHandler import paths #check if TWBlue is installed (Windows only) # ToDo: Remove this soon as this is done already when importing the paths module. if os.path.exists(os.path.join(paths.app_path(), "Uninstall.exe")): - paths.mode="installed" + paths.mode="installed" import commandline import config import output @@ -32,114 +32,114 @@ import widgetUtils import webbrowser from wxUI import commonMessageDialogs if system == "Windows": - from logger import logger - from update import updater - stdout_temp=sys.stdout - stderr_temp=sys.stderr + from logger import logger + from update import updater + stdout_temp=sys.stdout + stderr_temp=sys.stderr #if it's a binary version - if hasattr(sys, 'frozen'): - sys.stderr = open(os.path.join(paths.logs_path(), "stderr.log"), 'w') - sys.stdout = open(os.path.join(paths.logs_path(), "stdout.log"), 'w') - else: - sys.stdout=stdout - sys.stderr=stderr - # We are running from source, let's prepare vlc module for that situation - if system=="Windows": - arch="x86" - if platform.architecture()[0][:2] == "64": - arch="x64" - os.environ['PYTHON_VLC_MODULE_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch)) - os.environ['PYTHON_VLC_LIB_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch, "libvlc.dll")) - #the final log files have been opened succesfully, let's close the temporary files - stdout_temp.close() - stderr_temp.close() - #finally, remove the temporary files. TW Blue doesn't need them anymore, and we will get more free space on the harddrive - os.remove(stdout_temp.name) - os.remove(stderr_temp.name) + if hasattr(sys, 'frozen'): + sys.stderr = open(os.path.join(paths.logs_path(), "stderr.log"), 'w') + sys.stdout = open(os.path.join(paths.logs_path(), "stdout.log"), 'w') + else: + sys.stdout=stdout + sys.stderr=stderr + # We are running from source, let's prepare vlc module for that situation + if system=="Windows": + arch="x86" + if platform.architecture()[0][:2] == "64": + arch="x64" + os.environ['PYTHON_VLC_MODULE_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch)) + os.environ['PYTHON_VLC_LIB_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", arch, "libvlc.dll")) + #the final log files have been opened succesfully, let's close the temporary files + stdout_temp.close() + stderr_temp.close() + #finally, remove the temporary files. TW Blue doesn't need them anymore, and we will get more free space on the harddrive + os.remove(stdout_temp.name) + os.remove(stderr_temp.name) import sound if system == "Linux": - from gi.repository import Gdk, GObject, GLib + from gi.repository import Gdk, GObject, GLib log = logging.getLogger("main") def setup(): - log.debug("Starting " + application.name + " %s" % (application.version,)) - config.setup() - proxy_setup() - log.debug("Using %s %s" % (platform.system(), platform.architecture()[0])) - log.debug("Application path is %s" % (paths.app_path(),)) - log.debug("config path is %s" % (paths.config_path(),)) - sound.setup() - languageHandler.setLanguage(config.app["app-settings"]["language"]) - fixes.setup() - output.setup() - keys.setup() - from controller import settings - from controller import mainController - from sessionmanager import sessionManager - app = widgetUtils.mainLoopObject() - check_pid() - if system == "Windows": - if config.app["app-settings"]["donation_dialog_displayed"] == False: - donation() - if config.app['app-settings']['check_for_updates']: - updater.do_update() - sm = sessionManager.sessionManagerController() - sm.fill_list() - if len(sm.sessions) == 0: sm.show() - else: - sm.do_ok() - if hasattr(sm.view, "destroy"): - sm.view.destroy() - del sm - r = mainController.Controller() - r.view.show() - r.do_work() - r.check_invisible_at_startup() - if system == "Windows": - call_threaded(r.start) - elif system == "Linux": - GLib.idle_add(r.start) - app.run() + log.debug("Starting " + application.name + " %s" % (application.version,)) + config.setup() + proxy_setup() + log.debug("Using %s %s" % (platform.system(), platform.architecture()[0])) + log.debug("Application path is %s" % (paths.app_path(),)) + log.debug("config path is %s" % (paths.config_path(),)) + sound.setup() + languageHandler.setLanguage(config.app["app-settings"]["language"]) + fixes.setup() + output.setup() + keys.setup() + from controller import settings + from controller import mainController + from sessionmanager import sessionManager + app = widgetUtils.mainLoopObject() + check_pid() + if system == "Windows": + if config.app["app-settings"]["donation_dialog_displayed"] == False: + donation() + if config.app['app-settings']['check_for_updates']: + updater.do_update() + sm = sessionManager.sessionManagerController() + sm.fill_list() + if len(sm.sessions) == 0: sm.show() + else: + sm.do_ok() + if hasattr(sm.view, "destroy"): + sm.view.destroy() + del sm + r = mainController.Controller() + r.view.show() + r.do_work() + r.check_invisible_at_startup() + if system == "Windows": + call_threaded(r.start) + elif system == "Linux": + GLib.idle_add(r.start) + app.run() def proxy_setup(): - if config.app["proxy"]["server"] != "" and config.app["proxy"]["type"] > 0: - log.debug("Loading proxy settings") - proxy_url = config.app["proxy"]["server"] + ":" + str(config.app["proxy"]["port"]) - if config.app["proxy"]["user"] != "" and config.app["proxy"]["password"] != "": - proxy_url = config.app["proxy"]["user"] + ":" + config.app["proxy"]["password"] + "@" + proxy_url - elif config.app["proxy"]["user"] != "" and config.proxyTypes[config.app["proxy"]["type"]] in ["socks4", "socks4a"]: - proxy_url = config.app["proxy"]["user"] + "@" + proxy_url - proxy_url = config.proxyTypes[config.app["proxy"]["type"]] + "://" + proxy_url - os.environ["HTTP_PROXY"] = proxy_url - os.environ["HTTPS_PROXY"] = proxy_url + if config.app["proxy"]["server"] != "" and config.app["proxy"]["type"] > 0: + log.debug("Loading proxy settings") + proxy_url = config.app["proxy"]["server"] + ":" + str(config.app["proxy"]["port"]) + if config.app["proxy"]["user"] != "" and config.app["proxy"]["password"] != "": + proxy_url = config.app["proxy"]["user"] + ":" + config.app["proxy"]["password"] + "@" + proxy_url + elif config.app["proxy"]["user"] != "" and config.proxyTypes[config.app["proxy"]["type"]] in ["socks4", "socks4a"]: + proxy_url = config.app["proxy"]["user"] + "@" + proxy_url + proxy_url = config.proxyTypes[config.app["proxy"]["type"]] + "://" + proxy_url + os.environ["HTTP_PROXY"] = proxy_url + os.environ["HTTPS_PROXY"] = proxy_url def donation(): - dlg = commonMessageDialogs.donation() - if dlg == widgetUtils.YES: - webbrowser.open_new_tab(_("https://twblue.es/donate")) - config.app["app-settings"]["donation_dialog_displayed"] = True + dlg = commonMessageDialogs.donation() + if dlg == widgetUtils.YES: + webbrowser.open_new_tab(_("https://twblue.es/donate")) + config.app["app-settings"]["donation_dialog_displayed"] = True def is_running(pid): - "Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589" - WMI = GetObject('winmgmts:') - processes = WMI.InstancesOf('Win32_Process') - return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid] + "Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589" + WMI = GetObject('winmgmts:') + processes = WMI.InstancesOf('Win32_Process') + return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid] def check_pid(): - "Insures that only one copy of the application is running at a time." - pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) - if os.path.exists(pidpath): - with open(pidpath) as fin: - pid = int(fin.read()) - if is_running(pid): - # Display warning dialog - commonMessageDialogs.common_error(_(u"{0} is already running. Close the other instance before starting this one. If you're sure that {0} isn't running, try deleting the file at {1}. If you're unsure of how to do this, contact the {0} developers.").format(application.name, pidpath)) - sys.exit(1) - else: - commonMessageDialogs.dead_pid() - # Write the new PID - with open(pidpath,"w") as cam: - cam.write(str(os.getpid())) + "Insures that only one copy of the application is running at a time." + pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) + if os.path.exists(pidpath): + with open(pidpath) as fin: + pid = int(fin.read()) + if is_running(pid): + # Display warning dialog + commonMessageDialogs.common_error(_(u"{0} is already running. Close the other instance before starting this one. If you're sure that {0} isn't running, try deleting the file at {1}. If you're unsure of how to do this, contact the {0} developers.").format(application.name, pidpath)) + sys.exit(1) + else: + commonMessageDialogs.dead_pid() + # Write the new PID + with open(pidpath,"w") as cam: + cam.write(str(os.getpid())) setup() diff --git a/src/multiplatform_widgets/__init__.py b/src/multiplatform_widgets/__init__.py index fe9bf3f2..f50f564e 100644 --- a/src/multiplatform_widgets/__init__.py +++ b/src/multiplatform_widgets/__init__.py @@ -1,3 +1,3 @@ from __future__ import absolute_import from __future__ import unicode_literals -from . import widgets \ No newline at end of file +from . import widgets diff --git a/src/multiplatform_widgets/widgets.py b/src/multiplatform_widgets/widgets.py index 5693c245..1a15e4ca 100644 --- a/src/multiplatform_widgets/widgets.py +++ b/src/multiplatform_widgets/widgets.py @@ -8,85 +8,85 @@ import logging log = logging.getLogger("multiplatform_widgets.widgets") class list(object): - def __init__(self, parent, *columns, **listArguments): - self.system = platform.system() - self.columns = columns - self.listArguments = listArguments - log.debug("Creating list: Columns: %s, arguments: %s" % (self.columns, self.listArguments)) - self.create_list(parent) + def __init__(self, parent, *columns, **listArguments): + self.system = platform.system() + self.columns = columns + self.listArguments = listArguments + log.debug("Creating list: Columns: %s, arguments: %s" % (self.columns, self.listArguments)) + self.create_list(parent) # self.set_size() - def set_windows_size(self, column, characters_max): -# it = wx.ListItem() -# dc = wx.WindowDC(self.list) -# dc.SetFont(it.GetFont()) -# (x, y) = dc.GetTextExtent("r"*characters_max) - self.list.SetColumnWidth(column, characters_max*2) + def set_windows_size(self, column, characters_max): + # it = wx.ListItem() + # dc = wx.WindowDC(self.list) + # dc.SetFont(it.GetFont()) + # (x, y) = dc.GetTextExtent("r"*characters_max) + self.list.SetColumnWidth(column, characters_max*2) - def set_size(self): - self.list.SetSize((self.list.GetBestSize()[0], 728)) + def set_size(self): + self.list.SetSize((self.list.GetBestSize()[0], 728)) # self.list.SetSize((1439, 1000)) - def create_list(self, parent): - if self.system == "Windows": - self.list = wx.ListCtrl(parent, -1, **self.listArguments) - for i in range(0, len(self.columns)): - self.list.InsertColumn(i, u"%s" % (self.columns[i])) - else: - self.list = wx.ListBox(parent, -1, choices=[]) + def create_list(self, parent): + if self.system == "Windows": + self.list = wx.ListCtrl(parent, -1, **self.listArguments) + for i in range(0, len(self.columns)): + self.list.InsertColumn(i, u"%s" % (self.columns[i])) + else: + self.list = wx.ListBox(parent, -1, choices=[]) - def insert_item(self, reversed, *item): - """ Inserts an item on the list, depending on the OS.""" - if self.system == "Windows": - if reversed == False: items = self.list.GetItemCount() - else: items = 0 - self.list.InsertItem(items, item[0]) - for i in range(1, len(self.columns)): - self.list.SetItem(items, i, item[i]) - else: - self.list.Append(" ".join(item)) + def insert_item(self, reversed, *item): + """ Inserts an item on the list, depending on the OS.""" + if self.system == "Windows": + if reversed == False: items = self.list.GetItemCount() + else: items = 0 + self.list.InsertItem(items, item[0]) + for i in range(1, len(self.columns)): + self.list.SetItem(items, i, item[i]) + else: + self.list.Append(" ".join(item)) - def remove_item(self, pos): - """ Deletes an item from the list.""" - if self.system == "Windows": - if pos > 0: self.list.Focus(pos-1) - self.list.DeleteItem(pos) - else: - if pos > 0: self.list.SetSelection(pos-1) - self.list.Delete(pos) + def remove_item(self, pos): + """ Deletes an item from the list.""" + if self.system == "Windows": + if pos > 0: self.list.Focus(pos-1) + self.list.DeleteItem(pos) + else: + if pos > 0: self.list.SetSelection(pos-1) + self.list.Delete(pos) - def clear(self): - if self.system == "Windows": - self.list.DeleteAllItems() - else: - self.list.Clear() + def clear(self): + if self.system == "Windows": + self.list.DeleteAllItems() + else: + self.list.Clear() - def get_selected(self): - if self.system == "Windows": - return self.list.GetFocusedItem() - else: - return self.list.GetSelection() + def get_selected(self): + if self.system == "Windows": + return self.list.GetFocusedItem() + else: + return self.list.GetSelection() - def select_item(self, pos): - if self.system == "Windows": - self.list.Focus(pos) - else: - self.list.SetSelection(pos) + def select_item(self, pos): + if self.system == "Windows": + self.list.Focus(pos) + else: + self.list.SetSelection(pos) - def get_count(self): - if self.system == "Windows": - selected = self.list.GetItemCount() - else: - selected = self.list.GetCount() - if selected == -1: - return 0 - else: - return selected + def get_count(self): + if self.system == "Windows": + selected = self.list.GetItemCount() + else: + selected = self.list.GetCount() + if selected == -1: + return 0 + else: + return selected - def get_text_column(self, indexId, column): - item = self.list.GetItem(indexId, column) - return item.GetText() + def get_text_column(self, indexId, column): + item = self.list.GetItem(indexId, column) + return item.GetText() - def set_text_column(self, indexId, column, text): - item = self.list.SetStringItem(indexId, column, text) - return item \ No newline at end of file + def set_text_column(self, indexId, column, text): + item = self.list.SetStringItem(indexId, column, text) + return item diff --git a/src/mysc/autostart.py b/src/mysc/autostart.py index 01a555f2..845bd0b8 100644 --- a/src/mysc/autostart.py +++ b/src/mysc/autostart.py @@ -10,35 +10,35 @@ from platform_utils import paths RUN_REGKEY = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" def is_installed(app_subkey): - """Checks if the currently running copy is installed or portable variant. Requires the name of the application subkey found under the uninstall section in Windows registry.""" + """Checks if the currently running copy is installed or portable variant. Requires the name of the application subkey found under the uninstall section in Windows registry.""" - try: - key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" % app_subkey) - inst_dir = winreg.QueryValueEx(key,"InstallLocation")[0] - except WindowsError: - return False - winreg.CloseKey(key) - try: - return os.stat(inst_dir) == os.stat(paths.app_path()) - except WindowsError: - return False + try: + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s" % app_subkey) + inst_dir = winreg.QueryValueEx(key,"InstallLocation")[0] + except WindowsError: + return False + winreg.CloseKey(key) + try: + return os.stat(inst_dir) == os.stat(paths.app_path()) + except WindowsError: + return False def getAutoStart(app_name): - """Queries if the automatic startup should be set for the application or not, depending on it's current state.""" + """Queries if the automatic startup should be set for the application or not, depending on it's current state.""" - try: - key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY) - val = winreg.QueryValueEx(key, str(app_name))[0] - return os.stat(val) == os.stat(sys.argv[0]) - except (WindowsError, OSError): - return False + try: + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY) + val = winreg.QueryValueEx(key, str(app_name))[0] + return os.stat(val) == os.stat(sys.argv[0]) + except (WindowsError, OSError): + return False def setAutoStart(app_name, enable=True): - """Configures automatic startup for the application, if the enable argument is set to True. If set to False, deletes the application AutoStart value.""" - if getAutoStart(app_name) == enable: - return - key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY, 0, winreg.KEY_WRITE) - if enable: - winreg.SetValueEx(key, str(app_name), None, winreg.REG_SZ, paths.get_executable()) - else: - winreg.DeleteValue(key, str(app_name)) + """Configures automatic startup for the application, if the enable argument is set to True. If set to False, deletes the application AutoStart value.""" + if getAutoStart(app_name) == enable: + return + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, RUN_REGKEY, 0, winreg.KEY_WRITE) + if enable: + winreg.SetValueEx(key, str(app_name), None, winreg.REG_SZ, paths.get_executable()) + else: + winreg.DeleteValue(key, str(app_name)) diff --git a/src/mysc/localization.py b/src/mysc/localization.py index 01a7357d..b6e360cc 100644 --- a/src/mysc/localization.py +++ b/src/mysc/localization.py @@ -5,14 +5,14 @@ import logging log = logging.getLogger("mysc.localization") def get(rootFolder): - log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,)) - defaultLocale = languageHandler.curLang - if len(defaultLocale) > 2: - defaultLocale = defaultLocale[:2] - log.debug("Locale: %s" % (defaultLocale,)) - if os.path.exists(rootFolder+"/"+defaultLocale): - return defaultLocale - else: - log.debug("The folder does not exist, using the English folder...") - return "en" + log.debug("Getting documentation folder. RootFolder: %s" % (rootFolder,)) + defaultLocale = languageHandler.curLang + if len(defaultLocale) > 2: + defaultLocale = defaultLocale[:2] + log.debug("Locale: %s" % (defaultLocale,)) + if os.path.exists(rootFolder+"/"+defaultLocale): + return defaultLocale + else: + log.debug("The folder does not exist, using the English folder...") + return "en" diff --git a/src/mysc/repeating_timer.py b/src/mysc/repeating_timer.py index 41b4a5c5..fcc3c021 100644 --- a/src/mysc/repeating_timer.py +++ b/src/mysc/repeating_timer.py @@ -4,34 +4,34 @@ import logging log = logging.getLogger("mysc.repeating_timer") class RepeatingTimer(threading.Thread): - """Call a function after a specified number of seconds, it will then repeat again after the specified number of seconds - Note: If the function provided takes time to execute, this time is NOT taken from the next wait period + """Call a function after a specified number of seconds, it will then repeat again after the specified number of seconds + Note: If the function provided takes time to execute, this time is NOT taken from the next wait period - t = RepeatingTimer(30.0, f, args=[], kwargs={}) - t.start() - t.cancel() # stop the timer's actions - """ + t = RepeatingTimer(30.0, f, args=[], kwargs={}) + t.start() + t.cancel() # stop the timer's actions + """ - def __init__(self, interval, function, daemon=True, *args, **kwargs): - threading.Thread.__init__(self) - self.daemon = daemon - self.interval = float(interval) - self.function = function - self.args = args - self.kwargs = kwargs - self.finished = threading.Event() + def __init__(self, interval, function, daemon=True, *args, **kwargs): + threading.Thread.__init__(self) + self.daemon = daemon + self.interval = float(interval) + self.function = function + self.args = args + self.kwargs = kwargs + self.finished = threading.Event() - def cancel(self): - """Stop the timer if it hasn't finished yet""" - log.debug("Stopping repeater for %s" % (self.function,)) - self.finished.set() - stop = cancel + def cancel(self): + """Stop the timer if it hasn't finished yet""" + log.debug("Stopping repeater for %s" % (self.function,)) + self.finished.set() + stop = cancel - def run(self): - while not self.finished.is_set(): - self.finished.wait(self.interval) - if not self.finished.is_set(): #In case someone has canceled while waiting - try: - self.function(*self.args, **self.kwargs) - except: - log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs)) + def run(self): + while not self.finished.is_set(): + self.finished.wait(self.interval) + if not self.finished.is_set(): #In case someone has canceled while waiting + try: + self.function(*self.args, **self.kwargs) + except: + log.exception("Execution failed. Function: %r args: %r and kwargs: %r" % (self.function, self.args, self.kwargs)) diff --git a/src/mysc/restart.py b/src/mysc/restart.py index cd1a0926..3ea9d14a 100644 --- a/src/mysc/restart.py +++ b/src/mysc/restart.py @@ -4,13 +4,13 @@ import sys, os import application def restart_program(): - """ Function that restarts the application if is executed.""" - args = sys.argv[:] - if not hasattr(sys, "frozen"): - args.insert(0, sys.executable) - if sys.platform == 'win32': - args = ['"%s"' % arg for arg in args] - pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) - if os.path.exists(pidpath): - os.remove(pidpath) - os.execv(sys.executable, args) \ No newline at end of file + """ Function that restarts the application if is executed.""" + args = sys.argv[:] + if not hasattr(sys, "frozen"): + args.insert(0, sys.executable) + if sys.platform == 'win32': + args = ['"%s"' % arg for arg in args] + pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) + if os.path.exists(pidpath): + os.remove(pidpath) + os.execv(sys.executable, args) diff --git a/src/mysc/thread_utils.py b/src/mysc/thread_utils.py index 05cd8564..39cdaa09 100644 --- a/src/mysc/thread_utils.py +++ b/src/mysc/thread_utils.py @@ -6,14 +6,14 @@ import wx from pubsub import pub def call_threaded(func, *args, **kwargs): - #Call the given function in a daemonized thread and return the thread. - def new_func(*a, **k): - try: - func(*a, **k) - except: - log.exception("Thread %d with function %r, args of %r, and kwargs of %r failed to run." % (threading.current_thread().ident, func, a, k)) + #Call the given function in a daemonized thread and return the thread. + def new_func(*a, **k): + try: + func(*a, **k) + except: + log.exception("Thread %d with function %r, args of %r, and kwargs of %r failed to run." % (threading.current_thread().ident, func, a, k)) # pass - thread = threading.Thread(target=new_func, args=args, kwargs=kwargs) - thread.daemon = True - thread.start() - return thread \ No newline at end of file + thread = threading.Thread(target=new_func, args=args, kwargs=kwargs) + thread.daemon = True + thread.start() + return thread diff --git a/src/notifier/__init__.py b/src/notifier/__init__.py index 6283342c..381ca60a 100644 --- a/src/notifier/__init__.py +++ b/src/notifier/__init__.py @@ -8,16 +8,16 @@ import platform notify = None def setup(): - global notify - if platform.system() == "Windows": - from . import windows - notify = windows.notification() - elif platform.system() == "Linux": - from . import linux - notify = linux.notification() + global notify + if platform.system() == "Windows": + from . import windows + notify = windows.notification() + elif platform.system() == "Linux": + from . import linux + notify = linux.notification() def send(title, text): - global notify - if not notify or notify is None: - setup() - notify.notify(title, text) \ No newline at end of file + global notify + if not notify or notify is None: + setup() + notify.notify(title, text) diff --git a/src/notifier/linux.py b/src/notifier/linux.py index 18d78203..91b2e217 100644 --- a/src/notifier/linux.py +++ b/src/notifier/linux.py @@ -5,23 +5,23 @@ import dbus import application class notifications(object): - """Supports notifications on Linux. - """ + """Supports notifications on Linux. + """ - def __init__(self): - super(notifications, self).__init__() - self.item = "org.freedesktop.Notifications" - self.path = "/org/freedesktop/Notifications" - self.interface = "org.freedesktop.Notifications" - self.app_name = application.name - self.id_num_to_replace = 0 - self.icon = "/usr/share/icons/Tango/32x32/status/sunny.png" + def __init__(self): + super(notifications, self).__init__() + self.item = "org.freedesktop.Notifications" + self.path = "/org/freedesktop/Notifications" + self.interface = "org.freedesktop.Notifications" + self.app_name = application.name + self.id_num_to_replace = 0 + self.icon = "/usr/share/icons/Tango/32x32/status/sunny.png" - def notify(self, title="", text=""): - actions_list = '' - hint = '' - time = 5000 # Use seconds x 1000 - bus = dbus.SessionBus() - notif = bus.get_object(self.item, self.path) - notify = dbus.Interface(notif, self.interface) - notify.Notify(self.app_name, self.id_num_to_replace, self.icon, title, text, actions_list, hint, time) \ No newline at end of file + def notify(self, title="", text=""): + actions_list = '' + hint = '' + time = 5000 # Use seconds x 1000 + bus = dbus.SessionBus() + notif = bus.get_object(self.item, self.path) + notify = dbus.Interface(notif, self.interface) + notify.Notify(self.app_name, self.id_num_to_replace, self.icon, title, text, actions_list, hint, time) diff --git a/src/notifier/windows.py b/src/notifier/windows.py index af7b22cc..a521c4a5 100644 --- a/src/notifier/windows.py +++ b/src/notifier/windows.py @@ -5,5 +5,5 @@ import wx class notification(object): - def notify(self, title, text): - wx.NotificationMessage(title, text).Show() \ No newline at end of file + def notify(self, title, text): + wx.NotificationMessage(title, text).Show() diff --git a/src/output.py b/src/output.py index 1bb2975f..75ac2c6b 100644 --- a/src/output.py +++ b/src/output.py @@ -8,28 +8,28 @@ import sys speaker = None def speak(text, interrupt=0, speech=True, braille=True): - global speaker - if not speaker: - setup() - if speech: - speaker.speak(text, interrupt) - if braille: - speaker.braille(text) + global speaker + if not speaker: + setup() + if speech: + speaker.speak(text, interrupt) + if braille: + speaker.braille(text) def setup (): - global speaker - logging.debug("Initializing output subsystem.") - try: -# speaker = speech.Speaker(speech.outputs.Sapi5()) -# else: - speaker = outputs.auto.Auto() - except: - return logging.exception("Output: Error during initialization.") + global speaker + logging.debug("Initializing output subsystem.") + try: + # speaker = speech.Speaker(speech.outputs.Sapi5()) + # else: + speaker = outputs.auto.Auto() + except: + return logging.exception("Output: Error during initialization.") def copy(text): - import win32clipboard - #Copies text to the clipboard. - win32clipboard.OpenClipboard() - win32clipboard.EmptyClipboard() - win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT) - win32clipboard.CloseClipboard() + import win32clipboard + #Copies text to the clipboard. + win32clipboard.OpenClipboard() + win32clipboard.EmptyClipboard() + win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT) + win32clipboard.CloseClipboard() diff --git a/src/paths.py b/src/paths.py index 61f454b2..1eeb67d5 100644 --- a/src/paths.py +++ b/src/paths.py @@ -10,58 +10,58 @@ directory = None fsencoding = sys.getfilesystemencoding() if len(glob.glob("Uninstall.exe")) > 0: # installed copy - mode= "installed" + mode= "installed" def app_path(): - return paths_.app_path() + return paths_.app_path() def config_path(): - global mode, directory - if mode == "portable": - if directory != None: path = os.path.join(directory, "config") - elif directory == None: path = os.path.join(app_path(), "config") - elif mode == "installed": - path = os.path.join(data_path(), "config") - if not os.path.exists(path): -# log.debug("%s path does not exist, creating..." % (path,)) - os.mkdir(path) - return path + global mode, directory + if mode == "portable": + if directory != None: path = os.path.join(directory, "config") + elif directory == None: path = os.path.join(app_path(), "config") + elif mode == "installed": + path = os.path.join(data_path(), "config") + if not os.path.exists(path): + # log.debug("%s path does not exist, creating..." % (path,)) + os.mkdir(path) + return path def logs_path(): - global mode, directory - if mode == "portable": - if directory != None: path = os.path.join(directory, "logs") - elif directory == None: path = os.path.join(app_path(), "logs") - elif mode == "installed": - path = os.path.join(data_path(), "logs") - if not os.path.exists(path): -# log.debug("%s path does not exist, creating..." % (path,)) - os.mkdir(path) - return path + global mode, directory + if mode == "portable": + if directory != None: path = os.path.join(directory, "logs") + elif directory == None: path = os.path.join(app_path(), "logs") + elif mode == "installed": + path = os.path.join(data_path(), "logs") + if not os.path.exists(path): + # log.debug("%s path does not exist, creating..." % (path,)) + os.mkdir(path) + return path def data_path(app_name='socializer'): - if platform.system() == "Windows": - data_path = os.path.join(os.getenv("AppData"), app_name) - else: - data_path = os.path.join(os.environ['HOME'], ".%s" % app_name) - if not os.path.exists(data_path): - os.mkdir(data_path) - return data_path + if platform.system() == "Windows": + data_path = os.path.join(os.getenv("AppData"), app_name) + else: + data_path = os.path.join(os.environ['HOME'], ".%s" % app_name) + if not os.path.exists(data_path): + os.mkdir(data_path) + return data_path def locale_path(): - return os.path.join(app_path(), "locales") + return os.path.join(app_path(), "locales") def sound_path(): - return os.path.join(app_path(), "sounds") + return os.path.join(app_path(), "sounds") def com_path(): - global mode, directory - if mode == "portable": - if directory != None: path = os.path.join(directory, "com_cache") - elif directory == None: path = os.path.join(app_path(), "com_cache") - elif mode == "installed": - path = os.path.join(data_path(), "com_cache") - if not os.path.exists(path): -# log.debug("%s path does not exist, creating..." % (path,)) - os.mkdir(path) - return path + global mode, directory + if mode == "portable": + if directory != None: path = os.path.join(directory, "com_cache") + elif directory == None: path = os.path.join(app_path(), "com_cache") + elif mode == "installed": + path = os.path.join(data_path(), "com_cache") + if not os.path.exists(path): + # log.debug("%s path does not exist, creating..." % (path,)) + os.mkdir(path) + return path diff --git a/src/sessionmanager/__init__.py b/src/sessionmanager/__init__.py index 77b12468..000da2cf 100644 --- a/src/sessionmanager/__init__.py +++ b/src/sessionmanager/__init__.py @@ -7,4 +7,4 @@ Contents of this package: manager: Handles multiple sessions, setting the configuration files and check if the session is valid. Part of the model. session: Creates a twitter session for an user. The other part of the model. """ -from __future__ import unicode_literals \ No newline at end of file +from __future__ import unicode_literals diff --git a/src/sessionmanager/gtkUI.py b/src/sessionmanager/gtkUI.py index aa0b4a18..a6f8a4f0 100644 --- a/src/sessionmanager/gtkUI.py +++ b/src/sessionmanager/gtkUI.py @@ -3,55 +3,55 @@ from gi.repository import Gtk import widgetUtils class sessionManagerWindow(widgetUtils.baseDialog): - def __init__(self): - super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) - self.list = widgetUtils.list("Session") - self.box.add(self.list.list) - btnBox = Gtk.Box(spacing=6) - self.new = Gtk.Button("New account") - self.remove = Gtk.Button("Remove account") - self.configuration = Gtk.Button("Configuration") - btnBox.add(self.new) - btnBox.add(self.remove) - btnBox.add(self.configuration) - self.box.add(btnBox) - self.show_all() + def __init__(self): + super(sessionManagerWindow, self).__init__("Session Manager", None, 0, (Gtk.STOCK_OK, widgetUtils.OK, Gtk.STOCK_CANCEL, widgetUtils.CANCEL)) + self.list = widgetUtils.list("Session") + self.box.add(self.list.list) + btnBox = Gtk.Box(spacing=6) + self.new = Gtk.Button("New account") + self.remove = Gtk.Button("Remove account") + self.configuration = Gtk.Button("Configuration") + btnBox.add(self.new) + btnBox.add(self.remove) + btnBox.add(self.configuration) + self.box.add(btnBox) + self.show_all() - def fill_list(self, sessionsList): - for i in sessionsList: - self.list.insert_item(False, i) - if self.list.get_count() > 0: - self.list.select_item(0) + def fill_list(self, sessionsList): + for i in sessionsList: + self.list.insert_item(False, i) + if self.list.get_count() > 0: + self.list.select_item(0) - def new_account_dialog(self): - dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Authorization") - dialog.format_secondary_text("The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?") - answer = dialog.run() - dialog.destroy() - return answer + def new_account_dialog(self): + dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Authorization") + dialog.format_secondary_text("The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?") + answer = dialog.run() + dialog.destroy() + return answer - def add_new_session_to_list(self): - total = self.list.get_count() - name = "Authorized account %d" % (total+1) - self.list.insert_item(name) - if self.list.get_count() == 1: - self.list.select_item(0) + def add_new_session_to_list(self): + total = self.list.get_count() + name = "Authorized account %d" % (total+1) + self.list.insert_item(name) + if self.list.get_count() == 1: + self.list.select_item(0) - def show_unauthorised_error(self): - dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "Invalid user token") - dialog.format_secondary_text("Your access token is invalid or the authorization has failed. Please try again.") - answer = dialog.run() - return answer + def show_unauthorised_error(self): + dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "Invalid user token") + dialog.format_secondary_text("Your access token is invalid or the authorization has failed. Please try again.") + answer = dialog.run() + return answer - def remove_account_dialog(self): - dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Remove account") - dialog.format_secondary_text("Do you really want delete this account?") - answer = dialog.run() - return answer + def remove_account_dialog(self): + dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Remove account") + dialog.format_secondary_text("Do you really want delete this account?") + answer = dialog.run() + return answer - def get_selected(self): - return self.list.get_selected() + def get_selected(self): + return self.list.get_selected() - def remove_session(self, sessionID): - self.list.remove_item(sessionID) + def remove_session(self, sessionID): + self.list.remove_item(sessionID) diff --git a/src/sessionmanager/manager.py b/src/sessionmanager/manager.py index f0745cce..3ec251fe 100644 --- a/src/sessionmanager/manager.py +++ b/src/sessionmanager/manager.py @@ -11,41 +11,41 @@ from sessions import session_exceptions manager = None def setup(): - global manager - if not manager: - manager = sessionManager() + global manager + if not manager: + manager = sessionManager() class sessionManager(object): -# def __init__(self): -# FILE = "sessions.conf" -# SPEC = "app-configuration.defaults" -# try: -# self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC)) -# except ConfigurationResetException: -# pass + # def __init__(self): + # FILE = "sessions.conf" + # SPEC = "app-configuration.defaults" + # try: + # self.main = Configuration(paths.config_path(FILE), paths.app_path(SPEC)) + # except ConfigurationResetException: + # pass - def get_current_session(self): - if self.is_valid(config.app["sessions"]["current_session"]): - return config.app["sessions"]["current_session"] - else: - return False + def get_current_session(self): + if self.is_valid(config.app["sessions"]["current_session"]): + return config.app["sessions"]["current_session"] + else: + return False - def add_session(self, id): - log.debug("Adding a new session: %s" % (id,)) - path = os.path.join(paths.config_path(), id) - if not os.path.exists(path): - log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),)) - os.mkdir(path) - config.app["sessions"]["sessions"].append(id) + def add_session(self, id): + log.debug("Adding a new session: %s" % (id,)) + path = os.path.join(paths.config_path(), id) + if not os.path.exists(path): + log.debug("Creating %s path" % (os.path.join(paths.config_path(), path),)) + os.mkdir(path) + config.app["sessions"]["sessions"].append(id) - def set_current_session(self, sessionID): - config.app["sessions"]["current_session"] = sessionID - config.app.write() + def set_current_session(self, sessionID): + config.app["sessions"]["current_session"] = sessionID + config.app.write() - def is_valid(self, id): - if not os.path.exists(os.path.join(paths.config_path(), id)): - raise session_exceptions.NonExistentSessionError("That session does not exist.") - config.app["sessions"]["current_session"] = "" - return False - else: - return True \ No newline at end of file + def is_valid(self, id): + if not os.path.exists(os.path.join(paths.config_path(), id)): + raise session_exceptions.NonExistentSessionError("That session does not exist.") + config.app["sessions"]["current_session"] = "" + return False + else: + return True diff --git a/src/sessionmanager/sessionManager.py b/src/sessionmanager/sessionManager.py index 73757e4f..e81892c8 100644 --- a/src/sessionmanager/sessionManager.py +++ b/src/sessionmanager/sessionManager.py @@ -4,10 +4,10 @@ import widgetUtils import platform import output if platform.system() == "Windows": - from . import wxUI as view - from controller import settings + from . import wxUI as view + from controller import settings elif platform.system() == "Linux": - from . import gtkUI as view + from . import gtkUI as view import paths import time import os @@ -21,106 +21,106 @@ from tweepy.error import TweepError log = logging.getLogger("sessionmanager.sessionManager") class sessionManagerController(object): - def __init__(self, started=False): - super(sessionManagerController, self).__init__() - log.debug("Setting up the session manager.") - self.started = started - manager.setup() - self.view = view.sessionManagerWindow() - widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account) - widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove) - if self.started == False: - widgetUtils.connect_event(self.view.configuration, widgetUtils.BUTTON_PRESSED, self.configuration) - else: - self.view.hide_configuration() - self.new_sessions = {} - self.removed_sessions = [] + def __init__(self, started=False): + super(sessionManagerController, self).__init__() + log.debug("Setting up the session manager.") + self.started = started + manager.setup() + self.view = view.sessionManagerWindow() + widgetUtils.connect_event(self.view.new, widgetUtils.BUTTON_PRESSED, self.manage_new_account) + widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.remove) + if self.started == False: + widgetUtils.connect_event(self.view.configuration, widgetUtils.BUTTON_PRESSED, self.configuration) + else: + self.view.hide_configuration() + self.new_sessions = {} + self.removed_sessions = [] - def fill_list(self): - sessionsList = [] - reserved_dirs = ["dicts"] - log.debug("Filling the sessions list.") - self.sessions = [] - for i in os.listdir(paths.config_path()): - if os.path.isdir(os.path.join(paths.config_path(), i)) and i not in reserved_dirs: - log.debug("Adding session %s" % (i,)) - strconfig = "%s/session.conf" % (os.path.join(paths.config_path(), i)) - config_test = config_utils.load_config(strconfig) - if len(config_test) == 0: - try: - log.debug("Deleting session %s" % (i,)) - shutil.rmtree(os.path.join(paths.config_path(), i)) - continue - except: - output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True) - os.exception("Exception thrown while removing malformed session") - continue - name = config_test["twitter"]["user_name"] - if config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "": - sessionsList.append(name) - self.sessions.append(i) - else: - try: - log.debug("Deleting session %s" % (i,)) - shutil.rmtree(os.path.join(paths.config_path(), i)) - except: - output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True) - os.exception("Exception thrown while removing malformed session") - self.view.fill_list(sessionsList) + def fill_list(self): + sessionsList = [] + reserved_dirs = ["dicts"] + log.debug("Filling the sessions list.") + self.sessions = [] + for i in os.listdir(paths.config_path()): + if os.path.isdir(os.path.join(paths.config_path(), i)) and i not in reserved_dirs: + log.debug("Adding session %s" % (i,)) + strconfig = "%s/session.conf" % (os.path.join(paths.config_path(), i)) + config_test = config_utils.load_config(strconfig) + if len(config_test) == 0: + try: + log.debug("Deleting session %s" % (i,)) + shutil.rmtree(os.path.join(paths.config_path(), i)) + continue + except: + output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True) + os.exception("Exception thrown while removing malformed session") + continue + name = config_test["twitter"]["user_name"] + if config_test["twitter"]["user_key"] != "" and config_test["twitter"]["user_secret"] != "": + sessionsList.append(name) + self.sessions.append(i) + else: + try: + log.debug("Deleting session %s" % (i,)) + shutil.rmtree(os.path.join(paths.config_path(), i)) + except: + output.speak("An exception was raised while attempting to clean malformed session data. See the error log for details. If this message persists, contact the developers.",True) + os.exception("Exception thrown while removing malformed session") + self.view.fill_list(sessionsList) - def show(self): - if self.view.get_response() == widgetUtils.OK: - self.do_ok() + def show(self): + if self.view.get_response() == widgetUtils.OK: + self.do_ok() # else: - self.view.destroy() + self.view.destroy() - def do_ok(self): - log.debug("Starting sessions...") - for i in self.sessions: - if (i in sessions.sessions) == True: continue - s = session.Session(i) - s.get_configuration() - if i not in config.app["sessions"]["ignored_sessions"]: - try: - s.login() - except TweepError: - self.show_auth_error(s.settings["twitter"]["user_name"]) - continue - sessions.sessions[i] = s - self.new_sessions[i] = s + def do_ok(self): + log.debug("Starting sessions...") + for i in self.sessions: + if (i in sessions.sessions) == True: continue + s = session.Session(i) + s.get_configuration() + if i not in config.app["sessions"]["ignored_sessions"]: + try: + s.login() + except TweepError: + self.show_auth_error(s.settings["twitter"]["user_name"]) + continue + sessions.sessions[i] = s + self.new_sessions[i] = s # self.view.destroy() - def show_auth_error(self, user_name): - error = view.auth_error(user_name) + def show_auth_error(self, user_name): + error = view.auth_error(user_name) - def manage_new_account(self, *args, **kwargs): - if self.view.new_account_dialog() == widgetUtils.YES: - location = (str(time.time())[-6:]) - log.debug("Creating session in the %s path" % (location,)) - s = session.Session(location) - manager.manager.add_session(location) - s.get_configuration() + def manage_new_account(self, *args, **kwargs): + if self.view.new_account_dialog() == widgetUtils.YES: + location = (str(time.time())[-6:]) + log.debug("Creating session in the %s path" % (location,)) + s = session.Session(location) + manager.manager.add_session(location) + s.get_configuration() # try: - s.authorise() - self.sessions.append(location) - self.view.add_new_session_to_list() - s.settings.write() + s.authorise() + self.sessions.append(location) + self.view.add_new_session_to_list() + s.settings.write() # except: # log.exception("Error authorising the session") # self.view.show_unauthorised_error() # return - def remove(self, *args, **kwargs): - if self.view.remove_account_dialog() == widgetUtils.YES: - selected_account = self.sessions[self.view.get_selected()] - self.view.remove_session(self.view.get_selected()) - self.removed_sessions.append(selected_account) - self.sessions.remove(selected_account) - shutil.rmtree(path=os.path.join(paths.config_path(), selected_account), ignore_errors=True) + def remove(self, *args, **kwargs): + if self.view.remove_account_dialog() == widgetUtils.YES: + selected_account = self.sessions[self.view.get_selected()] + self.view.remove_session(self.view.get_selected()) + self.removed_sessions.append(selected_account) + self.sessions.remove(selected_account) + shutil.rmtree(path=os.path.join(paths.config_path(), selected_account), ignore_errors=True) - def configuration(self, *args, **kwargs): - """ Opens the global settings dialogue.""" - d = settings.globalSettingsController() - if d.response == widgetUtils.OK: - d.save_configuration() + def configuration(self, *args, **kwargs): + """ Opens the global settings dialogue.""" + d = settings.globalSettingsController() + if d.response == widgetUtils.OK: + d.save_configuration() diff --git a/src/sessionmanager/wxUI.py b/src/sessionmanager/wxUI.py index fccfcdbf..6441f6e8 100644 --- a/src/sessionmanager/wxUI.py +++ b/src/sessionmanager/wxUI.py @@ -5,77 +5,77 @@ from multiplatform_widgets import widgets import application class sessionManagerWindow(wx.Dialog): - def __init__(self): - super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize) - listSizer = wx.BoxSizer(wx.HORIZONTAL) - self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) - listSizer.Add(label, 0, wx.ALL, 5) - listSizer.Add(self.list.list, 0, wx.ALL, 5) - sizer.Add(listSizer, 0, wx.ALL, 5) - self.new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize) - self.remove = wx.Button(panel, -1, _(u"Remove account")) - self.configuration = wx.Button(panel, -1, _(u"Global Settings")) - ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize) - buttons = wx.BoxSizer(wx.HORIZONTAL) - buttons.Add(self.new, 0, wx.ALL, 5) - buttons.Add(self.configuration, 0, wx.ALL, 5) - buttons.Add(ok, 0, wx.ALL, 5) - buttons.Add(cancel, 0, wx.ALL, 5) - sizer.Add(buttons, 0, wx.ALL, 5) - panel.SetSizer(sizer) - min = sizer.CalcMin() - self.SetClientSize(min) + def __init__(self): + super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(panel, -1, _(u"Accounts list"), size=wx.DefaultSize) + listSizer = wx.BoxSizer(wx.HORIZONTAL) + self.list = widgets.list(panel, _(u"Account"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) + listSizer.Add(label, 0, wx.ALL, 5) + listSizer.Add(self.list.list, 0, wx.ALL, 5) + sizer.Add(listSizer, 0, wx.ALL, 5) + self.new = wx.Button(panel, -1, _(u"New account"), size=wx.DefaultSize) + self.remove = wx.Button(panel, -1, _(u"Remove account")) + self.configuration = wx.Button(panel, -1, _(u"Global Settings")) + ok = wx.Button(panel, wx.ID_OK, size=wx.DefaultSize) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, size=wx.DefaultSize) + buttons = wx.BoxSizer(wx.HORIZONTAL) + buttons.Add(self.new, 0, wx.ALL, 5) + buttons.Add(self.configuration, 0, wx.ALL, 5) + buttons.Add(ok, 0, wx.ALL, 5) + buttons.Add(cancel, 0, wx.ALL, 5) + sizer.Add(buttons, 0, wx.ALL, 5) + panel.SetSizer(sizer) + min = sizer.CalcMin() + self.SetClientSize(min) - def fill_list(self, sessionsList): - for i in sessionsList: - self.list.insert_item(False, i) - if self.list.get_count() > 0: - self.list.select_item(0) - self.list.list.SetSize(self.list.list.GetBestSize()) + def fill_list(self, sessionsList): + for i in sessionsList: + self.list.insert_item(False, i) + if self.list.get_count() > 0: + self.list.select_item(0) + self.list.list.SetSize(self.list.list.GetBestSize()) - def ok(self, ev): - if self.list.get_count() == 0: - wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal() - return - self.controller.do_ok() - self.EndModal(wx.ID_OK) + def ok(self, ev): + if self.list.get_count() == 0: + wx.MessageDialog(None, _(u"You need to configure an account."), _(u"Account Error"), wx.ICON_ERROR).ShowModal() + return + self.controller.do_ok() + self.EndModal(wx.ID_OK) - def new_account_dialog(self): - return wx.MessageDialog(self, _(u"The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?"), _(u"Authorization"), wx.YES_NO).ShowModal() + def new_account_dialog(self): + return wx.MessageDialog(self, _(u"The request to authorize your Twitter account will be opened in your browser. You only need to do this once. Would you like to continue?"), _(u"Authorization"), wx.YES_NO).ShowModal() - def add_new_session_to_list(self): - total = self.list.get_count() - name = _(u"Authorized account %d") % (total+1) - self.list.insert_item(False, name) - if self.list.get_count() == 1: - self.list.select_item(0) + def add_new_session_to_list(self): + total = self.list.get_count() + name = _(u"Authorized account %d") % (total+1) + self.list.insert_item(False, name) + if self.list.get_count() == 1: + self.list.select_item(0) - def show_unauthorised_error(self): - wx.MessageDialog(None, _(u"Your access token is invalid or the authorization has failed. Please try again."), _(u"Invalid user token"), wx.ICON_ERROR).ShowModal() + def show_unauthorised_error(self): + wx.MessageDialog(None, _(u"Your access token is invalid or the authorization has failed. Please try again."), _(u"Invalid user token"), wx.ICON_ERROR).ShowModal() - def get_response(self): - return self.ShowModal() + def get_response(self): + return self.ShowModal() - def remove_account_dialog(self): - return wx.MessageDialog(self, _(u"Do you really want to delete this account?"), _(u"Remove account"), wx.YES_NO).ShowModal() + def remove_account_dialog(self): + return wx.MessageDialog(self, _(u"Do you really want to delete this account?"), _(u"Remove account"), wx.YES_NO).ShowModal() - def get_selected(self): - return self.list.get_selected() + def get_selected(self): + return self.list.get_selected() - def remove_session(self, sessionID): - self.list.remove_item(sessionID) + def remove_session(self, sessionID): + self.list.remove_item(sessionID) - def hide_configuration(self): - self.configuration.Hide() + def hide_configuration(self): + self.configuration.Hide() - def destroy(self): - self.Destroy() + def destroy(self): + self.Destroy() def auth_error(user_name): - return wx.MessageDialog(None, _("TWBlue is unable to authenticate the account for {} in Twitter. It might be due to an invalid or expired token, revoqued access to the application, or after an account reactivation. Please remove the account manually from your Twitter sessions in order to stop seeing this message.").format(user_name,), _("Authentication error for session {}").format(user_name,), wx.OK).ShowModal() + return wx.MessageDialog(None, _("TWBlue is unable to authenticate the account for {} in Twitter. It might be due to an invalid or expired token, revoqued access to the application, or after an account reactivation. Please remove the account manually from your Twitter sessions in order to stop seeing this message.").format(user_name,), _("Authentication error for session {}").format(user_name,), wx.OK).ShowModal() diff --git a/src/sessions/__init__.py b/src/sessions/__init__.py index 4ab464c0..a9341e79 100644 --- a/src/sessions/__init__.py +++ b/src/sessions/__init__.py @@ -3,4 +3,4 @@ In TWBlue, a session module defines everything a social network needs to be used in the program.""" from __future__ import unicode_literals # let's define a global object for storing sessions across the program. -sessions = {} \ No newline at end of file +sessions = {} diff --git a/src/sessions/base.py b/src/sessions/base.py index 235245e8..597cacfc 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -18,103 +18,103 @@ from . import session_exceptions as Exceptions log = logging.getLogger("sessionmanager.session") class baseSession(object): - """ toDo: Decorators does not seem to be working when using them in an inherited class.""" + """ toDo: Decorators does not seem to be working when using them in an inherited class.""" - # Decorators. + # Decorators. - def _require_login(fn): - """ Decorator for checking if the user is logged in. - Some functions may need this to avoid making unneeded calls.""" - def f(self, *args, **kwargs): - if self.logged == True: - fn(self, *args, **kwargs) - else: - raise Exceptions.NotLoggedSessionError("You are not logged in yet.") - return f + def _require_login(fn): + """ Decorator for checking if the user is logged in. + Some functions may need this to avoid making unneeded calls.""" + def f(self, *args, **kwargs): + if self.logged == True: + fn(self, *args, **kwargs) + else: + raise Exceptions.NotLoggedSessionError("You are not logged in yet.") + return f - def _require_configuration(fn): - """ Check if the user has a configured session.""" - def f(self, *args, **kwargs): - if self.settings != None: - fn(self, *args, **kwargs) - else: - raise Exceptions.NotConfiguredSessionError("Not configured.") - return f + def _require_configuration(fn): + """ Check if the user has a configured session.""" + def f(self, *args, **kwargs): + if self.settings != None: + fn(self, *args, **kwargs) + else: + raise Exceptions.NotConfiguredSessionError("Not configured.") + return f - def __init__(self, session_id): - """ session_id (str): The name of the folder inside the config directory where the session is located.""" - super(baseSession, self).__init__() - self.session_id = session_id - self.logged = False - self.settings = None - self.db={} - - @property - def is_logged(self): - return self.logged + def __init__(self, session_id): + """ session_id (str): The name of the folder inside the config directory where the session is located.""" + super(baseSession, self).__init__() + self.session_id = session_id + self.logged = False + self.settings = None + self.db={} - def get_configuration(self): - """ Get settings for a session.""" - file_ = "%s/session.conf" % (self.session_id,) - log.debug("Creating config file %s" % (file_,)) - self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "Conf.defaults")) - self.init_sound() - self.deshelve() + @property + def is_logged(self): + return self.logged - def init_sound(self): - try: self.sound = sound.soundSystem(self.settings["sound"]) - except: pass + def get_configuration(self): + """ Get settings for a session.""" + file_ = "%s/session.conf" % (self.session_id,) + log.debug("Creating config file %s" % (file_,)) + self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "Conf.defaults")) + self.init_sound() + self.deshelve() - @_require_configuration - def login(self, verify_credentials=True): - pass + def init_sound(self): + try: self.sound = sound.soundSystem(self.settings["sound"]) + except: pass - @_require_configuration - def authorise(self): - pass + @_require_configuration + def login(self, verify_credentials=True): + pass - def shelve(self): - """Shelve the database to allow for persistance.""" - shelfname=os.path.join(paths.config_path(), str(self.session_id), "cache") - if self.settings["general"]["persist_size"] == 0: - if os.path.exists(shelfname+".dat"): - os.remove(shelfname+".dat") - return - try: - if not os.path.exists(shelfname+".dat"): - output.speak("Generating database, this might take a while.",True) - shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') - for key, value in list(self.db.items()): - if type(key) != str and type(key) != str: - output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True) - log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!") - if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]: - shelf[key]=value[self.settings["general"]["persist_size"]:] - else: - shelf[key]=value - shelf.close() - except: - output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) - log.exception("Exception while shelving" + shelfname) - os.remove(shelfname) + @_require_configuration + def authorise(self): + pass - def deshelve(self): - """Import a shelved database.""" - shelfname=os.path.join(paths.config_path(), str(self.session_id)+"/cache") - if self.settings["general"]["persist_size"] == 0: - if os.path.exists(shelfname+".dat"): - os.remove(shelfname+".dat") - return - try: - shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') - for key,value in list(shelf.items()): - self.db[key]=value - shelf.close() - except: - output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) - log.exception("Exception while deshelving" + shelfname) - try: - os.remove(shelfname) - except: - pass + def shelve(self): + """Shelve the database to allow for persistance.""" + shelfname=os.path.join(paths.config_path(), str(self.session_id), "cache") + if self.settings["general"]["persist_size"] == 0: + if os.path.exists(shelfname+".dat"): + os.remove(shelfname+".dat") + return + try: + if not os.path.exists(shelfname+".dat"): + output.speak("Generating database, this might take a while.",True) + shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') + for key, value in list(self.db.items()): + if type(key) != str and type(key) != str: + output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True) + log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!") + if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]: + shelf[key]=value[self.settings["general"]["persist_size"]:] + else: + shelf[key]=value + shelf.close() + except: + output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) + log.exception("Exception while shelving" + shelfname) + os.remove(shelfname) + + def deshelve(self): + """Import a shelved database.""" + shelfname=os.path.join(paths.config_path(), str(self.session_id)+"/cache") + if self.settings["general"]["persist_size"] == 0: + if os.path.exists(shelfname+".dat"): + os.remove(shelfname+".dat") + return + try: + shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') + for key,value in list(shelf.items()): + self.db[key]=value + shelf.close() + except: + output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) + log.exception("Exception while deshelving" + shelfname) + try: + os.remove(shelfname) + except: + pass diff --git a/src/sessions/session_exceptions.py b/src/sessions/session_exceptions.py index e45f843a..9b16e287 100644 --- a/src/sessions/session_exceptions.py +++ b/src/sessions/session_exceptions.py @@ -6,4 +6,4 @@ class NonExistentSessionError(Exception): pass class NotLoggedSessionError(BaseException): pass class NotConfiguredSessionError(BaseException): pass class RequireCredentialsSessionError(BaseException): pass -class AlreadyAuthorisedError(BaseException): pass \ No newline at end of file +class AlreadyAuthorisedError(BaseException): pass diff --git a/src/sessions/twitter/__init__.py b/src/sessions/twitter/__init__.py index 7c68785e..40a96afc 100644 --- a/src/sessions/twitter/__init__.py +++ b/src/sessions/twitter/__init__.py @@ -1 +1 @@ -# -*- coding: utf-8 -*- \ No newline at end of file +# -*- coding: utf-8 -*- diff --git a/src/sessions/twitter/compose.py b/src/sessions/twitter/compose.py index 89dc6f16..e76a7034 100644 --- a/src/sessions/twitter/compose.py +++ b/src/sessions/twitter/compose.py @@ -1,11 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -from builtins import str -from builtins import chr -from builtins import range import platform system = platform.system() from . import utils @@ -21,151 +14,151 @@ from .long_tweets import twishort, tweets log = logging.getLogger("compose") def StripChars(s): - """Converts any html entities in s to their unicode-decoded equivalents and returns a string.""" - entity_re = re.compile(r"&(#\d+|\w+);") - def matchFunc(match): - """Nested function to handle a match object. - If we match &blah; and it's not found, &blah; will be returned. - if we match #\d+, unichr(digits) will be returned. - Else, a unicode string will be returned.""" - if match.group(1).startswith('#'): return chr(int(match.group(1)[1:])) - replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1)) - return replacement - return str(entity_re.sub(matchFunc, s)) + """Converts any html entities in s to their unicode-decoded equivalents and returns a string.""" + entity_re = re.compile(r"&(#\d+|\w+);") + def matchFunc(match): + """Nested function to handle a match object. + If we match &blah; and it's not found, &blah; will be returned. + if we match #\d+, unichr(digits) will be returned. + Else, a unicode string will be returned.""" + if match.group(1).startswith('#'): return chr(int(match.group(1)[1:])) + replacement = html.entities.entitydefs.get(match.group(1), "&%s;" % match.group(1)) + return replacement + return str(entity_re.sub(matchFunc, s)) chars = "abcdefghijklmnopqrstuvwxyz" def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=None): - """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" - if system == "Windows": - original_date = arrow.get(tweet.created_at, locale="en") - if relative_times == True: - ts = original_date.humanize(locale=languageHandler.curLang[:2]) - else: - ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) - else: - ts = tweet.created_at - if hasattr(tweet, "message"): - value = "message" - elif hasattr(tweet, "full_text"): - value = "full_text" - else: - value = "text" - if hasattr(tweet, "retweeted_status") and value != "message": - text = StripChars(getattr(tweet.retweeted_status, value)) - else: - text = StripChars(getattr(tweet, value)) - if show_screen_names: - user = tweet.user.screen_name - else: - user = tweet.user.name - source = re.sub(r"(?s)<.*?>", "", tweet.source) - if hasattr(tweet, "retweeted_status"): - if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False: - text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) - elif tweet.retweeted_status.is_quote_status: - text = "%s" % (text) - else: - text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) - if not hasattr(tweet, "message"): + """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" + if system == "Windows": + original_date = arrow.get(tweet.created_at, locale="en") + if relative_times == True: + ts = original_date.humanize(locale=languageHandler.curLang[:2]) + else: + ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) + else: + ts = tweet.created_at + if hasattr(tweet, "message"): + value = "message" + elif hasattr(tweet, "full_text"): + value = "full_text" + else: + value = "text" + if hasattr(tweet, "retweeted_status") and value != "message": + text = StripChars(getattr(tweet.retweeted_status, value)) + else: + text = StripChars(getattr(tweet, value)) + if show_screen_names: + user = tweet.user.screen_name + else: + user = tweet.user.name + source = re.sub(r"(?s)<.*?>", "", tweet.source) + if hasattr(tweet, "retweeted_status"): + if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False: + text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) + elif tweet.retweeted_status.is_quote_status: + text = "%s" % (text) + else: + text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) + if not hasattr(tweet, "message"): - if hasattr(tweet, "retweeted_status"): - text = utils.expand_urls(text, tweet.retweeted_status.entities) - else: - text = utils.expand_urls(text, tweet.entities) - if config.app['app-settings']['handle_longtweets']: pass - return [user+", ", text, ts+", ", source] + if hasattr(tweet, "retweeted_status"): + text = utils.expand_urls(text, tweet.retweeted_status.entities) + else: + text = utils.expand_urls(text, tweet.entities) + if config.app['app-settings']['handle_longtweets']: pass + return [user+", ", text, ts+", ", source] def compose_direct_message(item, db, relative_times, show_screen_names=False, session=None): - if system == "Windows": - # Let's remove the last 3 digits in the timestamp string. - # Twitter sends their "epoch" timestamp with 3 digits for milliseconds and arrow doesn't like it. - original_date = arrow.get(int(item.created_timestamp)) - if relative_times == True: - ts = original_date.humanize(locale=languageHandler.curLang[:2]) - else: - ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) - else: - ts = item.created_timestamp - text = StripChars(item.message_create["message_data"]["text"]) - source = "DM" - sender = session.get_user(item.message_create["sender_id"]) - if db["user_name"] == sender.screen_name: - if show_screen_names: - user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).screen_name) - else: - user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).name) - else: - if show_screen_names: - user = sender.screen_name - else: - user = sender.name - if text[-1] in chars: text=text+"." - text = utils.expand_urls(text, item.message_create["message_data"]["entities"]) - return [user+", ", text, ts+", ", source] + if system == "Windows": + # Let's remove the last 3 digits in the timestamp string. + # Twitter sends their "epoch" timestamp with 3 digits for milliseconds and arrow doesn't like it. + original_date = arrow.get(int(item.created_timestamp)) + if relative_times == True: + ts = original_date.humanize(locale=languageHandler.curLang[:2]) + else: + ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) + else: + ts = item.created_timestamp + text = StripChars(item.message_create["message_data"]["text"]) + source = "DM" + sender = session.get_user(item.message_create["sender_id"]) + if db["user_name"] == sender.screen_name: + if show_screen_names: + user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).screen_name) + else: + user = _(u"Dm to %s ") % (session.get_user(item.message_create["target"]["recipient_id"]).name) + else: + if show_screen_names: + user = sender.screen_name + else: + user = sender.name + if text[-1] in chars: text=text+"." + text = utils.expand_urls(text, item.message_create["message_data"]["entities"]) + return [user+", ", text, ts+", ", source] def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, session=None): - """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" - if hasattr(quoted_tweet, "retweeted_status"): - if hasattr(quoted_tweet.retweeted_status, "full_text"): - value = "full_text" - else: - value = "text" - text = StripChars(getattr(quoted_tweet.retweeted_status, value)) - else: - if hasattr(quoted_tweet, "full_text"): - value = "full_text" - else: - value = "text" - text = StripChars(getattr(quoted_tweet, value)) - if show_screen_names: - quoting_user = quoted_tweet.user.screen_name - else: - quoting_user = quoted_tweet.user.name - source = quoted_tweet.source - if hasattr(quoted_tweet, "retweeted_status"): - text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text) - if text[-1] in chars: text=text+"." - original_user = original_tweet.user.screen_name - if hasattr(original_tweet, "message"): - original_text = original_tweet.message - elif hasattr(original_tweet, "full_text"): - original_text = StripChars(original_tweet.full_text) - else: - original_text = StripChars(original_tweet.text) - quoted_tweet.message = _(u"{0}. Quoted tweet from @{1}: {2}").format( text, original_user, original_text) - quoted_tweet = tweets.clear_url(quoted_tweet) - quoted_tweet.entities["urls"].extend(original_tweet.entities["urls"]) - return quoted_tweet + """ It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is.""" + if hasattr(quoted_tweet, "retweeted_status"): + if hasattr(quoted_tweet.retweeted_status, "full_text"): + value = "full_text" + else: + value = "text" + text = StripChars(getattr(quoted_tweet.retweeted_status, value)) + else: + if hasattr(quoted_tweet, "full_text"): + value = "full_text" + else: + value = "text" + text = StripChars(getattr(quoted_tweet, value)) + if show_screen_names: + quoting_user = quoted_tweet.user.screen_name + else: + quoting_user = quoted_tweet.user.name + source = quoted_tweet.source + if hasattr(quoted_tweet, "retweeted_status"): + text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text) + if text[-1] in chars: text=text+"." + original_user = original_tweet.user.screen_name + if hasattr(original_tweet, "message"): + original_text = original_tweet.message + elif hasattr(original_tweet, "full_text"): + original_text = StripChars(original_tweet.full_text) + else: + original_text = StripChars(original_tweet.text) + quoted_tweet.message = _(u"{0}. Quoted tweet from @{1}: {2}").format( text, original_user, original_text) + quoted_tweet = tweets.clear_url(quoted_tweet) + quoted_tweet.entities["urls"].extend(original_tweet.entities["urls"]) + return quoted_tweet def compose_followers_list(tweet, db, relative_times=True, show_screen_names=False, session=None): - if system == "Windows": - original_date = arrow.get(tweet.created_at, locale="en") - if relative_times == True: - ts = original_date.humanize(locale=languageHandler.curLang[:2]) - else: - ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) - else: - ts = tweet.created_at - if hasattr(tweet, "status"): - if system == "Windows": - original_date2 = arrow.get(tweet.status.created_at, locale="en") - if relative_times: - ts2 = original_date2.humanize(locale=languageHandler.curLang[:2]) - else: - ts2 = original_date2.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) - else: - ts2 = _("Unavailable") - else: - ts2 = _("Unavailable") - return [_(u"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined Twitter %s") % (tweet.name, tweet.screen_name, tweet.followers_count, tweet.friends_count, tweet.statuses_count, ts2, ts)] + if system == "Windows": + original_date = arrow.get(tweet.created_at, locale="en") + if relative_times == True: + ts = original_date.humanize(locale=languageHandler.curLang[:2]) + else: + ts = original_date.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) + else: + ts = tweet.created_at + if hasattr(tweet, "status"): + if system == "Windows": + original_date2 = arrow.get(tweet.status.created_at, locale="en") + if relative_times: + ts2 = original_date2.humanize(locale=languageHandler.curLang[:2]) + else: + ts2 = original_date2.shift(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.curLang[:2]) + else: + ts2 = _("Unavailable") + else: + ts2 = _("Unavailable") + return [_(u"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined Twitter %s") % (tweet.name, tweet.screen_name, tweet.followers_count, tweet.friends_count, tweet.statuses_count, ts2, ts)] def compose_list(list): - name = list.name - if list.description == None: description = _(u"No description available") - else: description = list.description - user = list.user.name - members = str(list.member_count) - if list.mode == "private": status = _(u"private") - else: status = _(u"public") - return [name, description, user, members, status] + name = list.name + if list.description == None: description = _(u"No description available") + else: description = list.description + user = list.user.name + members = str(list.member_count) + if list.mode == "private": status = _(u"private") + else: status = _(u"public") + return [name, description, user, members, status] diff --git a/src/sessions/twitter/long_tweets/__init__.py b/src/sessions/twitter/long_tweets/__init__.py index 20e9c4c4..007ad61c 100644 --- a/src/sessions/twitter/long_tweets/__init__.py +++ b/src/sessions/twitter/long_tweets/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """ this package holds different modules to extract information regarding long tweets. A long tweet contains more than one tweet (such a quoted tweet), or is made via services like twishort.""" -from __future__ import unicode_literals \ No newline at end of file +from __future__ import unicode_literals diff --git a/src/sessions/twitter/long_tweets/tweets.py b/src/sessions/twitter/long_tweets/tweets.py index 3ab7140d..54d8d86d 100644 --- a/src/sessions/twitter/long_tweets/tweets.py +++ b/src/sessions/twitter/long_tweets/tweets.py @@ -20,33 +20,33 @@ from __future__ import unicode_literals from sessions.twitter import utils def is_long(tweet): - """ Check if the passed tweet contains a quote in its metadata. - tweet dict: a tweet dictionary. - returns True if a quote is detected, False otherwise.""" - if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"): - return tweet.quoted_status_id - elif hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "quoted_status_id") and hasattr(tweet.retweeted_status, "quoted_status"): - return tweet.retweeted_status.quoted_status_id - return False + """ Check if the passed tweet contains a quote in its metadata. + tweet dict: a tweet dictionary. + returns True if a quote is detected, False otherwise.""" + if hasattr(tweet, "quoted_status_id") and hasattr(tweet, "quoted_status"): + return tweet.quoted_status_id + elif hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "quoted_status_id") and hasattr(tweet.retweeted_status, "quoted_status"): + return tweet.retweeted_status.quoted_status_id + return False def clear_url(tweet): - """ Reads data from a quoted tweet and removes the link to the Status from the tweet's text. - tweet dict: a tweet dictionary. - returns a tweet dictionary without the URL to the status ID in its text to display.""" - if hasattr(tweet, "retweeted_status"): - if hasattr(tweet.retweeted_status, "full_text"): - value = "full_text" - else: - value = "text" - urls = utils.find_urls_in_text(getattr(tweet.retweeted_status, value)) - try: tweet.message = tweet.message.replace(urls[-1], "") - except IndexError: pass - else: - if hasattr(tweet, "full_text"): - value = "full_text" - else: - value = "text" - urls = utils.find_urls_in_text(getattr(tweet, value)) - try: tweet.message = tweet.message.replace(urls[-1], "") - except IndexError: pass - return tweet \ No newline at end of file + """ Reads data from a quoted tweet and removes the link to the Status from the tweet's text. + tweet dict: a tweet dictionary. + returns a tweet dictionary without the URL to the status ID in its text to display.""" + if hasattr(tweet, "retweeted_status"): + if hasattr(tweet.retweeted_status, "full_text"): + value = "full_text" + else: + value = "text" + urls = utils.find_urls_in_text(getattr(tweet.retweeted_status, value)) + try: tweet.message = tweet.message.replace(urls[-1], "") + except IndexError: pass + else: + if hasattr(tweet, "full_text"): + value = "full_text" + else: + value = "text" + urls = utils.find_urls_in_text(getattr(tweet, value)) + try: tweet.message = tweet.message.replace(urls[-1], "") + except IndexError: pass + return tweet diff --git a/src/sessions/twitter/long_tweets/twishort.py b/src/sessions/twitter/long_tweets/twishort.py index 25878cf0..2f465cd3 100644 --- a/src/sessions/twitter/long_tweets/twishort.py +++ b/src/sessions/twitter/long_tweets/twishort.py @@ -28,77 +28,77 @@ from sessions.twitter import utils log = logging.getLogger("long_tweets.twishort") def get_twishort_uri(url): - """ Takes A twishort URl and returns the twishort ID. - url str: an url like http://twishort.com/id. - returns a twishort ID if the URL is valid, False otherwise.""" - try: - return url.split("twishort.com/")[1] - except ValueError: - return False + """ Takes A twishort URl and returns the twishort ID. + url str: an url like http://twishort.com/id. + returns a twishort ID if the URL is valid, False otherwise.""" + try: + return url.split("twishort.com/")[1] + except ValueError: + return False def is_long(tweet): - """ Check if the passed tweet is made with Twishort. - returns True if is a long tweet, False otherwise.""" - long = False - for url in range(0, len(tweet.entities["urls"])): - try: - if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]: - long = get_twishort_uri(tweet.entities["urls"][url]["expanded_url"]) - except IndexError: - pass - # sometimes Twitter returns URL's with None objects, so let's take it. - # see https://github.com/manuelcortez/TWBlue/issues/103 - except TypeError: - pass - if long == False and hasattr(tweet, "retweeted_status"): - for url in range(0, len(tweet.retweeted_status.entities["urls"])): - try: - if tweet.retweeted_status.entities["urls"][url] != None and "twishort.com" in tweet.retweeted_status.entities["urls"][url]["expanded_url"]: - long = get_twishort_uri(tweet.retweeted_status.entities["urls"][url]["expanded_url"]) - except IndexError: - pass - except TypeError: - pass - return long + """ Check if the passed tweet is made with Twishort. + returns True if is a long tweet, False otherwise.""" + long = False + for url in range(0, len(tweet.entities["urls"])): + try: + if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]: + long = get_twishort_uri(tweet.entities["urls"][url]["expanded_url"]) + except IndexError: + pass + # sometimes Twitter returns URL's with None objects, so let's take it. + # see https://github.com/manuelcortez/TWBlue/issues/103 + except TypeError: + pass + if long == False and hasattr(tweet, "retweeted_status"): + for url in range(0, len(tweet.retweeted_status.entities["urls"])): + try: + if tweet.retweeted_status.entities["urls"][url] != None and "twishort.com" in tweet.retweeted_status.entities["urls"][url]["expanded_url"]: + long = get_twishort_uri(tweet.retweeted_status.entities["urls"][url]["expanded_url"]) + except IndexError: + pass + except TypeError: + pass + return long def get_full_text(uri): - """ Get Twishort's full text. - uri str: Twishort's identifier. - returns the contents of the tweet.""" - try: - r = requests.get("http://api.twishort.com/1.1/get.json", params={"uri": uri, "api_key": keys.keyring.get("twishort_api_key")}) - msg = r.json()["text"] - # Try to parse possible HTML entities. - from sessions.twitter.compose import StripChars - msg = StripChars(msg) - return msg - except: - return False + """ Get Twishort's full text. + uri str: Twishort's identifier. + returns the contents of the tweet.""" + try: + r = requests.get("http://api.twishort.com/1.1/get.json", params={"uri": uri, "api_key": keys.keyring.get("twishort_api_key")}) + msg = r.json()["text"] + # Try to parse possible HTML entities. + from sessions.twitter.compose import StripChars + msg = StripChars(msg) + return msg + except: + return False def create_tweet(user_token, user_secret, text, media=0): - """ Send a tweet to be extended by using Twishort. - user_token, user_secret str: Twitter user access key and secret, used by TWBlue to authorise against Twitter. - text str: Tweet text, max 10000 characters. - media int: Not used currently. - Returns text to be placed in the Tweet if the post has been succeeded, 0 otherwise.""" - twitter = OAuth1Session(keys.keyring.get("api_key"), client_secret=keys.keyring.get("api_secret"), resource_owner_key=user_token, resource_owner_secret=user_secret) - twishort_key=keys.keyring.get("twishort_api_key") - x_auth_service_provider = "https://api.twitter.com/1.1/account/verify_credentials.json" - twishort_post_url = "http://api.twishort.com/1.1/post.json" - twishort_update_ids_url = "http://api.twishort.com/1.1/update_ids.json" - r=requests.Request('GET', x_auth_service_provider) - prep=twitter.prepare_request(r) - resp=twitter.send(prep) - twitter.headers={ - 'X-Auth-Service-Provider':x_auth_service_provider, - 'X-Verify-Credentials-Authorization':prep.headers['Authorization'], - } - data = {'api_key':twishort_key, - "text": text.encode("utf-8"), - "media": media} - response = twitter.post(twishort_post_url, data=data) - try: - return response.json()["text_to_tweet"] - except: - print("There was a problem creating a long tweet") - return 0 \ No newline at end of file + """ Send a tweet to be extended by using Twishort. + user_token, user_secret str: Twitter user access key and secret, used by TWBlue to authorise against Twitter. + text str: Tweet text, max 10000 characters. + media int: Not used currently. + Returns text to be placed in the Tweet if the post has been succeeded, 0 otherwise.""" + twitter = OAuth1Session(keys.keyring.get("api_key"), client_secret=keys.keyring.get("api_secret"), resource_owner_key=user_token, resource_owner_secret=user_secret) + twishort_key=keys.keyring.get("twishort_api_key") + x_auth_service_provider = "https://api.twitter.com/1.1/account/verify_credentials.json" + twishort_post_url = "http://api.twishort.com/1.1/post.json" + twishort_update_ids_url = "http://api.twishort.com/1.1/update_ids.json" + r=requests.Request('GET', x_auth_service_provider) + prep=twitter.prepare_request(r) + resp=twitter.send(prep) + twitter.headers={ + 'X-Auth-Service-Provider':x_auth_service_provider, + 'X-Verify-Credentials-Authorization':prep.headers['Authorization'], + } + data = {'api_key':twishort_key, + "text": text.encode("utf-8"), + "media": media} + response = twitter.post(twishort_post_url, data=data) + try: + return response.json()["text_to_tweet"] + except: + print("There was a problem creating a long tweet") + return 0 diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 7dd1fb79..1cdbece0 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -22,432 +22,432 @@ from .wxUI import authorisationDialog log = logging.getLogger("sessions.twitterSession") class Session(base.baseSession): - """ A session object where we will save configuration, the twitter object and a local storage for saving the items retrieved through the Twitter API methods""" + """ A session object where we will save configuration, the twitter object and a local storage for saving the items retrieved through the Twitter API methods""" - def order_buffer(self, name, data, ignore_older=True): - """ Put new items in the local database. - name str: The name for the buffer stored in the dictionary. - data list: A list with tweets. - ignore_older bool: if set to True, items older than the first element on the list will be ignored. - returns the number of items that have been added in this execution""" - if name == "direct_messages": - return self.order_direct_messages(data) - num = 0 - last_id = None - if (name in self.db) == False: - self.db[name] = [] - if ("users" in self.db) == False: - self.db["users"] = {} - if ignore_older and len(self.db[name]) > 0: - if self.settings["general"]["reverse_timelines"] == False: - last_id = self.db[name][0].id - else: - last_id = self.db[name][-1].id - for i in data: - if ignore_older and last_id != None: - if i.id < last_id: - log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id)) - continue - if utils.find_item(i.id, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True: - i = self.check_quoted_status(i) - i = self.check_long_tweet(i) - if i == False: continue - if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) - else: self.db[name].insert(0, i) - num = num+1 - if hasattr(i, "user"): - if (i.user.id in self.db["users"]) == False: - self.db["users"][i.user.id] = i.user - return num + def order_buffer(self, name, data, ignore_older=True): + """ Put new items in the local database. + name str: The name for the buffer stored in the dictionary. + data list: A list with tweets. + ignore_older bool: if set to True, items older than the first element on the list will be ignored. + returns the number of items that have been added in this execution""" + if name == "direct_messages": + return self.order_direct_messages(data) + num = 0 + last_id = None + if (name in self.db) == False: + self.db[name] = [] + if ("users" in self.db) == False: + self.db["users"] = {} + if ignore_older and len(self.db[name]) > 0: + if self.settings["general"]["reverse_timelines"] == False: + last_id = self.db[name][0].id + else: + last_id = self.db[name][-1].id + for i in data: + if ignore_older and last_id != None: + if i.id < last_id: + log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id)) + continue + if utils.find_item(i.id, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True: + i = self.check_quoted_status(i) + i = self.check_long_tweet(i) + if i == False: continue + if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) + else: self.db[name].insert(0, i) + num = num+1 + if hasattr(i, "user"): + if (i.user.id in self.db["users"]) == False: + self.db["users"][i.user.id] = i.user + return num - def order_people(self, name, data): - """ Put new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches) - name str: The name for the buffer stored in the dictionary. - data list: A list with items and some information about cursors. - returns the number of items that have been added in this execution""" - num = 0 - if (name in self.db) == False: - self.db[name] = [] - for i in data: - if utils.find_item(i.id, self.db[name]) == None: - if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) - else: self.db[name].insert(0, i) - num = num+1 - return num + def order_people(self, name, data): + """ Put new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches) + name str: The name for the buffer stored in the dictionary. + data list: A list with items and some information about cursors. + returns the number of items that have been added in this execution""" + num = 0 + if (name in self.db) == False: + self.db[name] = [] + for i in data: + if utils.find_item(i.id, self.db[name]) == None: + if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) + else: self.db[name].insert(0, i) + num = num+1 + return num - def order_direct_messages(self, data): - """ Add incoming and sent direct messages to their corresponding database items. - data list: A list of direct messages to add. - returns the number of incoming messages processed in this execution, and sends an event with data regarding amount of sent direct messages added.""" - incoming = 0 - sent = 0 - if ("direct_messages" in self.db) == False: - self.db["direct_messages"] = [] - for i in data: - # Twitter returns sender_id as str, which must be converted to int in order to match to our user_id object. - if int(i.message_create["sender_id"]) == self.db["user_id"]: - if "sent_direct_messages" in self.db and utils.find_item(i.id, self.db["sent_direct_messages"]) == None: - if self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i) - else: self.db["sent_direct_messages"].insert(0, i) - sent = sent+1 - else: - if utils.find_item(i.id, self.db["direct_messages"]) == None: - if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i) - else: self.db["direct_messages"].insert(0, i) - incoming = incoming+1 - pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) - return incoming + def order_direct_messages(self, data): + """ Add incoming and sent direct messages to their corresponding database items. + data list: A list of direct messages to add. + returns the number of incoming messages processed in this execution, and sends an event with data regarding amount of sent direct messages added.""" + incoming = 0 + sent = 0 + if ("direct_messages" in self.db) == False: + self.db["direct_messages"] = [] + for i in data: + # Twitter returns sender_id as str, which must be converted to int in order to match to our user_id object. + if int(i.message_create["sender_id"]) == self.db["user_id"]: + if "sent_direct_messages" in self.db and utils.find_item(i.id, self.db["sent_direct_messages"]) == None: + if self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i) + else: self.db["sent_direct_messages"].insert(0, i) + sent = sent+1 + else: + if utils.find_item(i.id, self.db["direct_messages"]) == None: + if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i) + else: self.db["direct_messages"].insert(0, i) + incoming = incoming+1 + pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) + return incoming - def __init__(self, *args, **kwargs): - super(Session, self).__init__(*args, **kwargs) - # Adds here the optional cursors objects. - cursors = dict(direct_messages=-1) - self.db["cursors"] = cursors - self.reconnection_function_active = False - self.counter = 0 - self.lists = [] + def __init__(self, *args, **kwargs): + super(Session, self).__init__(*args, **kwargs) + # Adds here the optional cursors objects. + cursors = dict(direct_messages=-1) + self.db["cursors"] = cursors + self.reconnection_function_active = False + self.counter = 0 + self.lists = [] # @_require_configuration - def login(self, verify_credentials=True): - """ Log into twitter using credentials from settings. - if the user account isn't authorised, it needs to call self.authorise() before login.""" - if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None: - try: - log.debug("Logging in to twitter...") - self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) - self.auth.set_access_token(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"]) - self.twitter = tweepy.API(self.auth) - if verify_credentials == True: - self.credentials = self.twitter.verify_credentials() - self.logged = True - log.debug("Logged.") - self.counter = 0 - except IOError: - log.error("The login attempt failed.") - self.logged = False - else: - self.logged = False - raise Exceptions.RequireCredentialsSessionError + def login(self, verify_credentials=True): + """ Log into twitter using credentials from settings. + if the user account isn't authorised, it needs to call self.authorise() before login.""" + if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None: + try: + log.debug("Logging in to twitter...") + self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) + self.auth.set_access_token(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"]) + self.twitter = tweepy.API(self.auth) + if verify_credentials == True: + self.credentials = self.twitter.verify_credentials() + self.logged = True + log.debug("Logged.") + self.counter = 0 + except IOError: + log.error("The login attempt failed.") + self.logged = False + else: + self.logged = False + raise Exceptions.RequireCredentialsSessionError # @_require_configuration - def authorise(self): - """ Authorises a Twitter account. This function needs to be called for each new session, after self.get_configuration() and before self.login()""" - if self.logged == True: - raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.") - else: - self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) - redirect_url = self.auth.get_authorization_url() - webbrowser.open_new_tab(redirect_url) - self.authorisation_dialog = authorisationDialog() - self.authorisation_dialog.cancel.Bind(wx.EVT_BUTTON, self.authorisation_cancelled) - self.authorisation_dialog.ok.Bind(wx.EVT_BUTTON, self.authorisation_accepted) - self.authorisation_dialog.ShowModal() + def authorise(self): + """ Authorises a Twitter account. This function needs to be called for each new session, after self.get_configuration() and before self.login()""" + if self.logged == True: + raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.") + else: + self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) + redirect_url = self.auth.get_authorization_url() + webbrowser.open_new_tab(redirect_url) + self.authorisation_dialog = authorisationDialog() + self.authorisation_dialog.cancel.Bind(wx.EVT_BUTTON, self.authorisation_cancelled) + self.authorisation_dialog.ok.Bind(wx.EVT_BUTTON, self.authorisation_accepted) + self.authorisation_dialog.ShowModal() - def verify_authorisation(self, pincode): - self.auth.get_access_token(pincode) - self.settings["twitter"]["user_key"] = self.auth.access_token - self.settings["twitter"]["user_secret"] = self.auth.access_token_secret - self.settings.write() - del self.auth + def verify_authorisation(self, pincode): + self.auth.get_access_token(pincode) + self.settings["twitter"]["user_key"] = self.auth.access_token + self.settings["twitter"]["user_secret"] = self.auth.access_token_secret + self.settings.write() + del self.auth - def authorisation_cancelled(self, *args, **kwargs): - """ Destroy the authorization dialog. """ - self.authorisation_dialog.Destroy() - del self.authorisation_dialog + def authorisation_cancelled(self, *args, **kwargs): + """ Destroy the authorization dialog. """ + self.authorisation_dialog.Destroy() + del self.authorisation_dialog - def authorisation_accepted(self, *args, **kwargs): - """ Gets the PIN code entered by user and validate it through Twitter.""" - pincode = self.authorisation_dialog.text.GetValue() - self.verify_authorisation(pincode) - self.authorisation_dialog.Destroy() + def authorisation_accepted(self, *args, **kwargs): + """ Gets the PIN code entered by user and validate it through Twitter.""" + pincode = self.authorisation_dialog.text.GetValue() + self.verify_authorisation(pincode) + self.authorisation_dialog.Destroy() - def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs): - """ Get more items for twitter objects. - update_function str: function to call for getting more items. Must be member of self.twitter. - users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling). - name str: name of the database item to put new element in.""" - results = [] - if "cursor" in kwargs and kwargs["cursor"] == 0: - output.speak(_(u"There are no more items to retrieve in this buffer.")) - return - data = getattr(self.twitter, update_function)(*args, **kwargs) - if users == True: - if type(data) == dict and "next_cursor" in data: - if "next_cursor" in data: # There are more objects to retrieve. - self.db[name]["cursor"] = data["next_cursor"] - else: # Set cursor to 0, wich means no more items available. - self.db[name]["cursor"] = 0 - for i in data["users"]: results.append(i) - elif type(data) == list: - results.extend(data[1:]) - elif dm == True: - if "next_cursor" in data: # There are more objects to retrieve. - self.db[name]["cursor"] = data["next_cursor"] - else: # Set cursor to 0, wich means no more items available. - self.db[name]["cursor"] = 0 - for i in data["events"]: results.append(i) - else: - results.extend(data[1:]) - return results + def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs): + """ Get more items for twitter objects. + update_function str: function to call for getting more items. Must be member of self.twitter. + users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling). + name str: name of the database item to put new element in.""" + results = [] + if "cursor" in kwargs and kwargs["cursor"] == 0: + output.speak(_(u"There are no more items to retrieve in this buffer.")) + return + data = getattr(self.twitter, update_function)(*args, **kwargs) + if users == True: + if type(data) == dict and "next_cursor" in data: + if "next_cursor" in data: # There are more objects to retrieve. + self.db[name]["cursor"] = data["next_cursor"] + else: # Set cursor to 0, wich means no more items available. + self.db[name]["cursor"] = 0 + for i in data["users"]: results.append(i) + elif type(data) == list: + results.extend(data[1:]) + elif dm == True: + if "next_cursor" in data: # There are more objects to retrieve. + self.db[name]["cursor"] = data["next_cursor"] + else: # Set cursor to 0, wich means no more items available. + self.db[name]["cursor"] = 0 + for i in data["events"]: results.append(i) + else: + results.extend(data[1:]) + return results - def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): - """ Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call the method again at least 25 times, waiting a while between calls. Useful for post methods. - If twitter returns an error, it will not call the method anymore. - call_name str: The method to call - action str: What you are doing on twitter, it will be reported to the user if report_success is set to True. - for example "following @tw_blue2" will be reported as "following @tw_blue2 succeeded". - _sound str: a sound to play if the call is executed properly. - report_success and report_failure bool: These are self explanatory. True or False. - preexec_message str: A message to speak to the user while the method is running, example: "trying to follow x user".""" - finished = False - tries = 0 - if preexec_message: - output.speak(preexec_message, True) - while finished==False and tries < 25: - try: - val = getattr(self.twitter, call_name)(*args, **kwargs) - finished = True - except TweepError as e: - output.speak(e.reason) - val = None - if e.error_code != 403 and e.error_code != 404: - tries = tries+1 - time.sleep(5) - elif report_failure and hasattr(e, 'reason'): - output.speak(_("%s failed. Reason: %s") % (action, e.reason)) - finished = True + def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): + """ Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call the method again at least 25 times, waiting a while between calls. Useful for post methods. + If twitter returns an error, it will not call the method anymore. + call_name str: The method to call + action str: What you are doing on twitter, it will be reported to the user if report_success is set to True. + for example "following @tw_blue2" will be reported as "following @tw_blue2 succeeded". + _sound str: a sound to play if the call is executed properly. + report_success and report_failure bool: These are self explanatory. True or False. + preexec_message str: A message to speak to the user while the method is running, example: "trying to follow x user".""" + finished = False + tries = 0 + if preexec_message: + output.speak(preexec_message, True) + while finished==False and tries < 25: + try: + val = getattr(self.twitter, call_name)(*args, **kwargs) + finished = True + except TweepError as e: + output.speak(e.reason) + val = None + if e.error_code != 403 and e.error_code != 404: + tries = tries+1 + time.sleep(5) + elif report_failure and hasattr(e, 'reason'): + output.speak(_("%s failed. Reason: %s") % (action, e.reason)) + finished = True # except: # tries = tries + 1 # time.sleep(5) - if report_success: - output.speak(_("%s succeeded.") % action) - if _sound != None: self.sound.play(_sound) - return val + if report_success: + output.speak(_("%s succeeded.") % action) + if _sound != None: self.sound.play(_sound) + return val - def search(self, name, *args, **kwargs): - """ Search in twitter, passing args and kwargs as arguments to the Twython function.""" - tl = self.twitter.search(*args, **kwargs) - tl.reverse() - return tl + def search(self, name, *args, **kwargs): + """ Search in twitter, passing args and kwargs as arguments to the Twython function.""" + tl = self.twitter.search(*args, **kwargs) + tl.reverse() + return tl # @_require_login - def get_favourites_timeline(self, name, *args, **kwargs): - """ Gets favourites for the authenticated user or a friend or follower. - name str: Name for storage in the database. - args and kwargs are passed directly to the Twython function.""" - tl = self.call_paged("favorites", *args, **kwargs) - return self.order_buffer(name, tl) + def get_favourites_timeline(self, name, *args, **kwargs): + """ Gets favourites for the authenticated user or a friend or follower. + name str: Name for storage in the database. + args and kwargs are passed directly to the Twython function.""" + tl = self.call_paged("favorites", *args, **kwargs) + return self.order_buffer(name, tl) - def call_paged(self, update_function, *args, **kwargs): - """ Makes a call to the Twitter API methods several times. Useful for get methods. - this function is needed for retrieving more than 200 items. - update_function str: The function to call. This function must be child of self.twitter - args and kwargs are passed to update_function. - returns a list with all items retrieved.""" - max = 0 - results = [] - data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) - results.extend(data) - for i in range(0, max): - if i == 0: max_id = results[-1].id - else: max_id = results[0].id - data = getattr(self.twitter, update_function)(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) - results.extend(data) - results.reverse() - return results + def call_paged(self, update_function, *args, **kwargs): + """ Makes a call to the Twitter API methods several times. Useful for get methods. + this function is needed for retrieving more than 200 items. + update_function str: The function to call. This function must be child of self.twitter + args and kwargs are passed to update_function. + returns a list with all items retrieved.""" + max = 0 + results = [] + data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + results.extend(data) + for i in range(0, max): + if i == 0: max_id = results[-1].id + else: max_id = results[0].id + data = getattr(self.twitter, update_function)(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + results.extend(data) + results.reverse() + return results # @_require_login - def get_user_info(self): - """ Retrieves some information required by TWBlue for setup.""" - f = self.twitter.get_settings() - sn = f["screen_name"] - self.settings["twitter"]["user_name"] = sn - self.db["user_name"] = sn - self.db["user_id"] = self.twitter.get_user(screen_name=sn).id - try: - self.db["utc_offset"] = f["time_zone"]["utc_offset"] - except KeyError: - self.db["utc_offset"] = -time.timezone - # Get twitter's supported languages and save them in a global variable - #so we won't call to this method once per session. - if len(application.supported_languages) == 0: - application.supported_languages = self.twitter.supported_languages() - self.get_lists() - self.get_muted_users() - self.settings.write() + def get_user_info(self): + """ Retrieves some information required by TWBlue for setup.""" + f = self.twitter.get_settings() + sn = f["screen_name"] + self.settings["twitter"]["user_name"] = sn + self.db["user_name"] = sn + self.db["user_id"] = self.twitter.get_user(screen_name=sn).id + try: + self.db["utc_offset"] = f["time_zone"]["utc_offset"] + except KeyError: + self.db["utc_offset"] = -time.timezone + # Get twitter's supported languages and save them in a global variable + #so we won't call to this method once per session. + if len(application.supported_languages) == 0: + application.supported_languages = self.twitter.supported_languages() + self.get_lists() + self.get_muted_users() + self.settings.write() # @_require_login - def get_lists(self): - """ Gets the lists that the user is subscribed to and stores them in the database. Returns None.""" - self.db["lists"] = self.twitter.lists_all(reverse=True) + def get_lists(self): + """ Gets the lists that the user is subscribed to and stores them in the database. Returns None.""" + self.db["lists"] = self.twitter.lists_all(reverse=True) # @_require_login - def get_muted_users(self): - """ Gets muted users (oh really?).""" - self.db["muted_users"] = self.twitter.mutes_ids() + def get_muted_users(self): + """ Gets muted users (oh really?).""" + self.db["muted_users"] = self.twitter.mutes_ids() # @_require_login - def get_stream(self, name, function, *args, **kwargs): - """ Retrieves the items for a regular stream. - name str: Name to save items to the database. - function str: A function to get the items.""" - last_id = -1 - if name in self.db: - try: - if self.db[name][0]["id"] > self.db[name][-1]["id"]: - last_id = self.db[name][0]["id"] - else: - last_id = self.db[name][-1]["id"] - except IndexError: - pass - tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs) - self.order_buffer(name, tl) + def get_stream(self, name, function, *args, **kwargs): + """ Retrieves the items for a regular stream. + name str: Name to save items to the database. + function str: A function to get the items.""" + last_id = -1 + if name in self.db: + try: + if self.db[name][0]["id"] > self.db[name][-1]["id"]: + last_id = self.db[name][0]["id"] + else: + last_id = self.db[name][-1]["id"] + except IndexError: + pass + tl = self.call_paged(function, sinze_id=last_id, *args, **kwargs) + self.order_buffer(name, tl) - def get_cursored_stream(self, name, function, items="users", get_previous=False, *args, **kwargs): - """ Gets items for API calls that require using cursors to paginate the results. - name str: Name to save it in the database. - function str: Function that provides the items. - items: When the function returns the list with results, items will tell how the order function should be look. for example get_followers_list returns a list and users are under list["users"], here the items should point to "users". - get_previous bool: wether this function will be used to get previous items in a buffer or load the buffer from scratch. - returns number of items retrieved.""" - items_ = [] - try: - if "cursor" in self.db[name] and get_previous: - cursor = self.db[name]["cursor"] - else: - cursor = -1 - except KeyError: - cursor = -1 - if cursor != -1: - tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) - else: - tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) - tl[items].reverse() - num = self.order_cursored_buffer(name, tl[items]) - # Recently, Twitter's new endpoints have cursor if there are more results. - if "next_cursor" in tl: - self.db[name]["cursor"] = tl["next_cursor"] - else: - self.db[name]["cursor"] = 0 - return num + def get_cursored_stream(self, name, function, items="users", get_previous=False, *args, **kwargs): + """ Gets items for API calls that require using cursors to paginate the results. + name str: Name to save it in the database. + function str: Function that provides the items. + items: When the function returns the list with results, items will tell how the order function should be look. for example get_followers_list returns a list and users are under list["users"], here the items should point to "users". + get_previous bool: wether this function will be used to get previous items in a buffer or load the buffer from scratch. + returns number of items retrieved.""" + items_ = [] + try: + if "cursor" in self.db[name] and get_previous: + cursor = self.db[name]["cursor"] + else: + cursor = -1 + except KeyError: + cursor = -1 + if cursor != -1: + tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + else: + tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs) + tl[items].reverse() + num = self.order_cursored_buffer(name, tl[items]) + # Recently, Twitter's new endpoints have cursor if there are more results. + if "next_cursor" in tl: + self.db[name]["cursor"] = tl["next_cursor"] + else: + self.db[name]["cursor"] = 0 + return num - def check_connection(self): - """ Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities.""" - log.debug("Executing check connection...") - self.counter += 1 - if self.counter >= 4: - log.debug("Restarting connection after 5 minutes.") - del self.twitter - self.logged = False - self.login(False) - self.counter = 0 + def check_connection(self): + """ Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities.""" + log.debug("Executing check connection...") + self.counter += 1 + if self.counter >= 4: + log.debug("Restarting connection after 5 minutes.") + del self.twitter + self.logged = False + self.login(False) + self.counter = 0 - def check_quoted_status(self, tweet): - """ Helper for get_quoted_tweet. Get a quoted status inside a tweet and create a special tweet with all info available. - tweet dict: A tweet dictionary. - Returns a quoted tweet or the original tweet if is not a quote""" - status = tweets.is_long(tweet) - if status != False and config.app["app-settings"]["handle_longtweets"]: - quoted_tweet = self.get_quoted_tweet(tweet) - return quoted_tweet - return tweet + def check_quoted_status(self, tweet): + """ Helper for get_quoted_tweet. Get a quoted status inside a tweet and create a special tweet with all info available. + tweet dict: A tweet dictionary. + Returns a quoted tweet or the original tweet if is not a quote""" + status = tweets.is_long(tweet) + if status != False and config.app["app-settings"]["handle_longtweets"]: + quoted_tweet = self.get_quoted_tweet(tweet) + return quoted_tweet + return tweet - def get_quoted_tweet(self, tweet): - """ Process a tweet and extract all information related to the quote. """ - quoted_tweet = tweet - if hasattr(tweet, "full_text"): - value = "full_text" - else: - value = "text" - setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities)) - if quoted_tweet.is_quote_status == True and hasattr(quoted_tweet, "quoted_status"): - original_tweet = quoted_tweet.quoted_status - elif hasattr(quoted_tweet, "retweeted_status") and quoted_tweet.retweeted_status.is_quote_status == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"): - original_tweet = quoted_tweet.retweeted_status.quoted_status - else: - return quoted_tweet - original_tweet = self.check_long_tweet(original_tweet) - if hasattr(original_tweet, "full_text"): - value = "full_text" - elif hasattr(original_tweet, "message"): - value = "message" - else: - value = "text" - setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities)) - return compose.compose_quoted_tweet(quoted_tweet, original_tweet) + def get_quoted_tweet(self, tweet): + """ Process a tweet and extract all information related to the quote. """ + quoted_tweet = tweet + if hasattr(tweet, "full_text"): + value = "full_text" + else: + value = "text" + setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities)) + if quoted_tweet.is_quote_status == True and hasattr(quoted_tweet, "quoted_status"): + original_tweet = quoted_tweet.quoted_status + elif hasattr(quoted_tweet, "retweeted_status") and quoted_tweet.retweeted_status.is_quote_status == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"): + original_tweet = quoted_tweet.retweeted_status.quoted_status + else: + return quoted_tweet + original_tweet = self.check_long_tweet(original_tweet) + if hasattr(original_tweet, "full_text"): + value = "full_text" + elif hasattr(original_tweet, "message"): + value = "message" + else: + value = "text" + setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities)) + return compose.compose_quoted_tweet(quoted_tweet, original_tweet) - def check_long_tweet(self, tweet): - """ Process a tweet and add extra info if it's a long tweet made with Twyshort. - tweet dict: a tweet object. - returns a tweet with a new argument message, or original tweet if it's not a long tweet.""" - long = twishort.is_long(tweet) - if long != False and config.app["app-settings"]["handle_longtweets"]: - message = twishort.get_full_text(long) - if hasattr(tweet, "quoted_status"): - tweet.quoted_status.message = message - if tweet.quoted_status.message == False: return False - tweet.quoted_status.twishort = True - for i in tweet.quoted_status.entities["user_mentions"]: - if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != tweet.user.screen_name: - if hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: - continue - tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message) - else: - tweet.message = message - if tweet.message == False: return False - tweet.twishort = True - for i in tweet.entities["user_mentions"]: - if "@%s" % (i["screen_name"]) not in tweet.message and i["screen_name"] != tweet.user.screen_name: - if hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: - continue - return tweet + def check_long_tweet(self, tweet): + """ Process a tweet and add extra info if it's a long tweet made with Twyshort. + tweet dict: a tweet object. + returns a tweet with a new argument message, or original tweet if it's not a long tweet.""" + long = twishort.is_long(tweet) + if long != False and config.app["app-settings"]["handle_longtweets"]: + message = twishort.get_full_text(long) + if hasattr(tweet, "quoted_status"): + tweet.quoted_status.message = message + if tweet.quoted_status.message == False: return False + tweet.quoted_status.twishort = True + for i in tweet.quoted_status.entities["user_mentions"]: + if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != tweet.user.screen_name: + if hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: + continue + tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message) + else: + tweet.message = message + if tweet.message == False: return False + tweet.twishort = True + for i in tweet.entities["user_mentions"]: + if "@%s" % (i["screen_name"]) not in tweet.message and i["screen_name"] != tweet.user.screen_name: + if hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: + continue + return tweet - def get_user(self, id): - """ Returns an user object associated with an ID. - id str: User identifier, provided by Twitter. - returns a tweepy user object.""" - if ("users" in self.db) == False or (id in self.db["users"]) == False: - try: - user = self.twitter.get_user(id=id) - except TweepError as err: - user = UserModel(None) - user.screen_name = "deleted_user" - user.id = id - user.name = _("Deleted account") - user.id_str = id - self.db["users"][user.id_str] = user - return user - else: - return self.db["users"][id] + def get_user(self, id): + """ Returns an user object associated with an ID. + id str: User identifier, provided by Twitter. + returns a tweepy user object.""" + if ("users" in self.db) == False or (id in self.db["users"]) == False: + try: + user = self.twitter.get_user(id=id) + except TweepError as err: + user = UserModel(None) + user.screen_name = "deleted_user" + user.id = id + user.name = _("Deleted account") + user.id_str = id + self.db["users"][user.id_str] = user + return user + else: + return self.db["users"][id] - def get_user_by_screen_name(self, screen_name): - """ Returns an user identifier associated with a screen_name. - screen_name str: User name, such as tw_blue2, provided by Twitter. - returns an user ID.""" - if ("users" in self.db) == False: - user = utils.if_user_exists(self.twitter, screen_name) - self.db["users"][user["id_str"]] = user - return user["id_str"] - else: - for i in list(self.db["users"].keys()): - if self.db["users"][i].screen_name == screen_name: - return self.db["users"][i].id_str - user = utils.if_user_exists(self.twitter, screen_name) - self.db["users"][user.id_str] = user - return user.id_str + def get_user_by_screen_name(self, screen_name): + """ Returns an user identifier associated with a screen_name. + screen_name str: User name, such as tw_blue2, provided by Twitter. + returns an user ID.""" + if ("users" in self.db) == False: + user = utils.if_user_exists(self.twitter, screen_name) + self.db["users"][user["id_str"]] = user + return user["id_str"] + else: + for i in list(self.db["users"].keys()): + if self.db["users"][i].screen_name == screen_name: + return self.db["users"][i].id_str + user = utils.if_user_exists(self.twitter, screen_name) + self.db["users"][user.id_str] = user + return user.id_str - def save_users(self, user_ids): - """ Adds all new users to the users database. """ - if len(user_ids) == 0: - return - log.debug("Received %d user IDS to be added in the database." % (len(user_ids))) - users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]] - # Remove duplicates - users_to_retrieve = list(dict.fromkeys(users_to_retrieve)) - if len(users_to_retrieve) == 0: - return - log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) - users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") - for user in users: - self.db["users"][user.id_str] = user - log.debug("Added %d new users" % (len(users))) \ No newline at end of file + def save_users(self, user_ids): + """ Adds all new users to the users database. """ + if len(user_ids) == 0: + return + log.debug("Received %d user IDS to be added in the database." % (len(user_ids))) + users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]] + # Remove duplicates + users_to_retrieve = list(dict.fromkeys(users_to_retrieve)) + if len(users_to_retrieve) == 0: + return + log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) + users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") + for user in users: + self.db["users"][user.id_str] = user + log.debug("Added %d new users" % (len(users))) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 57e02f3a..2e44f21b 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -19,198 +19,198 @@ url_re2 = re.compile("(?:\w+://|www\.)[^ ,.?!#%=+][^ \\n\\t]*") bad_chars = '\'\\\n.,[](){}:;"' def find_urls_in_text(text): - return url_re2.findall(text) + return url_re2.findall(text) def find_urls (tweet): - urls = [] - # Let's add URLS from tweet entities. - if hasattr(tweet, "message_create"): - entities = tweet.message_create["message_data"]["entities"] - else: - entities = tweet.entities - for i in entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) - if hasattr(tweet, "quoted_status"): - for i in tweet.quoted_status.entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) - if hasattr(tweet, "retweeted_status"): - for i in tweet.retweeted_status.entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) - if hasattr(tweet["retweeted_status"], "quoted_status"): - for i in tweet.retweeted_status.quoted_status.entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) - if hasattr(tweet, "message"): - i = "message" - elif hasattr(tweet, "full_text"): - i = "full_text" - else: - i = "text" - if hasattr(tweet, "message_create"): - extracted_urls = find_urls_in_text(tweet.message_create["message_data"]["text"]) - else: - extracted_urls = find_urls_in_text(getattr(tweet, i)) - # Don't include t.co links (mostly they are photos or shortened versions of already added URLS). - for i in extracted_urls: - if i not in urls and "https://t.co" not in i: - urls.append(i) - return urls + urls = [] + # Let's add URLS from tweet entities. + if hasattr(tweet, "message_create"): + entities = tweet.message_create["message_data"]["entities"] + else: + entities = tweet.entities + for i in entities["urls"]: + if i["expanded_url"] not in urls: + urls.append(i["expanded_url"]) + if hasattr(tweet, "quoted_status"): + for i in tweet.quoted_status.entities["urls"]: + if i["expanded_url"] not in urls: + urls.append(i["expanded_url"]) + if hasattr(tweet, "retweeted_status"): + for i in tweet.retweeted_status.entities["urls"]: + if i["expanded_url"] not in urls: + urls.append(i["expanded_url"]) + if hasattr(tweet["retweeted_status"], "quoted_status"): + for i in tweet.retweeted_status.quoted_status.entities["urls"]: + if i["expanded_url"] not in urls: + urls.append(i["expanded_url"]) + if hasattr(tweet, "message"): + i = "message" + elif hasattr(tweet, "full_text"): + i = "full_text" + else: + i = "text" + if hasattr(tweet, "message_create"): + extracted_urls = find_urls_in_text(tweet.message_create["message_data"]["text"]) + else: + extracted_urls = find_urls_in_text(getattr(tweet, i)) + # Don't include t.co links (mostly they are photos or shortened versions of already added URLS). + for i in extracted_urls: + if i not in urls and "https://t.co" not in i: + urls.append(i) + return urls def find_item(id, listItem): - for i in range(0, len(listItem)): - if listItem[i].id == id: return i - return None + for i in range(0, len(listItem)): + if listItem[i].id == id: return i + return None def find_list(name, lists): - for i in range(0, len(lists)): - if lists[i].name == name: return lists[i].id + for i in range(0, len(lists)): + if lists[i].name == name: return lists[i].id def is_audio(tweet): - try: - if len(find_urls(tweet)) < 1: - return False - if hasattr(tweet, "message_create"): - entities = tweet.message_create["message_data"]["entities"] - else: - entities = tweet.entities - if len(entities["hashtags"]) > 0: - for i in entities["hashtags"]: - if i["text"] == "audio": - return True - except IndexError: - print(tweet.entities["hashtags"]) - log.exception("Exception while executing is_audio hashtag algorithm") + try: + if len(find_urls(tweet)) < 1: + return False + if hasattr(tweet, "message_create"): + entities = tweet.message_create["message_data"]["entities"] + else: + entities = tweet.entities + if len(entities["hashtags"]) > 0: + for i in entities["hashtags"]: + if i["text"] == "audio": + return True + except IndexError: + print(tweet.entities["hashtags"]) + log.exception("Exception while executing is_audio hashtag algorithm") def is_geocoded(tweet): - if hasattr(tweet, "coordinates") and tweet.coordinates != None: - return True + if hasattr(tweet, "coordinates") and tweet.coordinates != None: + return True def is_media(tweet): - if hasattr(tweet, "message_create"): - entities = tweet.message_create["message_data"]["entities"] - else: - entities = tweet.entities - if entities.get("media") == None: - return False - for i in entities["media"]: - if i.get("type") != None and i.get("type") == "photo": - return True - return False + if hasattr(tweet, "message_create"): + entities = tweet.message_create["message_data"]["entities"] + else: + entities = tweet.entities + if entities.get("media") == None: + return False + for i in entities["media"]: + if i.get("type") != None and i.get("type") == "photo": + return True + return False def get_all_mentioned(tweet, conf, field="screen_name"): - """ Gets all users that have been mentioned.""" - results = [] - for i in tweet.entities["user_mentions"]: - if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: - if i.get(field) not in results: - results.append(i.get(field)) - return results + """ Gets all users that have been mentioned.""" + results = [] + for i in tweet.entities["user_mentions"]: + if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: + if i.get(field) not in results: + results.append(i.get(field)) + return results def get_all_users(tweet, conf): - string = [] - if hasattr(tweet, "retweeted_status"): - string.append(tweet.user.screen_name) - tweet = tweet.retweeted_status - if hasattr(tweet, "sender"): - string.append(tweet.sender.screen_name) - else: - if tweet.user.screen_name != conf["user_name"]: - string.append(tweet.user.screen_name) - for i in tweet.entities["user_mentions"]: - if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: - if i["screen_name"] not in string: - string.append(i["screen_name"]) - if len(string) == 0: - string.append(tweet.user.screen_name) - return string + string = [] + if hasattr(tweet, "retweeted_status"): + string.append(tweet.user.screen_name) + tweet = tweet.retweeted_status + if hasattr(tweet, "sender"): + string.append(tweet.sender.screen_name) + else: + if tweet.user.screen_name != conf["user_name"]: + string.append(tweet.user.screen_name) + for i in tweet.entities["user_mentions"]: + if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: + if i["screen_name"] not in string: + string.append(i["screen_name"]) + if len(string) == 0: + string.append(tweet.user.screen_name) + return string def if_user_exists(twitter, user): - try: - data = twitter.get_user(screen_name=user) - return data - except TweepError as err: - if err.api_code == 50: - return None - else: - return user + try: + data = twitter.get_user(screen_name=user) + return data + except TweepError as err: + if err.api_code == 50: + return None + else: + return user def is_allowed(tweet, settings, buffer_name): - clients = settings["twitter"]["ignored_clients"] - if hasattr(tweet, "sender"): return True - allowed = True - tweet_data = {} - if hasattr(tweet, "retweeted_status"): - tweet_data["retweet"] = True - if tweet.in_reply_to_status_id_str != None: - tweet_data["reply"] = True - if hasattr(tweet, "quoted_status"): - tweet_data["quote"] = True - if hasattr(tweet, "retweeted_status"): - tweet = tweet.retweeted_status - source = tweet.source - for i in clients: - if i.lower() == source.lower(): - return False - return filter_tweet(tweet, tweet_data, settings, buffer_name) + clients = settings["twitter"]["ignored_clients"] + if hasattr(tweet, "sender"): return True + allowed = True + tweet_data = {} + if hasattr(tweet, "retweeted_status"): + tweet_data["retweet"] = True + if tweet.in_reply_to_status_id_str != None: + tweet_data["reply"] = True + if hasattr(tweet, "quoted_status"): + tweet_data["quote"] = True + if hasattr(tweet, "retweeted_status"): + tweet = tweet.retweeted_status + source = tweet.source + for i in clients: + if i.lower() == source.lower(): + return False + return filter_tweet(tweet, tweet_data, settings, buffer_name) def filter_tweet(tweet, tweet_data, settings, buffer_name): - if hasattr(tweet, "full_text"): - value = "full_text" - else: - value = "text" - for i in settings["filters"]: - if settings["filters"][i]["in_buffer"] == buffer_name: - regexp = settings["filters"][i]["regexp"] - word = settings["filters"][i]["word"] - # Added if/else for compatibility reasons. - if "allow_rts" in settings["filters"][i]: - allow_rts = settings["filters"][i]["allow_rts"] - else: - allow_rts = "True" - if "allow_quotes" in settings["filters"][i]: - allow_quotes = settings["filters"][i]["allow_quotes"] - else: - allow_quotes = "True" - if "allow_replies" in settings["filters"][i]: - allow_replies = settings["filters"][i]["allow_replies"] - else: - allow_replies = "True" - if allow_rts == "False" and "retweet" in tweet_data: - return False - if allow_quotes == "False" and "quote" in tweet_data: - return False - if allow_replies == "False" and "reply" in tweet_data: - return False - if word != "" and settings["filters"][i]["if_word_exists"]: - if word in getattr(tweet, value): - return False - elif word != "" and settings["filters"][i]["if_word_exists"] == False: - if word not in getattr(tweet, value): - return False - if settings["filters"][i]["in_lang"] == "True": - if getattr(tweet, lang) not in settings["filters"][i]["languages"]: - return False - elif settings["filters"][i]["in_lang"] == "False": - if tweet.lang in settings["filters"][i]["languages"]: - return False - return True + if hasattr(tweet, "full_text"): + value = "full_text" + else: + value = "text" + for i in settings["filters"]: + if settings["filters"][i]["in_buffer"] == buffer_name: + regexp = settings["filters"][i]["regexp"] + word = settings["filters"][i]["word"] + # Added if/else for compatibility reasons. + if "allow_rts" in settings["filters"][i]: + allow_rts = settings["filters"][i]["allow_rts"] + else: + allow_rts = "True" + if "allow_quotes" in settings["filters"][i]: + allow_quotes = settings["filters"][i]["allow_quotes"] + else: + allow_quotes = "True" + if "allow_replies" in settings["filters"][i]: + allow_replies = settings["filters"][i]["allow_replies"] + else: + allow_replies = "True" + if allow_rts == "False" and "retweet" in tweet_data: + return False + if allow_quotes == "False" and "quote" in tweet_data: + return False + if allow_replies == "False" and "reply" in tweet_data: + return False + if word != "" and settings["filters"][i]["if_word_exists"]: + if word in getattr(tweet, value): + return False + elif word != "" and settings["filters"][i]["if_word_exists"] == False: + if word not in getattr(tweet, value): + return False + if settings["filters"][i]["in_lang"] == "True": + if getattr(tweet, lang) not in settings["filters"][i]["languages"]: + return False + elif settings["filters"][i]["in_lang"] == "False": + if tweet.lang in settings["filters"][i]["languages"]: + return False + return True def twitter_error(error): - if error.api_code == 179: - msg = _(u"Sorry, you are not authorised to see this status.") - elif error.api_code == 144: - msg = _(u"No status found with that ID") - else: - msg = _(u"Error code {0}").format(error.api_code,) - output.speak(msg) + if error.api_code == 179: + msg = _(u"Sorry, you are not authorised to see this status.") + elif error.api_code == 144: + msg = _(u"No status found with that ID") + else: + msg = _(u"Error code {0}").format(error.api_code,) + output.speak(msg) def expand_urls(text, entities): - """ Expand all URLS present in text with information found in entities""" - urls = find_urls_in_text(text) - for url in entities["urls"]: - if url["url"] in text: - text = text.replace(url["url"], url["expanded_url"]) - return text + """ Expand all URLS present in text with information found in entities""" + urls = find_urls_in_text(text) + for url in entities["urls"]: + if url["url"] in text: + text = text.replace(url["url"], url["expanded_url"]) + return text diff --git a/src/sessions/twitter/wxUI.py b/src/sessions/twitter/wxUI.py index 787e6581..a765e72c 100644 --- a/src/sessions/twitter/wxUI.py +++ b/src/sessions/twitter/wxUI.py @@ -1,18 +1,18 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals import wx - + class authorisationDialog(wx.Dialog): - def __init__(self): - super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account...")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here")) - self.text = wx.TextCtrl(panel, -1) - self.ok = wx.Button(panel, wx.ID_OK) - self.cancel = wx.Button(panel, wx.ID_CANCEL) - sizer.Add(self.text, 0, wx.ALL, 5) - sizer.Add(self.cancel, 0, wx.ALL, 5) - panel.SetSizer(sizer) - min = sizer.CalcMin() - self.SetClientSize(min) \ No newline at end of file + def __init__(self): + super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account...")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here")) + self.text = wx.TextCtrl(panel, -1) + self.ok = wx.Button(panel, wx.ID_OK) + self.cancel = wx.Button(panel, wx.ID_CANCEL) + sizer.Add(self.text, 0, wx.ALL, 5) + sizer.Add(self.cancel, 0, wx.ALL, 5) + panel.SetSizer(sizer) + min = sizer.CalcMin() + self.SetClientSize(min) diff --git a/src/setup.py b/src/setup.py index 1a5b013a..c6043db8 100644 --- a/src/setup.py +++ b/src/setup.py @@ -7,44 +7,44 @@ from cx_Freeze import setup, Executable from requests import certs def get_architecture_files(): - if platform.architecture()[0][:2] == "32": - return ["../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", "../windows-dependencies/x86/libvlc.dll", "../windows-dependencies/x86/libvlccore.dll", "../windows-dependencies/x86/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell"], ["../windows-dependencies/x86/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFC", "."]] - elif platform.architecture()[0][:2] == "64": - return ["../windows-dependencies/x64/oggenc2.exe", "../windows-dependencies/x64/bootstrap.exe", "../windows-dependencies/x64/libvlc.dll", "../windows-dependencies/x64/libvlccore.dll", "../windows-dependencies/x64/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw64/share/enchant/hunspell"], ["../windows-dependencies/x64/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFC", "."]] + if platform.architecture()[0][:2] == "32": + return ["../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", "../windows-dependencies/x86/libvlc.dll", "../windows-dependencies/x86/libvlccore.dll", "../windows-dependencies/x86/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell"], ["../windows-dependencies/x86/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFC", "."]] + elif platform.architecture()[0][:2] == "64": + return ["../windows-dependencies/x64/oggenc2.exe", "../windows-dependencies/x64/bootstrap.exe", "../windows-dependencies/x64/libvlc.dll", "../windows-dependencies/x64/libvlccore.dll", "../windows-dependencies/x64/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw64/share/enchant/hunspell"], ["../windows-dependencies/x64/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFC", "."]] def find_sound_lib_datafiles(): - import os - import platform - import sound_lib - path = os.path.join(sound_lib.__path__[0], 'lib') - if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin': - arch = 'x86' - else: - arch = 'x64' - dest_dir = os.path.join('sound_lib', 'lib', arch) - source = os.path.join(path, arch) - return (source, dest_dir) + import os + import platform + import sound_lib + path = os.path.join(sound_lib.__path__[0], 'lib') + if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin': + arch = 'x86' + else: + arch = 'x64' + dest_dir = os.path.join('sound_lib', 'lib', arch) + source = os.path.join(path, arch) + return (source, dest_dir) def find_accessible_output2_datafiles(): - import os - import accessible_output2 - path = os.path.join(accessible_output2.__path__[0], 'lib') - dest_dir = os.path.join('accessible_output2', 'lib') - return (path, dest_dir) + import os + import accessible_output2 + path = os.path.join(accessible_output2.__path__[0], 'lib') + dest_dir = os.path.join('accessible_output2', 'lib') + return (path, dest_dir) base = None if sys.platform == 'win32': base = 'Win32GUI' build_exe_options = dict( - build_exe="dist", - optimize=1, - includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze. - include_msvcr=True, - replace_paths = [("*", "")], - include_files=["icon.ico", "conf.defaults", "app-configuration.defaults", "keymaps", "locales", "sounds", "documentation", ("keys/lib", "keys/lib"), find_sound_lib_datafiles(), find_accessible_output2_datafiles()]+get_architecture_files(), - packages=["wxUI"], - ) + build_exe="dist", + optimize=1, + includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze. + include_msvcr=True, + replace_paths = [("*", "")], + include_files=["icon.ico", "conf.defaults", "app-configuration.defaults", "keymaps", "locales", "sounds", "documentation", ("keys/lib", "keys/lib"), find_sound_lib_datafiles(), find_accessible_output2_datafiles()]+get_architecture_files(), + packages=["wxUI"], +) executables = [ Executable('main.py', base=base, targetName="twblue") diff --git a/src/sound.py b/src/sound.py index 859001c7..1cd8ad78 100644 --- a/src/sound.py +++ b/src/sound.py @@ -15,11 +15,11 @@ from audio_services import youtube_utils import application system = platform.system() if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from source on Windows - current_dir=os.getcwd() - os.chdir(os.environ['PYTHON_VLC_MODULE_PATH']) + current_dir=os.getcwd() + os.chdir(os.environ['PYTHON_VLC_MODULE_PATH']) import vlc if system=="Windows" and not hasattr(sys, 'frozen'): # Restore the original folder - os.chdir(current_dir) + os.chdir(current_dir) import sound_lib.output, sound_lib.input, sound_lib.stream, sound_lib.recording from mysc.repeating_timer import RepeatingTimer from mysc.thread_utils import call_threaded @@ -29,132 +29,132 @@ URLPlayer = None log = original_logger.getLogger("sound") def setup(): - global URLPlayer - if not URLPlayer: - log.debug("creating stream URL player...") - URLPlayer = URLStream() + global URLPlayer + if not URLPlayer: + log.debug("creating stream URL player...") + URLPlayer = URLStream() def recode_audio(filename, quality=4.5): - global system - if system == "Windows": subprocess.call(r'"%s" -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename)) + global system + if system == "Windows": subprocess.call(r'"%s" -q %r "%s"' % (os.path.join(paths.app_path(), 'oggenc2.exe'), quality, filename)) def recording(filename): -# try: - val = sound_lib.recording.WaveRecording(filename=filename) + # try: + val = sound_lib.recording.WaveRecording(filename=filename) # except sound_lib.main.BassError: # sound_lib.input.Input() # val = sound_lib.recording.WaveRecording(filename=filename) - return val + return val class soundSystem(object): - def check_soundpack(self): - """ Checks if the folder where live the current soundpack exists.""" - self.soundpack_OK = False - if os.path.exists(os.path.join(paths.sound_path(), self.config["current_soundpack"])): - self.path = os.path.join(paths.sound_path(), self.config["current_soundpack"]) - self.soundpack_OK = True - elif os.path.exists(os.path.join(paths.sound_path(), "default")): - log.error("The soundpack does not exist, using default...") - self.path = os.path.join(paths.sound_path(), "default") - self.soundpack_OK = True - else: - log.error("The current soundpack could not be found and the default soundpack has been deleted, " + application.name + " will not play sounds.") - self.soundpack_OK = False + def check_soundpack(self): + """ Checks if the folder where live the current soundpack exists.""" + self.soundpack_OK = False + if os.path.exists(os.path.join(paths.sound_path(), self.config["current_soundpack"])): + self.path = os.path.join(paths.sound_path(), self.config["current_soundpack"]) + self.soundpack_OK = True + elif os.path.exists(os.path.join(paths.sound_path(), "default")): + log.error("The soundpack does not exist, using default...") + self.path = os.path.join(paths.sound_path(), "default") + self.soundpack_OK = True + else: + log.error("The current soundpack could not be found and the default soundpack has been deleted, " + application.name + " will not play sounds.") + self.soundpack_OK = False - def __init__(self, soundConfig): - """ Sound Player.""" - self.config = soundConfig - # Set the output and input default devices. - try: - self.output = sound_lib.output.Output() - self.input = sound_lib.input.Input() - except: - pass - # Try to use the selected device from the configuration. It can fail if the machine does not has a mic. - try: - log.debug("Setting input and output devices...") - self.output.set_device(self.output.find_device_by_name(self.config["output_device"])) - self.input.set_device(self.input.find_device_by_name(self.config["input_device"])) - except: - log.error("Error in input or output devices, using defaults...") - self.config["output_device"] = "Default" - self.config["input_device"] = "Default" + def __init__(self, soundConfig): + """ Sound Player.""" + self.config = soundConfig + # Set the output and input default devices. + try: + self.output = sound_lib.output.Output() + self.input = sound_lib.input.Input() + except: + pass + # Try to use the selected device from the configuration. It can fail if the machine does not has a mic. + try: + log.debug("Setting input and output devices...") + self.output.set_device(self.output.find_device_by_name(self.config["output_device"])) + self.input.set_device(self.input.find_device_by_name(self.config["input_device"])) + except: + log.error("Error in input or output devices, using defaults...") + self.config["output_device"] = "Default" + self.config["input_device"] = "Default" - self.files = [] - self.cleaner = RepeatingTimer(60, self.clear_list) - self.cleaner.start() - self.check_soundpack() + self.files = [] + self.cleaner = RepeatingTimer(60, self.clear_list) + self.cleaner.start() + self.check_soundpack() - def clear_list(self): - if len(self.files) == 0: return - try: - for i in range(0, len(self.files)): - if self.files[i].is_playing == False: - self.files[i].free() - self.files.pop(i) - except IndexError: - pass + def clear_list(self): + if len(self.files) == 0: return + try: + for i in range(0, len(self.files)): + if self.files[i].is_playing == False: + self.files[i].free() + self.files.pop(i) + except IndexError: + pass - def play(self, sound, argument=False): - if self.soundpack_OK == False: return - if self.config["session_mute"] == True: return - sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound)) - sound_object.volume = float(self.config["volume"]) - self.files.append(sound_object) - sound_object.play() + def play(self, sound, argument=False): + if self.soundpack_OK == False: return + if self.config["session_mute"] == True: return + sound_object = sound_lib.stream.FileStream(file="%s/%s" % (self.path, sound)) + sound_object.volume = float(self.config["volume"]) + self.files.append(sound_object) + sound_object.play() class URLStream(object): - """ URL Stream Player implementation.""" + """ URL Stream Player implementation.""" - def __init__(self): - # URL status. Should be True after URL expansion and transformation. - self.prepared = False - log.debug("URL Player initialized") - # LibVLC controls. - self.instance = vlc.Instance() - self.player = self.instance.media_player_new() + def __init__(self): + # URL status. Should be True after URL expansion and transformation. + self.prepared = False + log.debug("URL Player initialized") + # LibVLC controls. + self.instance = vlc.Instance() + self.player = self.instance.media_player_new() - def prepare(self, url): - """ Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL.""" - log.debug("Preparing URL: %s" % (url,)) - self.prepared = False - self.url = url_shortener.unshorten(url) - if self.url == None: - self.url = url - log.debug("Expanded URL: %s" % (self.url,)) - if self.url != None: - transformer = audio_services.find_url_transformer(self.url) - transformed_url = transformer(self.url) - self.url = transformed_url - log.debug("Transformed URL: %s. Prepared" % (self.url,)) - self.prepared = True + def prepare(self, url): + """ Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL.""" + log.debug("Preparing URL: %s" % (url,)) + self.prepared = False + self.url = url_shortener.unshorten(url) + if self.url == None: + self.url = url + log.debug("Expanded URL: %s" % (self.url,)) + if self.url != None: + transformer = audio_services.find_url_transformer(self.url) + transformed_url = transformer(self.url) + self.url = transformed_url + log.debug("Transformed URL: %s. Prepared" % (self.url,)) + self.prepared = True - def seek(self, step): - pos=self.player.get_time() - pos+=step - pos=self.player.set_time(pos) + def seek(self, step): + pos=self.player.get_time() + pos+=step + pos=self.player.set_time(pos) - def playpause(self): - if self.player.is_playing() == True: - self.player.pause() - else: - self.player.play() + def playpause(self): + if self.player.is_playing() == True: + self.player.pause() + else: + self.player.play() - def play(self, url=None, volume=1.0, announce=True): - if announce: - output.speak(_(u"Playing...")) - log.debug("Attempting to play an URL...") - if url != None: - self.prepare(url) - if self.prepared == True: - media = self.instance.media_new(self.url) - self.player.set_media(media) - self.player.audio_set_volume(int(volume*100)) - self.player.play() - log.debug("played") - self.prepared=False + def play(self, url=None, volume=1.0, announce=True): + if announce: + output.speak(_(u"Playing...")) + log.debug("Attempting to play an URL...") + if url != None: + self.prepare(url) + if self.prepared == True: + media = self.instance.media_new(self.url) + self.player.set_media(media) + self.player.audio_set_volume(int(volume*100)) + self.player.play() + log.debug("played") + self.prepared=False - def stop_audio(self): - output.speak(_(u"Stopped."), True) - self.player.stop() + def stop_audio(self): + output.speak(_(u"Stopped."), True) + self.player.stop() diff --git a/src/update/__init__.py b/src/update/__init__.py index 3c5275a4..443025e3 100644 --- a/src/update/__init__.py +++ b/src/update/__init__.py @@ -4,10 +4,10 @@ import os.path import platform def find_datafiles(): - system = platform.system() - if system == 'Windows': - file_ext = '*.exe' - else: - file_ext = '*.sh' - path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext)) - return [('', glob.glob(path))] + system = platform.system() + if system == 'Windows': + file_ext = '*.exe' + else: + file_ext = '*.sh' + path = os.path.abspath(os.path.join(__path__[0], 'bootstrappers', file_ext)) + return [('', glob.glob(path))] diff --git a/src/update/update.py b/src/update/update.py index ce5cfced..64bfd7de 100644 --- a/src/update/update.py +++ b/src/update/update.py @@ -12,116 +12,116 @@ from wxUI import commonMessageDialogs import widgetUtils import webbrowser try: - import czipfile as zipfile + import czipfile as zipfile except ImportError: - import zipfile + import zipfile from platform_utils import paths def perform_update(endpoint, current_version, app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None): - requests_session = create_requests_session(app_name=app_name, version=current_version) - available_update = find_update(endpoint, requests_session=requests_session) - if not available_update: - logger.debug("No update available") - return False - available_version = float(available_update['current_version']) - if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: - logger.debug("No update for this architecture") - return False - available_description = available_update.get('description', None) - available_date = available_update.get('date', None) - update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] - logger.info("A new update is available. Version %s" % available_version) - donation() - if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description, date=available_date): #update_available_callback should return a falsy value to stop the process - logger.info("User canceled update.") - return - base_path = tempfile.mkdtemp() - download_path = os.path.join(base_path, 'update.zip') - update_path = os.path.join(base_path, 'update') - downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback) - extracted = extract_update(downloaded, update_path, password=password) - bootstrap_path = move_bootstrap(extracted) - execute_bootstrap(bootstrap_path, extracted) - logger.info("Update prepared for installation.") - if callable(update_complete_callback): - update_complete_callback() + requests_session = create_requests_session(app_name=app_name, version=current_version) + available_update = find_update(endpoint, requests_session=requests_session) + if not available_update: + logger.debug("No update available") + return False + available_version = float(available_update['current_version']) + if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: + logger.debug("No update for this architecture") + return False + available_description = available_update.get('description', None) + available_date = available_update.get('date', None) + update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] + logger.info("A new update is available. Version %s" % available_version) + donation() + if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description, date=available_date): #update_available_callback should return a falsy value to stop the process + logger.info("User canceled update.") + return + base_path = tempfile.mkdtemp() + download_path = os.path.join(base_path, 'update.zip') + update_path = os.path.join(base_path, 'update') + downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback) + extracted = extract_update(downloaded, update_path, password=password) + bootstrap_path = move_bootstrap(extracted) + execute_bootstrap(bootstrap_path, extracted) + logger.info("Update prepared for installation.") + if callable(update_complete_callback): + update_complete_callback() def create_requests_session(app_name=None, version=None): - user_agent = '' - session = requests.session() - if app_name: - user_agent = ' %s/%r' % (app_name, version) - session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent - return session + user_agent = '' + session = requests.session() + if app_name: + user_agent = ' %s/%r' % (app_name, version) + session.headers['User-Agent'] = session.headers['User-Agent'] + user_agent + return session def find_update(endpoint, requests_session): - response = requests_session.get(endpoint) - response.raise_for_status() - content = response.json() - return content + response = requests_session.get(endpoint) + response.raise_for_status() + content = response.json() + return content def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE): - total_downloaded = total_size = 0 - with io.open(update_destination, 'w+b') as outfile: - download = requests_session.get(update_url, stream=True) - total_size = int(download.headers.get('content-length', 0)) - logger.debug("Total update size: %d" % total_size) - download.raise_for_status() - for chunk in download.iter_content(chunk_size): - outfile.write(chunk) - total_downloaded += len(chunk) - if callable(progress_callback): - call_callback(progress_callback, total_downloaded, total_size) - logger.debug("Update downloaded") - return update_destination + total_downloaded = total_size = 0 + with io.open(update_destination, 'w+b') as outfile: + download = requests_session.get(update_url, stream=True) + total_size = int(download.headers.get('content-length', 0)) + logger.debug("Total update size: %d" % total_size) + download.raise_for_status() + for chunk in download.iter_content(chunk_size): + outfile.write(chunk) + total_downloaded += len(chunk) + if callable(progress_callback): + call_callback(progress_callback, total_downloaded, total_size) + logger.debug("Update downloaded") + return update_destination def extract_update(update_archive, destination, password=None): - """Given an update archive, extracts it. Returns the directory to which it has been extracted""" - with contextlib.closing(zipfile.ZipFile(update_archive)) as archive: - if password: - archive.setpassword(password) - archive.extractall(path=destination) - logger.debug("Update extracted") - return destination + """Given an update archive, extracts it. Returns the directory to which it has been extracted""" + with contextlib.closing(zipfile.ZipFile(update_archive)) as archive: + if password: + archive.setpassword(password) + archive.extractall(path=destination) + logger.debug("Update extracted") + return destination def move_bootstrap(extracted_path): - working_path = os.path.abspath(os.path.join(extracted_path, '..')) - if platform.system() == 'Darwin': - extracted_path = os.path.join(extracted_path, 'Contents', 'Resources') - downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name()) - new_bootstrap_path = os.path.join(working_path, bootstrap_name()) - os.rename(downloaded_bootstrap, new_bootstrap_path) - return new_bootstrap_path + working_path = os.path.abspath(os.path.join(extracted_path, '..')) + if platform.system() == 'Darwin': + extracted_path = os.path.join(extracted_path, 'Contents', 'Resources') + downloaded_bootstrap = os.path.join(extracted_path, bootstrap_name()) + new_bootstrap_path = os.path.join(working_path, bootstrap_name()) + os.rename(downloaded_bootstrap, new_bootstrap_path) + return new_bootstrap_path def execute_bootstrap(bootstrap_path, source_path): - arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable()) - if platform.system() == 'Windows': - import win32api - win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5) - else: - import subprocess - make_executable(bootstrap_path) - subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True) - logger.info("Bootstrap executed") + arguments = r'"%s" "%s" "%s" "%s"' % (os.getpid(), source_path, paths.app_path(), paths.get_executable()) + if platform.system() == 'Windows': + import win32api + win32api.ShellExecute(0, 'open', bootstrap_path, arguments, '', 5) + else: + import subprocess + make_executable(bootstrap_path) + subprocess.Popen(['%s %s' % (bootstrap_path, arguments)], shell=True) + logger.info("Bootstrap executed") def bootstrap_name(): - if platform.system() == 'Windows': return 'bootstrap.exe' - if platform.system() == 'Darwin': return 'bootstrap-mac.sh' - return 'bootstrap-lin.sh' + if platform.system() == 'Windows': return 'bootstrap.exe' + if platform.system() == 'Darwin': return 'bootstrap-mac.sh' + return 'bootstrap-lin.sh' def make_executable(path): - import stat - st = os.stat(path) - os.chmod(path, st.st_mode | stat.S_IEXEC) + import stat + st = os.stat(path) + os.chmod(path, st.st_mode | stat.S_IEXEC) def call_callback(callback, *args, **kwargs): -# try: - callback(*args, **kwargs) + # try: + callback(*args, **kwargs) # except: # logger.exception("Failed calling callback %r with args %r and kwargs %r" % (callback, args, kwargs)) def donation(): - dlg = commonMessageDialogs.donation() - if dlg == widgetUtils.YES: - webbrowser.open_new_tab("http://twblue.es/?q=donate") \ No newline at end of file + dlg = commonMessageDialogs.donation() + if dlg == widgetUtils.YES: + webbrowser.open_new_tab("http://twblue.es/?q=donate") diff --git a/src/update/updater.py b/src/update/updater.py index 9cc20af2..2bef784b 100644 --- a/src/update/updater.py +++ b/src/update/updater.py @@ -11,13 +11,13 @@ from .wxUpdater import * logger = logging.getLogger("updater") def do_update(endpoint=application.update_url): - try: - result = update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished) - except: - if endpoint == application.update_url: - logger.error("Update failed! Using mirror URL...") - return do_update(endpoint=application.mirror_update_url) - else: - logger.exception("Update failed.") - output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True) - return result \ No newline at end of file + try: + result = update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished) + except: + if endpoint == application.update_url: + logger.error("Update failed! Using mirror URL...") + return do_update(endpoint=application.mirror_update_url) + else: + logger.exception("Update failed.") + output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True) + return result diff --git a/src/update/utils.py b/src/update/utils.py index 9ec89156..c9bbdc9a 100644 --- a/src/update/utils.py +++ b/src/update/utils.py @@ -3,42 +3,42 @@ from __future__ import unicode_literals from builtins import str def convert_bytes(n): - K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 - if n >= P: - return '%.2fPb' % (float(n) / T) - elif n >= T: - return '%.2fTb' % (float(n) / T) - elif n >= G: - return '%.2fGb' % (float(n) / G) - elif n >= M: - return '%.2fMb' % (float(n) / M) - elif n >= K: - return '%.2fKb' % (float(n) / K) - else: - return '%d' % n + K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 + if n >= P: + return '%.2fPb' % (float(n) / T) + elif n >= T: + return '%.2fTb' % (float(n) / T) + elif n >= G: + return '%.2fGb' % (float(n) / G) + elif n >= M: + return '%.2fMb' % (float(n) / M) + elif n >= K: + return '%.2fKb' % (float(n) / K) + else: + return '%d' % n def seconds_to_string(seconds, precision=0): - day = seconds // 86400 - hour = seconds // 3600 - min = (seconds // 60) % 60 - sec = seconds - (hour * 3600) - (min * 60) - sec_spec = "." + str(precision) + "f" - sec_string = sec.__format__(sec_spec) - string = "" - if day == 1: - string += _(u"%d day, ") % day - elif day >= 2: - string += _(u"%d days, ") % day - if (hour == 1): - string += _(u"%d hour, ") % hour - elif (hour >= 2): - string += _("%d hours, ") % hour - if (min == 1): - string += _(u"%d minute, ") % min - elif (min >= 2): - string += _(u"%d minutes, ") % min - if sec >= 0 and sec <= 2: - string += _(u"%s second") % sec_string - else: - string += _(u"%s seconds") % sec_string - return string \ No newline at end of file + day = seconds // 86400 + hour = seconds // 3600 + min = (seconds // 60) % 60 + sec = seconds - (hour * 3600) - (min * 60) + sec_spec = "." + str(precision) + "f" + sec_string = sec.__format__(sec_spec) + string = "" + if day == 1: + string += _(u"%d day, ") % day + elif day >= 2: + string += _(u"%d days, ") % day + if (hour == 1): + string += _(u"%d hour, ") % hour + elif (hour >= 2): + string += _("%d hours, ") % hour + if (min == 1): + string += _(u"%d minute, ") % min + elif (min >= 2): + string += _(u"%d minutes, ") % min + if sec >= 0 and sec <= 2: + string += _(u"%s second") % sec_string + else: + string += _(u"%s seconds") % sec_string + return string diff --git a/src/update/wxUpdater.py b/src/update/wxUpdater.py index 437e0a41..6ba6fd2a 100644 --- a/src/update/wxUpdater.py +++ b/src/update/wxUpdater.py @@ -11,25 +11,25 @@ from . import utils progress_dialog = None def available_update_dialog(version, description, date): - dialog = wx.MessageDialog(None, _(u"There's a new %s version available, released on %s. Would you like to download it now?\n\n %s version: %s\n\nChanges:\n%s") % (application.name, date, application.name, version, description), _(u"New version for %s") % application.name, style=wx.YES|wx.NO|wx.ICON_WARNING) - if dialog.ShowModal() == wx.ID_YES: - return True - else: - return False + dialog = wx.MessageDialog(None, _(u"There's a new %s version available, released on %s. Would you like to download it now?\n\n %s version: %s\n\nChanges:\n%s") % (application.name, date, application.name, version, description), _(u"New version for %s") % application.name, style=wx.YES|wx.NO|wx.ICON_WARNING) + if dialog.ShowModal() == wx.ID_YES: + return True + else: + return False def create_progress_dialog(): - return wx.ProgressDialog(_(u"Download in Progress"), _(u"Downloading the new version..."), parent=None, maximum=100) + return wx.ProgressDialog(_(u"Download in Progress"), _(u"Downloading the new version..."), parent=None, maximum=100) def progress_callback(total_downloaded, total_size): - global progress_dialog - if progress_dialog == None: - progress_dialog = create_progress_dialog() - progress_dialog.Show() - if total_downloaded == total_size: - progress_dialog.Destroy() - else: - progress_dialog.Update(old_div((total_downloaded*100),total_size), _(u"Updating... %s of %s") % (str(utils.convert_bytes(total_downloaded)), str(utils.convert_bytes(total_size)))) + global progress_dialog + if progress_dialog == None: + progress_dialog = create_progress_dialog() + progress_dialog.Show() + if total_downloaded == total_size: + progress_dialog.Destroy() + else: + progress_dialog.Update(old_div((total_downloaded*100),total_size), _(u"Updating... %s of %s") % (str(utils.convert_bytes(total_downloaded)), str(utils.convert_bytes(total_size)))) def update_finished(): - ms = wx.MessageDialog(None, _(u"The update has been downloaded and installed successfully. Press OK to continue."), _(u"Done!")).ShowModal() \ No newline at end of file + ms = wx.MessageDialog(None, _(u"The update has been downloaded and installed successfully. Press OK to continue."), _(u"Done!")).ShowModal() diff --git a/src/url_shortener/__main__.py b/src/url_shortener/__main__.py index 51ccf8d8..7e3dcf05 100644 --- a/src/url_shortener/__main__.py +++ b/src/url_shortener/__main__.py @@ -4,43 +4,43 @@ from . import shorteners def service_selecter (func): - @wraps(func) - def wrapper (*args, **kwargs): - tmp = dict(kwargs) - if 'service' in tmp: - del(tmp['service']) - kwargs['service'] = find_service(kwargs['service'], **tmp) or default_service() - else: - kwargs['service'] = default_service() - return func(*args, **kwargs) - return wrapper + @wraps(func) + def wrapper (*args, **kwargs): + tmp = dict(kwargs) + if 'service' in tmp: + del(tmp['service']) + kwargs['service'] = find_service(kwargs['service'], **tmp) or default_service() + else: + kwargs['service'] = default_service() + return func(*args, **kwargs) + return wrapper @service_selecter def shorten (url, service=None, **kwargs): - return service(**kwargs).shorten(url) + return service(**kwargs).shorten(url) @service_selecter def unshorten (url, service=None, **kwargs): - return service(**kwargs).unshorten(url) + return service(**kwargs).unshorten(url) def default_service (): - return shorteners.AcortameShortener + return shorteners.AcortameShortener def find_service (service, **kwargs): - for i in shorteners.__all__: - obj = getattr(shorteners, i)(**kwargs) - if obj.name.lower() == service.lower(): - return getattr(shorteners, i) + for i in shorteners.__all__: + obj = getattr(shorteners, i)(**kwargs) + if obj.name.lower() == service.lower(): + return getattr(shorteners, i) def list_services (): - return [getattr(shorteners, i)().name for i in shorteners.__all__] + return [getattr(shorteners, i)().name for i in shorteners.__all__] def unshorten_any (url): - """Unshortens an URL using any available unshortener. Check to see if unshortened URL was created by a shortener (nested) and unshorten if so.""" - unshortened_url = shorteners.URLShortener().unshorten(url) - # None is returned if URL not unshortened - if unshortened_url: - return unshorten_any(unshortened_url) - return url + """Unshortens an URL using any available unshortener. Check to see if unshortened URL was created by a shortener (nested) and unshorten if so.""" + unshortened_url = shorteners.URLShortener().unshorten(url) + # None is returned if URL not unshortened + if unshortened_url: + return unshorten_any(unshortened_url) + return url diff --git a/src/url_shortener/shorteners/acortame.py b/src/url_shortener/shorteners/acortame.py index fda92ce5..e7adafb6 100644 --- a/src/url_shortener/shorteners/acortame.py +++ b/src/url_shortener/shorteners/acortame.py @@ -5,26 +5,26 @@ from . url_shortener import URLShortener import requests import urllib.request, urllib.parse, urllib.error class AcortameShortener (URLShortener): - def __init__(self, *args, **kwargs): - self.name = "acorta.me" - super(AcortameShortener, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + self.name = "acorta.me" + super(AcortameShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("https://acorta.me/api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("https://acorta.me/api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'acorta.me' in url + def created_url (self, url): + return 'acorta.me' in url - def unshorten (self, url): - if not 'acorta.me' in url: - #use generic expand method - return super(AcortameShortener, self).unshorten(url) - answer = url - api = requests.get ("https://acorta.me/api.php?action=expand&format=simple&shorturl=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def unshorten (self, url): + if not 'acorta.me' in url: + #use generic expand method + return super(AcortameShortener, self).unshorten(url) + answer = url + api = requests.get ("https://acorta.me/api.php?action=expand&format=simple&shorturl=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer diff --git a/src/url_shortener/shorteners/clckru.py b/src/url_shortener/shorteners/clckru.py index 9d6ce136..9c527ea1 100644 --- a/src/url_shortener/shorteners/clckru.py +++ b/src/url_shortener/shorteners/clckru.py @@ -7,16 +7,16 @@ from . url_shortener import URLShortener class ClckruShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "clck.ru" - super(ClckruShortener, self).__init__(*args, **kwargs) + def __init__ (self, *args, **kwargs): + self.name = "clck.ru" + super(ClckruShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("http://clck.ru/--?url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("http://clck.ru/--?url=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'clck.ru' in url + def created_url (self, url): + return 'clck.ru' in url diff --git a/src/url_shortener/shorteners/hkcim.py b/src/url_shortener/shorteners/hkcim.py index 43b4d608..29ecd9ea 100644 --- a/src/url_shortener/shorteners/hkcim.py +++ b/src/url_shortener/shorteners/hkcim.py @@ -6,16 +6,16 @@ import requests from . url_shortener import URLShortener class HKCShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "HKC.im" - super(HKCShortener, self).__init__(*args, **kwargs) + def __init__ (self, *args, **kwargs): + self.name = "HKC.im" + super(HKCShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'hkc.im' in url.lower() + def created_url (self, url): + return 'hkc.im' in url.lower() diff --git a/src/url_shortener/shorteners/isgd.py b/src/url_shortener/shorteners/isgd.py index 006089de..ee817360 100644 --- a/src/url_shortener/shorteners/isgd.py +++ b/src/url_shortener/shorteners/isgd.py @@ -7,16 +7,16 @@ from . url_shortener import URLShortener class IsgdShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "Is.gd" - super(IsgdShortener, self).__init__(*args, **kwargs) + def __init__ (self, *args, **kwargs): + self.name = "Is.gd" + super(IsgdShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("http://is.gd/api.php?longurl=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("http://is.gd/api.php?longurl=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'is.gd' in url + def created_url (self, url): + return 'is.gd' in url diff --git a/src/url_shortener/shorteners/onjme.py b/src/url_shortener/shorteners/onjme.py index c2da3043..c6a21315 100644 --- a/src/url_shortener/shorteners/onjme.py +++ b/src/url_shortener/shorteners/onjme.py @@ -6,16 +6,16 @@ import requests from . url_shortener import URLShortener class OnjmeShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "Onj.me" - super(OnjmeShortener, self).__init__(*args, **kwargs) + def __init__ (self, *args, **kwargs): + self.name = "Onj.me" + super(OnjmeShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'onj.me' in url.lower() + def created_url (self, url): + return 'onj.me' in url.lower() diff --git a/src/url_shortener/shorteners/tinyarrows.py b/src/url_shortener/shorteners/tinyarrows.py index a544d7be..45a8990c 100644 --- a/src/url_shortener/shorteners/tinyarrows.py +++ b/src/url_shortener/shorteners/tinyarrows.py @@ -6,16 +6,16 @@ import requests from . url_shortener import URLShortener class TinyArrowsShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "TinyArro.ws" - super(TinyArrowsShortener, self).__init__(*args, **kwargs) + def __init__ (self, *args, **kwargs): + self.name = "TinyArro.ws" + super(TinyArrowsShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer.decode('UTF-8') + def _shorten (self, url): + answer = url + api = requests.get("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer.decode('UTF-8') - def created_url(self, url): - return "tinyarro.ws" in url + def created_url(self, url): + return "tinyarro.ws" in url diff --git a/src/url_shortener/shorteners/tinyurl.py b/src/url_shortener/shorteners/tinyurl.py index a762ff4e..0a5703a3 100644 --- a/src/url_shortener/shorteners/tinyurl.py +++ b/src/url_shortener/shorteners/tinyurl.py @@ -5,16 +5,16 @@ from .url_shortener import URLShortener import requests import urllib.request, urllib.parse, urllib.error class TinyurlShortener (URLShortener): - def __init__(self, *args, **kwargs): - self.name = "TinyURL.com" - super(TinyurlShortener, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + self.name = "TinyURL.com" + super(TinyurlShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("http://tinyurl.com/api-create.php?url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("http://tinyurl.com/api-create.php?url=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'tinyurl.com' in url + def created_url (self, url): + return 'tinyurl.com' in url diff --git a/src/url_shortener/shorteners/url_shortener.py b/src/url_shortener/shorteners/url_shortener.py index dad0e355..cf1d6f76 100644 --- a/src/url_shortener/shorteners/url_shortener.py +++ b/src/url_shortener/shorteners/url_shortener.py @@ -4,41 +4,41 @@ import requests class URLShortener (object): - def __init__ (self, *args, **kwargs): - #Stub out arguments, silly object. :( - return super(URLShortener, self).__init__() + def __init__ (self, *args, **kwargs): + #Stub out arguments, silly object. :( + return super(URLShortener, self).__init__() - def shorten (self, url): - if self.created_url(url): - return url - else: - return self._shorten(url) + def shorten (self, url): + if self.created_url(url): + return url + else: + return self._shorten(url) - def _shorten (self, url): - raise NotImplementedError + def _shorten (self, url): + raise NotImplementedError - def created_url (self, url): - """Returns a boolean indicating whether or not this shortener created a provided url""" - raise NotImplementedError + def created_url (self, url): + """Returns a boolean indicating whether or not this shortener created a provided url""" + raise NotImplementedError - def unshorten(self, url): - try: - r=requests.head(url) - if 'location' in list(r.headers.keys()): - if 'dropbox.com' in r.headers['location']: - return handle_dropbox(r.headers['location']) - else: - return r.headers['location'] - else: # if the head method does not work, use get instead. Performance may decrease - r=requests.get(url, allow_redirects=False, stream=True) - # release the connection without downloading the content, we only need the response headers - r.close() - return r.headers['location'] - except: - return url #we cannot expand + def unshorten(self, url): + try: + r=requests.head(url) + if 'location' in list(r.headers.keys()): + if 'dropbox.com' in r.headers['location']: + return handle_dropbox(r.headers['location']) + else: + return r.headers['location'] + else: # if the head method does not work, use get instead. Performance may decrease + r=requests.get(url, allow_redirects=False, stream=True) + # release the connection without downloading the content, we only need the response headers + r.close() + return r.headers['location'] + except: + return url #we cannot expand def handle_dropbox(url): - if url.endswith("dl=1"): - return url - else: - return url.replace("dl=0", "dl=1") + if url.endswith("dl=1"): + return url + else: + return url.replace("dl=0", "dl=1") diff --git a/src/url_shortener/shorteners/xedcc.py b/src/url_shortener/shorteners/xedcc.py index 8b2d2fb5..117b4f7c 100644 --- a/src/url_shortener/shorteners/xedcc.py +++ b/src/url_shortener/shorteners/xedcc.py @@ -6,16 +6,16 @@ import requests from . url_shortener import URLShortener class XedccShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "Xed.cc" - super(XedccShortener, self).__init__(*args, **kwargs) + def __init__ (self, *args, **kwargs): + self.name = "Xed.cc" + super(XedccShortener, self).__init__(*args, **kwargs) - def _shorten (self, url): - answer = url - api = requests.get ("http://xed.cc/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer + def _shorten (self, url): + answer = url + api = requests.get ("http://xed.cc/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) + if api.status_code == 200: + answer = api.text + return answer - def created_url (self, url): - return 'xed.cc' in url.lower() + def created_url (self, url): + return 'xed.cc' in url.lower() diff --git a/src/widgetUtils/__init__.py b/src/widgetUtils/__init__.py index 86202b09..8c88f5ee 100644 --- a/src/widgetUtils/__init__.py +++ b/src/widgetUtils/__init__.py @@ -2,6 +2,6 @@ from __future__ import absolute_import from __future__ import unicode_literals import platform if platform.system() == "Windows": - from .wxUtils import * + from .wxUtils import * #elif platform.system() == "Linux": # from gtkUtils import * diff --git a/src/widgetUtils/gtkUtils.py b/src/widgetUtils/gtkUtils.py index bec88129..6902d324 100644 --- a/src/widgetUtils/gtkUtils.py +++ b/src/widgetUtils/gtkUtils.py @@ -31,116 +31,116 @@ MENU = "activate" CHECKBOX = "toggled" def exit_application(): - """ Closes the current window cleanly. """ - Gtk.main_quit() + """ Closes the current window cleanly. """ + Gtk.main_quit() def connect_event(parent, event, func, menuitem=None, *args, **kwargs): - """ Connects an event to a function. - parent Gtk.widget: The widget that will listen for the event. - event widgetUtils.event: The event that will be listened for the parent. The event should be one of the widgetUtils events. - function func: The function that will be connected to the event.""" - if menuitem == None: - return getattr(parent, "connect")(event, func, *args, **kwargs) - else: - return getattr(menuitem, "connect")(event, func, *args, **kwargs) + """ Connects an event to a function. + parent Gtk.widget: The widget that will listen for the event. + event widgetUtils.event: The event that will be listened for the parent. The event should be one of the widgetUtils events. + function func: The function that will be connected to the event.""" + if menuitem == None: + return getattr(parent, "connect")(event, func, *args, **kwargs) + else: + return getattr(menuitem, "connect")(event, func, *args, **kwargs) class list(object): - def __init__(self, *columns, **listArguments): - self.columns = columns - self.list_arguments = listArguments - self.create_list() + def __init__(self, *columns, **listArguments): + self.columns = columns + self.list_arguments = listArguments + self.create_list() - def create_list(self): - columns = [] - [columns.append(str) for i in self.columns] - self.store = Gtk.ListStore(*columns) - self.list = Gtk.TreeView(model=self.store) - renderer = Gtk.CellRendererText() - for i in range(0, len(self.columns)): - column = Gtk.TreeViewColumn(self.columns[i], renderer, text=i) + def create_list(self): + columns = [] + [columns.append(str) for i in self.columns] + self.store = Gtk.ListStore(*columns) + self.list = Gtk.TreeView(model=self.store) + renderer = Gtk.CellRendererText() + for i in range(0, len(self.columns)): + column = Gtk.TreeViewColumn(self.columns[i], renderer, text=i) # column.set_sort_column_id(i) - self.list.append_column(column) + self.list.append_column(column) - def insert_item(self, reversed=False, *item): - if reversed == False: - self.store.append(row=item) - else: - self.store.insert(position=0, row=item) + def insert_item(self, reversed=False, *item): + if reversed == False: + self.store.append(row=item) + else: + self.store.insert(position=0, row=item) - def get_selected(self): - tree_selection = self.list.get_selection() - (model, pathlist) = tree_selection.get_selected_rows() - return int(pathlist[0].to_string() ) + def get_selected(self): + tree_selection = self.list.get_selection() + (model, pathlist) = tree_selection.get_selected_rows() + return int(pathlist[0].to_string() ) - def select_item(self, item): - tree_selection = self.list.get_selection() - tree_selection.select_path(item) + def select_item(self, item): + tree_selection = self.list.get_selection() + tree_selection.select_path(item) - def remove_item(self, item): - self.store.remove(self.store.get_iter(item)) + def remove_item(self, item): + self.store.remove(self.store.get_iter(item)) - def get_count(self): - return len(self.store) + def get_count(self): + return len(self.store) class baseDialog(Gtk.Dialog): - def __init__(self, *args, **kwargs): - super(baseDialog, self).__init__(*args, **kwargs) - self.box = self.get_content_area() + def __init__(self, *args, **kwargs): + super(baseDialog, self).__init__(*args, **kwargs) + self.box = self.get_content_area() - def get_response(self): - answer = self.run() - return answer + def get_response(self): + answer = self.run() + return answer class buffer(GObject.GObject): - name = GObject.property(type=str) + name = GObject.property(type=str) - def __init__(self, obj): - super(buffer, self).__init__() - self.buffer = obj + def __init__(self, obj): + super(buffer, self).__init__() + self.buffer = obj class notebook(object): - def __init__(self): - self.store = Gtk.TreeStore(buffer.__gtype__) - self.view = Gtk.TreeView() - self.view.set_model(self.store) + def __init__(self): + self.store = Gtk.TreeStore(buffer.__gtype__) + self.view = Gtk.TreeView() + self.view.set_model(self.store) - column = Gtk.TreeViewColumn("Buffer") - cell = Gtk.CellRendererText() - column.pack_start(cell, True) - column.set_cell_data_func(cell, self.get_buffer) - self.view.append_column(column) + column = Gtk.TreeViewColumn("Buffer") + cell = Gtk.CellRendererText() + column.pack_start(cell, True) + column.set_cell_data_func(cell, self.get_buffer) + self.view.append_column(column) - def get_current_page(self): - tree_selection = self.view.get_selection() - (model, pathlist) = tree_selection.get_selected_rows() - iter = pathlist[0] - return self.store[iter][0].buffer + def get_current_page(self): + tree_selection = self.view.get_selection() + (model, pathlist) = tree_selection.get_selected_rows() + iter = pathlist[0] + return self.store[iter][0].buffer - def get_buffer(self, column, cell, model, iter, data): - cell.set_property('text', self.store.get_value(iter, 0).name) + def get_buffer(self, column, cell, model, iter, data): + cell.set_property('text', self.store.get_value(iter, 0).name) - def match_func(self, row, name_, account): - name = name_ - account = account - iter = self.store.get_iter(row.path) - if self.store[iter][0].buffer.name == name and self.store[iter][0].buffer.account == account: - return (row.path, iter) - else: - return (None, None) + def match_func(self, row, name_, account): + name = name_ + account = account + iter = self.store.get_iter(row.path) + if self.store[iter][0].buffer.name == name and self.store[iter][0].buffer.account == account: + return (row.path, iter) + else: + return (None, None) - def search(self, rows, name_, account): - if not rows: return None - for row in rows: - (path, iter) = self.match_func(row, name_, account) - if iter != None: - return (path, iter) - (result_path, result_iter) = self.search(row.iterchildren(), name_, account) - if result_path: return (result_path, result_iter) - return (None, None) + def search(self, rows, name_, account): + if not rows: return None + for row in rows: + (path, iter) = self.match_func(row, name_, account) + if iter != None: + return (path, iter) + (result_path, result_iter) = self.search(row.iterchildren(), name_, account) + if result_path: return (result_path, result_iter) + return (None, None) class mainLoopObject(object): - def run(self): - GObject.type_register(buffer) - Gtk.main() + def run(self): + GObject.type_register(buffer) + Gtk.main() diff --git a/src/widgetUtils/wxUtils.py b/src/widgetUtils/wxUtils.py index 10c43362..9eb453ec 100644 --- a/src/widgetUtils/wxUtils.py +++ b/src/widgetUtils/wxUtils.py @@ -59,71 +59,71 @@ TASKBAR_RIGHT_CLICK = wx.adv.EVT_TASKBAR_RIGHT_DOWN TASKBAR_LEFT_CLICK = wx.adv.EVT_TASKBAR_LEFT_DOWN def exit_application(): - """ Closes the current window cleanly. """ - wx.GetApp().ExitMainLoop() + """ Closes the current window cleanly. """ + wx.GetApp().ExitMainLoop() def connect_event(parent, event, func, menuitem=None, *args, **kwargs): - """ Connects an event to a function. - parent wx.window: The widget that will listen for the event. - event widgetUtils.event: The event that will be listened for the parent. The event should be one of the widgetUtils events. - function func: The function that will be connected to the event.""" - if menuitem == None: - return getattr(parent, "Bind")(event, func, *args, **kwargs) - else: - return getattr(parent, "Bind")(event, func, menuitem, *args, **kwargs) + """ Connects an event to a function. + parent wx.window: The widget that will listen for the event. + event widgetUtils.event: The event that will be listened for the parent. The event should be one of the widgetUtils events. + function func: The function that will be connected to the event.""" + if menuitem == None: + return getattr(parent, "Bind")(event, func, *args, **kwargs) + else: + return getattr(parent, "Bind")(event, func, menuitem, *args, **kwargs) def connectExitFunction(exitFunction): - """ This connect the events in WX when an user is turning off the machine.""" - wx.GetApp().Bind(wx.EVT_QUERY_END_SESSION, exitFunction) - wx.GetApp().Bind(wx.EVT_END_SESSION, exitFunction) + """ This connect the events in WX when an user is turning off the machine.""" + wx.GetApp().Bind(wx.EVT_QUERY_END_SESSION, exitFunction) + wx.GetApp().Bind(wx.EVT_END_SESSION, exitFunction) class BaseDialog(wx.Dialog): - def __init__(self, *args, **kwargs): - super(BaseDialog, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(BaseDialog, self).__init__(*args, **kwargs) - def get_response(self): - return self.ShowModal() + def get_response(self): + return self.ShowModal() - def get(self, control): - if hasattr(self, control): - control = getattr(self, control) - if hasattr(control, "GetValue"): return getattr(control, "GetValue")() - elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() - else: return -1 - else: return 0 + def get(self, control): + if hasattr(self, control): + control = getattr(self, control) + if hasattr(control, "GetValue"): return getattr(control, "GetValue")() + elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() + else: return -1 + else: return 0 - def set(self, control, text): - if hasattr(self, control): - control = getattr(self, control) - if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text) - elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text) - elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text) - else: return -1 - else: return 0 + def set(self, control, text): + if hasattr(self, control): + control = getattr(self, control) + if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text) + elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text) + elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text) + else: return -1 + else: return 0 - def destroy(self): - self.Destroy() + def destroy(self): + self.Destroy() - def set_title(self, title): - self.SetTitle(title) + def set_title(self, title): + self.SetTitle(title) - def get_title(self): - return self.GetTitle() + def get_title(self): + return self.GetTitle() class mainLoopObject(wx.App): - def __init__(self): - self.app = wx.App() - self.lc = wx.Locale() - lang=languageHandler.getLanguage() - wxLang=self.lc.FindLanguageInfo(lang) - if not wxLang and '_' in lang: - wxLang=self.lc.FindLanguageInfo(lang.split('_')[0]) - if hasattr(sys,'frozen'): - self.lc.AddCatalogLookupPathPrefix(os.path.join(paths.app_path(), "locales")) - if wxLang: - self.lc.Init(wxLang.Language) + def __init__(self): + self.app = wx.App() + self.lc = wx.Locale() + lang=languageHandler.getLanguage() + wxLang=self.lc.FindLanguageInfo(lang) + if not wxLang and '_' in lang: + wxLang=self.lc.FindLanguageInfo(lang.split('_')[0]) + if hasattr(sys,'frozen'): + self.lc.AddCatalogLookupPathPrefix(os.path.join(paths.app_path(), "locales")) + if wxLang: + self.lc.Init(wxLang.Language) - def run(self): - self.app.MainLoop() + def run(self): + self.app.MainLoop() diff --git a/src/wxUI/buffers/__init__.py b/src/wxUI/buffers/__init__.py index cc9de3f1..2825b5fb 100644 --- a/src/wxUI/buffers/__init__.py +++ b/src/wxUI/buffers/__init__.py @@ -10,4 +10,4 @@ from .panels import accountPanel, emptyPanel from .people import peoplePanel from .trends import trendsPanel from .tweet_searches import searchPanel -from .user_searches import searchUsersPanel \ No newline at end of file +from .user_searches import searchUsersPanel diff --git a/src/wxUI/buffers/base.py b/src/wxUI/buffers/base.py index 32287f9d..657caee3 100644 --- a/src/wxUI/buffers/base.py +++ b/src/wxUI/buffers/base.py @@ -4,43 +4,43 @@ import wx from multiplatform_widgets import widgets class basePanel(wx.Panel): - - def set_focus_function(self, f): - self.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, f) - def create_list(self): - self.list = widgets.list(self, _(u"User"), _(u"Text"), _(u"Date"), _(u"Client"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) - self.list.set_windows_size(0, 60) - self.list.set_windows_size(1, 320) - self.list.set_windows_size(2, 110) - self.list.set_windows_size(3, 84) - self.list.set_size() + def set_focus_function(self, f): + self.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, f) - def __init__(self, parent, name): - super(basePanel, self).__init__(parent) - self.name = name - self.type = "baseBuffer" - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.create_list() - self.tweet = wx.Button(self, -1, _(u"Tweet")) - self.retweet = wx.Button(self, -1, _(u"Retweet")) - self.reply = wx.Button(self, -1, _(u"Reply")) - self.dm = wx.Button(self, -1, _(u"Direct message")) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer.Add(self.tweet, 0, wx.ALL, 5) - btnSizer.Add(self.retweet, 0, wx.ALL, 5) - btnSizer.Add(self.reply, 0, wx.ALL, 5) - btnSizer.Add(self.dm, 0, wx.ALL, 5) - self.sizer.Add(btnSizer, 0, wx.ALL, 5) - self.sizer.Add(self.list.list, 0, wx.ALL|wx.EXPAND, 5) - self.SetSizer(self.sizer) - self.SetClientSize(self.sizer.CalcMin()) + def create_list(self): + self.list = widgets.list(self, _(u"User"), _(u"Text"), _(u"Date"), _(u"Client"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) + self.list.set_windows_size(0, 60) + self.list.set_windows_size(1, 320) + self.list.set_windows_size(2, 110) + self.list.set_windows_size(3, 84) + self.list.set_size() - def set_position(self, reversed=False): - if reversed == False: - self.list.select_item(self.list.get_count()-1) - else: - self.list.select_item(0) + def __init__(self, parent, name): + super(basePanel, self).__init__(parent) + self.name = name + self.type = "baseBuffer" + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.create_list() + self.tweet = wx.Button(self, -1, _(u"Tweet")) + self.retweet = wx.Button(self, -1, _(u"Retweet")) + self.reply = wx.Button(self, -1, _(u"Reply")) + self.dm = wx.Button(self, -1, _(u"Direct message")) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add(self.tweet, 0, wx.ALL, 5) + btnSizer.Add(self.retweet, 0, wx.ALL, 5) + btnSizer.Add(self.reply, 0, wx.ALL, 5) + btnSizer.Add(self.dm, 0, wx.ALL, 5) + self.sizer.Add(btnSizer, 0, wx.ALL, 5) + self.sizer.Add(self.list.list, 0, wx.ALL|wx.EXPAND, 5) + self.SetSizer(self.sizer) + self.SetClientSize(self.sizer.CalcMin()) - def set_focus_in_list(self): - self.list.list.SetFocus() \ No newline at end of file + def set_position(self, reversed=False): + if reversed == False: + self.list.select_item(self.list.get_count()-1) + else: + self.list.select_item(0) + + def set_focus_in_list(self): + self.list.list.SetFocus() diff --git a/src/wxUI/buffers/dm.py b/src/wxUI/buffers/dm.py index 13ea457f..85cf7d11 100644 --- a/src/wxUI/buffers/dm.py +++ b/src/wxUI/buffers/dm.py @@ -5,9 +5,9 @@ import wx from .base import basePanel class dmPanel(basePanel): - def __init__(self, parent, name): - """ Class to DM'S. Reply and retweet buttons are not showed and they have your delete method for dm's.""" - super(dmPanel, self).__init__(parent, name) - self.retweet.Disable() - self.reply.Disable() - self.type = "dm" \ No newline at end of file + def __init__(self, parent, name): + """ Class to DM'S. Reply and retweet buttons are not showed and they have your delete method for dm's.""" + super(dmPanel, self).__init__(parent, name) + self.retweet.Disable() + self.reply.Disable() + self.type = "dm" diff --git a/src/wxUI/buffers/events.py b/src/wxUI/buffers/events.py index aaa9411c..9df06178 100644 --- a/src/wxUI/buffers/events.py +++ b/src/wxUI/buffers/events.py @@ -4,22 +4,22 @@ import wx from multiplatform_widgets import widgets class eventsPanel(wx.Panel): - """ Buffer to show events. Different than tweets or people.""" + """ Buffer to show events. Different than tweets or people.""" - def __init__(self, parent, name): - self.type = "event" - super(eventsPanel, self).__init__(parent) - self.name = name - sizer = wx.BoxSizer() - self.list = widgets.list(self, _(u"Date"), _(u"Event"), size=(600,600), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) - self.tweet = wx.Button(self, -1, _(u"Tweet")) - self.delete_event = wx.Button(self, -1, _(u"Remove event")) + def __init__(self, parent, name): + self.type = "event" + super(eventsPanel, self).__init__(parent) + self.name = name + sizer = wx.BoxSizer() + self.list = widgets.list(self, _(u"Date"), _(u"Event"), size=(600,600), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) + self.tweet = wx.Button(self, -1, _(u"Tweet")) + self.delete_event = wx.Button(self, -1, _(u"Remove event")) - def set_position(self, reversed=False): - if reversed == False: - self.list.select_item(self.list.get_count()-1) - else: - self.list.select_item(0) + def set_position(self, reversed=False): + if reversed == False: + self.list.select_item(self.list.get_count()-1) + else: + self.list.select_item(0) - def set_focus_in_list(self): - self.list.list.SetFocus() \ No newline at end of file + def set_focus_in_list(self): + self.list.list.SetFocus() diff --git a/src/wxUI/buffers/favourites.py b/src/wxUI/buffers/favourites.py index cc61e303..41ba04ae 100644 --- a/src/wxUI/buffers/favourites.py +++ b/src/wxUI/buffers/favourites.py @@ -5,6 +5,6 @@ import wx from .base import basePanel class favsPanel(basePanel): - def __init__(self, parent, name): - super(favsPanel, self).__init__(parent, name) - self.type = "favourites_timeline" \ No newline at end of file + def __init__(self, parent, name): + super(favsPanel, self).__init__(parent, name) + self.type = "favourites_timeline" diff --git a/src/wxUI/buffers/lists.py b/src/wxUI/buffers/lists.py index 9c31e95c..55c25813 100644 --- a/src/wxUI/buffers/lists.py +++ b/src/wxUI/buffers/lists.py @@ -5,6 +5,6 @@ import wx from .base import basePanel class listPanel(basePanel): - def __init__(self, parent, name): - super(listPanel, self).__init__(parent, name) - self.type = "list" + def __init__(self, parent, name): + super(listPanel, self).__init__(parent, name) + self.type = "list" diff --git a/src/wxUI/buffers/panels.py b/src/wxUI/buffers/panels.py index 5bd02498..f0ccfd4f 100644 --- a/src/wxUI/buffers/panels.py +++ b/src/wxUI/buffers/panels.py @@ -4,33 +4,33 @@ import wx from multiplatform_widgets import widgets class accountPanel(wx.Panel): - def __init__(self, parent, name=None): - super(accountPanel, self).__init__(parent=parent) - self.name = name - self.type = "account" - sizer = wx.BoxSizer(wx.VERTICAL) - self.login = wx.Button(self, -1, _(u"Login")) - sizer.Add(self.login, 0, wx.ALL, 5) - self.autostart_account = wx.CheckBox(self, -1, _(u"Log in automatically")) - sizer.Add(self.autostart_account, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent, name=None): + super(accountPanel, self).__init__(parent=parent) + self.name = name + self.type = "account" + sizer = wx.BoxSizer(wx.VERTICAL) + self.login = wx.Button(self, -1, _(u"Login")) + sizer.Add(self.login, 0, wx.ALL, 5) + self.autostart_account = wx.CheckBox(self, -1, _(u"Log in automatically")) + sizer.Add(self.autostart_account, 0, wx.ALL, 5) + self.SetSizer(sizer) - def change_login(self, login=True): - if login == True: - self.login.SetLabel(_(u"Login")) - else: - self.login.SetLabel(_(u"Logout")) + def change_login(self, login=True): + if login == True: + self.login.SetLabel(_(u"Login")) + else: + self.login.SetLabel(_(u"Logout")) - def change_autostart(self, autostart=True): - self.autostart_account.SetValue(autostart) + def change_autostart(self, autostart=True): + self.autostart_account.SetValue(autostart) - def get_autostart(self): - return self.autostart_account.GetValue() + def get_autostart(self): + return self.autostart_account.GetValue() class emptyPanel(wx.Panel): - def __init__(self, parent, name): - super(emptyPanel, self).__init__(parent=parent, name=name) - self.name = name - self.type = "account" - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(sizer) + def __init__(self, parent, name): + super(emptyPanel, self).__init__(parent=parent, name=name) + self.name = name + self.type = "account" + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) diff --git a/src/wxUI/buffers/people.py b/src/wxUI/buffers/people.py index 25490be4..b2248f84 100644 --- a/src/wxUI/buffers/people.py +++ b/src/wxUI/buffers/people.py @@ -6,13 +6,13 @@ from multiplatform_widgets import widgets from .base import basePanel class peoplePanel(basePanel): - """ Buffer used to show people.""" + """ Buffer used to show people.""" - def create_list(self): - self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) + def create_list(self): + self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) - def __init__(self, parent, name): - super(peoplePanel, self).__init__(parent, name) - self.type = "people" - self.reply.SetLabel(_(u"Mention")) - self.retweet.Disable() + def __init__(self, parent, name): + super(peoplePanel, self).__init__(parent, name) + self.type = "people" + self.reply.SetLabel(_(u"Mention")) + self.retweet.Disable() diff --git a/src/wxUI/buffers/trends.py b/src/wxUI/buffers/trends.py index 51058e78..975a88ca 100644 --- a/src/wxUI/buffers/trends.py +++ b/src/wxUI/buffers/trends.py @@ -4,31 +4,31 @@ import wx from multiplatform_widgets import widgets class trendsPanel(wx.Panel): - def create_list(self): - """ Returns the list for put the tweets here.""" - self.list = widgets.list(self, _(u"Trending topic"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) - self.list.set_windows_size(0, 30) - self.list.set_size() + def create_list(self): + """ Returns the list for put the tweets here.""" + self.list = widgets.list(self, _(u"Trending topic"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES) + self.list.set_windows_size(0, 30) + self.list.set_size() - def __init__(self, parent, name): - super(trendsPanel, self).__init__(parent) - self.type = "trends" - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.create_list() - self.tweet = wx.Button(self, -1, _(u"Tweet")) - self.tweetTrendBtn = wx.Button(self, -1, _(u"Tweet about this trend")) - self.search_topic = wx.Button(self, -1, _(u"Search topic")) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer.Add(self.tweet, 0, wx.ALL, 5) - btnSizer.Add(self.tweetTrendBtn, 0, wx.ALL, 5) - btnSizer.Add(self.search_topic, 0, wx.ALL, 5) - self.sizer.Add(btnSizer, 0, wx.ALL, 5) - self.sizer.Add(self.list.list, 0, wx.ALL, 5) - self.SetSizer(self.sizer) + def __init__(self, parent, name): + super(trendsPanel, self).__init__(parent) + self.type = "trends" + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.create_list() + self.tweet = wx.Button(self, -1, _(u"Tweet")) + self.tweetTrendBtn = wx.Button(self, -1, _(u"Tweet about this trend")) + self.search_topic = wx.Button(self, -1, _(u"Search topic")) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add(self.tweet, 0, wx.ALL, 5) + btnSizer.Add(self.tweetTrendBtn, 0, wx.ALL, 5) + btnSizer.Add(self.search_topic, 0, wx.ALL, 5) + self.sizer.Add(btnSizer, 0, wx.ALL, 5) + self.sizer.Add(self.list.list, 0, wx.ALL, 5) + self.SetSizer(self.sizer) + + def set_position(self, reversed=False): + if reversed == False: + self.list.select_item(self.list.get_count()-1) + else: + self.list.select_item(0) - def set_position(self, reversed=False): - if reversed == False: - self.list.select_item(self.list.get_count()-1) - else: - self.list.select_item(0) - \ No newline at end of file diff --git a/src/wxUI/buffers/tweet_searches.py b/src/wxUI/buffers/tweet_searches.py index 6862e482..df6560f0 100644 --- a/src/wxUI/buffers/tweet_searches.py +++ b/src/wxUI/buffers/tweet_searches.py @@ -5,6 +5,6 @@ import wx from .base import basePanel class searchPanel(basePanel): - def __init__(self, parent, name): - super(searchPanel, self).__init__(parent, name) - self.type = "search" + def __init__(self, parent, name): + super(searchPanel, self).__init__(parent, name) + self.type = "search" diff --git a/src/wxUI/buffers/user_searches.py b/src/wxUI/buffers/user_searches.py index 651c2a55..26292fd1 100644 --- a/src/wxUI/buffers/user_searches.py +++ b/src/wxUI/buffers/user_searches.py @@ -6,11 +6,11 @@ from .tweet_searches import searchPanel from multiplatform_widgets import widgets class searchUsersPanel(searchPanel): - def create_list(self): - """ Returns the list for put the tweets here.""" - self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) + def create_list(self): + """ Returns the list for put the tweets here.""" + self.list = widgets.list(self, _(u"User"), style=wx.LC_REPORT|wx.LC_SINGLE_SEL, size=(800, 800)) - def __init__(self, parent, name): - super(searchUsersPanel, self).__init__(parent, name) - self.create_list() - self.type = "user_searches" \ No newline at end of file + def __init__(self, parent, name): + super(searchUsersPanel, self).__init__(parent, name) + self.create_list() + self.type = "user_searches" diff --git a/src/wxUI/commonMessageDialogs.py b/src/wxUI/commonMessageDialogs.py index 8288af68..277ceca7 100644 --- a/src/wxUI/commonMessageDialogs.py +++ b/src/wxUI/commonMessageDialogs.py @@ -4,92 +4,92 @@ import wx import application def retweet_as_link(parent): - return wx.MessageDialog(parent, _(u"This retweet is over 140 characters. Would you like to post it as a mention to the poster with your comments and a link to the original tweet?"), application.name, wx.YES_NO|wx.ICON_QUESTION).ShowModal() + return wx.MessageDialog(parent, _(u"This retweet is over 140 characters. Would you like to post it as a mention to the poster with your comments and a link to the original tweet?"), application.name, wx.YES_NO|wx.ICON_QUESTION).ShowModal() def retweet_question(parent): - return wx.MessageDialog(parent, _(u"Would you like to add a comment to this tweet?"), _("Retweet"), wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION).ShowModal() + return wx.MessageDialog(parent, _(u"Would you like to add a comment to this tweet?"), _("Retweet"), wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION).ShowModal() def delete_tweet_dialog(parent): - return wx.MessageDialog(parent, _(u"Do you really want to delete this tweet? It will be deleted from Twitter as well."), _(u"Delete"), wx.ICON_QUESTION|wx.YES_NO).ShowModal() + return wx.MessageDialog(parent, _(u"Do you really want to delete this tweet? It will be deleted from Twitter as well."), _(u"Delete"), wx.ICON_QUESTION|wx.YES_NO).ShowModal() def exit_dialog(parent): - dlg = wx.MessageDialog(parent, _(u"Do you really want to close {0}?").format(application.name,), _(u"Exit"), wx.YES_NO|wx.ICON_QUESTION) - return dlg.ShowModal() + dlg = wx.MessageDialog(parent, _(u"Do you really want to close {0}?").format(application.name,), _(u"Exit"), wx.YES_NO|wx.ICON_QUESTION) + return dlg.ShowModal() def needs_restart(): - wx.MessageDialog(None, _(u" {0} must be restarted for these changes to take effect.").format(application.name,), _("Restart {0} ").format(application.name,), wx.OK).ShowModal() + wx.MessageDialog(None, _(u" {0} must be restarted for these changes to take effect.").format(application.name,), _("Restart {0} ").format(application.name,), wx.OK).ShowModal() def delete_user_from_db(): - return wx.MessageDialog(None, _(u"Are you sure you want to delete this user from the database? This user will not appear in autocomplete results anymore."), _(u"Confirm"), wx.YES_NO|wx.ICON_QUESTION).ShowModal() + return wx.MessageDialog(None, _(u"Are you sure you want to delete this user from the database? This user will not appear in autocomplete results anymore."), _(u"Confirm"), wx.YES_NO|wx.ICON_QUESTION).ShowModal() def get_ignored_client(): - entry = wx.TextEntryDialog(None, _(u"Enter the name of the client : "), _(u"Add client")) - if entry.ShowModal() == wx.ID_OK: - return entry.GetValue() - return None + entry = wx.TextEntryDialog(None, _(u"Enter the name of the client : "), _(u"Add client")) + if entry.ShowModal() == wx.ID_OK: + return entry.GetValue() + return None def clear_list(): - dlg = wx.MessageDialog(None, _(u"Do you really want to empty this buffer? It's items will be removed from the list but not from Twitter"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO) - return dlg.ShowModal() + dlg = wx.MessageDialog(None, _(u"Do you really want to empty this buffer? It's items will be removed from the list but not from Twitter"), _(u"Empty buffer"), wx.ICON_QUESTION|wx.YES_NO) + return dlg.ShowModal() def remove_buffer(): - return wx.MessageDialog(None, _(u"Do you really want to destroy this buffer?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() + return wx.MessageDialog(None, _(u"Do you really want to destroy this buffer?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() def user_not_exist(): - return wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() def timeline_exist(): - return wx.MessageDialog(None, _(u"A timeline for this user already exists. You can't open another"), _(u"Existing timeline"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"A timeline for this user already exists. You can't open another"), _(u"Existing timeline"), wx.ICON_ERROR).ShowModal() def no_tweets(): - return wx.MessageDialog(None, _(u"This user has no tweets, so you can't open a timeline for them."), _(u"Error!"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"This user has no tweets, so you can't open a timeline for them."), _(u"Error!"), wx.ICON_ERROR).ShowModal() def protected_user(): - return wx.MessageDialog(None, _(u"This is a protected Twitter user, which means you can't open a timeline using the Streaming API. The user's tweets will not update due to a twitter policy. Do you want to continue?"), _(u"Warning"), wx.ICON_WARNING|wx.YES_NO).ShowModal() + return wx.MessageDialog(None, _(u"This is a protected Twitter user, which means you can't open a timeline using the Streaming API. The user's tweets will not update due to a twitter policy. Do you want to continue?"), _(u"Warning"), wx.ICON_WARNING|wx.YES_NO).ShowModal() def no_following(): - return wx.MessageDialog(None, _(u"This is a protected user account, you need to follow this user to view their tweets or likes."), _(u"Error"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"This is a protected user account, you need to follow this user to view their tweets or likes."), _(u"Error"), wx.ICON_ERROR).ShowModal() def donation(): - dlg = wx.MessageDialog(None, _(u"If you like {0} we need your help to keep it going. Help us by donating to the project. This will help us pay for the server, the domain and some other things to ensure that {0} will be actively maintained. Your donation will give us the means to continue the development of {0}, and to keep {0} free. Would you like to donate now?").format(application.name), _(u"We need your help"), wx.ICON_QUESTION|wx.YES_NO) - return dlg.ShowModal() + dlg = wx.MessageDialog(None, _(u"If you like {0} we need your help to keep it going. Help us by donating to the project. This will help us pay for the server, the domain and some other things to ensure that {0} will be actively maintained. Your donation will give us the means to continue the development of {0}, and to keep {0} free. Would you like to donate now?").format(application.name), _(u"We need your help"), wx.ICON_QUESTION|wx.YES_NO) + return dlg.ShowModal() def no_tweets(): - return wx.MessageDialog(None, _(u"This user has no tweets. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"This user has no tweets. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() def no_favs(): - return wx.MessageDialog(None, _(u"This user has no favorited tweets. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"This user has no favorited tweets. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() def no_followers(): - return wx.MessageDialog(None, _(u"This user has no followers. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"This user has no followers. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() def no_friends(): - return wx.MessageDialog(None, _(u"This user has no friends. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(None, _(u"This user has no friends. {0} can't create a timeline.").format(application.name), _(u"Error"), wx.ICON_ERROR).ShowModal() def view_geodata(geotext): - """Specific message dialog to display geolocation data""" - return wx.MessageDialog(None, _(u"Geolocation data: {0}").format(geotext), _(u"Geo data for this tweet")).ShowModal() + """Specific message dialog to display geolocation data""" + return wx.MessageDialog(None, _(u"Geolocation data: {0}").format(geotext), _(u"Geo data for this tweet")).ShowModal() def changed_keymap(): - return wx.MessageDialog(None, _(u"TWBlue has detected that you're running windows 10 and has changed the default keymap to the Windows 10 keymap. It means that some keyboard shorcuts could be different. Please check the keystroke editor by pressing Alt+Win+K to see all available keystrokes for this keymap."), _(u"Information"), wx.OK).ShowModal() + return wx.MessageDialog(None, _(u"TWBlue has detected that you're running windows 10 and has changed the default keymap to the Windows 10 keymap. It means that some keyboard shorcuts could be different. Please check the keystroke editor by pressing Alt+Win+K to see all available keystrokes for this keymap."), _(u"Information"), wx.OK).ShowModal() def unauthorized(): - return wx.MessageDialog(None, _(u"You have been blocked from viewing this content"), _(u"Error"), wx.OK).ShowModal() + return wx.MessageDialog(None, _(u"You have been blocked from viewing this content"), _(u"Error"), wx.OK).ShowModal() def blocked_timeline(): - return wx.MessageDialog(None, _(u"You have been blocked from viewing someone's content. In order to avoid conflicts with the full session, TWBlue will remove the affected timeline."), _(u"Error"), wx.OK).ShowModal() - + return wx.MessageDialog(None, _(u"You have been blocked from viewing someone's content. In order to avoid conflicts with the full session, TWBlue will remove the affected timeline."), _(u"Error"), wx.OK).ShowModal() + def suspended_user(): - return wx.MessageDialog(None, _(u"TWBlue cannot load this timeline because the user has been suspended from Twitter."), _(u"Error"), wx.OK).ShowModal() + return wx.MessageDialog(None, _(u"TWBlue cannot load this timeline because the user has been suspended from Twitter."), _(u"Error"), wx.OK).ShowModal() def delete_filter(): - return wx.MessageDialog(None, _(u"Do you really want to delete this filter?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() + return wx.MessageDialog(None, _(u"Do you really want to delete this filter?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() def existing_filter(): - return wx.MessageDialog(None, _(u"This filter already exists. Please use a different title"), _(u"Error"), wx.OK).ShowModal() + return wx.MessageDialog(None, _(u"This filter already exists. Please use a different title"), _(u"Error"), wx.OK).ShowModal() def common_error(reason): - return wx.MessageDialog(None, reason, _(u"Error"), wx.OK).ShowModal() + return wx.MessageDialog(None, reason, _(u"Error"), wx.OK).ShowModal() def dead_pid(): - return wx.MessageDialog(None, _(u"{0} quit unexpectedly the last time it was run. If the problem persists, please report it to the {0} developers.").format(application.name), _(u"Warning"), wx.OK).ShowModal() \ No newline at end of file + return wx.MessageDialog(None, _(u"{0} quit unexpectedly the last time it was run. If the problem persists, please report it to the {0} developers.").format(application.name), _(u"Warning"), wx.OK).ShowModal() diff --git a/src/wxUI/dialogs/attach.py b/src/wxUI/dialogs/attach.py index ea8d35c1..0b20a422 100644 --- a/src/wxUI/dialogs/attach.py +++ b/src/wxUI/dialogs/attach.py @@ -6,43 +6,43 @@ import widgetUtils from multiplatform_widgets import widgets class attachDialog(widgetUtils.BaseDialog): - def __init__(self): - super(attachDialog, self).__init__(None, title=_(u"Add an attachment")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - lbl1 = wx.StaticText(panel, wx.ID_ANY, _(u"Attachments")) - self.attachments = widgets.list(panel, _(u"Type"), _(u"Title"), style=wx.LC_REPORT) - box = wx.BoxSizer(wx.HORIZONTAL) - box.Add(lbl1, 0, wx.ALL, 5) - box.Add(self.attachments.list, 0, wx.ALL, 5) - sizer.Add(box, 0, wx.ALL, 5) - static = wx.StaticBox(panel, label=_(u"Add attachments")) - self.photo = wx.Button(panel, wx.ID_ANY, _(u"&Photo")) - self.remove = wx.Button(panel, wx.ID_ANY, _(u"Remove attachment")) - self.remove.Enable(False) - btnsizer = wx.StaticBoxSizer(static, wx.HORIZONTAL) - btnsizer.Add(self.photo, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK) - ok.SetDefault() - cancelBtn = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(ok, 0, wx.ALL, 5) - btnSizer.Add(cancelBtn, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(attachDialog, self).__init__(None, title=_(u"Add an attachment")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + lbl1 = wx.StaticText(panel, wx.ID_ANY, _(u"Attachments")) + self.attachments = widgets.list(panel, _(u"Type"), _(u"Title"), style=wx.LC_REPORT) + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(lbl1, 0, wx.ALL, 5) + box.Add(self.attachments.list, 0, wx.ALL, 5) + sizer.Add(box, 0, wx.ALL, 5) + static = wx.StaticBox(panel, label=_(u"Add attachments")) + self.photo = wx.Button(panel, wx.ID_ANY, _(u"&Photo")) + self.remove = wx.Button(panel, wx.ID_ANY, _(u"Remove attachment")) + self.remove.Enable(False) + btnsizer = wx.StaticBoxSizer(static, wx.HORIZONTAL) + btnsizer.Add(self.photo, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK) + ok.SetDefault() + cancelBtn = wx.Button(panel, wx.ID_CANCEL) + btnSizer = wx.BoxSizer() + btnSizer.Add(ok, 0, wx.ALL, 5) + btnSizer.Add(cancelBtn, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return (None, None) - dsc = self.ask_description() - return (openFileDialog.GetPath(), dsc) + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return (None, None) + dsc = self.ask_description() + return (openFileDialog.GetPath(), dsc) - def ask_description(self): - dlg = wx.TextEntryDialog(self, _(u"please provide a description"), _(u"Description")) - dlg.ShowModal() - result = dlg.GetValue() - dlg.Destroy() - return result + def ask_description(self): + dlg = wx.TextEntryDialog(self, _(u"please provide a description"), _(u"Description")) + dlg.ShowModal() + result = dlg.GetValue() + dlg.Destroy() + return result diff --git a/src/wxUI/dialogs/baseDialog.py b/src/wxUI/dialogs/baseDialog.py index 01fe8b49..20480d9e 100644 --- a/src/wxUI/dialogs/baseDialog.py +++ b/src/wxUI/dialogs/baseDialog.py @@ -2,28 +2,28 @@ from __future__ import unicode_literals import wx class BaseWXDialog(wx.Dialog): - def __init__(self, *args, **kwargs): - super(BaseWXDialog, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(BaseWXDialog, self).__init__(*args, **kwargs) - def get_response(self): - return self.ShowModal() + def get_response(self): + return self.ShowModal() - def get(self, control): - if hasattr(self, control): - control = getattr(self, control) - if hasattr(control, "GetValue"): return getattr(control, "GetValue")() - elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() - else: return -1 - else: return 0 + def get(self, control): + if hasattr(self, control): + control = getattr(self, control) + if hasattr(control, "GetValue"): return getattr(control, "GetValue")() + elif hasattr(control, "GetLabel"): return getattr(control, "GetLabel")() + else: return -1 + else: return 0 - def set(self, control, text): - if hasattr(self, control): - control = getattr(self, control) - if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text) - elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text) - elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text) - else: return -1 - else: return 0 + def set(self, control, text): + if hasattr(self, control): + control = getattr(self, control) + if hasattr(control, "SetValue"): return getattr(control, "SetValue")(text) + elif hasattr(control, "SetLabel"): return getattr(control, "SetLabel")(text) + elif hasattr(control, "ChangeValue"): return getattr(control, "ChangeValue")(text) + else: return -1 + else: return 0 - def set_title(self, title): - self.SetTitle(title) + def set_title(self, title): + self.SetTitle(title) diff --git a/src/wxUI/dialogs/configuration.py b/src/wxUI/dialogs/configuration.py index def44926..147bba1d 100644 --- a/src/wxUI/dialogs/configuration.py +++ b/src/wxUI/dialogs/configuration.py @@ -12,403 +12,403 @@ from . import baseDialog from multiplatform_widgets import widgets class general(wx.Panel, baseDialog.BaseWXDialog): - def __init__(self, parent, languages,keymaps): - super(general, self).__init__(parent) - sizer = wx.BoxSizer(wx.VERTICAL) - language = wx.StaticText(self, -1, _(u"Language")) - self.language = wx.ListBox(self, -1, choices=languages) - self.language.SetSize(self.language.GetBestSize()) - langBox = wx.BoxSizer(wx.HORIZONTAL) - langBox.Add(language, 0, wx.ALL, 5) - langBox.Add(self.language, 0, wx.ALL, 5) - sizer.Add(langBox, 0, wx.ALL, 5) - self.autostart = wx.CheckBox(self, -1, _(u"Run {0} at Windows startup").format(application.name,)) - self.ask_at_exit = wx.CheckBox(self, -1, _(U"ask before exiting {0}").format(application.name,)) - sizer.Add(self.autostart, 0, wx.ALL, 5) - sizer.Add(self.ask_at_exit, 0, wx.ALL, 5) - self.no_streaming = wx.CheckBox(self, -1, _(U"Disable Streaming functions")) - sizer.Add(self.no_streaming, 0, wx.ALL, 5) - updatePeriodBox = wx.BoxSizer(wx.HORIZONTAL) - updatePeriodBox.Add(wx.StaticText(self, -1, _(u"Buffer update interval, in minutes")), 0, wx.ALL, 5) - self.update_period = wx.SpinCtrl(self, wx.ID_ANY) - self.update_period.SetRange(1, 30) - self.update_period.SetSize(self.update_period.GetBestSize()) - updatePeriodBox.Add(self.update_period, 0, wx.ALL, 5) - sizer.Add(updatePeriodBox, 0, wx.ALL, 5) - self.play_ready_sound = wx.CheckBox(self, -1, _(U"Play a sound when {0} launches").format(application.name,)) - sizer.Add(self.play_ready_sound, 0, wx.ALL, 5) - self.speak_ready_msg = wx.CheckBox(self, -1, _(U"Speak a message when {0} launches").format(application.name,)) - sizer.Add(self.speak_ready_msg, 0, wx.ALL, 5) - self.use_invisible_shorcuts = wx.CheckBox(self, -1, _(u"Use invisible interface's keyboard shortcuts while GUI is visible")) - sizer.Add(self.use_invisible_shorcuts, 0, wx.ALL, 5) - self.disable_sapi5 = wx.CheckBox(self, -1, _(u"Activate Sapi5 when any other screen reader is not being run")) - sizer.Add(self.disable_sapi5, 0, wx.ALL, 5) - self.hide_gui = wx.CheckBox(self, -1, _(u"Hide GUI on launch")) - sizer.Add(self.hide_gui, 0, wx.ALL, 5) - self.handle_longtweets = wx.CheckBox(self, wx.ID_ANY, _(u"Use Codeofdusk's longtweet handlers (may decrease client performance)")) - sizer.Add(self.handle_longtweets, 0, wx.ALL, 5) - self.remember_mention_and_longtweet = wx.CheckBox(self, -1, _(u"Remember state for mention all and long tweet")) - sizer.Add(self.remember_mention_and_longtweet, 0, wx.ALL, 5) - kmbox = wx.BoxSizer(wx.VERTICAL) - km_label = wx.StaticText(self, -1, _(u"Keymap")) - self.km = wx.ComboBox(self, -1, choices=keymaps, style=wx.CB_READONLY) - self.km.SetSize(self.km.GetBestSize()) - kmbox.Add(km_label, 0, wx.ALL, 5) - kmbox.Add(self.km, 0, wx.ALL, 5) - self.check_for_updates = wx.CheckBox(self, -1, _(U"Check for updates when {0} launches").format(application.name,)) - sizer.Add(self.check_for_updates, 0, wx.ALL, 5) - sizer.Add(kmbox, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent, languages,keymaps): + super(general, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + language = wx.StaticText(self, -1, _(u"Language")) + self.language = wx.ListBox(self, -1, choices=languages) + self.language.SetSize(self.language.GetBestSize()) + langBox = wx.BoxSizer(wx.HORIZONTAL) + langBox.Add(language, 0, wx.ALL, 5) + langBox.Add(self.language, 0, wx.ALL, 5) + sizer.Add(langBox, 0, wx.ALL, 5) + self.autostart = wx.CheckBox(self, -1, _(u"Run {0} at Windows startup").format(application.name,)) + self.ask_at_exit = wx.CheckBox(self, -1, _(U"ask before exiting {0}").format(application.name,)) + sizer.Add(self.autostart, 0, wx.ALL, 5) + sizer.Add(self.ask_at_exit, 0, wx.ALL, 5) + self.no_streaming = wx.CheckBox(self, -1, _(U"Disable Streaming functions")) + sizer.Add(self.no_streaming, 0, wx.ALL, 5) + updatePeriodBox = wx.BoxSizer(wx.HORIZONTAL) + updatePeriodBox.Add(wx.StaticText(self, -1, _(u"Buffer update interval, in minutes")), 0, wx.ALL, 5) + self.update_period = wx.SpinCtrl(self, wx.ID_ANY) + self.update_period.SetRange(1, 30) + self.update_period.SetSize(self.update_period.GetBestSize()) + updatePeriodBox.Add(self.update_period, 0, wx.ALL, 5) + sizer.Add(updatePeriodBox, 0, wx.ALL, 5) + self.play_ready_sound = wx.CheckBox(self, -1, _(U"Play a sound when {0} launches").format(application.name,)) + sizer.Add(self.play_ready_sound, 0, wx.ALL, 5) + self.speak_ready_msg = wx.CheckBox(self, -1, _(U"Speak a message when {0} launches").format(application.name,)) + sizer.Add(self.speak_ready_msg, 0, wx.ALL, 5) + self.use_invisible_shorcuts = wx.CheckBox(self, -1, _(u"Use invisible interface's keyboard shortcuts while GUI is visible")) + sizer.Add(self.use_invisible_shorcuts, 0, wx.ALL, 5) + self.disable_sapi5 = wx.CheckBox(self, -1, _(u"Activate Sapi5 when any other screen reader is not being run")) + sizer.Add(self.disable_sapi5, 0, wx.ALL, 5) + self.hide_gui = wx.CheckBox(self, -1, _(u"Hide GUI on launch")) + sizer.Add(self.hide_gui, 0, wx.ALL, 5) + self.handle_longtweets = wx.CheckBox(self, wx.ID_ANY, _(u"Use Codeofdusk's longtweet handlers (may decrease client performance)")) + sizer.Add(self.handle_longtweets, 0, wx.ALL, 5) + self.remember_mention_and_longtweet = wx.CheckBox(self, -1, _(u"Remember state for mention all and long tweet")) + sizer.Add(self.remember_mention_and_longtweet, 0, wx.ALL, 5) + kmbox = wx.BoxSizer(wx.VERTICAL) + km_label = wx.StaticText(self, -1, _(u"Keymap")) + self.km = wx.ComboBox(self, -1, choices=keymaps, style=wx.CB_READONLY) + self.km.SetSize(self.km.GetBestSize()) + kmbox.Add(km_label, 0, wx.ALL, 5) + kmbox.Add(self.km, 0, wx.ALL, 5) + self.check_for_updates = wx.CheckBox(self, -1, _(U"Check for updates when {0} launches").format(application.name,)) + sizer.Add(self.check_for_updates, 0, wx.ALL, 5) + sizer.Add(kmbox, 0, wx.ALL, 5) + self.SetSizer(sizer) class proxy(wx.Panel, baseDialog.BaseWXDialog): - def __init__(self, parent, proxyTypes): - super(proxy, self).__init__(parent) - sizer = wx.BoxSizer(wx.VERTICAL) - type=wx.StaticText(self, wx.ID_ANY, _(u"Proxy type: ")) - self.type=wx.ComboBox(self, -1, choices=proxyTypes, style=wx.CB_READONLY) - self.type.SetSize(self.type.GetBestSize()) - typeBox = wx.BoxSizer(wx.HORIZONTAL) - typeBox.Add(type, 0, wx.ALL, 5) - typeBox.Add(self.type, 0, wx.ALL, 5) - sizer.Add(typeBox, 0, wx.ALL, 5) - lbl = wx.StaticText(self, wx.ID_ANY, _(u"Proxy server: ")) - self.server = wx.TextCtrl(self, -1) - serverBox = wx.BoxSizer(wx.HORIZONTAL) - serverBox.Add(lbl, 0, wx.ALL, 5) - serverBox.Add(self.server, 0, wx.ALL, 5) - sizer.Add(serverBox, 0, wx.ALL, 5) - lbl = wx.StaticText(self, wx.ID_ANY, _(u"Port: ")) - self.port = wx.SpinCtrl(self, wx.ID_ANY, min=1, max=65535) - portBox = wx.BoxSizer(wx.HORIZONTAL) - portBox.Add(lbl, 0, wx.ALL, 5) - portBox.Add(self.port, 0, wx.ALL, 5) - sizer.Add(portBox, 0, wx.ALL, 5) - lbl = wx.StaticText(self, wx.ID_ANY, _(u"User: ")) - self.user = wx.TextCtrl(self, wx.ID_ANY) - userBox = wx.BoxSizer(wx.HORIZONTAL) - userBox.Add(lbl, 0, wx.ALL, 5) - userBox.Add(self.user, 0, wx.ALL, 5) - sizer.Add(userBox, 0, wx.ALL, 5) - lbl = wx.StaticText(self, wx.ID_ANY, _(u"Password: ")) - self.password = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PASSWORD) - passwordBox = wx.BoxSizer(wx.HORIZONTAL) - passwordBox.Add(lbl, 0, wx.ALL, 5) - passwordBox.Add(self.password, 0, wx.ALL, 5) - sizer.Add(serverBox, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent, proxyTypes): + super(proxy, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + type=wx.StaticText(self, wx.ID_ANY, _(u"Proxy type: ")) + self.type=wx.ComboBox(self, -1, choices=proxyTypes, style=wx.CB_READONLY) + self.type.SetSize(self.type.GetBestSize()) + typeBox = wx.BoxSizer(wx.HORIZONTAL) + typeBox.Add(type, 0, wx.ALL, 5) + typeBox.Add(self.type, 0, wx.ALL, 5) + sizer.Add(typeBox, 0, wx.ALL, 5) + lbl = wx.StaticText(self, wx.ID_ANY, _(u"Proxy server: ")) + self.server = wx.TextCtrl(self, -1) + serverBox = wx.BoxSizer(wx.HORIZONTAL) + serverBox.Add(lbl, 0, wx.ALL, 5) + serverBox.Add(self.server, 0, wx.ALL, 5) + sizer.Add(serverBox, 0, wx.ALL, 5) + lbl = wx.StaticText(self, wx.ID_ANY, _(u"Port: ")) + self.port = wx.SpinCtrl(self, wx.ID_ANY, min=1, max=65535) + portBox = wx.BoxSizer(wx.HORIZONTAL) + portBox.Add(lbl, 0, wx.ALL, 5) + portBox.Add(self.port, 0, wx.ALL, 5) + sizer.Add(portBox, 0, wx.ALL, 5) + lbl = wx.StaticText(self, wx.ID_ANY, _(u"User: ")) + self.user = wx.TextCtrl(self, wx.ID_ANY) + userBox = wx.BoxSizer(wx.HORIZONTAL) + userBox.Add(lbl, 0, wx.ALL, 5) + userBox.Add(self.user, 0, wx.ALL, 5) + sizer.Add(userBox, 0, wx.ALL, 5) + lbl = wx.StaticText(self, wx.ID_ANY, _(u"Password: ")) + self.password = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PASSWORD) + passwordBox = wx.BoxSizer(wx.HORIZONTAL) + passwordBox.Add(lbl, 0, wx.ALL, 5) + passwordBox.Add(self.password, 0, wx.ALL, 5) + sizer.Add(serverBox, 0, wx.ALL, 5) + self.SetSizer(sizer) class generalAccount(wx.Panel, baseDialog.BaseWXDialog): - def __init__(self, parent): - super(generalAccount, self).__init__(parent) - sizer = wx.BoxSizer(wx.VERTICAL) - self.au = wx.Button(self, wx.ID_ANY, _(u"Autocompletion settings...")) - sizer.Add(self.au, 0, wx.ALL, 5) - self.relative_time = wx.CheckBox(self, wx.ID_ANY, _(U"Relative timestamps")) - sizer.Add(self.relative_time, 0, wx.ALL, 5) - tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL) - tweetsPerCallBox.Add(wx.StaticText(self, -1, _(u"Items on each API call")), 0, wx.ALL, 5) - self.itemsPerApiCall = wx.SpinCtrl(self, wx.ID_ANY) - self.itemsPerApiCall.SetRange(0, 200) - self.itemsPerApiCall.SetSize(self.itemsPerApiCall.GetBestSize()) - tweetsPerCallBox.Add(self.itemsPerApiCall, 0, wx.ALL, 5) - sizer.Add(tweetsPerCallBox, 0, wx.ALL, 5) - self.reverse_timelines = wx.CheckBox(self, wx.ID_ANY, _(u"Inverted buffers: The newest tweets will be shown at the beginning while the oldest at the end")) - sizer.Add(self.reverse_timelines, 0, wx.ALL, 5) - lbl = wx.StaticText(self, wx.ID_ANY, _(u"Retweet mode")) - self.retweet_mode = wx.ComboBox(self, wx.ID_ANY, choices=[_(u"Ask"), _(u"Retweet without comments"), _(u"Retweet with comments")], style=wx.CB_READONLY) - rMode = wx.BoxSizer(wx.HORIZONTAL) - rMode.Add(lbl, 0, wx.ALL, 5) - rMode.Add(self.retweet_mode, 0, wx.ALL, 5) - sizer.Add(rMode, 0, wx.ALL, 5) - self.show_screen_names = wx.CheckBox(self, wx.ID_ANY, _(U"Show screen names instead of full names")) - sizer.Add(self.show_screen_names, 0, wx.ALL, 5) - PersistSizeLabel = wx.StaticText(self, -1, _(u"Number of items per buffer to cache in database (0 to disable caching, blank for unlimited)")) - self.persist_size = wx.TextCtrl(self, -1) - sizer.Add(PersistSizeLabel, 0, wx.ALL, 5) - sizer.Add(self.persist_size, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent): + super(generalAccount, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + self.au = wx.Button(self, wx.ID_ANY, _(u"Autocompletion settings...")) + sizer.Add(self.au, 0, wx.ALL, 5) + self.relative_time = wx.CheckBox(self, wx.ID_ANY, _(U"Relative timestamps")) + sizer.Add(self.relative_time, 0, wx.ALL, 5) + tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL) + tweetsPerCallBox.Add(wx.StaticText(self, -1, _(u"Items on each API call")), 0, wx.ALL, 5) + self.itemsPerApiCall = wx.SpinCtrl(self, wx.ID_ANY) + self.itemsPerApiCall.SetRange(0, 200) + self.itemsPerApiCall.SetSize(self.itemsPerApiCall.GetBestSize()) + tweetsPerCallBox.Add(self.itemsPerApiCall, 0, wx.ALL, 5) + sizer.Add(tweetsPerCallBox, 0, wx.ALL, 5) + self.reverse_timelines = wx.CheckBox(self, wx.ID_ANY, _(u"Inverted buffers: The newest tweets will be shown at the beginning while the oldest at the end")) + sizer.Add(self.reverse_timelines, 0, wx.ALL, 5) + lbl = wx.StaticText(self, wx.ID_ANY, _(u"Retweet mode")) + self.retweet_mode = wx.ComboBox(self, wx.ID_ANY, choices=[_(u"Ask"), _(u"Retweet without comments"), _(u"Retweet with comments")], style=wx.CB_READONLY) + rMode = wx.BoxSizer(wx.HORIZONTAL) + rMode.Add(lbl, 0, wx.ALL, 5) + rMode.Add(self.retweet_mode, 0, wx.ALL, 5) + sizer.Add(rMode, 0, wx.ALL, 5) + self.show_screen_names = wx.CheckBox(self, wx.ID_ANY, _(U"Show screen names instead of full names")) + sizer.Add(self.show_screen_names, 0, wx.ALL, 5) + PersistSizeLabel = wx.StaticText(self, -1, _(u"Number of items per buffer to cache in database (0 to disable caching, blank for unlimited)")) + self.persist_size = wx.TextCtrl(self, -1) + sizer.Add(PersistSizeLabel, 0, wx.ALL, 5) + sizer.Add(self.persist_size, 0, wx.ALL, 5) + self.SetSizer(sizer) class reporting(wx.Panel, baseDialog.BaseWXDialog): - def __init__(self, parent): - super(reporting, self).__init__(parent) - sizer = wx.BoxSizer(wx.VERTICAL) - self.speech_reporting = wx.CheckBox(self, wx.ID_ANY, _(U"Enable automatic speech feedback")) - sizer.Add(self.speech_reporting, 0, wx.ALL, 5) - self.braille_reporting = wx.CheckBox(self, wx.ID_ANY, _(U"Enable automatic Braille feedback")) - sizer.Add(self.braille_reporting, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent): + super(reporting, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + self.speech_reporting = wx.CheckBox(self, wx.ID_ANY, _(U"Enable automatic speech feedback")) + sizer.Add(self.speech_reporting, 0, wx.ALL, 5) + self.braille_reporting = wx.CheckBox(self, wx.ID_ANY, _(U"Enable automatic Braille feedback")) + sizer.Add(self.braille_reporting, 0, wx.ALL, 5) + self.SetSizer(sizer) class other_buffers(wx.Panel): - def __init__(self, parent): - super(other_buffers, self).__init__(parent) - sizer = wx.BoxSizer(wx.VERTICAL) - self.buffers = widgets.list(self, _(u"Buffer"), _(u"Name"), _(u"Status"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) - sizer.Add(self.buffers.list, 0, wx.ALL, 5) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - self.toggle_state = wx.Button(self, -1, _(u"Show/hide")) - self.up = wx.Button(self, -1, _(u"Move up")) - self.down = wx.Button(self, -1, _(u"Move down")) - btnSizer.Add(self.toggle_state, 0, wx.ALL, 5) - btnSizer.Add(self.up, 0, wx.ALL, 5) - btnSizer.Add(self.down, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent): + super(other_buffers, self).__init__(parent) + sizer = wx.BoxSizer(wx.VERTICAL) + self.buffers = widgets.list(self, _(u"Buffer"), _(u"Name"), _(u"Status"), style=wx.LC_SINGLE_SEL|wx.LC_REPORT) + sizer.Add(self.buffers.list, 0, wx.ALL, 5) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + self.toggle_state = wx.Button(self, -1, _(u"Show/hide")) + self.up = wx.Button(self, -1, _(u"Move up")) + self.down = wx.Button(self, -1, _(u"Move down")) + btnSizer.Add(self.toggle_state, 0, wx.ALL, 5) + btnSizer.Add(self.up, 0, wx.ALL, 5) + btnSizer.Add(self.down, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + self.SetSizer(sizer) - def insert_buffers(self, buffers): - for i in buffers: - if i[2] == True: - self.buffers.insert_item(False, *[i[0], i[1], _(u"Show")]) - else: - self.buffers.insert_item(False, *[i[0], i[1], _(u"Hide")]) + def insert_buffers(self, buffers): + for i in buffers: + if i[2] == True: + self.buffers.insert_item(False, *[i[0], i[1], _(u"Show")]) + else: + self.buffers.insert_item(False, *[i[0], i[1], _(u"Hide")]) - def connect_hook_func(self, func): - self.buffers.list.Bind(wx.EVT_CHAR_HOOK, func) + def connect_hook_func(self, func): + self.buffers.list.Bind(wx.EVT_CHAR_HOOK, func) - def move_up(self, *args, **kwargs): - current = self.buffers.get_selected() - if current == -1: - output.speak(_(u"Select a buffer first."), True) - return False - if self.buffers.get_text_column(current, 2) == _(u"Hide"): - output.speak(_(u"The buffer is hidden, show it first."), True) - return False - if current <= 0: - output.speak(_(u"The buffer is already at the top of the list."), True) - return False - current_text = self.buffers.get_text_column(self.buffers.get_selected(), 0) - current_name = self.buffers.get_text_column(self.buffers.get_selected(), 1) - current_text_state = self.buffers.get_text_column(self.buffers.get_selected(), 2) - text_above = self.buffers.get_text_column(self.buffers.get_selected()-1, 0) - name_above = self.buffers.get_text_column(self.buffers.get_selected()-1, 1) - text_above_state = self.buffers.get_text_column(self.buffers.get_selected()-1, 2) - self.buffers.set_text_column(self.buffers.get_selected()-1, 0, current_text) - self.buffers.set_text_column(self.buffers.get_selected()-1, 1, current_name) - self.buffers.set_text_column(self.buffers.get_selected()-1, 2, current_text_state) - self.buffers.set_text_column(self.buffers.get_selected(), 0, text_above) - self.buffers.set_text_column(self.buffers.get_selected(), 1, name_above) - self.buffers.set_text_column(self.buffers.get_selected(), 2, text_above_state) + def move_up(self, *args, **kwargs): + current = self.buffers.get_selected() + if current == -1: + output.speak(_(u"Select a buffer first."), True) + return False + if self.buffers.get_text_column(current, 2) == _(u"Hide"): + output.speak(_(u"The buffer is hidden, show it first."), True) + return False + if current <= 0: + output.speak(_(u"The buffer is already at the top of the list."), True) + return False + current_text = self.buffers.get_text_column(self.buffers.get_selected(), 0) + current_name = self.buffers.get_text_column(self.buffers.get_selected(), 1) + current_text_state = self.buffers.get_text_column(self.buffers.get_selected(), 2) + text_above = self.buffers.get_text_column(self.buffers.get_selected()-1, 0) + name_above = self.buffers.get_text_column(self.buffers.get_selected()-1, 1) + text_above_state = self.buffers.get_text_column(self.buffers.get_selected()-1, 2) + self.buffers.set_text_column(self.buffers.get_selected()-1, 0, current_text) + self.buffers.set_text_column(self.buffers.get_selected()-1, 1, current_name) + self.buffers.set_text_column(self.buffers.get_selected()-1, 2, current_text_state) + self.buffers.set_text_column(self.buffers.get_selected(), 0, text_above) + self.buffers.set_text_column(self.buffers.get_selected(), 1, name_above) + self.buffers.set_text_column(self.buffers.get_selected(), 2, text_above_state) - def move_down(self, *args, **kwargs): - current = self.buffers.get_selected() - if current == -1: - output.speak(_(u"Select a buffer first."), True) - return False - if self.buffers.get_text_column(current, 2) == _(u"Hide"): - output.speak(_(u"The buffer is hidden, show it first."), True) - return False - if current+1 >= self.buffers.get_count(): - output.speak(_(u"The buffer is already at the bottom of the list."), True) - return False - current_text = self.buffers.get_text_column(self.buffers.get_selected(), 0) - current_name = self.buffers.get_text_column(self.buffers.get_selected(), 1) - current_text_state = self.buffers.get_text_column(self.buffers.get_selected(), 2) - text_below = self.buffers.get_text_column(self.buffers.get_selected()+1, 0) - name_below = self.buffers.get_text_column(self.buffers.get_selected()+1, 1) - text_below_state = self.buffers.get_text_column(self.buffers.get_selected()+1, 2) - self.buffers.set_text_column(self.buffers.get_selected()+1, 0, current_text) - self.buffers.set_text_column(self.buffers.get_selected()+1, 1, current_name) - self.buffers.set_text_column(self.buffers.get_selected()+1, 2, current_text_state) - self.buffers.set_text_column(self.buffers.get_selected(), 0, text_below) - self.buffers.set_text_column(self.buffers.get_selected(), 1, name_below) - self.buffers.set_text_column(self.buffers.get_selected(), 2, text_below_state) + def move_down(self, *args, **kwargs): + current = self.buffers.get_selected() + if current == -1: + output.speak(_(u"Select a buffer first."), True) + return False + if self.buffers.get_text_column(current, 2) == _(u"Hide"): + output.speak(_(u"The buffer is hidden, show it first."), True) + return False + if current+1 >= self.buffers.get_count(): + output.speak(_(u"The buffer is already at the bottom of the list."), True) + return False + current_text = self.buffers.get_text_column(self.buffers.get_selected(), 0) + current_name = self.buffers.get_text_column(self.buffers.get_selected(), 1) + current_text_state = self.buffers.get_text_column(self.buffers.get_selected(), 2) + text_below = self.buffers.get_text_column(self.buffers.get_selected()+1, 0) + name_below = self.buffers.get_text_column(self.buffers.get_selected()+1, 1) + text_below_state = self.buffers.get_text_column(self.buffers.get_selected()+1, 2) + self.buffers.set_text_column(self.buffers.get_selected()+1, 0, current_text) + self.buffers.set_text_column(self.buffers.get_selected()+1, 1, current_name) + self.buffers.set_text_column(self.buffers.get_selected()+1, 2, current_text_state) + self.buffers.set_text_column(self.buffers.get_selected(), 0, text_below) + self.buffers.set_text_column(self.buffers.get_selected(), 1, name_below) + self.buffers.set_text_column(self.buffers.get_selected(), 2, text_below_state) - def get_event(self, ev): - if ev.GetKeyCode() == wx.WXK_SPACE: - return True - else: - ev.Skip() - return False + def get_event(self, ev): + if ev.GetKeyCode() == wx.WXK_SPACE: + return True + else: + ev.Skip() + return False - def change_selected_item(self): - current = self.buffers.get_selected() - text = self.buffers.get_text_column(current, 2) - if text == _(u"Show"): - self.buffers.set_text_column(current, 2, _(u"Hide")) - else: - self.buffers.set_text_column(current, 2, _(u"Show")) - output.speak(self.buffers.get_text_column(current, 2),True) - def get_list(self): - buffers_list = [] - for i in range(0, self.buffers.get_count()): - if self.buffers.get_text_column(i, 2) == _(u"Show"): - buffers_list.append(self.buffers.get_text_column(i, 0)) - return buffers_list + def change_selected_item(self): + current = self.buffers.get_selected() + text = self.buffers.get_text_column(current, 2) + if text == _(u"Show"): + self.buffers.set_text_column(current, 2, _(u"Hide")) + else: + self.buffers.set_text_column(current, 2, _(u"Show")) + output.speak(self.buffers.get_text_column(current, 2),True) + def get_list(self): + buffers_list = [] + for i in range(0, self.buffers.get_count()): + if self.buffers.get_text_column(i, 2) == _(u"Show"): + buffers_list.append(self.buffers.get_text_column(i, 0)) + return buffers_list class ignoredClients(wx.Panel): - def __init__(self, parent, choices): - super(ignoredClients, self).__init__(parent=parent) - sizer = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(self, -1, _(u"Ignored clients")) - self.clients = wx.ListBox(self, -1, choices=choices) - self.clients.SetSize(self.clients.GetBestSize()) - clientsBox = wx.BoxSizer(wx.HORIZONTAL) - clientsBox.Add(label, 0, wx.ALL, 5) - clientsBox.Add(self.clients, 0, wx.ALL, 5) - self.add = wx.Button(self, -1, _(u"Add client")) - self.remove = wx.Button(self, -1, _(u"Remove client")) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(self.add, 0, wx.ALL, 5) - btnBox.Add(self.remove, 0, wx.ALL, 5) - sizer.Add(clientsBox, 0, wx.ALL, 5) - sizer.Add(btnBox, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent, choices): + super(ignoredClients, self).__init__(parent=parent) + sizer = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(self, -1, _(u"Ignored clients")) + self.clients = wx.ListBox(self, -1, choices=choices) + self.clients.SetSize(self.clients.GetBestSize()) + clientsBox = wx.BoxSizer(wx.HORIZONTAL) + clientsBox.Add(label, 0, wx.ALL, 5) + clientsBox.Add(self.clients, 0, wx.ALL, 5) + self.add = wx.Button(self, -1, _(u"Add client")) + self.remove = wx.Button(self, -1, _(u"Remove client")) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.add, 0, wx.ALL, 5) + btnBox.Add(self.remove, 0, wx.ALL, 5) + sizer.Add(clientsBox, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + self.SetSizer(sizer) - def append(self, client): - self.clients.Append(client) + def append(self, client): + self.clients.Append(client) - def get_clients(self): - return self.clients.GetCount() + def get_clients(self): + return self.clients.GetCount() - def get_client_id(self): - return self.clients.GetSelection() + def get_client_id(self): + return self.clients.GetSelection() - def remove_(self, id): - self.clients.Delete(id) + def remove_(self, id): + self.clients.Delete(id) class sound(wx.Panel): - def __init__(self, parent, input_devices, output_devices, soundpacks): - wx.Panel.__init__(self, parent) - sizer = wx.BoxSizer(wx.VERTICAL) - volume = wx.StaticText(self, -1, _(u"Volume")) - self.volumeCtrl = wx.Slider(self) - # Connect a key handler here to handle volume slider being inverted when moving with up and down arrows. - # see https://github.com/manuelcortez/TWBlue/issues/261 - widgetUtils.connect_event(self.volumeCtrl, widgetUtils.KEYPRESS, self.on_keypress) - self.volumeCtrl.SetRange(0, 100) - self.volumeCtrl.SetSize(self.volumeCtrl.GetBestSize()) - volumeBox = wx.BoxSizer(wx.HORIZONTAL) - volumeBox.Add(volume, 0, wx.ALL, 5) - volumeBox.Add(self.volumeCtrl, 0, wx.ALL, 5) - sizer.Add(volumeBox, 0, wx.ALL, 5) - self.session_mute = wx.CheckBox(self, -1, _(u"Session mute")) - sizer.Add(self.session_mute, 0, wx.ALL, 5) - output_label = wx.StaticText(self, -1, _(u"Output device")) - self.output = wx.ComboBox(self, -1, choices=output_devices, style=wx.CB_READONLY) - self.output.SetSize(self.output.GetBestSize()) - outputBox = wx.BoxSizer(wx.HORIZONTAL) - outputBox.Add(output_label, 0, wx.ALL, 5) - outputBox.Add(self.output, 0, wx.ALL, 5) - sizer.Add(outputBox, 0, wx.ALL, 5) - input_label = wx.StaticText(self, -1, _(u"Input device")) - self.input = wx.ComboBox(self, -1, choices=input_devices, style=wx.CB_READONLY) - self.input.SetSize(self.input.GetBestSize()) - inputBox = wx.BoxSizer(wx.HORIZONTAL) - inputBox.Add(input_label, 0, wx.ALL, 5) - inputBox.Add(self.input, 0, wx.ALL, 5) - sizer.Add(inputBox, 0, wx.ALL, 5) - soundBox = wx.BoxSizer(wx.VERTICAL) - soundpack_label = wx.StaticText(self, -1, _(u"Sound pack")) - self.soundpack = wx.ComboBox(self, -1, choices=soundpacks, style=wx.CB_READONLY) - self.soundpack.SetSize(self.soundpack.GetBestSize()) - soundBox.Add(soundpack_label, 0, wx.ALL, 5) - soundBox.Add(self.soundpack, 0, wx.ALL, 5) - sizer.Add(soundBox, 0, wx.ALL, 5) - self.indicate_audio = wx.CheckBox(self, -1, _(u"Indicate audio tweets with sound")) - sizer.Add(self.indicate_audio, 0, wx.ALL, 5) - self.indicate_geo = wx.CheckBox(self, -1, _(u"Indicate geotweets with sound")) - sizer.Add(self.indicate_geo, 0, wx.ALL, 5) - self.indicate_img = wx.CheckBox(self, -1, _(u"Indicate tweets containing images with sound")) - sizer.Add(self.indicate_img, 0, wx.ALL, 5) - self.SetSizer(sizer) + def __init__(self, parent, input_devices, output_devices, soundpacks): + wx.Panel.__init__(self, parent) + sizer = wx.BoxSizer(wx.VERTICAL) + volume = wx.StaticText(self, -1, _(u"Volume")) + self.volumeCtrl = wx.Slider(self) + # Connect a key handler here to handle volume slider being inverted when moving with up and down arrows. + # see https://github.com/manuelcortez/TWBlue/issues/261 + widgetUtils.connect_event(self.volumeCtrl, widgetUtils.KEYPRESS, self.on_keypress) + self.volumeCtrl.SetRange(0, 100) + self.volumeCtrl.SetSize(self.volumeCtrl.GetBestSize()) + volumeBox = wx.BoxSizer(wx.HORIZONTAL) + volumeBox.Add(volume, 0, wx.ALL, 5) + volumeBox.Add(self.volumeCtrl, 0, wx.ALL, 5) + sizer.Add(volumeBox, 0, wx.ALL, 5) + self.session_mute = wx.CheckBox(self, -1, _(u"Session mute")) + sizer.Add(self.session_mute, 0, wx.ALL, 5) + output_label = wx.StaticText(self, -1, _(u"Output device")) + self.output = wx.ComboBox(self, -1, choices=output_devices, style=wx.CB_READONLY) + self.output.SetSize(self.output.GetBestSize()) + outputBox = wx.BoxSizer(wx.HORIZONTAL) + outputBox.Add(output_label, 0, wx.ALL, 5) + outputBox.Add(self.output, 0, wx.ALL, 5) + sizer.Add(outputBox, 0, wx.ALL, 5) + input_label = wx.StaticText(self, -1, _(u"Input device")) + self.input = wx.ComboBox(self, -1, choices=input_devices, style=wx.CB_READONLY) + self.input.SetSize(self.input.GetBestSize()) + inputBox = wx.BoxSizer(wx.HORIZONTAL) + inputBox.Add(input_label, 0, wx.ALL, 5) + inputBox.Add(self.input, 0, wx.ALL, 5) + sizer.Add(inputBox, 0, wx.ALL, 5) + soundBox = wx.BoxSizer(wx.VERTICAL) + soundpack_label = wx.StaticText(self, -1, _(u"Sound pack")) + self.soundpack = wx.ComboBox(self, -1, choices=soundpacks, style=wx.CB_READONLY) + self.soundpack.SetSize(self.soundpack.GetBestSize()) + soundBox.Add(soundpack_label, 0, wx.ALL, 5) + soundBox.Add(self.soundpack, 0, wx.ALL, 5) + sizer.Add(soundBox, 0, wx.ALL, 5) + self.indicate_audio = wx.CheckBox(self, -1, _(u"Indicate audio tweets with sound")) + sizer.Add(self.indicate_audio, 0, wx.ALL, 5) + self.indicate_geo = wx.CheckBox(self, -1, _(u"Indicate geotweets with sound")) + sizer.Add(self.indicate_geo, 0, wx.ALL, 5) + self.indicate_img = wx.CheckBox(self, -1, _(u"Indicate tweets containing images with sound")) + sizer.Add(self.indicate_img, 0, wx.ALL, 5) + self.SetSizer(sizer) - def on_keypress(self, event, *args, **kwargs): - """ Invert movement of up and down arrow keys when dealing with a wX Slider. - See https://github.com/manuelcortez/TWBlue/issues/261 - and http://trac.wxwidgets.org/ticket/2068 - """ - keycode = event.GetKeyCode() - if keycode == wx.WXK_UP: - return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()+1) - elif keycode == wx.WXK_DOWN: - return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()-1) - event.Skip() + def on_keypress(self, event, *args, **kwargs): + """ Invert movement of up and down arrow keys when dealing with a wX Slider. + See https://github.com/manuelcortez/TWBlue/issues/261 + and http://trac.wxwidgets.org/ticket/2068 + """ + keycode = event.GetKeyCode() + if keycode == wx.WXK_UP: + return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()+1) + elif keycode == wx.WXK_DOWN: + return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()-1) + event.Skip() - def get(self, control): - return getattr(self, control).GetStringSelection() + def get(self, control): + return getattr(self, control).GetStringSelection() class extrasPanel(wx.Panel): - def __init__(self, parent, ocr_languages=[], translation_languages=[]): - super(extrasPanel, self).__init__(parent) - mainSizer = wx.BoxSizer(wx.VERTICAL) - OCRBox = wx.StaticBox(self, label=_(u"Language for OCR")) - self.ocr_lang = wx.ListBox(self, -1, choices=ocr_languages) - self.ocr_lang.SetSize(self.ocr_lang.GetBestSize()) - ocrLanguageSizer = wx.StaticBoxSizer(OCRBox, wx.HORIZONTAL) - ocrLanguageSizer.Add(self.ocr_lang, 0, wx.ALL, 5) - mainSizer.Add(ocrLanguageSizer, 0, wx.ALL, 5) - lbl = wx.StaticText(self, wx.ID_ANY, _(u"API Key for SndUp")) - self.sndup_apiKey = wx.TextCtrl(self, -1) - sndupBox = wx.BoxSizer(wx.HORIZONTAL) - sndupBox.Add(lbl, 0, wx.ALL, 5) - sndupBox.Add(self.sndup_apiKey, 0, wx.ALL, 5) - mainSizer.Add(sndupBox, 0, wx.ALL, 5) - self.SetSizer(mainSizer) + def __init__(self, parent, ocr_languages=[], translation_languages=[]): + super(extrasPanel, self).__init__(parent) + mainSizer = wx.BoxSizer(wx.VERTICAL) + OCRBox = wx.StaticBox(self, label=_(u"Language for OCR")) + self.ocr_lang = wx.ListBox(self, -1, choices=ocr_languages) + self.ocr_lang.SetSize(self.ocr_lang.GetBestSize()) + ocrLanguageSizer = wx.StaticBoxSizer(OCRBox, wx.HORIZONTAL) + ocrLanguageSizer.Add(self.ocr_lang, 0, wx.ALL, 5) + mainSizer.Add(ocrLanguageSizer, 0, wx.ALL, 5) + lbl = wx.StaticText(self, wx.ID_ANY, _(u"API Key for SndUp")) + self.sndup_apiKey = wx.TextCtrl(self, -1) + sndupBox = wx.BoxSizer(wx.HORIZONTAL) + sndupBox.Add(lbl, 0, wx.ALL, 5) + sndupBox.Add(self.sndup_apiKey, 0, wx.ALL, 5) + mainSizer.Add(sndupBox, 0, wx.ALL, 5) + self.SetSizer(mainSizer) class configurationDialog(baseDialog.BaseWXDialog): - def set_title(self, title): - self.SetTitle(title) + def set_title(self, title): + self.SetTitle(title) - def __init__(self): - super(configurationDialog, self).__init__(None, -1) - self.panel = wx.Panel(self) - self.SetTitle(_(u"{0} preferences").format(application.name,)) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.notebook = wx.Notebook(self.panel) + def __init__(self): + super(configurationDialog, self).__init__(None, -1) + self.panel = wx.Panel(self) + self.SetTitle(_(u"{0} preferences").format(application.name,)) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.notebook = wx.Notebook(self.panel) - def create_general(self, languageList,keymaps): - self.general = general(self.notebook, languageList,keymaps) - self.notebook.AddPage(self.general, _(u"General")) - self.general.SetFocus() + def create_general(self, languageList,keymaps): + self.general = general(self.notebook, languageList,keymaps) + self.notebook.AddPage(self.general, _(u"General")) + self.general.SetFocus() - def create_proxy(self, proxyTypes): - self.proxy = proxy(self.notebook, proxyTypes) - self.notebook.AddPage(self.proxy, _(u"Proxy")) + def create_proxy(self, proxyTypes): + self.proxy = proxy(self.notebook, proxyTypes) + self.notebook.AddPage(self.proxy, _(u"Proxy")) - def create_general_account(self): - self.general = generalAccount(self.notebook) - self.notebook.AddPage(self.general, _(u"General")) - self.general.SetFocus() + def create_general_account(self): + self.general = generalAccount(self.notebook) + self.notebook.AddPage(self.general, _(u"General")) + self.general.SetFocus() - def create_reporting(self): - self.reporting = reporting(self.notebook) - self.notebook.AddPage(self.reporting, _(u"Feedback")) + def create_reporting(self): + self.reporting = reporting(self.notebook) + self.notebook.AddPage(self.reporting, _(u"Feedback")) - def create_other_buffers(self): - self.buffers = other_buffers(self.notebook) - self.notebook.AddPage(self.buffers, _(u"Buffers")) + def create_other_buffers(self): + self.buffers = other_buffers(self.notebook) + self.notebook.AddPage(self.buffers, _(u"Buffers")) - def create_ignored_clients(self, ignored_clients_list): - self.ignored_clients = ignoredClients(self.notebook, ignored_clients_list) - self.notebook.AddPage(self.ignored_clients, _(u"Ignored clients")) + def create_ignored_clients(self, ignored_clients_list): + self.ignored_clients = ignoredClients(self.notebook, ignored_clients_list) + self.notebook.AddPage(self.ignored_clients, _(u"Ignored clients")) - def create_sound(self, output_devices, input_devices, soundpacks): - self.sound = sound(self.notebook, output_devices, input_devices, soundpacks) - self.notebook.AddPage(self.sound, _(u"Sound")) + def create_sound(self, output_devices, input_devices, soundpacks): + self.sound = sound(self.notebook, output_devices, input_devices, soundpacks) + self.notebook.AddPage(self.sound, _(u"Sound")) - def create_extras(self, ocr_languages=[], translator_languages=[]): - self.extras = extrasPanel(self.notebook, ocr_languages, translator_languages) - self.notebook.AddPage(self.extras, _(u"Extras")) + def create_extras(self, ocr_languages=[], translator_languages=[]): + self.extras = extrasPanel(self.notebook, ocr_languages, translator_languages) + self.notebook.AddPage(self.extras, _(u"Extras")) - def realize(self): - self.sizer.Add(self.notebook, 0, wx.ALL, 5) - ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL) - ok = wx.Button(self.panel, wx.ID_OK, _(u"Save")) - ok.SetDefault() - cancel = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close")) - self.SetEscapeId(cancel.GetId()) - ok_cancel_box.Add(ok, 0, wx.ALL, 5) - ok_cancel_box.Add(cancel, 0, wx.ALL, 5) - self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5) - self.panel.SetSizer(self.sizer) - self.SetClientSize(self.sizer.CalcMin()) + def realize(self): + self.sizer.Add(self.notebook, 0, wx.ALL, 5) + ok_cancel_box = wx.BoxSizer(wx.HORIZONTAL) + ok = wx.Button(self.panel, wx.ID_OK, _(u"Save")) + ok.SetDefault() + cancel = wx.Button(self.panel, wx.ID_CANCEL, _(u"Close")) + self.SetEscapeId(cancel.GetId()) + ok_cancel_box.Add(ok, 0, wx.ALL, 5) + ok_cancel_box.Add(cancel, 0, wx.ALL, 5) + self.sizer.Add(ok_cancel_box, 0, wx.ALL, 5) + self.panel.SetSizer(self.sizer) + self.SetClientSize(self.sizer.CalcMin()) - def get_value(self, panel, key): - p = getattr(self, panel) - return getattr(p, key).GetValue() + def get_value(self, panel, key): + p = getattr(self, panel) + return getattr(p, key).GetValue() - def set_value(self, panel, key, value): - p = getattr(self, panel) - control = getattr(p, key) - getattr(control, "SetValue")(value) + def set_value(self, panel, key, value): + p = getattr(self, panel) + control = getattr(p, key) + getattr(control, "SetValue")(value) diff --git a/src/wxUI/dialogs/filterDialogs.py b/src/wxUI/dialogs/filterDialogs.py index edff9d6a..bf7f45b2 100644 --- a/src/wxUI/dialogs/filterDialogs.py +++ b/src/wxUI/dialogs/filterDialogs.py @@ -8,139 +8,139 @@ import widgetUtils from multiplatform_widgets import widgets class filterDialog(baseDialog.BaseWXDialog): - def __init__(self, value="", languages=[]): - super(filterDialog, self).__init__(None, -1) - self.langs_list = languages - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle(_(u"Create a filter for this buffer")) - label = wx.StaticText(panel, wx.ID_ANY, _(u"Filter title")) - self.title = wx.TextCtrl(panel, -1, value) - dc = wx.WindowDC(self.title) - dc.SetFont(self.title.GetFont()) - self.title.SetSize(dc.GetTextExtent("0"*40)) - tsizer = wx.BoxSizer(wx.HORIZONTAL) - tsizer.Add(label, 0, wx.ALL, 5) - tsizer.Add(self.title, 0, wx.ALL, 5) - sizer.Add(tsizer, 0, wx.ALL, 5) - staticbox = wx.StaticBox(panel, label=_(u"Filter by word")) - self.contains = wx.RadioButton(panel, -1, _(u"Ignore tweets wich contain the following word"), style=wx.RB_GROUP) - self.doesnt_contain = wx.RadioButton(panel, -1, _(u"Ignore tweets without the following word")) - radioSizer1 = wx.StaticBoxSizer(staticbox, wx.HORIZONTAL) - radioSizer1.Add(self.contains, 0, wx.ALL, 5) - radioSizer1.Add(self.doesnt_contain, 0, wx.ALL, 5) - sizer.Add(radioSizer1, 0, wx.ALL, 5) - label = wx.StaticText(panel, -1, _(u"word")) - self.term = wx.TextCtrl(panel, -1, value) - dc = wx.WindowDC(self.term) - dc.SetFont(self.term.GetFont()) - self.term.SetSize(dc.GetTextExtent("0"*40)) - self.allow_rts = wx.CheckBox(panel, wx.ID_ANY, _(u"Allow retweets")) - self.allow_quotes = wx.CheckBox(panel, wx.ID_ANY, _(u"Allow quoted tweets")) - self.allow_replies = wx.CheckBox(panel, wx.ID_ANY, _(u"Allow replies")) - self.allow_rts.SetValue(True) - self.allow_quotes.SetValue(True) - self.allow_replies.SetValue(True) - bsizer = wx.BoxSizer(wx.HORIZONTAL) - bsizer.Add(label, 0, wx.ALL, 5) - bsizer.Add(self.term, 0, wx.ALL, 5) - sizer.Add(bsizer, 0, wx.ALL, 5) - self.regexp = wx.CheckBox(panel, wx.ID_ANY, _(u"Use this term as a regular expression")) - sizer.Add(self.regexp, 0, wx.ALL, 5) - staticbox = wx.StaticBox(panel, label=_(u"Filter by language")) - self.load_language = wx.RadioButton(panel, -1, _(u"Load tweets in the following languages"), style=wx.RB_GROUP) - self.ignore_language = wx.RadioButton(panel, -1, _(u"Ignore tweets in the following languages")) - self.skip_language_filtering = wx.RadioButton(panel, -1, _(u"Don't filter by language")) - self.skip_language_filtering.SetValue(True) - widgetUtils.connect_event(self.load_language, widgetUtils.RADIOBUTTON, self.show_language_options) - widgetUtils.connect_event(self.ignore_language, widgetUtils.RADIOBUTTON, self.show_language_options) - widgetUtils.connect_event(self.skip_language_filtering, widgetUtils.RADIOBUTTON, self.hide_language_options) - radioSizer2 = wx.StaticBoxSizer(staticbox, wx.HORIZONTAL) - radioSizer2.Add(self.load_language, 0, wx.ALL, 5) - radioSizer2.Add(self.ignore_language, 0, wx.ALL, 5) - radioSizer2.Add(self.skip_language_filtering, 0, wx.ALL, 5) - sizer.Add(radioSizer2, 0, wx.ALL, 5) - self.indexes = [] - langsLabel = wx.StaticText(panel, -1, _(u"Supported languages")) - self.cb = wx.ComboBox(panel, -1, choices=languages, value=languages[0]) - langsSizer = wx.BoxSizer() - langsSizer.Add(langsLabel, 0, wx.ALL, 5) - langsSizer.Add(self.cb, 0, wx.ALL, 5) - self.add = wx.Button(panel, wx.ID_ANY, _(u"Add selected language to filter")) - self.add.Bind(wx.EVT_BUTTON, self.add_lang) - langsSizer.Add(self.add, 0, wx.ALL, 5) - sizer.Add(langsSizer, 0, wx.ALL, 5) - lbl = wx.StaticText(panel, wx.ID_ANY, _(u"Selected languages")) - self.langs = wx.ListBox(panel, -1) - self.remove = wx.Button(panel, wx.ID_ANY, _(u"Remove")) - self.remove.Bind(wx.EVT_BUTTON, self.remove_lang) - selectionSizer = wx.BoxSizer(wx.HORIZONTAL) - selectionSizer.Add(lbl, 0, wx.ALL, 5) - selectionSizer.Add(self.langs, 0, wx.ALL, 5) - selectionSizer.Add(self.remove, 0, wx.ALL, 5) - sizer.Add(selectionSizer, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.hide_language_options() - self.SetClientSize(sizer.CalcMin()) + def __init__(self, value="", languages=[]): + super(filterDialog, self).__init__(None, -1) + self.langs_list = languages + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle(_(u"Create a filter for this buffer")) + label = wx.StaticText(panel, wx.ID_ANY, _(u"Filter title")) + self.title = wx.TextCtrl(panel, -1, value) + dc = wx.WindowDC(self.title) + dc.SetFont(self.title.GetFont()) + self.title.SetSize(dc.GetTextExtent("0"*40)) + tsizer = wx.BoxSizer(wx.HORIZONTAL) + tsizer.Add(label, 0, wx.ALL, 5) + tsizer.Add(self.title, 0, wx.ALL, 5) + sizer.Add(tsizer, 0, wx.ALL, 5) + staticbox = wx.StaticBox(panel, label=_(u"Filter by word")) + self.contains = wx.RadioButton(panel, -1, _(u"Ignore tweets wich contain the following word"), style=wx.RB_GROUP) + self.doesnt_contain = wx.RadioButton(panel, -1, _(u"Ignore tweets without the following word")) + radioSizer1 = wx.StaticBoxSizer(staticbox, wx.HORIZONTAL) + radioSizer1.Add(self.contains, 0, wx.ALL, 5) + radioSizer1.Add(self.doesnt_contain, 0, wx.ALL, 5) + sizer.Add(radioSizer1, 0, wx.ALL, 5) + label = wx.StaticText(panel, -1, _(u"word")) + self.term = wx.TextCtrl(panel, -1, value) + dc = wx.WindowDC(self.term) + dc.SetFont(self.term.GetFont()) + self.term.SetSize(dc.GetTextExtent("0"*40)) + self.allow_rts = wx.CheckBox(panel, wx.ID_ANY, _(u"Allow retweets")) + self.allow_quotes = wx.CheckBox(panel, wx.ID_ANY, _(u"Allow quoted tweets")) + self.allow_replies = wx.CheckBox(panel, wx.ID_ANY, _(u"Allow replies")) + self.allow_rts.SetValue(True) + self.allow_quotes.SetValue(True) + self.allow_replies.SetValue(True) + bsizer = wx.BoxSizer(wx.HORIZONTAL) + bsizer.Add(label, 0, wx.ALL, 5) + bsizer.Add(self.term, 0, wx.ALL, 5) + sizer.Add(bsizer, 0, wx.ALL, 5) + self.regexp = wx.CheckBox(panel, wx.ID_ANY, _(u"Use this term as a regular expression")) + sizer.Add(self.regexp, 0, wx.ALL, 5) + staticbox = wx.StaticBox(panel, label=_(u"Filter by language")) + self.load_language = wx.RadioButton(panel, -1, _(u"Load tweets in the following languages"), style=wx.RB_GROUP) + self.ignore_language = wx.RadioButton(panel, -1, _(u"Ignore tweets in the following languages")) + self.skip_language_filtering = wx.RadioButton(panel, -1, _(u"Don't filter by language")) + self.skip_language_filtering.SetValue(True) + widgetUtils.connect_event(self.load_language, widgetUtils.RADIOBUTTON, self.show_language_options) + widgetUtils.connect_event(self.ignore_language, widgetUtils.RADIOBUTTON, self.show_language_options) + widgetUtils.connect_event(self.skip_language_filtering, widgetUtils.RADIOBUTTON, self.hide_language_options) + radioSizer2 = wx.StaticBoxSizer(staticbox, wx.HORIZONTAL) + radioSizer2.Add(self.load_language, 0, wx.ALL, 5) + radioSizer2.Add(self.ignore_language, 0, wx.ALL, 5) + radioSizer2.Add(self.skip_language_filtering, 0, wx.ALL, 5) + sizer.Add(radioSizer2, 0, wx.ALL, 5) + self.indexes = [] + langsLabel = wx.StaticText(panel, -1, _(u"Supported languages")) + self.cb = wx.ComboBox(panel, -1, choices=languages, value=languages[0]) + langsSizer = wx.BoxSizer() + langsSizer.Add(langsLabel, 0, wx.ALL, 5) + langsSizer.Add(self.cb, 0, wx.ALL, 5) + self.add = wx.Button(panel, wx.ID_ANY, _(u"Add selected language to filter")) + self.add.Bind(wx.EVT_BUTTON, self.add_lang) + langsSizer.Add(self.add, 0, wx.ALL, 5) + sizer.Add(langsSizer, 0, wx.ALL, 5) + lbl = wx.StaticText(panel, wx.ID_ANY, _(u"Selected languages")) + self.langs = wx.ListBox(panel, -1) + self.remove = wx.Button(panel, wx.ID_ANY, _(u"Remove")) + self.remove.Bind(wx.EVT_BUTTON, self.remove_lang) + selectionSizer = wx.BoxSizer(wx.HORIZONTAL) + selectionSizer.Add(lbl, 0, wx.ALL, 5) + selectionSizer.Add(self.langs, 0, wx.ALL, 5) + selectionSizer.Add(self.remove, 0, wx.ALL, 5) + sizer.Add(selectionSizer, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.hide_language_options() + self.SetClientSize(sizer.CalcMin()) - def get_lang(self): - return self.cb.GetValue() + def get_lang(self): + return self.cb.GetValue() - def add_lang(self, *args, **kwargs): - selection = self.get_lang() - if selection in self.langs_list: - self.langs.Append(selection) - self.indexes.append(selection) + def add_lang(self, *args, **kwargs): + selection = self.get_lang() + if selection in self.langs_list: + self.langs.Append(selection) + self.indexes.append(selection) - def remove_lang(self, *args, **kwargs): - n = self.langs.GetSelection() - v = self.langs.GetStringSelection() - self.langs.Delete(n) - self.indexes.remove(v) + def remove_lang(self, *args, **kwargs): + n = self.langs.GetSelection() + v = self.langs.GetStringSelection() + self.langs.Delete(n) + self.indexes.remove(v) - def get_selected_langs(self): - return self.indexes + def get_selected_langs(self): + return self.indexes - def hide_language_options(self, *args, **kwargs): - for i in [self.cb, self.add, self.langs, self.remove]: - i.Hide() + def hide_language_options(self, *args, **kwargs): + for i in [self.cb, self.add, self.langs, self.remove]: + i.Hide() - def show_language_options(self, *args, **kwargs): - for i in [self.cb, self.add, self.langs, self.remove]: - i.Show() + def show_language_options(self, *args, **kwargs): + for i in [self.cb, self.add, self.langs, self.remove]: + i.Show() class filterManagerDialog(widgetUtils.BaseDialog): - def __init__(self, *args, **kwargs): - super(filterManagerDialog, self).__init__(parent=None, *args, **kwargs) - self.SetTitle(_(u"Manage filters")) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Filters")) - self.filters = widgets.list(panel, _(u"Filter"), _(u"Buffer"), _(u"Filter by word"), _(u"Filter by language"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) - self.filters.list.SetFocus() - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(label) - sizer.Add(self.filters.list) - self.edit = wx.Button(panel, wx.ID_ANY, _(u"Edit")) - self.edit.Enable(False) - self.delete = wx.Button(panel, wx.ID_ANY, _(u"Remove")) - self.cancel = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(self.edit, 0, wx.ALL, 5) - btnSizer.Add(self.delete, 0, wx.ALL, 5) - btnSizer.Add(self.cancel, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) + def __init__(self, *args, **kwargs): + super(filterManagerDialog, self).__init__(parent=None, *args, **kwargs) + self.SetTitle(_(u"Manage filters")) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Filters")) + self.filters = widgets.list(panel, _(u"Filter"), _(u"Buffer"), _(u"Filter by word"), _(u"Filter by language"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) + self.filters.list.SetFocus() + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label) + sizer.Add(self.filters.list) + self.edit = wx.Button(panel, wx.ID_ANY, _(u"Edit")) + self.edit.Enable(False) + self.delete = wx.Button(panel, wx.ID_ANY, _(u"Remove")) + self.cancel = wx.Button(panel, wx.ID_CANCEL) + btnSizer = wx.BoxSizer() + btnSizer.Add(self.edit, 0, wx.ALL, 5) + btnSizer.Add(self.delete, 0, wx.ALL, 5) + btnSizer.Add(self.cancel, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) - def get_item(self): - return self.filters.get_selected() + def get_item(self): + return self.filters.get_selected() - def clear(self): - self.filters.clear() + def clear(self): + self.filters.clear() diff --git a/src/wxUI/dialogs/find.py b/src/wxUI/dialogs/find.py index 73a3dd6f..c6176fc4 100644 --- a/src/wxUI/dialogs/find.py +++ b/src/wxUI/dialogs/find.py @@ -6,24 +6,24 @@ from . import baseDialog import wx class findDialog(baseDialog.BaseWXDialog): - def __init__(self, value=""): - super(findDialog, self).__init__(None, -1) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle(_(u"Find in current buffer")) - label = wx.StaticText(panel, -1, _(u"String")) - self.string = wx.TextCtrl(panel, -1, value) - dc = wx.WindowDC(self.string) - dc.SetFont(self.string.GetFont()) - self.string.SetSize(dc.GetTextExtent("0"*40)) - sizer.Add(label, 0, wx.ALL, 5) - sizer.Add(self.string, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) \ No newline at end of file + def __init__(self, value=""): + super(findDialog, self).__init__(None, -1) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle(_(u"Find in current buffer")) + label = wx.StaticText(panel, -1, _(u"String")) + self.string = wx.TextCtrl(panel, -1, value) + dc = wx.WindowDC(self.string) + dc.SetFont(self.string.GetFont()) + self.string.SetSize(dc.GetTextExtent("0"*40)) + sizer.Add(label, 0, wx.ALL, 5) + sizer.Add(self.string, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) diff --git a/src/wxUI/dialogs/lists.py b/src/wxUI/dialogs/lists.py index 9a30a4a3..cc8c3485 100644 --- a/src/wxUI/dialogs/lists.py +++ b/src/wxUI/dialogs/lists.py @@ -6,145 +6,145 @@ from multiplatform_widgets import widgets class listViewer(widgetUtils.BaseDialog): - def __init__(self, *args, **kwargs): - super(listViewer, self).__init__(parent=None, *args, **kwargs) - self.SetTitle(_(u"Lists manager")) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Lists")) - self.lista = widgets.list(panel, _(u"List"), _(u"Description"), _(u"Owner"), _(u"Members"), _(u"mode"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) - self.lista.list.SetFocus() - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(label) - sizer.Add(self.lista.list) - self.createBtn = wx.Button(panel, wx.ID_ANY, _(u"Create a new list")) - self.editBtn = wx.Button(panel, -1, _(u"Edit")) - self.deleteBtn = wx.Button(panel, -1, _(u"Remove")) - self.view = wx.Button(panel, -1, _(u"Open in buffer")) + def __init__(self, *args, **kwargs): + super(listViewer, self).__init__(parent=None, *args, **kwargs) + self.SetTitle(_(u"Lists manager")) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Lists")) + self.lista = widgets.list(panel, _(u"List"), _(u"Description"), _(u"Owner"), _(u"Members"), _(u"mode"), size=(800, 800), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) + self.lista.list.SetFocus() + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label) + sizer.Add(self.lista.list) + self.createBtn = wx.Button(panel, wx.ID_ANY, _(u"Create a new list")) + self.editBtn = wx.Button(panel, -1, _(u"Edit")) + self.deleteBtn = wx.Button(panel, -1, _(u"Remove")) + self.view = wx.Button(panel, -1, _(u"Open in buffer")) # self.members = wx.Button(panel, -1, _(u"View members")) # self.members.Disable() # self.subscriptors = wx.Button(panel, -1, _(u"View subscribers")) # self.subscriptors.Disable() # self.get_linkBtn = wx.Button(panel, -1, _(u"Get link for the list")) # self.get_linkBtn.Bind(wx.EVT_BUTTON, self.onGetLink) - self.cancelBtn = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(self.createBtn) - btnSizer.Add(self.editBtn) - btnSizer.Add(self.cancelBtn) - panel.SetSizer(sizer) + self.cancelBtn = wx.Button(panel, wx.ID_CANCEL) + btnSizer = wx.BoxSizer() + btnSizer.Add(self.createBtn) + btnSizer.Add(self.editBtn) + btnSizer.Add(self.cancelBtn) + panel.SetSizer(sizer) - def populate_list(self, lists, clear=False): - if clear == True: - self.clear() - for item in lists: - self.lista.insert_item(False, *item) + def populate_list(self, lists, clear=False): + if clear == True: + self.clear() + for item in lists: + self.lista.insert_item(False, *item) - def get_item(self): - return self.lista.get_selected() + def get_item(self): + return self.lista.get_selected() - def clear(self): - self.lista.clear() + def clear(self): + self.lista.clear() class userListViewer(listViewer): - def __init__(self, username, *args, **kwargs): - self.username = username - super(userListViewer, self).__init__(*args, **kwargs) - self.SetTitle(_(u"Viewing lists for %s") % (self.username)) - self.createBtn.SetLabel(_(u"Subscribe")) - self.deleteBtn.SetLabel(_(u"Unsubscribe")) - self.editBtn.Disable() - self.view.Disable() + def __init__(self, username, *args, **kwargs): + self.username = username + super(userListViewer, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Viewing lists for %s") % (self.username)) + self.createBtn.SetLabel(_(u"Subscribe")) + self.deleteBtn.SetLabel(_(u"Unsubscribe")) + self.editBtn.Disable() + self.view.Disable() class createListDialog(widgetUtils.BaseDialog): - def __init__(self, *args, **kwargs): - super(createListDialog, self).__init__(parent=None, *args, **kwargs) - self.SetTitle(_(u"Create a new list")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - name = wx.StaticText(panel, -1, _(u"Name (20 characters maximun)")) - self.name = wx.TextCtrl(panel, -1) - nameSizer = wx.BoxSizer(wx.HORIZONTAL) - nameSizer.Add(name) - nameSizer.Add(self.name) - description = wx.StaticText(panel, -1, _(u"Description")) - self.description = wx.TextCtrl(panel, -1) - descriptionSizer = wx.BoxSizer(wx.HORIZONTAL) - descriptionSizer.Add(description) - descriptionSizer.Add(self.description) - mode = wx.StaticText(panel, -1, _(u"Mode")) - self.public = wx.RadioButton(panel, -1, _(u"Public"), style=wx.RB_GROUP) - self.private = wx.RadioButton(panel, -1, _(u"Private")) - modeBox = wx.BoxSizer(wx.HORIZONTAL) - modeBox.Add(mode) - modeBox.Add(self.public) - modeBox.Add(self.private) - ok = wx.Button(panel, wx.ID_OK) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(ok) - btnBox.Add(cancel) - sizer.Add(nameSizer) - sizer.Add(descriptionSizer) - sizer.Add(modeBox) - sizer.Add(btnBox) + def __init__(self, *args, **kwargs): + super(createListDialog, self).__init__(parent=None, *args, **kwargs) + self.SetTitle(_(u"Create a new list")) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + name = wx.StaticText(panel, -1, _(u"Name (20 characters maximun)")) + self.name = wx.TextCtrl(panel, -1) + nameSizer = wx.BoxSizer(wx.HORIZONTAL) + nameSizer.Add(name) + nameSizer.Add(self.name) + description = wx.StaticText(panel, -1, _(u"Description")) + self.description = wx.TextCtrl(panel, -1) + descriptionSizer = wx.BoxSizer(wx.HORIZONTAL) + descriptionSizer.Add(description) + descriptionSizer.Add(self.description) + mode = wx.StaticText(panel, -1, _(u"Mode")) + self.public = wx.RadioButton(panel, -1, _(u"Public"), style=wx.RB_GROUP) + self.private = wx.RadioButton(panel, -1, _(u"Private")) + modeBox = wx.BoxSizer(wx.HORIZONTAL) + modeBox.Add(mode) + modeBox.Add(self.public) + modeBox.Add(self.private) + ok = wx.Button(panel, wx.ID_OK) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(ok) + btnBox.Add(cancel) + sizer.Add(nameSizer) + sizer.Add(descriptionSizer) + sizer.Add(modeBox) + sizer.Add(btnBox) class editListDialog(createListDialog): - def __init__(self, list, *args, **kwargs): - super(editListDialog, self).__init__(*args, **kwargs) - self.SetTitle(_(u"Editing the list %s") % (list.name)) - self.name.ChangeValue(list.name) - self.description.ChangeValue(list.description) - if list.mode == "public": - self.public.SetValue(True) - else: - self.private.SetValue(True) + def __init__(self, list, *args, **kwargs): + super(editListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Editing the list %s") % (list.name)) + self.name.ChangeValue(list.name) + self.description.ChangeValue(list.description) + if list.mode == "public": + self.public.SetValue(True) + else: + self.private.SetValue(True) class addUserListDialog(listViewer): - def __init__(self, *args, **kwargs): - super(addUserListDialog, self).__init__(*args, **kwargs) - self.SetTitle(_(u"Select a list to add the user")) - self.createBtn.SetLabel(_(u"Add")) - self.createBtn.SetDefault() - self.createBtn.Bind(wx.EVT_BUTTON, self.ok) - self.editBtn.Disable() - self.view.Disable() + def __init__(self, *args, **kwargs): + super(addUserListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Select a list to add the user")) + self.createBtn.SetLabel(_(u"Add")) + self.createBtn.SetDefault() + self.createBtn.Bind(wx.EVT_BUTTON, self.ok) + self.editBtn.Disable() + self.view.Disable() # self.subscriptors.Disable() # self.members.Disable() - self.deleteBtn.Disable() - widgetUtils.connect_event(self.lista.list, widgetUtils.KEYPRESS, self.on_keypress) + self.deleteBtn.Disable() + widgetUtils.connect_event(self.lista.list, widgetUtils.KEYPRESS, self.on_keypress) - def on_keypress(self, event): - """Catch return and execute ok()""" - if event.GetKeyCode() == wx.WXK_RETURN: - return self.ok() - event.Skip() + def on_keypress(self, event): + """Catch return and execute ok()""" + if event.GetKeyCode() == wx.WXK_RETURN: + return self.ok() + event.Skip() - def ok(self, *args, **kwargs): - self.EndModal(wx.ID_OK) + def ok(self, *args, **kwargs): + self.EndModal(wx.ID_OK) class removeUserListDialog(listViewer): - def __init__(self, *args, **kwargs): - super(removeUserListDialog, self).__init__(*args, **kwargs) - self.SetTitle(_(u"Select a list to remove the user")) - self.createBtn.SetLabel(_(u"Remove")) - self.createBtn.SetDefault() - self.createBtn.SetId(wx.ID_OK) - self.editBtn.Disable() - self.view.Disable() + def __init__(self, *args, **kwargs): + super(removeUserListDialog, self).__init__(*args, **kwargs) + self.SetTitle(_(u"Select a list to remove the user")) + self.createBtn.SetLabel(_(u"Remove")) + self.createBtn.SetDefault() + self.createBtn.SetId(wx.ID_OK) + self.editBtn.Disable() + self.view.Disable() # self.subscriptors.Disable() # self.members.Disable() - self.deleteBtn.Disable() - widgetUtils.connect_event(self.lista.list, widgetUtils.KEYPRESS, self.on_keypress) + self.deleteBtn.Disable() + widgetUtils.connect_event(self.lista.list, widgetUtils.KEYPRESS, self.on_keypress) - def on_keypress(self, event): - """Catch return and execute EndModal()""" - if event.GetKeyCode() == wx.WXK_RETURN: - return self.EndModal(wx.ID_OK) - event.Skip() + def on_keypress(self, event): + """Catch return and execute EndModal()""" + if event.GetKeyCode() == wx.WXK_RETURN: + return self.EndModal(wx.ID_OK) + event.Skip() def remove_list(): - return wx.MessageDialog(None, _("Do you really want to delete this list?"), _("Delete"), wx.YES_NO).ShowModal() + return wx.MessageDialog(None, _("Do you really want to delete this list?"), _("Delete"), wx.YES_NO).ShowModal() diff --git a/src/wxUI/dialogs/message.py b/src/wxUI/dialogs/message.py index 97f8a22a..6a74b32e 100644 --- a/src/wxUI/dialogs/message.py +++ b/src/wxUI/dialogs/message.py @@ -5,463 +5,463 @@ import wx import widgetUtils class textLimited(widgetUtils.BaseDialog): - def __init__(self, *args, **kwargs): - super(textLimited, self).__init__(parent=None, *args, **kwargs) + def __init__(self, *args, **kwargs): + super(textLimited, self).__init__(parent=None, *args, **kwargs) - def createTextArea(self, message="", text=""): - if not hasattr(self, "panel"): - self.panel = wx.Panel(self) - self.label = wx.StaticText(self.panel, -1, message) - self.SetTitle(str(len(text))) - self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1),style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + def createTextArea(self, message="", text=""): + if not hasattr(self, "panel"): + self.panel = wx.Panel(self) + self.label = wx.StaticText(self.panel, -1, message) + self.SetTitle(str(len(text))) + self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1),style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) # font = self.text.GetFont() # dc = wx.WindowDC(self.text) # dc.SetFont(font) # x, y = dc.GetTextExtent("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") # self.text.SetSize((x, y)) - self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) - self.text.SetFocus() - self.textBox = wx.BoxSizer(wx.HORIZONTAL) - self.textBox.Add(self.label, 0, wx.ALL, 5) - self.textBox.Add(self.text, 0, wx.ALL, 5) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetFocus() + self.textBox = wx.BoxSizer(wx.HORIZONTAL) + self.textBox.Add(self.label, 0, wx.ALL, 5) + self.textBox.Add(self.text, 0, wx.ALL, 5) - def text_focus(self): - self.text.SetFocus() + def text_focus(self): + self.text.SetFocus() - def get_text(self): - return self.text.GetValue() + def get_text(self): + return self.text.GetValue() - def set_text(self, text): - return self.text.ChangeValue(text) + def set_text(self, text): + return self.text.ChangeValue(text) - def set_title(self, new_title): - return self.SetTitle(new_title) + def set_title(self, new_title): + return self.SetTitle(new_title) - def enable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Enable() + def enable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Enable() - def disable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Disable() + def disable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Disable() - def onSelect(self, ev): - self.text.SelectAll() + def onSelect(self, ev): + self.text.SelectAll() - def handle_keys(self, event): - shift=event.ShiftDown() - if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'okButton'): - wx.PostEvent(self.okButton.GetEventHandler(), wx.PyCommandEvent(wx.EVT_BUTTON.typeId,wx.ID_OK)) - else: - event.Skip() + def handle_keys(self, event): + shift=event.ShiftDown() + if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'okButton'): + wx.PostEvent(self.okButton.GetEventHandler(), wx.PyCommandEvent(wx.EVT_BUTTON.typeId,wx.ID_OK)) + else: + event.Skip() - def set_cursor_at_end(self): - self.text.SetInsertionPoint(len(self.text.GetValue())) + def set_cursor_at_end(self): + self.text.SetInsertionPoint(len(self.text.GetValue())) - def set_cursor_at_position(self, position): - self.text.SetInsertionPoint(position) + def set_cursor_at_position(self, position): + self.text.SetInsertionPoint(position) - def get_position(self): - return self.text.GetInsertionPoint() + def get_position(self): + return self.text.GetInsertionPoint() - def popup_menu(self, menu): - self.PopupMenu(menu, self.text.GetPosition()) + def popup_menu(self, menu): + self.PopupMenu(menu, self.text.GetPosition()) class tweet(textLimited): - def createControls(self, title, message, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, text) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.long_tweet = wx.CheckBox(self.panel, -1, _(u"&Long tweet")) - self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) - self.mainBox.Add(self.ok_cancelSizer) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) + def createControls(self, title, message, text): + self.mainBox = wx.BoxSizer(wx.VERTICAL) + self.createTextArea(message, text) + self.mainBox.Add(self.textBox, 0, wx.ALL, 5) + self.long_tweet = wx.CheckBox(self.panel, -1, _(u"&Long tweet")) + self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) + self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) + self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.shortenButton.Disable() + self.unshortenButton.Disable() + self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) + self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) + self.okButton.SetDefault() + cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) + self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) + self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) + self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) + self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) + self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) + self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) + self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) + self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) + self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) + self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) + self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) + self.mainBox.Add(self.ok_cancelSizer) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + self.panel.SetSizer(self.mainBox) - def __init__(self, title, message, text, *args, **kwargs): - super(tweet, self).__init__() - self.shift=False - self.createControls(message, title, text) - self.SetClientSize(self.mainBox.CalcMin()) + def __init__(self, title, message, text, *args, **kwargs): + super(tweet, self).__init__() + self.shift=False + self.createControls(message, title, text) + self.SetClientSize(self.mainBox.CalcMin()) + + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return None + return open(openFileDialog.GetPath(), "rb") - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return open(openFileDialog.GetPath(), "rb") - class retweet(tweet): - def createControls(self, title, message, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, "") - label = wx.StaticText(self.panel, -1, _(u"Retweet")) - self.text2 = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE|wx.TE_READONLY) - self.retweetBox = wx.BoxSizer(wx.HORIZONTAL) - self.retweetBox.Add(label, 0, wx.ALL, 5) - self.retweetBox.Add(self.text2, 0, wx.ALL, 5) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.mainBox.Add(self.retweetBox, 0, wx.ALL, 5) - self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) - self.mainBox.Add(self.ok_cancelSizer) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) + def createControls(self, title, message, text): + self.mainBox = wx.BoxSizer(wx.VERTICAL) + self.createTextArea(message, "") + label = wx.StaticText(self.panel, -1, _(u"Retweet")) + self.text2 = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE|wx.TE_READONLY) + self.retweetBox = wx.BoxSizer(wx.HORIZONTAL) + self.retweetBox.Add(label, 0, wx.ALL, 5) + self.retweetBox.Add(self.text2, 0, wx.ALL, 5) + self.mainBox.Add(self.textBox, 0, wx.ALL, 5) + self.mainBox.Add(self.retweetBox, 0, wx.ALL, 5) + self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) + self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) + self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.shortenButton.Disable() + self.unshortenButton.Disable() + self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) + self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) + self.okButton.SetDefault() + cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) + self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) + self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) + self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) + self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) + self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) + self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) + self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) + self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) + self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) + self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) + self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) + self.mainBox.Add(self.ok_cancelSizer) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + self.panel.SetSizer(self.mainBox) - def __init__(self, title, message, text, *args, **kwargs): - super(tweet, self).__init__() - self.createControls(message, title, text) + def __init__(self, title, message, text, *args, **kwargs): + super(tweet, self).__init__() + self.createControls(message, title, text) # self.onTimer(wx.EVT_CHAR_HOOK) - self.SetClientSize(self.mainBox.CalcMin()) + self.SetClientSize(self.mainBox.CalcMin()) - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return open(openFileDialog.GetPath(), "rb") + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return None + return open(openFileDialog.GetPath(), "rb") class dm(textLimited): - def createControls(self, title, message, users): - self.panel = wx.Panel(self) - self.mainBox = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(self.panel, -1, _(u"&Recipient")) - self.cb = wx.ComboBox(self.panel, -1, choices=users, value=users[0], size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.createTextArea(message, text="") - userBox = wx.BoxSizer(wx.HORIZONTAL) - userBox.Add(label, 0, wx.ALL, 5) - userBox.Add(self.cb, 0, wx.ALL, 5) - userBox.Add(self.autocompletionButton, 0, wx.ALL, 5) - self.mainBox.Add(userBox, 0, wx.ALL, 5) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - self.buttonsBox.Add(self.attach, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox, 0, wx.ALL, 5) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.shortenButton, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.unshortenButton, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) - self.buttonsBox3 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox3.Add(self.okButton, 0, wx.ALL, 5) - self.buttonsBox3.Add(cancelButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox3, 0, wx.ALL, 5) - self.panel.SetSizer(self.mainBox) - self.SetClientSize(self.mainBox.CalcMin()) + def createControls(self, title, message, users): + self.panel = wx.Panel(self) + self.mainBox = wx.BoxSizer(wx.VERTICAL) + label = wx.StaticText(self.panel, -1, _(u"&Recipient")) + self.cb = wx.ComboBox(self.panel, -1, choices=users, value=users[0], size=wx.DefaultSize) + self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) + self.createTextArea(message, text="") + userBox = wx.BoxSizer(wx.HORIZONTAL) + userBox.Add(label, 0, wx.ALL, 5) + userBox.Add(self.cb, 0, wx.ALL, 5) + userBox.Add(self.autocompletionButton, 0, wx.ALL, 5) + self.mainBox.Add(userBox, 0, wx.ALL, 5) + self.mainBox.Add(self.textBox, 0, wx.ALL, 5) + self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) + self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.shortenButton.Disable() + self.unshortenButton.Disable() + self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) + self.okButton.SetDefault() + cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + self.buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + self.buttonsBox.Add(self.attach, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox, 0, wx.ALL, 5) + self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox1.Add(self.shortenButton, 0, wx.ALL, 5) + self.buttonsBox1.Add(self.unshortenButton, 0, wx.ALL, 5) + self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) + self.buttonsBox3 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox3.Add(self.okButton, 0, wx.ALL, 5) + self.buttonsBox3.Add(cancelButton, 0, wx.ALL, 5) + self.mainBox.Add(self.buttonsBox3, 0, wx.ALL, 5) + self.panel.SetSizer(self.mainBox) + self.SetClientSize(self.mainBox.CalcMin()) - def __init__(self, title, message, users, *args, **kwargs): - super(dm, self).__init__() - self.createControls(title, message, users) + def __init__(self, title, message, users, *args, **kwargs): + super(dm, self).__init__() + self.createControls(title, message, users) # self.onTimer(wx.EVT_CHAR_HOOK) # self.SetClientSize(self.mainBox.CalcMin()) - def get_user(self): - return self.cb.GetValue() + def get_user(self): + return self.cb.GetValue() - def set_user(self, user): - return self.cb.SetValue(user) + def set_user(self, user): + return self.cb.SetValue(user) class reply(textLimited): - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return open(openFileDialog.GetPath(), "rb") + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return None + return open(openFileDialog.GetPath(), "rb") - def createControls(self, title, message, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, text) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.usersbox = wx.BoxSizer(wx.VERTICAL) - self.mentionAll = wx.CheckBox(self.panel, -1, _(u"&Mention to all"), size=wx.DefaultSize) - self.mentionAll.Disable() - self.usersbox.Add(self.mentionAll, 0, wx.ALL, 5) - self.checkboxes = [] - for i in self.users: - user_checkbox = wx.CheckBox(self.panel, -1, "@"+i, size=wx.DefaultSize) - self.checkboxes.append(user_checkbox) - self.usersbox.Add(self.checkboxes[-1], 0, wx.ALL, 5) - self.mainBox.Add(self.usersbox, 0, wx.ALL, 10) - self.long_tweet = wx.CheckBox(self.panel, -1, _(u"&Long tweet")) - self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) - self.mainBox.Add(self.ok_cancelSizer, 0, wx.ALL, 10) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) + def createControls(self, title, message, text): + self.mainBox = wx.BoxSizer(wx.VERTICAL) + self.createTextArea(message, text) + self.mainBox.Add(self.textBox, 0, wx.ALL, 5) + self.usersbox = wx.BoxSizer(wx.VERTICAL) + self.mentionAll = wx.CheckBox(self.panel, -1, _(u"&Mention to all"), size=wx.DefaultSize) + self.mentionAll.Disable() + self.usersbox.Add(self.mentionAll, 0, wx.ALL, 5) + self.checkboxes = [] + for i in self.users: + user_checkbox = wx.CheckBox(self.panel, -1, "@"+i, size=wx.DefaultSize) + self.checkboxes.append(user_checkbox) + self.usersbox.Add(self.checkboxes[-1], 0, wx.ALL, 5) + self.mainBox.Add(self.usersbox, 0, wx.ALL, 10) + self.long_tweet = wx.CheckBox(self.panel, -1, _(u"&Long tweet")) + self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) + self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) + self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) + self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.shortenButton.Disable() + self.unshortenButton.Disable() + self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) + self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) + self.okButton.SetDefault() + cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) + self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) + self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) + self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) + self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) + self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) + self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) + self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) + self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) + self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) + self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) + self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) + self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) + self.mainBox.Add(self.ok_cancelSizer, 0, wx.ALL, 10) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + self.panel.SetSizer(self.mainBox) - def __init__(self, title, message, text, users=[], *args, **kwargs): - self.users = users - super(reply, self).__init__() - self.shift=False - self.createControls(message, title, text) - self.SetClientSize(self.mainBox.CalcMin()) + def __init__(self, title, message, text, users=[], *args, **kwargs): + self.users = users + super(reply, self).__init__() + self.shift=False + self.createControls(message, title, text) + self.SetClientSize(self.mainBox.CalcMin()) class viewTweet(widgetUtils.BaseDialog): - def set_title(self, lenght): - self.SetTitle(_(u"Tweet - %i characters ") % (lenght,)) + def set_title(self, lenght): + self.SetTitle(_(u"Tweet - %i characters ") % (lenght,)) - def __init__(self, text, rt_count, favs_count, source, date="", *args, **kwargs): - super(viewTweet, self).__init__(None, size=(850,850)) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Tweet")) - self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.text) - dc.SetFont(self.text.GetFont()) - (x, y) = dc.GetMultiLineTextExtent("0"*140) - self.text.SetSize((x, y)) - self.text.SetFocus() - textBox = wx.BoxSizer(wx.HORIZONTAL) - textBox.Add(label, 0, wx.ALL, 5) - textBox.Add(self.text, 1, wx.EXPAND, 5) - mainBox = wx.BoxSizer(wx.VERTICAL) - mainBox.Add(textBox, 0, wx.ALL, 5) - label2 = wx.StaticText(panel, -1, _(u"Image description")) - self.image_description = wx.TextCtrl(panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.image_description) - dc.SetFont(self.image_description.GetFont()) - (x, y) = dc.GetMultiLineTextExtent("0"*450) - self.image_description.SetSize((x, y)) - self.image_description.Enable(False) - iBox = wx.BoxSizer(wx.HORIZONTAL) - iBox.Add(label2, 0, wx.ALL, 5) - iBox.Add(self.image_description, 1, wx.EXPAND, 5) - mainBox.Add(iBox, 0, wx.ALL, 5) - rtCountLabel = wx.StaticText(panel, -1, _(u"Retweets: ")) - rtCount = wx.TextCtrl(panel, -1, rt_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - rtBox = wx.BoxSizer(wx.HORIZONTAL) - rtBox.Add(rtCountLabel, 0, wx.ALL, 5) - rtBox.Add(rtCount, 0, wx.ALL, 5) - favsCountLabel = wx.StaticText(panel, -1, _(u"Likes: ")) - favsCount = wx.TextCtrl(panel, -1, favs_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - favsBox = wx.BoxSizer(wx.HORIZONTAL) - favsBox.Add(favsCountLabel, 0, wx.ALL, 5) - favsBox.Add(favsCount, 0, wx.ALL, 5) - sourceLabel = wx.StaticText(panel, -1, _(u"Source: ")) - sourceTweet = wx.TextCtrl(panel, -1, source, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - sourceBox = wx.BoxSizer(wx.HORIZONTAL) - sourceBox.Add(sourceLabel, 0, wx.ALL, 5) - sourceBox.Add(sourceTweet, 0, wx.ALL, 5) - dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) - dateTweet = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - dc = wx.WindowDC(dateTweet) - dc.SetFont(dateTweet.GetFont()) - (x, y) = dc.GetTextExtent("0"*100) - dateTweet.SetSize((x, y)) - dateBox = wx.BoxSizer(wx.HORIZONTAL) - dateBox.Add(dateLabel, 0, wx.ALL, 5) - dateBox.Add(dateTweet, 0, wx.ALL, 5) - infoBox = wx.BoxSizer(wx.HORIZONTAL) - infoBox.Add(rtBox, 0, wx.ALL, 5) - infoBox.Add(favsBox, 0, wx.ALL, 5) - infoBox.Add(sourceBox, 0, wx.ALL, 5) - mainBox.Add(infoBox, 0, wx.ALL, 5) - mainBox.Add(dateBox, 0, wx.ALL, 5) - self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Disable() - self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - cancelButton.SetDefault() - buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) - buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) - buttonsBox.Add(cancelButton, 0, wx.ALL, 5) - mainBox.Add(buttonsBox, 0, wx.ALL, 5) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - panel.SetSizer(mainBox) - self.SetClientSize(mainBox.CalcMin()) + def __init__(self, text, rt_count, favs_count, source, date="", *args, **kwargs): + super(viewTweet, self).__init__(None, size=(850,850)) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Tweet")) + self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*140) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + label2 = wx.StaticText(panel, -1, _(u"Image description")) + self.image_description = wx.TextCtrl(panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.image_description) + dc.SetFont(self.image_description.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*450) + self.image_description.SetSize((x, y)) + self.image_description.Enable(False) + iBox = wx.BoxSizer(wx.HORIZONTAL) + iBox.Add(label2, 0, wx.ALL, 5) + iBox.Add(self.image_description, 1, wx.EXPAND, 5) + mainBox.Add(iBox, 0, wx.ALL, 5) + rtCountLabel = wx.StaticText(panel, -1, _(u"Retweets: ")) + rtCount = wx.TextCtrl(panel, -1, rt_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + rtBox = wx.BoxSizer(wx.HORIZONTAL) + rtBox.Add(rtCountLabel, 0, wx.ALL, 5) + rtBox.Add(rtCount, 0, wx.ALL, 5) + favsCountLabel = wx.StaticText(panel, -1, _(u"Likes: ")) + favsCount = wx.TextCtrl(panel, -1, favs_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + favsBox = wx.BoxSizer(wx.HORIZONTAL) + favsBox.Add(favsCountLabel, 0, wx.ALL, 5) + favsBox.Add(favsCount, 0, wx.ALL, 5) + sourceLabel = wx.StaticText(panel, -1, _(u"Source: ")) + sourceTweet = wx.TextCtrl(panel, -1, source, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + sourceBox = wx.BoxSizer(wx.HORIZONTAL) + sourceBox.Add(sourceLabel, 0, wx.ALL, 5) + sourceBox.Add(sourceTweet, 0, wx.ALL, 5) + dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) + dateTweet = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + dc = wx.WindowDC(dateTweet) + dc.SetFont(dateTweet.GetFont()) + (x, y) = dc.GetTextExtent("0"*100) + dateTweet.SetSize((x, y)) + dateBox = wx.BoxSizer(wx.HORIZONTAL) + dateBox.Add(dateLabel, 0, wx.ALL, 5) + dateBox.Add(dateTweet, 0, wx.ALL, 5) + infoBox = wx.BoxSizer(wx.HORIZONTAL) + infoBox.Add(rtBox, 0, wx.ALL, 5) + infoBox.Add(favsBox, 0, wx.ALL, 5) + infoBox.Add(sourceBox, 0, wx.ALL, 5) + mainBox.Add(infoBox, 0, wx.ALL, 5) + mainBox.Add(dateBox, 0, wx.ALL, 5) + self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.unshortenButton.Disable() + self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + cancelButton.SetDefault() + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) + buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) - def set_text(self, text): - self.text.ChangeValue(text) + def set_text(self, text): + self.text.ChangeValue(text) - def get_text(self): - return self.text.GetValue() + def get_text(self): + return self.text.GetValue() - def set_image_description(self, desc): - self.image_description.Enable(True) - if len(self.image_description.GetValue()) == 0: - self.image_description.SetValue(desc) - else: - self.image_description.SetValue(self.image_description.GetValue()+"\n"+desc) + def set_image_description(self, desc): + self.image_description.Enable(True) + if len(self.image_description.GetValue()) == 0: + self.image_description.SetValue(desc) + else: + self.image_description.SetValue(self.image_description.GetValue()+"\n"+desc) - def text_focus(self): - self.text.SetFocus() + def text_focus(self): + self.text.SetFocus() - def onSelect(self, ev): - self.text.SelectAll() + def onSelect(self, ev): + self.text.SelectAll() - def enable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Enable() + def enable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Enable() class viewNonTweet(widgetUtils.BaseDialog): - def __init__(self, text, date="", *args, **kwargs): - super(viewNonTweet, self).__init__(None, size=(850,850)) - self.SetTitle(_(u"View")) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Item")) - self.text = wx.TextCtrl(parent=panel, id=-1, value=text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.text) - dc.SetFont(self.text.GetFont()) - (x, y) = dc.GetMultiLineTextExtent("0"*140) - self.text.SetSize((x, y)) - self.text.SetFocus() - textBox = wx.BoxSizer(wx.HORIZONTAL) - textBox.Add(label, 0, wx.ALL, 5) - textBox.Add(self.text, 1, wx.EXPAND, 5) - mainBox = wx.BoxSizer(wx.VERTICAL) - mainBox.Add(textBox, 0, wx.ALL, 5) - if date != "": - dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) - date = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - dc = wx.WindowDC(date) - dc.SetFont(date.GetFont()) - (x, y) = dc.GetTextExtent("0"*100) - date.SetSize((x, y)) - dateBox = wx.BoxSizer(wx.HORIZONTAL) - dateBox.Add(dateLabel, 0, wx.ALL, 5) - dateBox.Add(date, 0, wx.ALL, 5) - mainBox.Add(dateBox, 0, wx.ALL, 5) - self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Disable() - self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - cancelButton.SetDefault() - buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) - buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) - buttonsBox.Add(cancelButton, 0, wx.ALL, 5) - mainBox.Add(buttonsBox, 0, wx.ALL, 5) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('A'), selectId), -]) - self.SetAcceleratorTable(self.accel_tbl) - panel.SetSizer(mainBox) - self.SetClientSize(mainBox.CalcMin()) + def __init__(self, text, date="", *args, **kwargs): + super(viewNonTweet, self).__init__(None, size=(850,850)) + self.SetTitle(_(u"View")) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Item")) + self.text = wx.TextCtrl(parent=panel, id=-1, value=text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*140) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + if date != "": + dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) + date = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + dc = wx.WindowDC(date) + dc.SetFont(date.GetFont()) + (x, y) = dc.GetTextExtent("0"*100) + date.SetSize((x, y)) + dateBox = wx.BoxSizer(wx.HORIZONTAL) + dateBox.Add(dateLabel, 0, wx.ALL, 5) + dateBox.Add(date, 0, wx.ALL, 5) + mainBox.Add(dateBox, 0, wx.ALL, 5) + self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.unshortenButton.Disable() + self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + cancelButton.SetDefault() + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) + buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) - def onSelect(self, ev): - self.text.SelectAll() + def onSelect(self, ev): + self.text.SelectAll() - def set_text(self, text): - self.text.ChangeValue(text) + def set_text(self, text): + self.text.ChangeValue(text) - def get_text(self): - return self.text.GetValue() + def get_text(self): + return self.text.GetValue() - def text_focus(self): - self.text.SetFocus() + def text_focus(self): + self.text.SetFocus() - def enable_button(self, buttonName): - if getattr(self, buttonName): - return getattr(self, buttonName).Enable() + def enable_button(self, buttonName): + if getattr(self, buttonName): + return getattr(self, buttonName).Enable() diff --git a/src/wxUI/dialogs/search.py b/src/wxUI/dialogs/search.py index b8b6da56..504cab9a 100644 --- a/src/wxUI/dialogs/search.py +++ b/src/wxUI/dialogs/search.py @@ -5,69 +5,69 @@ import wx from extra import translator class searchDialog(baseDialog.BaseWXDialog): - def __init__(self, value=""): - super(searchDialog, self).__init__(None, -1) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle(_(u"Search on Twitter")) - label = wx.StaticText(panel, -1, _(u"&Search")) - self.term = wx.TextCtrl(panel, -1, value) - self.term.SetFocus() - dc = wx.WindowDC(self.term) - dc.SetFont(self.term.GetFont()) - self.term.SetSize(dc.GetTextExtent("0"*40)) - sizer.Add(label, 0, wx.ALL, 5) - sizer.Add(self.term, 0, wx.ALL, 5) - self.tweets = wx.RadioButton(panel, -1, _(u"Tweets"), style=wx.RB_GROUP) - self.users = wx.RadioButton(panel, -1, _(u"Users")) - widgetUtils.connect_event(self.tweets, widgetUtils.RADIOBUTTON, self.show_advanced_search) - widgetUtils.connect_event(self.users, widgetUtils.RADIOBUTTON, self.hide_advanced_search) - radioSizer = wx.BoxSizer(wx.HORIZONTAL) - radioSizer.Add(self.tweets, 0, wx.ALL, 5) - radioSizer.Add(self.users, 0, wx.ALL, 5) - sizer.Add(radioSizer, 0, wx.ALL, 5) - lang = wx.StaticText(panel, -1, _(u"&Language for results: ")) - langs = [x for x in list(translator.translator.languages.values())] - langs.insert(0, _(u"any")) - self.lang = wx.ComboBox(panel, -1, choices=langs, value=langs[0], style = wx.CB_READONLY) - langBox = wx.BoxSizer(wx.HORIZONTAL) - langBox.Add(lang, 0, wx.ALL, 5) - langBox.Add(self.lang, 0, wx.ALL, 5) - sizer.Add(langBox, 0, wx.ALL, 5) - resulttype = wx.StaticText(panel, -1, _(U"Results &type: ")) - self.resultstype = wx.ComboBox(panel, -1, choices=[_(u"Mixed"), _(u"Recent"), _(u"Popular")], value=_(u"Mixed"), style=wx.CB_READONLY) - rBox = wx.BoxSizer(wx.HORIZONTAL) - rBox.Add(resulttype, 0, wx.ALL, 5) - rBox.Add(self.resultstype, 0, wx.ALL, 5) - sizer.Add(rBox, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self, value=""): + super(searchDialog, self).__init__(None, -1) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle(_(u"Search on Twitter")) + label = wx.StaticText(panel, -1, _(u"&Search")) + self.term = wx.TextCtrl(panel, -1, value) + self.term.SetFocus() + dc = wx.WindowDC(self.term) + dc.SetFont(self.term.GetFont()) + self.term.SetSize(dc.GetTextExtent("0"*40)) + sizer.Add(label, 0, wx.ALL, 5) + sizer.Add(self.term, 0, wx.ALL, 5) + self.tweets = wx.RadioButton(panel, -1, _(u"Tweets"), style=wx.RB_GROUP) + self.users = wx.RadioButton(panel, -1, _(u"Users")) + widgetUtils.connect_event(self.tweets, widgetUtils.RADIOBUTTON, self.show_advanced_search) + widgetUtils.connect_event(self.users, widgetUtils.RADIOBUTTON, self.hide_advanced_search) + radioSizer = wx.BoxSizer(wx.HORIZONTAL) + radioSizer.Add(self.tweets, 0, wx.ALL, 5) + radioSizer.Add(self.users, 0, wx.ALL, 5) + sizer.Add(radioSizer, 0, wx.ALL, 5) + lang = wx.StaticText(panel, -1, _(u"&Language for results: ")) + langs = [x for x in list(translator.translator.languages.values())] + langs.insert(0, _(u"any")) + self.lang = wx.ComboBox(panel, -1, choices=langs, value=langs[0], style = wx.CB_READONLY) + langBox = wx.BoxSizer(wx.HORIZONTAL) + langBox.Add(lang, 0, wx.ALL, 5) + langBox.Add(self.lang, 0, wx.ALL, 5) + sizer.Add(langBox, 0, wx.ALL, 5) + resulttype = wx.StaticText(panel, -1, _(U"Results &type: ")) + self.resultstype = wx.ComboBox(panel, -1, choices=[_(u"Mixed"), _(u"Recent"), _(u"Popular")], value=_(u"Mixed"), style=wx.CB_READONLY) + rBox = wx.BoxSizer(wx.HORIZONTAL) + rBox.Add(resulttype, 0, wx.ALL, 5) + rBox.Add(self.resultstype, 0, wx.ALL, 5) + sizer.Add(rBox, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def get_language(self): - l = self.lang.GetStringSelection() - if l == _(u"any"): - return "" - for langcode, langname in translator.translator.languages.items(): - if langname == l: - return langcode + def get_language(self): + l = self.lang.GetStringSelection() + if l == _(u"any"): + return "" + for langcode, langname in translator.translator.languages.items(): + if langname == l: + return langcode - def get_result_type(self): - r = self.resultstype.GetValue() - if r == _(u"Mixed"): return "mixed" - elif r == _(u"Recent"): return "recent" - elif r == _(u"Popular"): return "popular" + def get_result_type(self): + r = self.resultstype.GetValue() + if r == _(u"Mixed"): return "mixed" + elif r == _(u"Recent"): return "recent" + elif r == _(u"Popular"): return "popular" - def hide_advanced_search(self, *args, **kwargs): - self.lang.Hide() - self.resultstype.Hide() + def hide_advanced_search(self, *args, **kwargs): + self.lang.Hide() + self.resultstype.Hide() - def show_advanced_search(self, *args, **kwargs): - self.lang.Show() - self.resultstype.Show() + def show_advanced_search(self, *args, **kwargs): + self.lang.Show() + self.resultstype.Show() diff --git a/src/wxUI/dialogs/show_user.py b/src/wxUI/dialogs/show_user.py index 1c7be5b4..fe6c8b11 100644 --- a/src/wxUI/dialogs/show_user.py +++ b/src/wxUI/dialogs/show_user.py @@ -5,24 +5,24 @@ import wx from . import baseDialog class showUserProfile(baseDialog.BaseWXDialog): - def __init__(self): - super(showUserProfile, self).__init__(parent=None, id=wx.ID_ANY) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - static = wx.StaticText(panel, -1, _(u"Details")) - sizer.Add(static, 0, wx.ALL, 5) - self.text = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY, size=(350, 250)) - self.text.SetFocus() - sizer.Add(self.text, 0, wx.ALL|wx.EXPAND, 5) - self.url = wx.Button(panel, -1, _(u"&Go to URL"), size=wx.DefaultSize) - self.url.Disable() - close = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) - btnSizer = wx.BoxSizer(wx.HORIZONTAL) - btnSizer.Add(self.url, 0, wx.ALL, 5) - btnSizer.Add(close, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(showUserProfile, self).__init__(parent=None, id=wx.ID_ANY) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + static = wx.StaticText(panel, -1, _(u"Details")) + sizer.Add(static, 0, wx.ALL, 5) + self.text = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY, size=(350, 250)) + self.text.SetFocus() + sizer.Add(self.text, 0, wx.ALL|wx.EXPAND, 5) + self.url = wx.Button(panel, -1, _(u"&Go to URL"), size=wx.DefaultSize) + self.url.Disable() + close = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.Add(self.url, 0, wx.ALL, 5) + btnSizer.Add(close, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def enable_url(self, enabled=True): - self.url.Enable(enabled) \ No newline at end of file + def enable_url(self, enabled=True): + self.url.Enable(enabled) diff --git a/src/wxUI/dialogs/trends.py b/src/wxUI/dialogs/trends.py index d2d6ae75..24613e53 100644 --- a/src/wxUI/dialogs/trends.py +++ b/src/wxUI/dialogs/trends.py @@ -3,43 +3,43 @@ from . import baseDialog import wx class trendingTopicsDialog(baseDialog.BaseWXDialog): - def __init__(self): - super(trendingTopicsDialog, self).__init__(None, -1) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle(_(u"View trending topics")) - label = wx.StaticText(panel, wx.NewId(), _(u"Trending topics by")) - self.country = wx.RadioButton(panel, -1, _(u"Country"), style=wx.RB_GROUP) - self.city = wx.RadioButton(panel, -1, _(u"City")) - radioSizer = wx.BoxSizer(wx.HORIZONTAL) - radioSizer.Add(label, 0, wx.ALL, 5) - radioSizer.Add(self.country, 0, wx.ALL, 5) - radioSizer.Add(self.city, 0, wx.ALL, 5) - sizer.Add(radioSizer, 0, wx.ALL, 5) - label = wx.StaticText(panel, -1, _(u"&Location")) - self.location = wx.ListBox(panel, -1, choices=[], style=wx.CB_READONLY) - locationBox = wx.BoxSizer(wx.HORIZONTAL) - locationBox.Add(label, 0, wx.ALL, 5) - locationBox.Add(self.location, 0, wx.ALL, 5) - sizer.Add(locationBox, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(trendingTopicsDialog, self).__init__(None, -1) + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle(_(u"View trending topics")) + label = wx.StaticText(panel, wx.NewId(), _(u"Trending topics by")) + self.country = wx.RadioButton(panel, -1, _(u"Country"), style=wx.RB_GROUP) + self.city = wx.RadioButton(panel, -1, _(u"City")) + radioSizer = wx.BoxSizer(wx.HORIZONTAL) + radioSizer.Add(label, 0, wx.ALL, 5) + radioSizer.Add(self.country, 0, wx.ALL, 5) + radioSizer.Add(self.city, 0, wx.ALL, 5) + sizer.Add(radioSizer, 0, wx.ALL, 5) + label = wx.StaticText(panel, -1, _(u"&Location")) + self.location = wx.ListBox(panel, -1, choices=[], style=wx.CB_READONLY) + locationBox = wx.BoxSizer(wx.HORIZONTAL) + locationBox.Add(label, 0, wx.ALL, 5) + locationBox.Add(self.location, 0, wx.ALL, 5) + sizer.Add(locationBox, 0, wx.ALL, 5) + ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def get_active(self): - if self.country.GetValue() == True: - return "country" - else: - return "city" + def get_active(self): + if self.country.GetValue() == True: + return "country" + else: + return "city" - def get_item(self): - return self.location.GetStringSelection() + def get_item(self): + return self.location.GetStringSelection() - def set(self, values): - self.location.Set(values) \ No newline at end of file + def set(self, values): + self.location.Set(values) diff --git a/src/wxUI/dialogs/update_profile.py b/src/wxUI/dialogs/update_profile.py index ba1cb541..034c2388 100644 --- a/src/wxUI/dialogs/update_profile.py +++ b/src/wxUI/dialogs/update_profile.py @@ -5,96 +5,96 @@ import wx from . import baseDialog class updateProfileDialog(baseDialog.BaseWXDialog): - def __init__(self): - super(updateProfileDialog, self).__init__(parent=None, id=-1) - self.SetTitle(_(u"Update your profile")) - panel = wx.Panel(self) - labelName = wx.StaticText(panel, -1, _(u"&Name (50 characters maximum)")) - self.name = wx.TextCtrl(panel, -1) - self.name.SetFocus() - dc = wx.WindowDC(self.name) - dc.SetFont(self.name.GetFont()) - self.name.SetSize(dc.GetTextExtent("0"*50)) - labelLocation = wx.StaticText(panel, -1, _(u"&Location")) - self.location = wx.TextCtrl(panel, -1) - dc = wx.WindowDC(self.location) - dc.SetFont(self.location.GetFont()) - self.location.SetSize(dc.GetTextExtent("0"*35)) - labelUrl = wx.StaticText(panel, -1, _(u"&Website")) - self.url = wx.TextCtrl(panel, -1) - dc = wx.WindowDC(self.url) - dc.SetFont(self.url.GetFont()) - self.url.SetSize(dc.GetTextExtent("0"*22)) - labelDescription = wx.StaticText(panel, -1, _(u"&Bio (160 characters maximum)")) - self.description = wx.TextCtrl(panel, -1, size=(400, 400)) - dc = wx.WindowDC(self.description) - dc.SetFont(self.description.GetFont()) - self.description.SetSize(dc.GetTextExtent("0"*160)) - self.image = None - self.upload_image = wx.Button(panel, -1, _(u"Upload a &picture")) - self.ok = wx.Button(panel, wx.ID_OK, _(u"&Update profile")) - self.ok.SetDefault() - close = wx.Button(panel, wx.ID_CANCEL, _("&Close")) - sizer = wx.BoxSizer(wx.VERTICAL) - nameBox = wx.BoxSizer(wx.HORIZONTAL) - nameBox.Add(labelName, 0, wx.ALL, 5) - nameBox.Add(self.name, 0, wx.ALL, 5) - sizer.Add(nameBox, 0, wx.ALL, 5) - locationBox = wx.BoxSizer(wx.HORIZONTAL) - locationBox.Add(labelLocation, 0, wx.ALL, 5) - locationBox.Add(self.location, 0, wx.ALL, 5) - sizer.Add(locationBox, 0, wx.ALL, 5) - urlBox = wx.BoxSizer(wx.HORIZONTAL) - urlBox.Add(labelUrl, 0, wx.ALL, 5) - urlBox.Add(self.url, 0, wx.ALL, 5) - sizer.Add(urlBox, 0, wx.ALL, 5) - descriptionBox = wx.BoxSizer(wx.HORIZONTAL) - descriptionBox.Add(labelDescription, 0, wx.ALL, 5) - descriptionBox.Add(self.description, 0, wx.ALL, 5) - sizer.Add(descriptionBox, 0, wx.ALL, 5) - sizer.Add(self.upload_image, 5, wx.CENTER, 5) - btnBox = wx.BoxSizer(wx.HORIZONTAL) - btnBox.Add(self.ok, 0, wx.ALL, 5) - btnBox.Add(close, 0, wx.ALL, 5) - sizer.Add(btnBox, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self): + super(updateProfileDialog, self).__init__(parent=None, id=-1) + self.SetTitle(_(u"Update your profile")) + panel = wx.Panel(self) + labelName = wx.StaticText(panel, -1, _(u"&Name (50 characters maximum)")) + self.name = wx.TextCtrl(panel, -1) + self.name.SetFocus() + dc = wx.WindowDC(self.name) + dc.SetFont(self.name.GetFont()) + self.name.SetSize(dc.GetTextExtent("0"*50)) + labelLocation = wx.StaticText(panel, -1, _(u"&Location")) + self.location = wx.TextCtrl(panel, -1) + dc = wx.WindowDC(self.location) + dc.SetFont(self.location.GetFont()) + self.location.SetSize(dc.GetTextExtent("0"*35)) + labelUrl = wx.StaticText(panel, -1, _(u"&Website")) + self.url = wx.TextCtrl(panel, -1) + dc = wx.WindowDC(self.url) + dc.SetFont(self.url.GetFont()) + self.url.SetSize(dc.GetTextExtent("0"*22)) + labelDescription = wx.StaticText(panel, -1, _(u"&Bio (160 characters maximum)")) + self.description = wx.TextCtrl(panel, -1, size=(400, 400)) + dc = wx.WindowDC(self.description) + dc.SetFont(self.description.GetFont()) + self.description.SetSize(dc.GetTextExtent("0"*160)) + self.image = None + self.upload_image = wx.Button(panel, -1, _(u"Upload a &picture")) + self.ok = wx.Button(panel, wx.ID_OK, _(u"&Update profile")) + self.ok.SetDefault() + close = wx.Button(panel, wx.ID_CANCEL, _("&Close")) + sizer = wx.BoxSizer(wx.VERTICAL) + nameBox = wx.BoxSizer(wx.HORIZONTAL) + nameBox.Add(labelName, 0, wx.ALL, 5) + nameBox.Add(self.name, 0, wx.ALL, 5) + sizer.Add(nameBox, 0, wx.ALL, 5) + locationBox = wx.BoxSizer(wx.HORIZONTAL) + locationBox.Add(labelLocation, 0, wx.ALL, 5) + locationBox.Add(self.location, 0, wx.ALL, 5) + sizer.Add(locationBox, 0, wx.ALL, 5) + urlBox = wx.BoxSizer(wx.HORIZONTAL) + urlBox.Add(labelUrl, 0, wx.ALL, 5) + urlBox.Add(self.url, 0, wx.ALL, 5) + sizer.Add(urlBox, 0, wx.ALL, 5) + descriptionBox = wx.BoxSizer(wx.HORIZONTAL) + descriptionBox.Add(labelDescription, 0, wx.ALL, 5) + descriptionBox.Add(self.description, 0, wx.ALL, 5) + sizer.Add(descriptionBox, 0, wx.ALL, 5) + sizer.Add(self.upload_image, 5, wx.CENTER, 5) + btnBox = wx.BoxSizer(wx.HORIZONTAL) + btnBox.Add(self.ok, 0, wx.ALL, 5) + btnBox.Add(close, 0, wx.ALL, 5) + sizer.Add(btnBox, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def set_name(self, name): - self.set("name", name) + def set_name(self, name): + self.set("name", name) - def set_description(self, description): - self.set("description", description) + def set_description(self, description): + self.set("description", description) - def set_location(self, location): - self.set("location", location) + def set_location(self, location): + self.set("location", location) - def set_url(self, url): - self.set("url", url) + def set_url(self, url): + self.set("url", url) - def change_upload_button(self, uploaded=False): - if uploaded == False: - self.upload_image.SetLabel(_(u"Upload a picture")) - else: - self.upload_image.SetLabel(_(u"Discard image")) + def change_upload_button(self, uploaded=False): + if uploaded == False: + self.upload_image.SetLabel(_(u"Upload a picture")) + else: + self.upload_image.SetLabel(_(u"Discard image")) - def upload_picture(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return openFileDialog.GetPath() + def upload_picture(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return None + return openFileDialog.GetPath() - def hide_upload_button(self, hide): - self.upload_image.Enable(hide) + def hide_upload_button(self, hide): + self.upload_image.Enable(hide) - def set_readonly(self): - self.name.style = wx.TE_READONLY - self.name.Refresh() - self.description.style = wx.TE_READONLY - self.description.Refresh() - self.location.style = wx.TE_READONLY - self.location.Refresh() - self.url.style = wx.TE_READONLY - self.url.Refresh() - self.hide_upload_button(False) - self.ok.Enable(False) \ No newline at end of file + def set_readonly(self): + self.name.style = wx.TE_READONLY + self.name.Refresh() + self.description.style = wx.TE_READONLY + self.description.Refresh() + self.location.style = wx.TE_READONLY + self.location.Refresh() + self.url.style = wx.TE_READONLY + self.url.Refresh() + self.hide_upload_button(False) + self.ok.Enable(False) diff --git a/src/wxUI/dialogs/urlList.py b/src/wxUI/dialogs/urlList.py index 16012f57..f8bdd7da 100644 --- a/src/wxUI/dialogs/urlList.py +++ b/src/wxUI/dialogs/urlList.py @@ -3,34 +3,34 @@ from __future__ import unicode_literals import wx class urlList(wx.Dialog): - def __init__(self, title=_(u"Select URL")): - super(urlList, self).__init__(parent=None, title=title) - panel = wx.Panel(self) - self.lista = wx.ListBox(panel, -1) - self.lista.SetFocus() - self.lista.SetSize(self.lista.GetBestSize()) - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self.lista, 0, wx.ALL, 5) - goBtn = wx.Button(panel, wx.ID_OK) - goBtn.SetDefault() - cancelBtn = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(goBtn, 0, wx.ALL, 5) - btnSizer.Add(cancelBtn, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + def __init__(self, title=_(u"Select URL")): + super(urlList, self).__init__(parent=None, title=title) + panel = wx.Panel(self) + self.lista = wx.ListBox(panel, -1) + self.lista.SetFocus() + self.lista.SetSize(self.lista.GetBestSize()) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.lista, 0, wx.ALL, 5) + goBtn = wx.Button(panel, wx.ID_OK) + goBtn.SetDefault() + cancelBtn = wx.Button(panel, wx.ID_CANCEL) + btnSizer = wx.BoxSizer() + btnSizer.Add(goBtn, 0, wx.ALL, 5) + btnSizer.Add(cancelBtn, 0, wx.ALL, 5) + sizer.Add(btnSizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def populate_list(self, urls): - for i in urls: - self.lista.Append(i) - self.lista.SetSelection(0) + def populate_list(self, urls): + for i in urls: + self.lista.Append(i) + self.lista.SetSelection(0) - def get_string(self): - return self.lista.GetStringSelection() + def get_string(self): + return self.lista.GetStringSelection() - def get_item(self): - return self.lista.GetSelection() + def get_item(self): + return self.lista.GetSelection() - def get_response(self): - return self.ShowModal() \ No newline at end of file + def get_response(self): + return self.ShowModal() diff --git a/src/wxUI/dialogs/userActions.py b/src/wxUI/dialogs/userActions.py index c60f24bf..629d02aa 100644 --- a/src/wxUI/dialogs/userActions.py +++ b/src/wxUI/dialogs/userActions.py @@ -3,88 +3,88 @@ from __future__ import unicode_literals import wx class UserActionsDialog(wx.Dialog): - def __init__(self, users=[], default="follow", *args, **kwargs): - super(UserActionsDialog, self).__init__(parent=None, *args, **kwargs) - panel = wx.Panel(self) - userSizer = wx.BoxSizer() - self.SetTitle(_(u"Action")) - userLabel = wx.StaticText(panel, -1, _(u"&User")) - self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) - self.cb.SetFocus() - self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) - userSizer.Add(userLabel, 0, wx.ALL, 5) - userSizer.Add(self.cb, 0, wx.ALL, 5) - userSizer.Add(self.autocompletion, 0, wx.ALL, 5) - actionSizer = wx.BoxSizer(wx.VERTICAL) - label2 = wx.StaticText(panel, -1, _(u"Action")) - self.follow = wx.RadioButton(panel, -1, _(u"&Follow"), name=_(u"Action"), style=wx.RB_GROUP) - self.unfollow = wx.RadioButton(panel, -1, _(u"U&nfollow")) - self.mute = wx.RadioButton(panel, -1, _(u"&Mute")) - self.unmute = wx.RadioButton(panel, -1, _(u"Unmu&te")) - self.block = wx.RadioButton(panel, -1, _(u"&Block")) - self.unblock = wx.RadioButton(panel, -1, _(u"Unbl&ock")) - self.reportSpam = wx.RadioButton(panel, -1, _(u"&Report as spam")) - self.ignore_client = wx.RadioButton(panel, -1, _(u"&Ignore tweets from this client")) - self.setup_default(default) - hSizer = wx.BoxSizer(wx.HORIZONTAL) - hSizer.Add(label2, 0, wx.ALL, 5) - actionSizer.Add(self.follow, 0, wx.ALL, 5) - actionSizer.Add(self.unfollow, 0, wx.ALL, 5) - actionSizer.Add(self.mute, 0, wx.ALL, 5) - actionSizer.Add(self.unmute, 0, wx.ALL, 5) - actionSizer.Add(self.block, 0, wx.ALL, 5) - actionSizer.Add(self.unblock, 0, wx.ALL, 5) - actionSizer.Add(self.reportSpam, 0, wx.ALL, 5) - actionSizer.Add(self.ignore_client, 0, wx.ALL, 5) - hSizer.Add(actionSizer, 0, wx.ALL, 5) - sizer = wx.BoxSizer(wx.VERTICAL) - ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok) - btnsizer.Add(cancel) - sizer.Add(userSizer) - sizer.Add(hSizer, 0, wx.ALL, 5) - sizer.Add(btnsizer) - panel.SetSizer(sizer) + def __init__(self, users=[], default="follow", *args, **kwargs): + super(UserActionsDialog, self).__init__(parent=None, *args, **kwargs) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.SetTitle(_(u"Action")) + userLabel = wx.StaticText(panel, -1, _(u"&User")) + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) + self.cb.SetFocus() + self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) + userSizer.Add(userLabel, 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + userSizer.Add(self.autocompletion, 0, wx.ALL, 5) + actionSizer = wx.BoxSizer(wx.VERTICAL) + label2 = wx.StaticText(panel, -1, _(u"Action")) + self.follow = wx.RadioButton(panel, -1, _(u"&Follow"), name=_(u"Action"), style=wx.RB_GROUP) + self.unfollow = wx.RadioButton(panel, -1, _(u"U&nfollow")) + self.mute = wx.RadioButton(panel, -1, _(u"&Mute")) + self.unmute = wx.RadioButton(panel, -1, _(u"Unmu&te")) + self.block = wx.RadioButton(panel, -1, _(u"&Block")) + self.unblock = wx.RadioButton(panel, -1, _(u"Unbl&ock")) + self.reportSpam = wx.RadioButton(panel, -1, _(u"&Report as spam")) + self.ignore_client = wx.RadioButton(panel, -1, _(u"&Ignore tweets from this client")) + self.setup_default(default) + hSizer = wx.BoxSizer(wx.HORIZONTAL) + hSizer.Add(label2, 0, wx.ALL, 5) + actionSizer.Add(self.follow, 0, wx.ALL, 5) + actionSizer.Add(self.unfollow, 0, wx.ALL, 5) + actionSizer.Add(self.mute, 0, wx.ALL, 5) + actionSizer.Add(self.unmute, 0, wx.ALL, 5) + actionSizer.Add(self.block, 0, wx.ALL, 5) + actionSizer.Add(self.unblock, 0, wx.ALL, 5) + actionSizer.Add(self.reportSpam, 0, wx.ALL, 5) + actionSizer.Add(self.ignore_client, 0, wx.ALL, 5) + hSizer.Add(actionSizer, 0, wx.ALL, 5) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok) + btnsizer.Add(cancel) + sizer.Add(userSizer) + sizer.Add(hSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer) + panel.SetSizer(sizer) - def get_action(self): - if self.follow.GetValue() == True: return "follow" - elif self.unfollow.GetValue() == True: return "unfollow" - elif self.mute.GetValue() == True: return "mute" - elif self.unmute.GetValue() == True: return "unmute" - elif self.reportSpam.GetValue() == True: return "report" - elif self.block.GetValue() == True: return "block" - elif self.unblock.GetValue() == True: return "unblock" - elif self.ignore_client.GetValue() == True: return "ignore_client" + def get_action(self): + if self.follow.GetValue() == True: return "follow" + elif self.unfollow.GetValue() == True: return "unfollow" + elif self.mute.GetValue() == True: return "mute" + elif self.unmute.GetValue() == True: return "unmute" + elif self.reportSpam.GetValue() == True: return "report" + elif self.block.GetValue() == True: return "block" + elif self.unblock.GetValue() == True: return "unblock" + elif self.ignore_client.GetValue() == True: return "ignore_client" - def setup_default(self, default): - if default == "follow": - self.follow.SetValue(True) - elif default == "unfollow": - self.unfollow.SetValue(True) - elif default == "mute": - self.mute.SetValue(True) - elif default == "unmute": - self.unmute.SetValue(True) - elif default == "report": - self.reportSpam.SetValue(True) - elif default == "block": - self.block.SetValue(True) - elif default == "unblock": - self.unblock.SetValue(True) - elif default == "ignore_client": - self.ignore_client.SetValue(True) + def setup_default(self, default): + if default == "follow": + self.follow.SetValue(True) + elif default == "unfollow": + self.unfollow.SetValue(True) + elif default == "mute": + self.mute.SetValue(True) + elif default == "unmute": + self.unmute.SetValue(True) + elif default == "report": + self.reportSpam.SetValue(True) + elif default == "block": + self.block.SetValue(True) + elif default == "unblock": + self.unblock.SetValue(True) + elif default == "ignore_client": + self.ignore_client.SetValue(True) - def get_response(self): - return self.ShowModal() + def get_response(self): + return self.ShowModal() - def get_user(self): - return self.cb.GetValue() + def get_user(self): + return self.cb.GetValue() - def get_position(self): - return self.cb.GetPosition() + def get_position(self): + return self.cb.GetPosition() - def popup_menu(self, menu): - self.PopupMenu(menu, self.cb.GetPosition()) + def popup_menu(self, menu): + self.PopupMenu(menu, self.cb.GetPosition()) diff --git a/src/wxUI/dialogs/userSelection.py b/src/wxUI/dialogs/userSelection.py index 30dc67d3..bb110910 100644 --- a/src/wxUI/dialogs/userSelection.py +++ b/src/wxUI/dialogs/userSelection.py @@ -3,64 +3,64 @@ from __future__ import unicode_literals import wx class selectUserDialog(wx.Dialog): - def __init__(self, users=[], default="tweets", *args, **kwargs): - super(selectUserDialog, self).__init__(parent=None, *args, **kwargs) - panel = wx.Panel(self) - userSizer = wx.BoxSizer() - self.SetTitle(_(u"Timeline for %s") % (users[0])) - userLabel = wx.StaticText(panel, -1, _(u"User")) - self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) - self.cb.SetFocus() - self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) - userSizer.Add(userLabel, 0, wx.ALL, 5) - userSizer.Add(self.cb, 0, wx.ALL, 5) - userSizer.Add(self.autocompletion, 0, wx.ALL, 5) - actionSizer = wx.BoxSizer(wx.VERTICAL) - label2 = wx.StaticText(panel, -1, _(u"Buffer type")) - self.tweets = wx.RadioButton(panel, -1, _(u"&Tweets"), style=wx.RB_GROUP) - self.favourites = wx.RadioButton(panel, -1, _(u"&Likes")) - self.followers = wx.RadioButton(panel, -1, _(u"&Followers")) - self.friends = wx.RadioButton(panel, -1, _(u"F&riends")) - self.setup_default(default) - hSizer = wx.BoxSizer(wx.HORIZONTAL) - hSizer.Add(label2, 0, wx.ALL, 5) - actionSizer.Add(self.tweets, 0, wx.ALL, 5) - actionSizer.Add(self.favourites, 0, wx.ALL, 5) - actionSizer.Add(self.followers, 0, wx.ALL, 5) - actionSizer.Add(self.friends, 0, wx.ALL, 5) - hSizer.Add(actionSizer, 0, wx.ALL, 5) - sizer = wx.BoxSizer(wx.VERTICAL) - ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) - ok.SetDefault() - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok) - btnsizer.Add(cancel) - sizer.Add(userSizer) - sizer.Add(hSizer, 0, wx.ALL, 5) - sizer.Add(btnsizer) - panel.SetSizer(sizer) + def __init__(self, users=[], default="tweets", *args, **kwargs): + super(selectUserDialog, self).__init__(parent=None, *args, **kwargs) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.SetTitle(_(u"Timeline for %s") % (users[0])) + userLabel = wx.StaticText(panel, -1, _(u"User")) + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) + self.cb.SetFocus() + self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) + userSizer.Add(userLabel, 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + userSizer.Add(self.autocompletion, 0, wx.ALL, 5) + actionSizer = wx.BoxSizer(wx.VERTICAL) + label2 = wx.StaticText(panel, -1, _(u"Buffer type")) + self.tweets = wx.RadioButton(panel, -1, _(u"&Tweets"), style=wx.RB_GROUP) + self.favourites = wx.RadioButton(panel, -1, _(u"&Likes")) + self.followers = wx.RadioButton(panel, -1, _(u"&Followers")) + self.friends = wx.RadioButton(panel, -1, _(u"F&riends")) + self.setup_default(default) + hSizer = wx.BoxSizer(wx.HORIZONTAL) + hSizer.Add(label2, 0, wx.ALL, 5) + actionSizer.Add(self.tweets, 0, wx.ALL, 5) + actionSizer.Add(self.favourites, 0, wx.ALL, 5) + actionSizer.Add(self.followers, 0, wx.ALL, 5) + actionSizer.Add(self.friends, 0, wx.ALL, 5) + hSizer.Add(actionSizer, 0, wx.ALL, 5) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok) + btnsizer.Add(cancel) + sizer.Add(userSizer) + sizer.Add(hSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer) + panel.SetSizer(sizer) - def get_action(self): - if self.tweets.GetValue() == True: return "tweets" - elif self.favourites.GetValue() == True: return "favourites" - elif self.followers.GetValue() == True: return "followers" - elif self.friends.GetValue() == True: return "friends" + def get_action(self): + if self.tweets.GetValue() == True: return "tweets" + elif self.favourites.GetValue() == True: return "favourites" + elif self.followers.GetValue() == True: return "followers" + elif self.friends.GetValue() == True: return "friends" - def setup_default(self, default): - if default == "tweets": - self.tweets.SetValue(True) - elif default == "favourites": - self.favourites.SetValue(True) + def setup_default(self, default): + if default == "tweets": + self.tweets.SetValue(True) + elif default == "favourites": + self.favourites.SetValue(True) - def get_response(self): - return self.ShowModal() + def get_response(self): + return self.ShowModal() - def get_user(self): - return self.cb.GetValue() + def get_user(self): + return self.cb.GetValue() - def get_position(self): - return self.cb.GetPosition() + def get_position(self): + return self.cb.GetPosition() - def popup_menu(self, menu): - self.PopupMenu(menu, self.cb.GetPosition()) + def popup_menu(self, menu): + self.PopupMenu(menu, self.cb.GetPosition()) diff --git a/src/wxUI/dialogs/utils.py b/src/wxUI/dialogs/utils.py index 36bdc8a8..8335d61d 100644 --- a/src/wxUI/dialogs/utils.py +++ b/src/wxUI/dialogs/utils.py @@ -22,29 +22,29 @@ import wx from . import baseDialog class selectUserDialog(baseDialog.BaseWXDialog): - def __init__(self, title, users): - super(selectUserDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title) - panel = wx.Panel(self) - userSizer = wx.BoxSizer() - self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize) - self.cb.SetFocus() - self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) - userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) - userSizer.Add(self.cb, 0, wx.ALL, 5) - userSizer.Add(self.autocompletion, 0, wx.ALL, 5) - sizer = wx.BoxSizer(wx.VERTICAL) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() + def __init__(self, title, users): + super(selectUserDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize) + self.cb.SetFocus() + self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) + userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + userSizer.Add(self.autocompletion, 0, wx.ALL, 5) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() # ok.Bind(wx.EVT_BUTTON, self.onok) - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(userSizer, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(userSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) - def get_user(self): - return self.cb.GetValue() + def get_user(self): + return self.cb.GetValue() diff --git a/src/wxUI/menus.py b/src/wxUI/menus.py index 70fbd7fa..9f2defed 100644 --- a/src/wxUI/menus.py +++ b/src/wxUI/menus.py @@ -3,102 +3,102 @@ from __future__ import unicode_literals import wx class basePanelMenu(wx.Menu): - def __init__(self): - super(basePanelMenu, self).__init__() - self.retweet = wx.MenuItem(self, wx.ID_ANY, _(u"&Retweet")) - self.Append(self.retweet) - self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Re&ply")) - self.Append(self.reply) - self.fav = wx.MenuItem(self, wx.ID_ANY, _(u"&Like")) - self.Append(self.fav) - self.unfav = wx.MenuItem(self, wx.ID_ANY, _(u"&Unlike")) - self.Append(self.unfav) - self.openUrl = wx.MenuItem(self, wx.ID_ANY, _(u"&Open URL")) - self.Append(self.openUrl) - self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in Twitter")) - self.Append(self.openInBrowser) - self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio")) - self.Append(self.play) - self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show tweet")) - self.Append(self.view) - self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) - self.Append(self.copy) - self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) - self.Append(self.remove) - self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions...")) - self.Append(self.userActions) + def __init__(self): + super(basePanelMenu, self).__init__() + self.retweet = wx.MenuItem(self, wx.ID_ANY, _(u"&Retweet")) + self.Append(self.retweet) + self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Re&ply")) + self.Append(self.reply) + self.fav = wx.MenuItem(self, wx.ID_ANY, _(u"&Like")) + self.Append(self.fav) + self.unfav = wx.MenuItem(self, wx.ID_ANY, _(u"&Unlike")) + self.Append(self.unfav) + self.openUrl = wx.MenuItem(self, wx.ID_ANY, _(u"&Open URL")) + self.Append(self.openUrl) + self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in Twitter")) + self.Append(self.openInBrowser) + self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio")) + self.Append(self.play) + self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show tweet")) + self.Append(self.view) + self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) + self.Append(self.copy) + self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) + self.Append(self.remove) + self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions...")) + self.Append(self.userActions) class dmPanelMenu(wx.Menu): - def __init__(self): - super(dmPanelMenu, self).__init__() - self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Re&ply")) - self.Append(self.reply) - self.openUrl = wx.MenuItem(self, wx.ID_ANY, _(u"&Open URL")) - self.Append(self.openUrl) - self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio")) - self.Append(self.play) - self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show direct message")) - self.Append(self.view) - self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) - self.Append(self.copy) - self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) - self.Append(self.remove) - self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions...")) - self.Append(self.userActions) + def __init__(self): + super(dmPanelMenu, self).__init__() + self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Re&ply")) + self.Append(self.reply) + self.openUrl = wx.MenuItem(self, wx.ID_ANY, _(u"&Open URL")) + self.Append(self.openUrl) + self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio")) + self.Append(self.play) + self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show direct message")) + self.Append(self.view) + self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) + self.Append(self.copy) + self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) + self.Append(self.remove) + self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions...")) + self.Append(self.userActions) class sentPanelMenu(wx.Menu): - def __init__(self): - super(sentPanelMenu, self).__init__() - self.openUrl = wx.MenuItem(self, wx.ID_ANY, _(u"&Open URL")) - self.Append(self.openUrl) - self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in Twitter")) - self.Append(self.openInBrowser) - self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio")) - self.Append(self.play) - self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show tweet")) - self.Append(self.view) - self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) - self.Append(self.copy) - self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) - self.Append(self.remove) + def __init__(self): + super(sentPanelMenu, self).__init__() + self.openUrl = wx.MenuItem(self, wx.ID_ANY, _(u"&Open URL")) + self.Append(self.openUrl) + self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in Twitter")) + self.Append(self.openInBrowser) + self.play = wx.MenuItem(self, wx.ID_ANY, _(u"&Play audio")) + self.Append(self.play) + self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show tweet")) + self.Append(self.view) + self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) + self.Append(self.copy) + self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) + self.Append(self.remove) class eventsPanelMenu(wx.Menu): - def __init__(self): - super(eventsPanelMenu, self).__init__() - self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show event")) - self.Append(self.view) - self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) - self.Append(self.copy) - self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) - self.Append(self.remove) + def __init__(self): + super(eventsPanelMenu, self).__init__() + self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show event")) + self.Append(self.view) + self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) + self.Append(self.copy) + self.remove = wx.MenuItem(self, wx.ID_ANY, _(u"&Delete")) + self.Append(self.remove) class peoplePanelMenu(wx.Menu): - def __init__(self): - super(peoplePanelMenu, self).__init__() - self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Direct &message")) - self.Append(self.reply) - self.lists = wx.MenuItem(self, wx.ID_ANY, _(u"&View lists")) - self.Append(self.lists) - self.lists.Enable(False) - self.details = wx.MenuItem(self, wx.ID_ANY, _(u"Show user &profile")) - self.Append(self.details) - self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show user")) - self.Append(self.view) - self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in Twitter")) - self.Append(self.openInBrowser) - self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) - self.Append(self.copy) - self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions...")) - self.Append(self.userActions) + def __init__(self): + super(peoplePanelMenu, self).__init__() + self.reply = wx.MenuItem(self, wx.ID_ANY, _(u"Direct &message")) + self.Append(self.reply) + self.lists = wx.MenuItem(self, wx.ID_ANY, _(u"&View lists")) + self.Append(self.lists) + self.lists.Enable(False) + self.details = wx.MenuItem(self, wx.ID_ANY, _(u"Show user &profile")) + self.Append(self.details) + self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show user")) + self.Append(self.view) + self.openInBrowser = wx.MenuItem(self, wx.ID_ANY, _(u"&Open in Twitter")) + self.Append(self.openInBrowser) + self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) + self.Append(self.copy) + self.userActions = wx.MenuItem(self, wx.ID_ANY, _(u"&User actions...")) + self.Append(self.userActions) class trendsPanelMenu(wx.Menu): - def __init__(self): - super(trendsPanelMenu, self).__init__() - self.search_topic = wx.MenuItem(self, wx.ID_ANY, _(u"Search topic")) - self.Append(self.search_topic) - self.tweetThisTrend = wx.MenuItem(self, wx.ID_ANY, _(u"&Tweet about this trend")) - self.Append(self.tweetThisTrend) - self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show item")) - self.Append(self.view) - self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) - self.Append(self.copy) + def __init__(self): + super(trendsPanelMenu, self).__init__() + self.search_topic = wx.MenuItem(self, wx.ID_ANY, _(u"Search topic")) + self.Append(self.search_topic) + self.tweetThisTrend = wx.MenuItem(self, wx.ID_ANY, _(u"&Tweet about this trend")) + self.Append(self.tweetThisTrend) + self.view = wx.MenuItem(self, wx.ID_ANY, _(u"&Show item")) + self.Append(self.view) + self.copy = wx.MenuItem(self, wx.ID_ANY, _(u"&Copy to clipboard")) + self.Append(self.copy) diff --git a/src/wxUI/sysTrayIcon.py b/src/wxUI/sysTrayIcon.py index 81efcd10..a408c35c 100644 --- a/src/wxUI/sysTrayIcon.py +++ b/src/wxUI/sysTrayIcon.py @@ -27,23 +27,23 @@ import os class SysTrayIcon(wx.adv.TaskBarIcon): - def __init__(self): - super(SysTrayIcon, self).__init__() - icon=wx.Icon(os.path.join(paths.app_path(), "icon.ico"), wx.BITMAP_TYPE_ICO) - self.SetIcon(icon, application.name) - self.menu=wx.Menu() - self.tweet = self.menu.Append(wx.ID_ANY, _(u"Tweet")) - self.global_settings = self.menu.Append(wx.ID_ANY, _(u"&Global settings")) - self.account_settings = self.menu.Append(wx.ID_ANY, _(u"Account se&ttings")) - self.update_profile = self.menu.Append(wx.ID_ANY, _(u"Update &profile")) - self.show_hide = self.menu.Append(wx.ID_ANY, _(u"&Show / hide")) - self.doc = self.menu.Append(wx.ID_ANY, _(u"&Documentation")) - self.check_for_updates = self.menu.Append(wx.ID_ANY, _(u"Check for &updates")) - self.exit = self.menu.Append(wx.ID_ANY, _(u"&Exit")) + def __init__(self): + super(SysTrayIcon, self).__init__() + icon=wx.Icon(os.path.join(paths.app_path(), "icon.ico"), wx.BITMAP_TYPE_ICO) + self.SetIcon(icon, application.name) + self.menu=wx.Menu() + self.tweet = self.menu.Append(wx.ID_ANY, _(u"Tweet")) + self.global_settings = self.menu.Append(wx.ID_ANY, _(u"&Global settings")) + self.account_settings = self.menu.Append(wx.ID_ANY, _(u"Account se&ttings")) + self.update_profile = self.menu.Append(wx.ID_ANY, _(u"Update &profile")) + self.show_hide = self.menu.Append(wx.ID_ANY, _(u"&Show / hide")) + self.doc = self.menu.Append(wx.ID_ANY, _(u"&Documentation")) + self.check_for_updates = self.menu.Append(wx.ID_ANY, _(u"Check for &updates")) + self.exit = self.menu.Append(wx.ID_ANY, _(u"&Exit")) - def show_menu(self): - self.PopupMenu(self.menu) + def show_menu(self): + self.PopupMenu(self.menu) - def Destroy(self): - self.menu.Destroy() - super(SysTrayIcon, self).Destroy() \ No newline at end of file + def Destroy(self): + self.menu.Destroy() + super(SysTrayIcon, self).Destroy() diff --git a/src/wxUI/view.py b/src/wxUI/view.py index 2729f6bf..cef105be 100644 --- a/src/wxUI/view.py +++ b/src/wxUI/view.py @@ -6,200 +6,200 @@ import wx.adv import application class mainFrame(wx.Frame): - """ Main class of the Frame. This is the Main Window.""" + """ Main class of the Frame. This is the Main Window.""" - ### MENU - def makeMenus(self): - """ Creates, bind and returns the menu bar for the application. Also in this function, the accel table is created.""" - menuBar = wx.MenuBar() + ### MENU + def makeMenus(self): + """ Creates, bind and returns the menu bar for the application. Also in this function, the accel table is created.""" + menuBar = wx.MenuBar() - # Application menu - app = wx.Menu() - self.manage_accounts = app.Append(wx.ID_ANY, _(u"&Manage accounts")) - self.updateProfile = app.Append(wx.ID_ANY, _(u"&Update profile")) - self.show_hide = app.Append(wx.ID_ANY, _(u"&Hide window")) - self.menuitem_search = app.Append(wx.ID_ANY, _(u"&Search")) - self.lists = app.Append(wx.ID_ANY, _(u"&Lists manager")) - self.keystroke_editor = app.Append(wx.ID_ANY, _(u"&Edit keystrokes")) - self.account_settings = app.Append(wx.ID_ANY, _(u"Account se&ttings")) - self.prefs = app.Append(wx.ID_PREFERENCES, _(u"&Global settings")) - self.close = app.Append(wx.ID_EXIT, _(u"E&xit")) + # Application menu + app = wx.Menu() + self.manage_accounts = app.Append(wx.ID_ANY, _(u"&Manage accounts")) + self.updateProfile = app.Append(wx.ID_ANY, _(u"&Update profile")) + self.show_hide = app.Append(wx.ID_ANY, _(u"&Hide window")) + self.menuitem_search = app.Append(wx.ID_ANY, _(u"&Search")) + self.lists = app.Append(wx.ID_ANY, _(u"&Lists manager")) + self.keystroke_editor = app.Append(wx.ID_ANY, _(u"&Edit keystrokes")) + self.account_settings = app.Append(wx.ID_ANY, _(u"Account se&ttings")) + self.prefs = app.Append(wx.ID_PREFERENCES, _(u"&Global settings")) + self.close = app.Append(wx.ID_EXIT, _(u"E&xit")) - # Tweet menu - tweet = wx.Menu() - self.compose = tweet.Append(wx.ID_ANY, _(u"&Tweet")) - self.reply = tweet.Append(wx.ID_ANY, _(u"Re&ply")) - self.retweet = tweet.Append(wx.ID_ANY, _(u"&Retweet")) - self.fav = tweet.Append(wx.ID_ANY, _(u"&Like")) - self.unfav = tweet.Append(wx.ID_ANY, _(u"&Unlike")) - self.view = tweet.Append(wx.ID_ANY, _(u"&Show tweet")) - self.view_coordinates = tweet.Append(wx.ID_ANY, _(u"View &address")) - self.view_conversation = tweet.Append(wx.ID_ANY, _(u"View conversa&tion")) - self.ocr = tweet.Append(wx.ID_ANY, _(u"Read text in picture")) - self.delete = tweet.Append(wx.ID_ANY, _(u"&Delete")) + # Tweet menu + tweet = wx.Menu() + self.compose = tweet.Append(wx.ID_ANY, _(u"&Tweet")) + self.reply = tweet.Append(wx.ID_ANY, _(u"Re&ply")) + self.retweet = tweet.Append(wx.ID_ANY, _(u"&Retweet")) + self.fav = tweet.Append(wx.ID_ANY, _(u"&Like")) + self.unfav = tweet.Append(wx.ID_ANY, _(u"&Unlike")) + self.view = tweet.Append(wx.ID_ANY, _(u"&Show tweet")) + self.view_coordinates = tweet.Append(wx.ID_ANY, _(u"View &address")) + self.view_conversation = tweet.Append(wx.ID_ANY, _(u"View conversa&tion")) + self.ocr = tweet.Append(wx.ID_ANY, _(u"Read text in picture")) + self.delete = tweet.Append(wx.ID_ANY, _(u"&Delete")) - # User menu - user = wx.Menu() - self.follow = user.Append(wx.ID_ANY, _(u"&Actions...")) - self.timeline = user.Append(wx.ID_ANY, _(u"&View timeline...")) - self.dm = user.Append(wx.ID_ANY, _(u"Direct me&ssage")) - self.addToList = user.Append(wx.ID_ANY, _(u"&Add to list")) - self.removeFromList = user.Append(wx.ID_ANY, _(u"R&emove from list")) - self.viewLists = user.Append(wx.ID_ANY, _(u"&View lists")) - self.details = user.Append(wx.ID_ANY, _(u"Show user &profile")) - self.favs = user.Append(wx.ID_ANY, _(u"V&iew likes")) + # User menu + user = wx.Menu() + self.follow = user.Append(wx.ID_ANY, _(u"&Actions...")) + self.timeline = user.Append(wx.ID_ANY, _(u"&View timeline...")) + self.dm = user.Append(wx.ID_ANY, _(u"Direct me&ssage")) + self.addToList = user.Append(wx.ID_ANY, _(u"&Add to list")) + self.removeFromList = user.Append(wx.ID_ANY, _(u"R&emove from list")) + self.viewLists = user.Append(wx.ID_ANY, _(u"&View lists")) + self.details = user.Append(wx.ID_ANY, _(u"Show user &profile")) + self.favs = user.Append(wx.ID_ANY, _(u"V&iew likes")) - # buffer menu - buffer = wx.Menu() - self.update_buffer = buffer.Append(wx.ID_ANY, _(u"&Update buffer")) - self.trends = buffer.Append(wx.ID_ANY, _(u"New &trending topics buffer...")) - self.filter = buffer.Append(wx.ID_ANY, _(u"Create a &filter")) - self.manage_filters = buffer.Append(wx.ID_ANY, _(u"&Manage filters")) - self.find = buffer.Append(wx.ID_ANY, _(u"Find a string in the currently focused buffer...")) - self.load_previous_items = buffer.Append(wx.ID_ANY, _(u"&Load previous items")) - buffer.AppendSeparator() - self.mute_buffer = buffer.AppendCheckItem(wx.ID_ANY, _(u"&Mute")) - self.autoread = buffer.AppendCheckItem(wx.ID_ANY, _(u"&Autoread")) - self.clear = buffer.Append(wx.ID_ANY, _(u"&Clear buffer")) - self.deleteTl = buffer.Append(wx.ID_ANY, _(u"&Destroy")) + # buffer menu + buffer = wx.Menu() + self.update_buffer = buffer.Append(wx.ID_ANY, _(u"&Update buffer")) + self.trends = buffer.Append(wx.ID_ANY, _(u"New &trending topics buffer...")) + self.filter = buffer.Append(wx.ID_ANY, _(u"Create a &filter")) + self.manage_filters = buffer.Append(wx.ID_ANY, _(u"&Manage filters")) + self.find = buffer.Append(wx.ID_ANY, _(u"Find a string in the currently focused buffer...")) + self.load_previous_items = buffer.Append(wx.ID_ANY, _(u"&Load previous items")) + buffer.AppendSeparator() + self.mute_buffer = buffer.AppendCheckItem(wx.ID_ANY, _(u"&Mute")) + self.autoread = buffer.AppendCheckItem(wx.ID_ANY, _(u"&Autoread")) + self.clear = buffer.Append(wx.ID_ANY, _(u"&Clear buffer")) + self.deleteTl = buffer.Append(wx.ID_ANY, _(u"&Destroy")) - # audio menu - audio = wx.Menu() - self.seekLeft = audio.Append(wx.ID_ANY, _(u"&Seek back 5 seconds")) - self.seekRight = audio.Append(wx.ID_ANY, _(u"&Seek forward 5 seconds")) + # audio menu + audio = wx.Menu() + self.seekLeft = audio.Append(wx.ID_ANY, _(u"&Seek back 5 seconds")) + self.seekRight = audio.Append(wx.ID_ANY, _(u"&Seek forward 5 seconds")) - # Help Menu - help = wx.Menu() - self.doc = help.Append(-1, _(u"&Documentation")) - self.sounds_tutorial = help.Append(wx.ID_ANY, _(u"Sounds &tutorial")) - self.changelog = help.Append(wx.ID_ANY, _(u"&What's new in this version?")) - self.check_for_updates = help.Append(wx.ID_ANY, _(u"&Check for updates")) - self.reportError = help.Append(wx.ID_ANY, _(u"&Report an error")) - self.visit_website = help.Append(-1, _(u"{0}'s &website").format(application.name,)) - self.get_soundpacks = help.Append(-1, _(u"Get soundpacks for TWBlue")) - self.about = help.Append(-1, _(u"About &{0}").format(application.name,)) + # Help Menu + help = wx.Menu() + self.doc = help.Append(-1, _(u"&Documentation")) + self.sounds_tutorial = help.Append(wx.ID_ANY, _(u"Sounds &tutorial")) + self.changelog = help.Append(wx.ID_ANY, _(u"&What's new in this version?")) + self.check_for_updates = help.Append(wx.ID_ANY, _(u"&Check for updates")) + self.reportError = help.Append(wx.ID_ANY, _(u"&Report an error")) + self.visit_website = help.Append(-1, _(u"{0}'s &website").format(application.name,)) + self.get_soundpacks = help.Append(-1, _(u"Get soundpacks for TWBlue")) + self.about = help.Append(-1, _(u"About &{0}").format(application.name,)) - # Add all to the menu Bar - menuBar.Append(app, _(u"&Application")) - menuBar.Append(tweet, _(u"&Tweet")) - menuBar.Append(user, _(u"&User")) - menuBar.Append(buffer, _(u"&Buffer")) - menuBar.Append(audio, _(u"&Audio")) - menuBar.Append(help, _(u"&Help")) + # Add all to the menu Bar + menuBar.Append(app, _(u"&Application")) + menuBar.Append(tweet, _(u"&Tweet")) + menuBar.Append(user, _(u"&User")) + menuBar.Append(buffer, _(u"&Buffer")) + menuBar.Append(audio, _(u"&Audio")) + menuBar.Append(help, _(u"&Help")) - self.accel_tbl = wx.AcceleratorTable([ -(wx.ACCEL_CTRL, ord('N'), self.compose.GetId()), -(wx.ACCEL_CTRL, ord('R'), self.reply.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('R'), self.retweet.GetId()), -(wx.ACCEL_CTRL, ord('F'), self.fav.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('F'), self.unfav.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('V'), self.view.GetId()), -(wx.ACCEL_CTRL, ord('D'), self.dm.GetId()), + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('N'), self.compose.GetId()), + (wx.ACCEL_CTRL, ord('R'), self.reply.GetId()), + (wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('R'), self.retweet.GetId()), + (wx.ACCEL_CTRL, ord('F'), self.fav.GetId()), + (wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('F'), self.unfav.GetId()), + (wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('V'), self.view.GetId()), + (wx.ACCEL_CTRL, ord('D'), self.dm.GetId()), -(wx.ACCEL_CTRL, ord('Q'), self.close.GetId()), -(wx.ACCEL_CTRL, ord('S'), self.follow.GetId()), -(wx.ACCEL_CTRL, ord('I'), self.timeline.GetId()), -(wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('I'), self.deleteTl.GetId()), -(wx.ACCEL_CTRL, ord('M'), self.show_hide.GetId()), -(wx.ACCEL_CTRL, wx.WXK_LEFT, self.seekLeft.GetId()), -(wx.ACCEL_CTRL, ord('P'), self.updateProfile.GetId()), -(wx.ACCEL_CTRL, wx.WXK_RIGHT, self.seekRight.GetId()), -(wx.ACCEL_CTRL, ord(' '), self.seekLeft.GetId()), - ]) + (wx.ACCEL_CTRL, ord('Q'), self.close.GetId()), + (wx.ACCEL_CTRL, ord('S'), self.follow.GetId()), + (wx.ACCEL_CTRL, ord('I'), self.timeline.GetId()), + (wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('I'), self.deleteTl.GetId()), + (wx.ACCEL_CTRL, ord('M'), self.show_hide.GetId()), + (wx.ACCEL_CTRL, wx.WXK_LEFT, self.seekLeft.GetId()), + (wx.ACCEL_CTRL, ord('P'), self.updateProfile.GetId()), + (wx.ACCEL_CTRL, wx.WXK_RIGHT, self.seekRight.GetId()), + (wx.ACCEL_CTRL, ord(' '), self.seekLeft.GetId()), + ]) - self.SetAcceleratorTable(self.accel_tbl) - return menuBar + self.SetAcceleratorTable(self.accel_tbl) + return menuBar - ### MAIN - def __init__(self): - """ Main function of this class.""" - super(mainFrame, self).__init__(None, -1, application.name, size=(1600, 1600)) - self.panel = wx.Panel(self) - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.SetTitle(application.name) - self.SetMenuBar(self.makeMenus()) - self.nb = wx.Treebook(self.panel, wx.ID_ANY) - self.buffers = {} + ### MAIN + def __init__(self): + """ Main function of this class.""" + super(mainFrame, self).__init__(None, -1, application.name, size=(1600, 1600)) + self.panel = wx.Panel(self) + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.SetTitle(application.name) + self.SetMenuBar(self.makeMenus()) + self.nb = wx.Treebook(self.panel, wx.ID_ANY) + self.buffers = {} - def get_buffer_count(self): - return self.nb.GetPageCount() + def get_buffer_count(self): + return self.nb.GetPageCount() - def add_buffer(self, buffer, name): - self.nb.AddPage(buffer, name) - self.buffers[name] = buffer.GetId() + def add_buffer(self, buffer, name): + self.nb.AddPage(buffer, name) + self.buffers[name] = buffer.GetId() - def insert_buffer(self, buffer, name, pos): - self.nb.InsertSubPage(pos, buffer, name) - self.buffers[name] = buffer.GetId() + def insert_buffer(self, buffer, name, pos): + self.nb.InsertSubPage(pos, buffer, name) + self.buffers[name] = buffer.GetId() - def prepare(self): - self.sizer.Add(self.nb, 0, wx.ALL, 5) - self.panel.SetSizer(self.sizer) + def prepare(self): + self.sizer.Add(self.nb, 0, wx.ALL, 5) + self.panel.SetSizer(self.sizer) # self.Maximize() - self.sizer.Layout() - self.SetClientSize(self.sizer.CalcMin()) + self.sizer.Layout() + self.SetClientSize(self.sizer.CalcMin()) # print self.GetSize() - def get_buffers(self): - return [self.nb.GetPage(i) for i in range(0, self.nb.GetPageCount())] + def get_buffers(self): + return [self.nb.GetPage(i) for i in range(0, self.nb.GetPageCount())] - def search(self, name_, account): - for i in range(0, self.nb.GetPageCount()): - if self.nb.GetPage(i).name == name_ and self.nb.GetPage(i).account == account: return i + def search(self, name_, account): + for i in range(0, self.nb.GetPageCount()): + if self.nb.GetPage(i).name == name_ and self.nb.GetPage(i).account == account: return i - def get_current_buffer(self): - return self.nb.GetCurrentPage() + def get_current_buffer(self): + return self.nb.GetCurrentPage() - def get_current_buffer_pos(self): - return self.nb.GetSelection() + def get_current_buffer_pos(self): + return self.nb.GetSelection() - def get_buffer(self, pos): - return self.GetPage(pos) + def get_buffer(self, pos): + return self.GetPage(pos) - def change_buffer(self, position): - self.nb.ChangeSelection(position) + def change_buffer(self, position): + self.nb.ChangeSelection(position) - def get_buffer_text(self): - return self.nb.GetPageText(self.nb.GetSelection()) + def get_buffer_text(self): + return self.nb.GetPageText(self.nb.GetSelection()) - def get_buffer_by_id(self, id): - return self.nb.FindWindowById(id) - def advance_selection(self, forward): - self.nb.AdvanceSelection(forward) + def get_buffer_by_id(self, id): + return self.nb.FindWindowById(id) + def advance_selection(self, forward): + self.nb.AdvanceSelection(forward) - def show(self): - self.Show() + def show(self): + self.Show() - def show_address(self, address): - wx.MessageDialog(self, address, _(u"Address"), wx.OK).ShowModal() + def show_address(self, address): + wx.MessageDialog(self, address, _(u"Address"), wx.OK).ShowModal() - def delete_buffer(self, pos): - self.nb.DeletePage(pos) + def delete_buffer(self, pos): + self.nb.DeletePage(pos) - def about_dialog(self): - info = wx.adv.AboutDialogInfo() - info.SetName(application.name) - info.SetVersion(application.version) - info.SetDescription(application.description) - info.SetCopyright(application.copyright) - info.SetTranslators(application.translators) + def about_dialog(self): + info = wx.adv.AboutDialogInfo() + info.SetName(application.name) + info.SetVersion(application.version) + info.SetDescription(application.description) + info.SetCopyright(application.copyright) + info.SetTranslators(application.translators) # info.SetLicence(application.licence) - for i in application.authors: - info.AddDeveloper(i) - wx.adv.AboutBox(info) + for i in application.authors: + info.AddDeveloper(i) + wx.adv.AboutBox(info) - def set_focus(self): - self.SetFocus() + def set_focus(self): + self.SetFocus() - def check_menuitem(self, menuitem, check=True): - if hasattr(self, menuitem): - getattr(self, menuitem).Check(check) + def check_menuitem(self, menuitem, check=True): + if hasattr(self, menuitem): + getattr(self, menuitem).Check(check) - def set_page_title(self, page, title): - return self.nb.SetPageText(page, title) + def set_page_title(self, page, title): + return self.nb.SetPageText(page, title) - def get_page_title(self, page): - return self.nb.GetPageText(page) + def get_page_title(self, page): + return self.nb.GetPageText(page) def no_update_available(): - wx.MessageDialog(None, _(u"Your {0} version is up to date").format(application.name,), _(u"Update"), style=wx.OK).ShowModal() + wx.MessageDialog(None, _(u"Your {0} version is up to date").format(application.name,), _(u"Update"), style=wx.OK).ShowModal() From 50125fc55a88c1f539ddfaf77e183fa6032b33f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Novegil?= Date: Wed, 23 Jun 2021 18:45:33 +0200 Subject: [PATCH 035/245] Fix arrow for Galician. Modify some existing translations to localize them properly --- src/fixes/fix_arrow.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/fixes/fix_arrow.py b/src/fixes/fix_arrow.py index d1d3dca4..322c9af7 100644 --- a/src/fixes/fix_arrow.py +++ b/src/fixes/fix_arrow.py @@ -17,26 +17,33 @@ def get_locale(name): class GalicianLocale(object): names = ['gl', 'gl_es', 'gl_gl'] - past = 'Fai {0}' + past = 'Hai {0}' future = 'En {0}' + and_word = "e" timeframes = { - 'now': 'Agora mesmo', - 'seconds': 'segundos', + 'now': 'Agora', + "second": "un segundo", + 'seconds': '{0} segundos', 'minute': 'un minuto', 'minutes': '{0} minutos', - 'hour': 'una hora', + 'hour': 'unha hora', 'hours': '{0} horas', 'day': 'un día', 'days': '{0} días', + "week": "unha semana", + "weeks": "{0} semanas", 'month': 'un mes', 'months': '{0} meses', 'year': 'un ano', 'years': '{0} anos', } - month_names = ['', 'Xaneiro', 'Febreiro', 'Marzo', 'Abril', 'Maio', 'Xuño', 'Xullo', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Decembro'] - month_abbreviations = ['', 'Xan', 'Feb', 'Mar', 'Abr', 'Mai', 'Xun', 'Xul', 'Ago', 'Set', 'Out', 'Nov', 'Dec'] - day_names = ['', 'Luns', 'Martes', 'Mércores', 'Xoves', 'Venres', 'Sábado', 'Domingo'] - day_abbreviations = ['', 'Lun', 'Mar', 'Mer', 'xov', 'Ven' 'Sab', 'Dom'] + meridians = {"am": "am", "pm": "pm", "AM": "AM", "PM": "PM"} + + month_names = ['', 'xaneiro', 'febreiro', 'marzo', 'abril', 'maio', 'xuño', 'xullo', 'agosto', 'setembro', 'outubro', 'novembro', 'decembro'] + month_abbreviations = ['', 'xan', 'feb', 'mar', 'abr', 'mai', 'xun', 'xul', 'ago', 'set', 'out', 'nov', 'dec'] + day_names = ['', 'luns', 'martes', 'mércores', 'xoves', 'venres', 'sábado', 'domingo'] + day_abbreviations = ['', 'lun', 'mar', 'mer', 'xov', 'ven', 'sab', 'dom'] + ordinal_day_re = r"((?P[1-3]?[0-9](?=[ºª]))[ºª])" From 382acf7c8cf9d8aa69ce24d2cf30b4ae1d1c9b26 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 23 Jun 2021 13:40:21 -0500 Subject: [PATCH 036/245] Use slitedict to attempt to reduce memory usage when caching tweets --- requirements.txt | 1 + src/controller/mainController.py | 4 ++-- src/sessions/base.py | 39 ++++++++++++++++++-------------- src/sessions/twitter/session.py | 26 ++++++++++++++------- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/requirements.txt b/requirements.txt index ae1296b8..9943eb0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,6 +31,7 @@ cx_freeze tweepy twitter-text-parser pyenchant +sqlitedict git+https://github.com/accessibleapps/libloader git+https://github.com/accessibleapps/platform_utils git+https://github.com/accessibleapps/accessible_output2 diff --git a/src/controller/mainController.py b/src/controller/mainController.py index ed8bf128..1c11c404 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -254,8 +254,8 @@ class Controller(object): # Connection checker executed each minute. self.checker_function = RepeatingTimer(60, self.check_connection) # self.checker_function.start() - self.save_db = RepeatingTimer(300, self.save_data_in_db) - self.save_db.start() +# self.save_db = RepeatingTimer(300, self.save_data_in_db) +# self.save_db.start() log.debug("Setting updates to buffers every %d seconds..." % (60*config.app["app-settings"]["update_period"],)) self.update_buffers_function = RepeatingTimer(60*config.app["app-settings"]["update_period"], self.update_buffers) self.update_buffers_function.start() diff --git a/src/sessions/base.py b/src/sessions/base.py index 597cacfc..6f3ecef9 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -11,12 +11,13 @@ import time import sound import logging import config_utils -import shelve +import sqlitedict import application import os from . import session_exceptions as Exceptions log = logging.getLogger("sessionmanager.session") + class baseSession(object): """ toDo: Decorators does not seem to be working when using them in an inherited class.""" @@ -81,18 +82,19 @@ class baseSession(object): os.remove(shelfname+".dat") return try: - if not os.path.exists(shelfname+".dat"): - output.speak("Generating database, this might take a while.",True) - shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') - for key, value in list(self.db.items()): - if type(key) != str and type(key) != str: - output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True) - log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!") - if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]: - shelf[key]=value[self.settings["general"]["persist_size"]:] - else: - shelf[key]=value - shelf.close() + self.db.commit() +# if not os.path.exists(shelfname+".dat"): +# output.speak("Generating database, this might take a while.",True) +# shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') +# for key, value in list(self.db.items()): +# if type(key) != str and type(key) != str: +# output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True) +# log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!") +# if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]: +# shelf[key]=value[self.settings["general"]["persist_size"]:] +# else: +# shelf[key]=value +# shelf.close() except: output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) log.exception("Exception while shelving" + shelfname) @@ -106,10 +108,13 @@ class baseSession(object): os.remove(shelfname+".dat") return try: - shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') - for key,value in list(shelf.items()): - self.db[key]=value - shelf.close() + self.db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), shelfname), 'c') + if self.db.get("cursors") == None: + cursors = dict(direct_messages=-1) + self.db["cursors"] = cursors +# for key,value in list(shelf.items()): +# self.db[key]=value +# shelf.close() except: output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) log.exception("Exception while deshelving" + shelfname) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 1cdbece0..01801319 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -38,6 +38,7 @@ class Session(base.baseSession): self.db[name] = [] if ("users" in self.db) == False: self.db["users"] = {} + objects = self.db[name] if ignore_older and len(self.db[name]) > 0: if self.settings["general"]["reverse_timelines"] == False: last_id = self.db[name][0].id @@ -52,12 +53,13 @@ class Session(base.baseSession): i = self.check_quoted_status(i) i = self.check_long_tweet(i) if i == False: continue - if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) - else: self.db[name].insert(0, i) + if self.settings["general"]["reverse_timelines"] == False: objects.append(i) + else: objects.insert(0, i) num = num+1 if hasattr(i, "user"): if (i.user.id in self.db["users"]) == False: self.db["users"][i.user.id] = i.user + self.db[name] = objects return num def order_people(self, name, data): @@ -68,11 +70,13 @@ class Session(base.baseSession): num = 0 if (name in self.db) == False: self.db[name] = [] + objects = self.db[name] for i in data: if utils.find_item(i.id, self.db[name]) == None: - if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i) - else: self.db[name].insert(0, i) + if self.settings["general"]["reverse_timelines"] == False: objects.append(i) + else: objects.insert(0, i) num = num+1 + self.db[name] = objects return num def order_direct_messages(self, data): @@ -83,19 +87,25 @@ class Session(base.baseSession): sent = 0 if ("direct_messages" in self.db) == False: self.db["direct_messages"] = [] + if ("sent_direct_messages" in self.db) == False: + self.db["sent_direct_messages"] = [] + objects = self.db["direct_messages"] + sent_objects = self.db["sent_direct_messages"] for i in data: # Twitter returns sender_id as str, which must be converted to int in order to match to our user_id object. if int(i.message_create["sender_id"]) == self.db["user_id"]: if "sent_direct_messages" in self.db and utils.find_item(i.id, self.db["sent_direct_messages"]) == None: - if self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"].append(i) - else: self.db["sent_direct_messages"].insert(0, i) + if self.settings["general"]["reverse_timelines"] == False: sent_objects.append(i) + else: sent_objects.insert(0, i) sent = sent+1 else: if utils.find_item(i.id, self.db["direct_messages"]) == None: - if self.settings["general"]["reverse_timelines"] == False: self.db["direct_messages"].append(i) - else: self.db["direct_messages"].insert(0, i) + if self.settings["general"]["reverse_timelines"] == False: objects.append(i) + else: objects.insert(0, i) incoming = incoming+1 pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) + self.db["direct_messages"] = objects + self.db["sent_direct_messages"] = sent_objects return incoming def __init__(self, *args, **kwargs): From 60144a6b086cc112247178826e9bf635a48a0a14 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 24 Jun 2021 09:52:10 -0500 Subject: [PATCH 037/245] Added initial support to SqliteDict package --- src/controller/buffers/twitterBuffers.py | 61 ++++++++++++++++-------- src/controller/mainController.py | 6 ++- src/sessions/twitter/session.py | 45 +++++------------ 3 files changed, 57 insertions(+), 55 deletions(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 0fdacac4..25081b72 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -178,7 +178,9 @@ class baseBufferController(baseBuffers.buffer): val, cursor = val if type(cursor) == tuple: cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors results = [i for i in val] val = results val.reverse() @@ -190,7 +192,6 @@ class baseBufferController(baseBuffers.buffer): return number_of_items = self.session.order_buffer(self.name, val) log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) if hasattr(self, "finished_timeline") and self.finished_timeline == False: if "-timeline" in self.name: @@ -229,15 +230,17 @@ class baseBufferController(baseBuffers.buffer): return if items == None: return + items_db = self.session.db[self.name] for i in items: if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i.id, self.session.db[self.name]) == None: i = self.session.check_quoted_status(i) i = self.session.check_long_tweet(i) elements.append(i) if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) + items_db.insert(0, i) else: - self.session.db[self.name].append(i) + items_db.append(i) + self.session.db[self.name] = items_db selection = self.buffer.list.get_selected() log.debug("Retrieved %d items from cursored search in function %s." % (len(elements), self.function)) if self.session.settings["general"]["reverse_timelines"] == False: @@ -286,10 +289,12 @@ class baseBufferController(baseBuffers.buffer): def remove_tweet(self, id): if type(self.session.db[self.name]) == dict: return - for i in range(0, len(self.session.db[self.name])): - if self.session.db[self.name][i].id == id: - self.session.db[self.name].pop(i) + items = self.session.db[self.name] + for i in range(0, len(items)): + if items[i].id == id: + items.pop(i) self.remove_item(i) + self.session.db[self.name] = items def put_items_on_list(self, number_of_items): list_to_use = self.session.db[self.name] @@ -471,10 +476,12 @@ class baseBufferController(baseBuffers.buffer): text = dm.message.get_text() val = self.session.api_call(call_name="send_direct_message", recipient_id=recipient_id, text=text) if val != None: + sent_dms = self.session.db["sent_direct_messages"] if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db["sent_direct_messages"].append(val) + sent_dms.append(val) else: - self.session.db["sent_direct_messages"].insert(0, val) + sent_dms.insert(0, val) + self.session.db["sent_direct_messages"] = sent_dms pub.sendMessage("sent-dm", data=val, user=self.session.db["user_name"]) if hasattr(dm.message, "destroy"): dm.message.destroy() @@ -588,16 +595,18 @@ class baseBufferController(baseBuffers.buffer): if self.type == "events" or self.type == "people" or self.type == "empty" or self.type == "account": return answer = commonMessageDialogs.delete_tweet_dialog(None) if answer == widgetUtils.YES: + items = self.session.db[self.name] try: if self.name == "direct_messages" or self.name == "sent_direct_messages": self.session.twitter.destroy_direct_message(id=self.get_right_tweet().id) - self.session.db[self.name].pop(index) + items.pop(index) else: self.session.twitter.destroy_status(id=self.get_right_tweet().id) - self.session.db[self.name].pop(index) + items.pop(index) self.buffer.list.remove_item(index) except TweepError: self.session.sound.play("error.ogg") + self.session.db[self.name] = items @_tweets_exist def user_details(self): @@ -646,7 +655,9 @@ class directMessagesController(baseBufferController): items, cursor = items if type(cursor) == tuple: cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors results = [i for i in items] items = results log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) @@ -657,22 +668,26 @@ class directMessagesController(baseBufferController): return sent = [] received = [] + sent_dms = self.session.db["sent_direct_messages"] + received_dms = self.session.db["direct_messages"] for i in items: if int(i.message_create["sender_id"]) == self.session.db["user_id"]: if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db["sent_direct_messages"].insert(0, i) + sent_dms.insert(0, i) sent.append(i) else: - self.session.db["sent_direct_messages"].append(i) + sent_dms.append(i) sent.insert(0, i) else: if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) + received_dms.insert(0, i) received.append(i) else: - self.session.db[self.name].append(i) + received_dms.append(i) received.insert(0, i) total = total+1 + self.session.db["direct_messages"] = received_dms + self.session.db["sent_direct_messages"] = sent_dms user_ids = [item.message_create["sender_id"] for item in items] self.session.save_users(user_ids) pub.sendMessage("more-sent-dms", data=sent, account=self.session.db["user_name"]) @@ -885,7 +900,9 @@ class peopleBufferController(baseBufferController): val, cursor = val if type(cursor) == tuple: cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors results = [i for i in val] val = results val.reverse() @@ -914,7 +931,9 @@ class peopleBufferController(baseBufferController): items, cursor = items if type(cursor) == tuple: cursor = cursor[1] - self.session.db["cursors"][self.name] = cursor + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors results = [i for i in items] items = results log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) @@ -923,11 +942,13 @@ class peopleBufferController(baseBufferController): return if items == None: return + items_db = self.session.db[self.name] for i in items: if self.session.settings["general"]["reverse_timelines"] == False: - self.session.db[self.name].insert(0, i) + items_db.insert(0, i) else: - self.session.db[self.name].append(i) + items_db.append(i) + self.session.db[self.name] = items_db selected = self.buffer.list.get_selected() if self.session.settings["general"]["reverse_timelines"] == True: for i in items: diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 1c11c404..f37f7677 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1274,10 +1274,12 @@ class Controller(object): data = buffer.session.check_long_tweet(data) if data == False: # Long tweet deleted from twishort. return + items = buffer.session.db[buffer.name] if buffer.session.settings["general"]["reverse_timelines"] == False: - buffer.session.db[buffer.name].append(data) + items.append(data) else: - buffer.session.db[buffer.name].insert(0, data) + items.insert(0, data) + buffer.session.db[buffer.name] = items buffer.add_new_item(data) def manage_friend(self, data, user): diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 01801319..f29401db 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -171,35 +171,6 @@ class Session(base.baseSession): self.verify_authorisation(pincode) self.authorisation_dialog.Destroy() - def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs): - """ Get more items for twitter objects. - update_function str: function to call for getting more items. Must be member of self.twitter. - users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling). - name str: name of the database item to put new element in.""" - results = [] - if "cursor" in kwargs and kwargs["cursor"] == 0: - output.speak(_(u"There are no more items to retrieve in this buffer.")) - return - data = getattr(self.twitter, update_function)(*args, **kwargs) - if users == True: - if type(data) == dict and "next_cursor" in data: - if "next_cursor" in data: # There are more objects to retrieve. - self.db[name]["cursor"] = data["next_cursor"] - else: # Set cursor to 0, wich means no more items available. - self.db[name]["cursor"] = 0 - for i in data["users"]: results.append(i) - elif type(data) == list: - results.extend(data[1:]) - elif dm == True: - if "next_cursor" in data: # There are more objects to retrieve. - self.db[name]["cursor"] = data["next_cursor"] - else: # Set cursor to 0, wich means no more items available. - self.db[name]["cursor"] = 0 - for i in data["events"]: results.append(i) - else: - results.extend(data[1:]) - return results - def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): """ Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call the method again at least 25 times, waiting a while between calls. Useful for post methods. If twitter returns an error, it will not call the method anymore. @@ -425,7 +396,9 @@ class Session(base.baseSession): user.id = id user.name = _("Deleted account") user.id_str = id - self.db["users"][user.id_str] = user + users = self.db["users"] + users[user.id_str] = user + self.db["users"] = users return user else: return self.db["users"][id] @@ -436,14 +409,18 @@ class Session(base.baseSession): returns an user ID.""" if ("users" in self.db) == False: user = utils.if_user_exists(self.twitter, screen_name) - self.db["users"][user["id_str"]] = user + users = self.db["users"] + users[user["id_str"]] = user + self.db["users"] = users return user["id_str"] else: for i in list(self.db["users"].keys()): if self.db["users"][i].screen_name == screen_name: return self.db["users"][i].id_str user = utils.if_user_exists(self.twitter, screen_name) - self.db["users"][user.id_str] = user + users = self.db["users"] + users[user.id_str] = user + self.db["users"] = users return user.id_str def save_users(self, user_ids): @@ -458,6 +435,8 @@ class Session(base.baseSession): return log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") + users_db = self.db["users"] for user in users: - self.db["users"][user.id_str] = user + users_db[user.id_str] = user log.debug("Added %d new users" % (len(users))) + self.db["users"] = users_db \ No newline at end of file From 44c25e54f811b5ea025a09dfc28e45da576ae18c Mon Sep 17 00:00:00 2001 From: nikola nikola Date: Fri, 25 Jun 2021 18:33:16 +0200 Subject: [PATCH 038/245] Updated Serbian translation. --- src/locales/sr/LC_MESSAGES/twblue.mo | Bin 47003 -> 50471 bytes src/locales/sr/LC_MESSAGES/twblue.po | 181 ++++++++++++--------------- 2 files changed, 77 insertions(+), 104 deletions(-) diff --git a/src/locales/sr/LC_MESSAGES/twblue.mo b/src/locales/sr/LC_MESSAGES/twblue.mo index 5a32e58db69a8f10d5fecaf86c8cda6c707c6b98..1669d1bd0f64831676bc1a12594d621d03726cfc 100644 GIT binary patch delta 20648 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 P)6ehuziXxNRcZY{28*=b delta 17479 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\n" +"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" +"PO-Revision-Date: 2021-06-25 18:32+0100\n" +"Last-Translator: Nikola Jović \n" "Language-Team: Aleksandar Đurić \n" "Language: sr_RS@latin\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.0.1\n" +"X-Generator: Poedit 1.6.10\n" "X-Poedit-Bookmarks: -1,442,-1,-1,-1,-1,-1,-1,-1,-1\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -82,26 +82,24 @@ msgid "Muted users" msgstr "Utišani korisnici" #: ../src\controller\buffers\twitterBuffers.py:75 -#, fuzzy msgid "{username}'s timeline" -msgstr "Otvori korisničku vremensku crtu" +msgstr "Vremenska linija korisnika {username}" #: ../src\controller\buffers\twitterBuffers.py:77 msgid "{username}'s likes" -msgstr "" +msgstr "Sviđanja korisnika {username}" #: ../src\controller\buffers\twitterBuffers.py:79 msgid "{username}'s followers" -msgstr "" +msgstr "Pratioci korisnika {username}" #: ../src\controller\buffers\twitterBuffers.py:81 msgid "{username}'s friends" -msgstr "" +msgstr "Prijatelji korisnika {username}" #: ../src\controller\buffers\twitterBuffers.py:83 -#, fuzzy msgid "Unknown buffer" -msgstr "Nepoznato" +msgstr "Nepoznat kanal" #: ../src\controller\buffers\twitterBuffers.py:86 #: ../src\controller\buffers\twitterBuffers.py:1242 @@ -117,14 +115,12 @@ msgid "Write the tweet here" msgstr "Otkucajte tvit ovde:" #: ../src\controller\buffers\twitterBuffers.py:194 -#, fuzzy msgid "New tweet in {0}" -msgstr "Novi tvit" +msgstr "Novi tvit u kanalu {0}" #: ../src\controller\buffers\twitterBuffers.py:197 -#, fuzzy msgid "{0} new tweets in {1}." -msgstr "@{0} citira vaš tvit: {1}" +msgstr "{0} novih tvitova u kanalu {1}." #: ../src\controller\buffers\twitterBuffers.py:232 #: ../src\controller\buffers\twitterBuffers.py:676 @@ -180,7 +176,7 @@ msgstr "Podaci o korisniku" #: ../src\controller\buffers\twitterBuffers.py:634 #: ../src\controller\buffers\twitterBuffers.py:987 msgid "Opening item in web browser..." -msgstr "" +msgstr "Otvaram stavku u Web pretraživaču..." #: ../src\controller\buffers\twitterBuffers.py:688 #: ../src\controller\buffers\twitterBuffers.py:855 @@ -194,30 +190,28 @@ msgid "Mention" msgstr "Spomeni" #: ../src\controller\buffers\twitterBuffers.py:728 -#, fuzzy msgid "{0} new direct messages." -msgstr "Nova direktna poruka" +msgstr "{0} novih direktnih poruka." #: ../src\controller\buffers\twitterBuffers.py:731 -#, fuzzy msgid "This action is not supported in the buffer yet." -msgstr "Ova radnja nije podržana na ovom kanalu" +msgstr "Ova radnja još uvek nije podržana na ovom kanalu." #: ../src\controller\buffers\twitterBuffers.py:741 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." msgstr "" +"Nemoguće preuzeti dodatne stavke za ovaj kanal. Umesto toga, koristite kanal " +"direktne poruke." #: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy msgid "{0} new followers." -msgstr "Novi pratilac." +msgstr "{0} novih pratilaca." #: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy msgid "This action is not supported in the buffer, yet." -msgstr "Ova radnja nije podržana na ovom kanalu" +msgstr "Ova radnja još uvek nije podržana na ovom kanalu" #: ../src\controller\mainController.py:273 msgid "Ready" @@ -308,9 +302,8 @@ msgid "{0} not found." msgstr "{0} nije pronađen." #: ../src\controller\mainController.py:482 -#, fuzzy msgid "Filters cannot be applied on this buffer" -msgstr "Ova radnja nije podržana na ovom kanalu" +msgstr "Filteri se ne mogu primeniti na ovaj kanal" #: ../src\controller\mainController.py:535 #: ../src\controller\mainController.py:552 @@ -319,9 +312,8 @@ msgid "Select the user" msgstr "Izaberite korisnika" #: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy msgid "MMM D, YYYY. H:m" -msgstr "dddd, MMMM D, YYYY H:m:s" +msgstr "MMM D, YYYY. H:m" #: ../src\controller\mainController.py:934 msgid "Conversation with {0}" @@ -379,12 +371,11 @@ msgstr "Ova lista je već otvorena" #: ../src\controller\mainController.py:1423 #: ../src\controller\mainController.py:1439 -#, fuzzy msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" -"Dogodilo se nešto neočekivano prilikom prijavljivanja greške. Molimo vas da " -"pokušate kasnije." +"Došlo je do greške pri pokušaju povezivanja na server. Molimo pokušajte " +"kasnije." #: ../src\controller\mainController.py:1475 msgid "The auto-reading of new tweets is enabled for this buffer" @@ -475,9 +466,8 @@ msgid "%s - %s characters" msgstr "%s - %s znakova" #: ../src\controller\messages.py:262 -#, fuzzy msgid "View item" -msgstr "Vidi liste" +msgstr "Prikaži stavku" #: ../src\controller\settings.py:75 msgid "Direct connection" @@ -533,7 +523,8 @@ msgstr "Korisnik je suspendovan." msgid "Information for %s" msgstr "Informacija za %s" -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 +#: ../src\controller\user.py:66 +#: ../src\extra\AudioUploader\audioUploader.py:124 msgid "Discarded" msgstr "Odbačeno" @@ -658,9 +649,8 @@ msgstr "Snimam zvučni zapis..." #: ../src\extra\AudioUploader\transfer.py:78 #: ../src\extra\AudioUploader\transfer.py:84 -#, fuzzy msgid "Error in file upload: {0}" -msgstr "Kod greške {0}" +msgstr "Greška u otpremanju datoteke: {0}" #: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 msgid "%d day, " @@ -871,28 +861,24 @@ msgid "Suggestions" msgstr "Predlozi" #: ../src\extra\SpellChecker\wx_ui.py:42 -#, fuzzy msgid "&Ignore" -msgstr "Zamenari." +msgstr "&Zanemari" #: ../src\extra\SpellChecker\wx_ui.py:43 -#, fuzzy msgid "I&gnore all" -msgstr "Zanemari sve" +msgstr "Z&anemai sve" #: ../src\extra\SpellChecker\wx_ui.py:44 -#, fuzzy msgid "&Replace" -msgstr "Zameni" +msgstr "&Zameni" #: ../src\extra\SpellChecker\wx_ui.py:45 -#, fuzzy msgid "R&eplace all" -msgstr "Zameni sve" +msgstr "Zam&eni sve" #: ../src\extra\SpellChecker\wx_ui.py:46 msgid "&Add to personal dictionary" -msgstr "" +msgstr "&Dodaj u lični rečnik" #: ../src\extra\SpellChecker\wx_ui.py:79 msgid "" @@ -1553,9 +1539,8 @@ msgid "Like a tweet" msgstr "Označi tvit sa sviđa mi se" #: ../src\keystrokeEditor\constants.py:15 -#, fuzzy msgid "Like/unlike a tweet" -msgstr "Označi tvit sa ne sviđa mi se" +msgstr "Označi da ti se tvit sviđa / ne sviđa" #: ../src\keystrokeEditor\constants.py:16 msgid "Unlike a tweet" @@ -1594,9 +1579,8 @@ msgid "Open URL" msgstr "Otvori vezu" #: ../src\keystrokeEditor\constants.py:25 -#, fuzzy msgid "View in Twitter" -msgstr "Pretraži ttwitter" +msgstr "Prikaži na Twitteru" #: ../src\keystrokeEditor\constants.py:26 msgid "Increase volume by 5%" @@ -1715,9 +1699,8 @@ msgid "Opens the global settings dialogue" msgstr "Otvara dijalog globalnih podešavanja" #: ../src\keystrokeEditor\constants.py:54 -#, fuzzy msgid "Opens the list manager" -msgstr "Upravljanje listama" +msgstr "Otvara upravljanje listama" #: ../src\keystrokeEditor\constants.py:55 msgid "Opens the account settings dialogue" @@ -1821,6 +1804,10 @@ msgid "" "If you're sure that {0} isn't running, try deleting the file at {1}. If " "you're unsure of how to do this, contact the {0} developers." msgstr "" +"{0} je već pokrenut. Zatvorite druge pokrenute prozore aplikacije pre " +"pokretanja ovog. Ako ste sigurni da {0} nije pokrenut, pokušajte da obrišete " +"datoteku koja se nalazi na {1}. Ako niste sigurni kako ovo da uradite, " +"kontaktirajte {0} programere." #: ../src\sessionmanager\wxUI.py:8 msgid "Session manager" @@ -1926,9 +1913,8 @@ msgid "public" msgstr "Javno" #: ../src\sessions\twitter\session.py:169 -#, fuzzy msgid "There are no more items to retrieve in this buffer." -msgstr "Nema koordinata u ovom tvitu." +msgstr "Nema više stavki koje se mogu preuzeti u ovom kanalu." #: ../src\sessions\twitter\session.py:215 msgid "%s failed. Reason: %s" @@ -1951,13 +1937,12 @@ msgid "Error code {0}" msgstr "Kod greške {0}" #: ../src\sessions\twitter\wxUI.py:6 -#, fuzzy msgid "Authorising account..." -msgstr "Autorizovan nalog %d" +msgstr "Autorizacija naloga..." #: ../src\sessions\twitter\wxUI.py:9 msgid "Enter your PIN code here" -msgstr "" +msgstr "Ovde upišite vaš PIN kod" #: ../src\sound.py:159 msgid "Stopped." @@ -2266,19 +2251,20 @@ msgstr "" "suspendovan sa tvitera." #: ../src\wxUI\commonMessageDialogs.py:85 -#, fuzzy msgid "Do you really want to delete this filter?" -msgstr "Želite li zaista da izbrišete ovu listu?" +msgstr "Da li zaista želite da izbrišete ovaj filter?" #: ../src\wxUI\commonMessageDialogs.py:88 msgid "This filter already exists. Please use a different title" -msgstr "" +msgstr "Ovaj filter već postoji. Molimo koristite drugi naziv" #: ../src\wxUI\commonMessageDialogs.py:94 msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." msgstr "" +"{0} je neočekivano zatvoren pri poslednjem pokretanju. Ako se problem " +"nastavi, molimo prijavite ga{0} programerima." #: ../src\wxUI\dialogs\attach.py:9 msgid "Add an attachment" @@ -2343,11 +2329,11 @@ msgstr "Pitaj pre zatvaranja {0}" #: ../src\wxUI\dialogs\configuration.py:27 msgid "Disable Streaming functions" -msgstr "" +msgstr "Onemogući streaming funkcije" #: ../src\wxUI\dialogs\configuration.py:30 msgid "Buffer update interval, in minutes" -msgstr "" +msgstr "Interval ažuriranja kanala, u minutima" #: ../src\wxUI\dialogs\configuration.py:36 msgid "Play a sound when {0} launches" @@ -2378,7 +2364,7 @@ msgstr "" #: ../src\wxUI\dialogs\configuration.py:48 msgid "Remember state for mention all and long tweet" -msgstr "" +msgstr "Pamti stanje opcija spomeni sve i dug tvit" #: ../src\wxUI\dialogs\configuration.py:51 msgid "Keymap" @@ -2446,11 +2432,11 @@ msgstr "" #: ../src\wxUI\dialogs\configuration.py:134 msgid "Enable automatic speech feedback" -msgstr "" +msgstr "Omogući automatske govorne povratne informacije" #: ../src\wxUI\dialogs\configuration.py:136 msgid "Enable automatic Braille feedback" -msgstr "" +msgstr "Omogući automatske povratne informacije na brajevom redu" #: ../src\wxUI\dialogs\configuration.py:144 msgid "Status" @@ -2564,7 +2550,7 @@ msgstr "Proksi" #: ../src\wxUI\dialogs\configuration.py:373 msgid "Feedback" -msgstr "" +msgstr "Povratne informacije" #: ../src\wxUI\dialogs\configuration.py:377 msgid "Buffers" @@ -2583,81 +2569,74 @@ msgid "Save" msgstr "Sačuvaj" #: ../src\wxUI\dialogs\filterDialogs.py:15 -#, fuzzy msgid "Create a filter for this buffer" -msgstr "Stvori kanal trenutnih tema u trendu" +msgstr "Napravi filter za ovaj kanal" #: ../src\wxUI\dialogs\filterDialogs.py:16 msgid "Filter title" -msgstr "" +msgstr "Naziv filtera" #: ../src\wxUI\dialogs\filterDialogs.py:25 #: ../src\wxUI\dialogs\filterDialogs.py:125 msgid "Filter by word" -msgstr "" +msgstr "Filtriraj na osnovu reči" #: ../src\wxUI\dialogs\filterDialogs.py:26 msgid "Ignore tweets wich contain the following word" -msgstr "" +msgstr "Zanemari tvitove koji sadrže sledeću reč" #: ../src\wxUI\dialogs\filterDialogs.py:27 -#, fuzzy msgid "Ignore tweets without the following word" -msgstr "Zanemari tvitove iz ovog klijenta" +msgstr "Zanemari tvitove bez sledeće reči" #: ../src\wxUI\dialogs\filterDialogs.py:32 msgid "word" -msgstr "" +msgstr "Reč" #: ../src\wxUI\dialogs\filterDialogs.py:37 -#, fuzzy msgid "Allow retweets" -msgstr "Prikaži tvit" +msgstr "Dozvoli retvitove" #: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow quoted tweets" -msgstr "" +msgstr "Dozvoli citirane tvitove" #: ../src\wxUI\dialogs\filterDialogs.py:39 -#, fuzzy msgid "Allow replies" -msgstr "Vremenska linija pratilaca" +msgstr "Dozvoli odgovore" #: ../src\wxUI\dialogs\filterDialogs.py:47 msgid "Use this term as a regular expression" -msgstr "" +msgstr "Koristi ovaj termin kao regulara nizraz" #: ../src\wxUI\dialogs\filterDialogs.py:49 #: ../src\wxUI\dialogs\filterDialogs.py:125 -#, fuzzy msgid "Filter by language" -msgstr "Izvorni jezik" +msgstr "Filtriraj na osnovu jezika" #: ../src\wxUI\dialogs\filterDialogs.py:50 msgid "Load tweets in the following languages" -msgstr "" +msgstr "Učitaj tvitove na sledećim jezicima" #: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Ignore tweets in the following languages" -msgstr "" +msgstr "Zanemari tvitove na sledećim jezicima" #: ../src\wxUI\dialogs\filterDialogs.py:52 msgid "Don't filter by language" -msgstr "" +msgstr "Ne filtriraj na osnovu jezika" #: ../src\wxUI\dialogs\filterDialogs.py:63 -#, fuzzy msgid "Supported languages" -msgstr "Izvorni jezik" +msgstr "Podržani jezici" #: ../src\wxUI\dialogs\filterDialogs.py:68 msgid "Add selected language to filter" -msgstr "" +msgstr "Dodaj izabrani jezik u filter" #: ../src\wxUI\dialogs\filterDialogs.py:72 -#, fuzzy msgid "Selected languages" -msgstr "Izvorni jezik" +msgstr "Izabrani jezici" #: ../src\wxUI\dialogs\filterDialogs.py:74 #: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 @@ -2666,17 +2645,16 @@ msgid "Remove" msgstr "Ukloni" #: ../src\wxUI\dialogs\filterDialogs.py:122 -#, fuzzy msgid "Manage filters" -msgstr "Upravljaj nalozima" +msgstr "Upravljanje filterima" #: ../src\wxUI\dialogs\filterDialogs.py:124 msgid "Filters" -msgstr "" +msgstr "Filteri" #: ../src\wxUI\dialogs\filterDialogs.py:125 msgid "Filter" -msgstr "" +msgstr "Filter" #: ../src\wxUI\dialogs\find.py:12 msgid "Find in current buffer" @@ -2844,9 +2822,8 @@ msgid "Source: " msgstr "Izvor:" #: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -#, fuzzy msgid "Date: " -msgstr "Datum" +msgstr "Datum:" #: ../src\wxUI\dialogs\message.py:405 msgid "View" @@ -2942,9 +2919,8 @@ msgid "Update your profile" msgstr "Ažurirajte vaš profil" #: ../src\wxUI\dialogs\update_profile.py:11 -#, fuzzy msgid "&Name (50 characters maximum)" -msgstr "Ime, najviše 20 znakova" +msgstr "&Ime(najviše 50 znakova)" #: ../src\wxUI\dialogs\update_profile.py:22 msgid "&Website" @@ -3060,9 +3036,8 @@ msgid "&Open URL" msgstr "otvori vezu" #: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -#, fuzzy msgid "&Open in Twitter" -msgstr "Pretraži ttwitter" +msgstr "&Otvori na Twitteru" #: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 msgid "&Play audio" @@ -3215,14 +3190,12 @@ msgid "New &trending topics buffer..." msgstr "Novi kanal sa temama u trendu" #: ../src\wxUI\view.py:54 -#, fuzzy msgid "Create a &filter" -msgstr "Stvori novu listu" +msgstr "Napravi &filter" #: ../src\wxUI\view.py:55 -#, fuzzy msgid "&Manage filters" -msgstr "Upravljaj nalozima" +msgstr "&Upravljanje filterima" #: ../src\wxUI\view.py:56 msgid "Find a string in the currently focused buffer..." @@ -3274,7 +3247,7 @@ msgstr "{0} &website" #: ../src\wxUI\view.py:77 msgid "Get soundpacks for TWBlue" -msgstr "" +msgstr "Nabavi zvučne pakete za TW Blue" #: ../src\wxUI\view.py:78 msgid "About &{0}" From ab1a13f8869eb4960f591c6a2245c4c0646d717d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 13:11:33 -0500 Subject: [PATCH 039/245] Improve save_users() and get_user() as those will be used in more places later --- src/sessions/twitter/session.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index f29401db..7135078d 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -104,8 +104,6 @@ class Session(base.baseSession): else: objects.insert(0, i) incoming = incoming+1 pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) - self.db["direct_messages"] = objects - self.db["sent_direct_messages"] = sent_objects return incoming def __init__(self, *args, **kwargs): @@ -387,7 +385,7 @@ class Session(base.baseSession): """ Returns an user object associated with an ID. id str: User identifier, provided by Twitter. returns a tweepy user object.""" - if ("users" in self.db) == False or (id in self.db["users"]) == False: + if ("users" in self.db) == False or (str(id) in self.db["users"]) == False: try: user = self.twitter.get_user(id=id) except TweepError as err: @@ -395,9 +393,9 @@ class Session(base.baseSession): user.screen_name = "deleted_user" user.id = id user.name = _("Deleted account") - user.id_str = id + return user users = self.db["users"] - users[user.id_str] = user + users[user.id] = user self.db["users"] = users return user else: @@ -410,18 +408,18 @@ class Session(base.baseSession): if ("users" in self.db) == False: user = utils.if_user_exists(self.twitter, screen_name) users = self.db["users"] - users[user["id_str"]] = user + users[user["id"]] = user self.db["users"] = users - return user["id_str"] + return user["id"] else: for i in list(self.db["users"].keys()): if self.db["users"][i].screen_name == screen_name: - return self.db["users"][i].id_str + return self.db["users"][i].id user = utils.if_user_exists(self.twitter, screen_name) users = self.db["users"] - users[user.id_str] = user + users[user.id] = user self.db["users"] = users - return user.id_str + return user.id def save_users(self, user_ids): """ Adds all new users to the users database. """ From 4ad01d783308b34acfd9a1228f8e8e657fb3ccbf Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 13:13:00 -0500 Subject: [PATCH 040/245] Retrieve user objects from the users list stored in SqlDict as opposed to loading it from tweet objects --- src/controller/buffers/twitterBuffers.py | 15 ++++++++------- src/controller/mainController.py | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 25081b72..6141319d 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -413,7 +413,8 @@ class baseBufferController(baseBuffers.buffer): @_tweets_exist def reply(self, *args, **kwargs): tweet = self.get_right_tweet() - screen_name = tweet.user.screen_name + user = self.session.get_user(tweet.user) + screen_name = user.screen_name id = tweet.id twishort_enabled = hasattr(tweet, "twishort") users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name") @@ -466,8 +467,8 @@ class baseBufferController(baseBuffers.buffer): screen_name = tweet.screen_name users = [screen_name] else: - screen_name = tweet.user.screen_name - users = utils.get_all_users(tweet, self.session.db) + screen_name = self.session.get_user(tweet.user).screen_name + users = utils.get_all_users(tweet, self.session) dm = messages.dm(self.session, _(u"Direct message to %s") % (screen_name,), _(u"New direct message"), users) if dm.message.get_response() == widgetUtils.OK: screen_name = dm.message.get("cb") @@ -508,12 +509,12 @@ class baseBufferController(baseBuffers.buffer): comments = tweet.full_text else: comments = tweet.text - retweet = messages.tweet(self.session, _(u"Quote"), _(u"Add your comment to the tweet"), u"“@%s: %s ”" % (tweet.user.screen_name, comments), max=256, messageType="retweet") + retweet = messages.tweet(self.session, _(u"Quote"), _(u"Add your comment to the tweet"), u"“@%s: %s ”" % (self.session.get_user(tweet.user).screen_name, comments), max=256, messageType="retweet") if comment != '': retweet.message.set_text(comment) if retweet.message.get_response() == widgetUtils.OK: text = retweet.message.get_text() - text = text+" https://twitter.com/{0}/status/{1}".format(tweet.user.screen_name, id) + text = text+" https://twitter.com/{0}/status/{1}".format(self.session.get_user(tweet.user).screen_name, id) if retweet.image == None: item = self.session.api_call(call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id, tweet_mode="extended") if item != None: @@ -616,7 +617,7 @@ class baseBufferController(baseBuffers.buffer): elif self.type == "people": users = [tweet.screen_name] else: - users = utils.get_all_users(tweet, self.session.db) + users = utils.get_all_users(tweet, self.session) dlg = dialogs.utils.selectUserDialog(title=_(u"User details"), users=users) if dlg.get_response() == widgetUtils.OK: user.profileController(session=self.session, user=dlg.get_user()) @@ -634,7 +635,7 @@ class baseBufferController(baseBuffers.buffer): def open_in_browser(self, *args, **kwargs): tweet = self.get_tweet() output.speak(_(u"Opening item in web browser...")) - url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=tweet.user.screen_name, tweet_id=tweet.id) + url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=self.session.get_user(tweet.user).screen_name, tweet_id=tweet.id) webbrowser.open(url) class directMessagesController(baseBufferController): diff --git a/src/controller/mainController.py b/src/controller/mainController.py index f37f7677..da92d8eb 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -530,7 +530,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) if dlg.get_response() == widgetUtils.OK: user = dlg.get_user() @@ -547,7 +547,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) if dlg.get_response() == widgetUtils.OK: user = dlg.get_user() @@ -575,7 +575,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) dlg = dialogs.utils.selectUserDialog(_(u"Select the user"), users) if dlg.get_response() == widgetUtils.OK: user = dlg.get_user() @@ -669,7 +669,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users) def unfollow(self, *args, **kwargs): @@ -681,7 +681,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "unfollow") def mute(self, *args, **kwargs): @@ -693,7 +693,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "mute") def unmute(self, *args, **kwargs): @@ -705,7 +705,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "unmute") def block(self, *args, **kwargs): @@ -717,7 +717,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "block") def unblock(self, *args, **kwargs): @@ -729,7 +729,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "unblock") def report(self, *args, **kwargs): @@ -741,7 +741,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "report") def post_tweet(self, event=None): @@ -828,7 +828,7 @@ class Controller(object): elif buff.type == "dm": users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: - users = utils.get_all_users(tweet, buff.session.db) + users = utils.get_all_users(tweet, buff.session) dlg = dialogs.userSelection.selectUserDialog(users=users, default=default) if dlg.get_response() == widgetUtils.OK: usr = utils.if_user_exists(buff.session.twitter, dlg.get_user()) @@ -924,7 +924,7 @@ class Controller(object): def open_conversation(self, *args, **kwargs): buffer = self.get_current_buffer() id = buffer.get_right_tweet().id_str - user = buffer.get_right_tweet().user.screen_name + user = buff.session.get_user(buffer.get_right_tweet().user).screen_name search = twitterBuffers.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) search.tweet = buffer.get_right_tweet() search.start_stream(start=True) From 49505fabcd0dacd8a292cea650ab6930d6202241 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 13:14:01 -0500 Subject: [PATCH 041/245] Modify utils so those will take into account that entities might be not present in tweet objects --- src/sessions/twitter/utils.py | 44 +++++++++++++++-------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 2e44f21b..95f36ea4 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -27,22 +27,16 @@ def find_urls (tweet): if hasattr(tweet, "message_create"): entities = tweet.message_create["message_data"]["entities"] else: - entities = tweet.entities - for i in entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) + if hasattr(tweet, "entities") == True: + entities = tweet.entities + if entities.get("urls") != None: + for i in entities["urls"]: + if i["expanded_url"] not in urls: + urls.append(i["expanded_url"]) if hasattr(tweet, "quoted_status"): - for i in tweet.quoted_status.entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) + urls.extend(find_urls(tweet.quoted_status)) if hasattr(tweet, "retweeted_status"): - for i in tweet.retweeted_status.entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) - if hasattr(tweet["retweeted_status"], "quoted_status"): - for i in tweet.retweeted_status.quoted_status.entities["urls"]: - if i["expanded_url"] not in urls: - urls.append(i["expanded_url"]) + urls.extend(find_urls(tweet.retweeted_status)) if hasattr(tweet, "message"): i = "message" elif hasattr(tweet, "full_text"): @@ -109,22 +103,22 @@ def get_all_mentioned(tweet, conf, field="screen_name"): results.append(i.get(field)) return results -def get_all_users(tweet, conf): +def get_all_users(tweet, session): string = [] + user = session.get_user(tweet.user) if hasattr(tweet, "retweeted_status"): - string.append(tweet.user.screen_name) + string.append(user.screen_name) tweet = tweet.retweeted_status - if hasattr(tweet, "sender"): - string.append(tweet.sender.screen_name) else: - if tweet.user.screen_name != conf["user_name"]: - string.append(tweet.user.screen_name) - for i in tweet.entities["user_mentions"]: - if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: - if i["screen_name"] not in string: - string.append(i["screen_name"]) + if user.screen_name != session.db["user_name"]: + string.append(user.screen_name) + if tweet.get("entities") != None and tweet["entities"].get("user_mentions") != None: + for i in tweet.entities["user_mentions"]: + if i["screen_name"] != session.db["user_name"] and i["screen_name"] != user.screen_name: + if i["screen_name"] not in string: + string.append(i["screen_name"]) if len(string) == 0: - string.append(tweet.user.screen_name) + string.append(user.screen_name) return string def if_user_exists(twitter, user): From c7612305665ca609eb284a83bc7b4b0fdb89a283 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 16:25:51 -0500 Subject: [PATCH 042/245] Reduce the size of all tweets so it might make easier to handle those in a realtime database --- src/controller/buffers/twitterBuffers.py | 2 +- src/controller/mainController.py | 4 +- src/sessions/twitter/compose.py | 34 ++++++----- src/sessions/twitter/reduce.py | 32 ++++++++++ src/sessions/twitter/session.py | 77 ++++++++++++++++-------- src/sessions/twitter/utils.py | 11 +++- 6 files changed, 114 insertions(+), 46 deletions(-) create mode 100644 src/sessions/twitter/reduce.py diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 6141319d..d44d0b1d 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -418,7 +418,7 @@ class baseBufferController(baseBuffers.buffer): id = tweet.id twishort_enabled = hasattr(tweet, "twishort") users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name") - ids = utils.get_all_mentioned(tweet, self.session.db, field="id_str") + ids = utils.get_all_mentioned(tweet, self.session.db, field="id") # Build the window title if len(users) < 1: title=_("Reply to {arg0}").format(arg0=screen_name) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index da92d8eb..0329a316 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -923,8 +923,8 @@ class Controller(object): def open_conversation(self, *args, **kwargs): buffer = self.get_current_buffer() - id = buffer.get_right_tweet().id_str - user = buff.session.get_user(buffer.get_right_tweet().user).screen_name + id = buffer.get_right_tweet().id + user = buffer.session.get_user(buffer.get_right_tweet().user).screen_name search = twitterBuffers.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) search.tweet = buffer.get_right_tweet() search.start_stream(start=True) diff --git a/src/sessions/twitter/compose.py b/src/sessions/twitter/compose.py index e76a7034..b6ceb4ae 100644 --- a/src/sessions/twitter/compose.py +++ b/src/sessions/twitter/compose.py @@ -49,23 +49,24 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No else: text = StripChars(getattr(tweet, value)) if show_screen_names: - user = tweet.user.screen_name + user = session.get_user(tweet.user).screen_name else: - user = tweet.user.name + user = session.get_user(tweet.user).name source = re.sub(r"(?s)<.*?>", "", tweet.source) if hasattr(tweet, "retweeted_status"): - if (hasattr(tweet, "message")) == False and tweet.retweeted_status.is_quote_status == False: - text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) - elif tweet.retweeted_status.is_quote_status: + if hasattr(tweet, "message") == False and hasattr(tweet.retweeted_status, "is_quote_status") == False: + text = "RT @%s: %s" % (session.get_user(tweet.retweeted_status.user).screen_name, text) + elif hasattr(tweet.retweeted_status, "is_quote_status"): text = "%s" % (text) else: - text = "RT @%s: %s" % (tweet.retweeted_status.user.screen_name, text) + text = "RT @%s: %s" % (session.get_user(tweet.retweeted_status.user).screen_name, text) if not hasattr(tweet, "message"): - if hasattr(tweet, "retweeted_status"): - text = utils.expand_urls(text, tweet.retweeted_status.entities) + if hasattr(tweet.retweeted_status, "entities"): + text = utils.expand_urls(text, tweet.retweeted_status.entities) else: - text = utils.expand_urls(text, tweet.entities) + if hasattr(tweet, "entities"): + text = utils.expand_urls(text, tweet.entities) if config.app['app-settings']['handle_longtweets']: pass return [user+", ", text, ts+", ", source] @@ -112,14 +113,14 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, value = "text" text = StripChars(getattr(quoted_tweet, value)) if show_screen_names: - quoting_user = quoted_tweet.user.screen_name + quoting_user = session.get_user(quoted_tweet.user).screen_name else: - quoting_user = quoted_tweet.user.name + quoting_user = session.get_user(quoted_tweet.user).name source = quoted_tweet.source if hasattr(quoted_tweet, "retweeted_status"): - text = "rt @%s: %s" % (quoted_tweet.retweeted_status.user.screen_name, text) + text = "rt @%s: %s" % (session.get_user(quoted_tweet.retweeted_status.user).screen_name, text) if text[-1] in chars: text=text+"." - original_user = original_tweet.user.screen_name + original_user = session.get_user(original_tweet.user).screen_name if hasattr(original_tweet, "message"): original_text = original_tweet.message elif hasattr(original_tweet, "full_text"): @@ -128,7 +129,12 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, original_text = StripChars(original_tweet.text) quoted_tweet.message = _(u"{0}. Quoted tweet from @{1}: {2}").format( text, original_user, original_text) quoted_tweet = tweets.clear_url(quoted_tweet) - quoted_tweet.entities["urls"].extend(original_tweet.entities["urls"]) + if hasattr(original_tweet, "entities") and original_tweet.entities.get("urls"): + if hasattr(quoted_tweet, "entities") == False: + quoted_tweet.entities = {} + if quoted_tweet.entities.get("urls") == None: + quoted_tweet.entities["urls"] = [] + quoted_tweet.entities["urls"].extend(original_tweet.entities["urls"]) return quoted_tweet def compose_followers_list(tweet, db, relative_times=True, show_screen_names=False, session=None): diff --git a/src/sessions/twitter/reduce.py b/src/sessions/twitter/reduce.py new file mode 100644 index 00000000..6ce28985 --- /dev/null +++ b/src/sessions/twitter/reduce.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +""" Strips unneeded tweet information in order to store tweet objects by using less memory. """ +from tweepy.models import Status + +def reduce_tweet(tweet): + allowed_values = ["created_at", "id", "full_text", "text", "message", "in_reply_to_status_id", "in_reply_to_user_id", "is_quote_status", "lang", "source", "coordinates", "quoted_status_id", ] + allowed_entities = ["hashtags", "media", "urls", "user_mentions", "polls"] + status_dict = {} + for key in allowed_values: + if tweet._json.get(key): + status_dict[key] = tweet._json[key] + entities = dict() + for key in allowed_entities: + if tweet._json["entities"].get(key) and tweet._json["entities"].get(key) != None: + entities[key] = tweet._json["entities"][key] + status_dict["entities"] = entities + # Quotes and retweets are different objects. + status = Status().parse(api=tweet._api, json=status_dict) + if tweet._json.get("quoted_status"): + quoted_tweet = reduce_tweet(tweet.quoted_status) +# print(quoted_tweet) + status.quoted_status = quoted_tweet + if tweet._json.get("retweeted_status"): + retweeted_tweet = reduce_tweet(tweet.retweeted_status) + status.retweeted_status = retweeted_tweet + # Adds user ID to here so we can reference it later. + # Sometimes, the conversations buffer would send an already reduced tweet here so we will need to return it as is. + if isinstance(tweet.user, str) == False: + status.user = tweet.user.id_str + else: + return tweet + return status \ No newline at end of file diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 7135078d..6dc9858a 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -17,6 +17,7 @@ from keys import keyring from sessions import base from sessions.twitter import utils, compose from sessions.twitter.long_tweets import tweets, twishort +from . import reduce from .wxUI import authorisationDialog log = logging.getLogger("sessions.twitterSession") @@ -44,21 +45,20 @@ class Session(base.baseSession): last_id = self.db[name][0].id else: last_id = self.db[name][-1].id + self.add_users_from_results(data) for i in data: if ignore_older and last_id != None: if i.id < last_id: log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id)) continue if utils.find_item(i.id, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True: - i = self.check_quoted_status(i) - i = self.check_long_tweet(i) if i == False: continue - if self.settings["general"]["reverse_timelines"] == False: objects.append(i) - else: objects.insert(0, i) + reduced_object = reduce.reduce_tweet(i) + reduced_object = self.check_quoted_status(reduced_object) + reduced_object = self.check_long_tweet(reduced_object) + if self.settings["general"]["reverse_timelines"] == False: objects.append(reduced_object) + else: objects.insert(0, reduced_object) num = num+1 - if hasattr(i, "user"): - if (i.user.id in self.db["users"]) == False: - self.db["users"][i.user.id] = i.user self.db[name] = objects return num @@ -338,10 +338,11 @@ class Session(base.baseSession): value = "full_text" else: value = "text" - setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities)) - if quoted_tweet.is_quote_status == True and hasattr(quoted_tweet, "quoted_status"): + if hasattr(quoted_tweet, "entities"): + setattr(quoted_tweet, value, utils.expand_urls(getattr(quoted_tweet, value), quoted_tweet.entities)) + if hasattr(quoted_tweet, "is_quote_status") == True and hasattr(quoted_tweet, "quoted_status"): original_tweet = quoted_tweet.quoted_status - elif hasattr(quoted_tweet, "retweeted_status") and quoted_tweet.retweeted_status.is_quote_status == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"): + elif hasattr(quoted_tweet, "retweeted_status") and hasattr(quoted_tweet.retweeted_status, "is_quote_status") == True and hasattr(quoted_tweet.retweeted_status, "quoted_status"): original_tweet = quoted_tweet.retweeted_status.quoted_status else: return quoted_tweet @@ -352,33 +353,40 @@ class Session(base.baseSession): value = "message" else: value = "text" - setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities)) - return compose.compose_quoted_tweet(quoted_tweet, original_tweet) + if hasattr(original_tweet, "entities"): + setattr(original_tweet, value, utils.expand_urls(getattr(original_tweet, value), original_tweet.entities)) + # ToDo: Shall we check whether we should add show_screen_names here? + return compose.compose_quoted_tweet(quoted_tweet, original_tweet, session=self) def check_long_tweet(self, tweet): """ Process a tweet and add extra info if it's a long tweet made with Twyshort. tweet dict: a tweet object. returns a tweet with a new argument message, or original tweet if it's not a long tweet.""" - long = twishort.is_long(tweet) + long = False + if hasattr(tweet, "entities") and tweet.entities.get("urls"): + long = twishort.is_long(tweet) if long != False and config.app["app-settings"]["handle_longtweets"]: message = twishort.get_full_text(long) if hasattr(tweet, "quoted_status"): tweet.quoted_status.message = message if tweet.quoted_status.message == False: return False tweet.quoted_status.twishort = True - for i in tweet.quoted_status.entities["user_mentions"]: - if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != tweet.user.screen_name: - if hasattr(tweet.quoted_status, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: - continue - tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message) + if hasattr(tweet.quoted_status, "entities") and tweet.quoted_status.entities.get("user_mentions"): + for i in tweet.quoted_status.entities["user_mentions"]: + if "@%s" % (i["screen_name"]) not in tweet.quoted_status.message and i["screen_name"] != self.get_user(tweet.user).screen_name: + if hasattr(tweet.quoted_status, "retweeted_status") and self.get_user(tweet.retweeted_status.user).screen_name == i["screen_name"]: + continue + tweet.quoted_status.message = u"@%s %s" % (i["screen_name"], tweet.message) else: tweet.message = message if tweet.message == False: return False tweet.twishort = True - for i in tweet.entities["user_mentions"]: - if "@%s" % (i["screen_name"]) not in tweet.message and i["screen_name"] != tweet.user.screen_name: - if hasattr(tweet, "retweeted_status") and tweet.retweeted_status.user.screen_name == i["screen_name"]: - continue + if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): + for i in tweet.entities["user_mentions"]: + if "@%s" % (i["screen_name"]) not in tweet.message and i["screen_name"] != self.get_user(tweet.user).screen_name: + if hasattr(tweet, "retweeted_status") and self.get_user(tweet.retweeted_status.user).screen_name == i["screen_name"]: + continue + tweet.message = u"@%s %s" % (i["screen_name"], tweet.message) return tweet def get_user(self, id): @@ -386,20 +394,21 @@ class Session(base.baseSession): id str: User identifier, provided by Twitter. returns a tweepy user object.""" if ("users" in self.db) == False or (str(id) in self.db["users"]) == False: + log.debug("Requesting user id {} as it is not present in the users database.".format(id)) try: user = self.twitter.get_user(id=id) - except TweepError as err: + except ValueError as err: user = UserModel(None) user.screen_name = "deleted_user" user.id = id user.name = _("Deleted account") return user users = self.db["users"] - users[user.id] = user + users[user.id_str] = user self.db["users"] = users return user else: - return self.db["users"][id] + return self.db["users"][str(id)] def get_user_by_screen_name(self, screen_name): """ Returns an user identifier associated with a screen_name. @@ -437,4 +446,20 @@ class Session(base.baseSession): for user in users: users_db[user.id_str] = user log.debug("Added %d new users" % (len(users))) - self.db["users"] = users_db \ No newline at end of file + self.db["users"] = users_db + + def add_users_from_results(self, data): + users = self.db["users"] + for i in data: + if hasattr(i, "user"): + if isinstance(i.user, str): + log.warning("A String was passed to be added as an user. This is normal only if TWBlue tried to load a conversation.") + continue + if (i.user.id_str in self.db["users"]) == False: + users[i.user.id_str] = i.user + if hasattr(i, "quoted_status") and (i.quoted_status.user.id_str in self.db["users"]) == False: + users[i.quoted_status.user.id_str] = i.quoted_status.user + + if hasattr(i, "retweeted_status") and (i.retweeted_status.user.id_str in self.db["users"]) == False: + users[i.retweeted_status.user.id_str] = i.retweeted_status.user + self.db["users"] = users diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 95f36ea4..f74eea5c 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -69,13 +69,14 @@ def is_audio(tweet): if hasattr(tweet, "message_create"): entities = tweet.message_create["message_data"]["entities"] else: + if hasattr(tweet, "entities") == False or tweet.entities.get("hashtags") == None: + return False entities = tweet.entities if len(entities["hashtags"]) > 0: for i in entities["hashtags"]: if i["text"] == "audio": return True except IndexError: - print(tweet.entities["hashtags"]) log.exception("Exception while executing is_audio hashtag algorithm") def is_geocoded(tweet): @@ -86,6 +87,8 @@ def is_media(tweet): if hasattr(tweet, "message_create"): entities = tweet.message_create["message_data"]["entities"] else: + if hasattr(tweet, "entities") == False or tweet.entities.get("hashtags") == None: + return False entities = tweet.entities if entities.get("media") == None: return False @@ -112,7 +115,7 @@ def get_all_users(tweet, session): else: if user.screen_name != session.db["user_name"]: string.append(user.screen_name) - if tweet.get("entities") != None and tweet["entities"].get("user_mentions") != None: + if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): for i in tweet.entities["user_mentions"]: if i["screen_name"] != session.db["user_name"] and i["screen_name"] != user.screen_name: if i["screen_name"] not in string: @@ -138,7 +141,7 @@ def is_allowed(tweet, settings, buffer_name): tweet_data = {} if hasattr(tweet, "retweeted_status"): tweet_data["retweet"] = True - if tweet.in_reply_to_status_id_str != None: + if tweet.in_reply_to_status_id != None: tweet_data["reply"] = True if hasattr(tweet, "quoted_status"): tweet_data["quote"] = True @@ -203,6 +206,8 @@ def twitter_error(error): def expand_urls(text, entities): """ Expand all URLS present in text with information found in entities""" + if entities.get("urls") == None: + return text urls = find_urls_in_text(text) for url in entities["urls"]: if url["url"] in text: From 77bee64421ffa7c2e9db8cf80493a2e4d706fd92 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 16:48:44 -0500 Subject: [PATCH 043/245] Pass a null value to tweepy.models.Status as sometimes database saved objects might not include it --- src/sessions/twitter/reduce.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/reduce.py b/src/sessions/twitter/reduce.py index 6ce28985..5af9b450 100644 --- a/src/sessions/twitter/reduce.py +++ b/src/sessions/twitter/reduce.py @@ -15,7 +15,11 @@ def reduce_tweet(tweet): entities[key] = tweet._json["entities"][key] status_dict["entities"] = entities # Quotes and retweets are different objects. - status = Status().parse(api=tweet._api, json=status_dict) + if hasattr(tweet, "_api"): + api = tweet._api + else: + api = None + status = Status().parse(api=api, json=status_dict) if tweet._json.get("quoted_status"): quoted_tweet = reduce_tweet(tweet.quoted_status) # print(quoted_tweet) From 74e4fe635792ba33a20d1c41bab6ac426cbf6ca1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 16:49:23 -0500 Subject: [PATCH 044/245] Ensure direct message buffers are correctly saved in database --- src/sessions/twitter/session.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 6dc9858a..4e3278cf 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -103,7 +103,12 @@ class Session(base.baseSession): if self.settings["general"]["reverse_timelines"] == False: objects.append(i) else: objects.insert(0, i) incoming = incoming+1 + self.db["direct_messages"] = objects + + self.db["sent_direct_messages"] = sent_objects pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) + + return incoming def __init__(self, *args, **kwargs): From b8f822830fab8f7a553a8adde211060aadb829ec Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 22:47:10 -0500 Subject: [PATCH 045/245] Added proper docstrings to reduce twitter objects --- src/sessions/twitter/reduce.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sessions/twitter/reduce.py b/src/sessions/twitter/reduce.py index 5af9b450..eae64a70 100644 --- a/src/sessions/twitter/reduce.py +++ b/src/sessions/twitter/reduce.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- -""" Strips unneeded tweet information in order to store tweet objects by using less memory. """ +""" Strips unneeded tweet information in order to store tweet objects by using less memory. This is especially useful when buffers start to contain more than a certain amount of items. """ from tweepy.models import Status def reduce_tweet(tweet): + """ generates a new Tweet model with the fields we currently need, excluding everything else including null values and empty collections. """ allowed_values = ["created_at", "id", "full_text", "text", "message", "in_reply_to_status_id", "in_reply_to_user_id", "is_quote_status", "lang", "source", "coordinates", "quoted_status_id", ] allowed_entities = ["hashtags", "media", "urls", "user_mentions", "polls"] status_dict = {} @@ -14,15 +15,15 @@ def reduce_tweet(tweet): if tweet._json["entities"].get(key) and tweet._json["entities"].get(key) != None: entities[key] = tweet._json["entities"][key] status_dict["entities"] = entities - # Quotes and retweets are different objects. + # If tweet comes from the cached database, it does not include an API, so we can pass None here as we do not use that reference to tweepy's API. if hasattr(tweet, "_api"): api = tweet._api else: api = None status = Status().parse(api=api, json=status_dict) + # Quotes and retweets are different objects. So we parse a new tweet when we have a quoted or retweeted status here. if tweet._json.get("quoted_status"): quoted_tweet = reduce_tweet(tweet.quoted_status) -# print(quoted_tweet) status.quoted_status = quoted_tweet if tweet._json.get("retweeted_status"): retweeted_tweet = reduce_tweet(tweet.retweeted_status) From 71358ea74d6469fba39072677566476adcf2d09d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 25 Jun 2021 23:35:33 -0500 Subject: [PATCH 046/245] changed function names and cleaned code a little bit to reflect better the changes to object percistance --- src/controller/mainController.py | 6 ++-- src/sessions/base.py | 55 +++++++++++++------------------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 0329a316..0dfe9039 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -651,8 +651,8 @@ class Controller(object): if sessions.sessions[item].logged == False: continue log.debug("Disconnecting streams for %s session" % (sessions.sessions[item].session_id,)) sessions.sessions[item].sound.cleaner.cancel() - log.debug("Shelving database for " + sessions.sessions[item].session_id) - sessions.sessions[item].shelve() + log.debug("Saving database for " + sessions.sessions[item].session_id) + sessions.sessions[item].save_persistent_data() if system == "Windows": self.systrayIcon.RemoveIcon() pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) @@ -1625,4 +1625,4 @@ class Controller(object): def save_data_in_db(self): for i in sessions.sessions: - sessions.sessions[i].shelve() + sessions.sessions[i].save_persistent_data() diff --git a/src/sessions/base.py b/src/sessions/base.py index 6f3ecef9..b2dba051 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -60,7 +60,7 @@ class baseSession(object): log.debug("Creating config file %s" % (file_,)) self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "Conf.defaults")) self.init_sound() - self.deshelve() + self.load_persistent_data() def init_sound(self): try: self.sound = sound.soundSystem(self.settings["sound"]) @@ -74,52 +74,41 @@ class baseSession(object): def authorise(self): pass - def shelve(self): - """Shelve the database to allow for persistance.""" - shelfname=os.path.join(paths.config_path(), str(self.session_id), "cache") + def save_persistent_data(self): + """ Save the data to a persistant sqlite backed file. .""" + dbname=os.path.join(paths.config_path(), str(self.session_id), "cache.db") + # persist_size set to 0 means not saving data actually. if self.settings["general"]["persist_size"] == 0: - if os.path.exists(shelfname+".dat"): - os.remove(shelfname+".dat") + if os.path.exists(dbname): + os.remove(dbname) return try: self.db.commit() -# if not os.path.exists(shelfname+".dat"): -# output.speak("Generating database, this might take a while.",True) -# shelf=shelve.open(os.path.join(paths.config_path(), shelfname),'c') -# for key, value in list(self.db.items()): -# if type(key) != str and type(key) != str: -# output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True) -# log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!") -# if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]: -# shelf[key]=value[self.settings["general"]["persist_size"]:] -# else: -# shelf[key]=value -# shelf.close() except: - output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) - log.exception("Exception while shelving" + shelfname) - os.remove(shelfname) + output.speak(_("An exception occurred while saving the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name),True) + log.exception("Exception while saving {}".format(dbname)) + os.remove(dbname) - def deshelve(self): - """Import a shelved database.""" - shelfname=os.path.join(paths.config_path(), str(self.session_id)+"/cache") + def load_persistent_data(self): + """Import data from a database file from user config.""" + dbname=os.path.join(paths.config_path(), str(self.session_id), "cache.db") + # If persist_size is set to 0, we should remove the db file as we are no longer going to save anything. if self.settings["general"]["persist_size"] == 0: - if os.path.exists(shelfname+".dat"): - os.remove(shelfname+".dat") + if os.path.exists(dbname): + os.remove(dbname) + # Let's return from here, as we are not loading anything. return + # try to load the db file. try: - self.db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), shelfname), 'c') + self.db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), dbname), 'c') if self.db.get("cursors") == None: cursors = dict(direct_messages=-1) self.db["cursors"] = cursors -# for key,value in list(shelf.items()): -# self.db[key]=value -# shelf.close() except: - output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True) - log.exception("Exception while deshelving" + shelfname) + output.speak(_("An exception occurred while loading the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name), True) + log.exception("Exception while loading {}".format(dbname)) try: - os.remove(shelfname) + os.remove(dbname) except: pass From e35f37fcc211e1b3774cd1ae8c57c713ccb1945c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 26 Jun 2021 01:49:55 -0500 Subject: [PATCH 047/245] Updated changelog --- doc/changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/changelog.md b/doc/changelog.md index e4369880..66ef6a13 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,11 @@ ## changes in this version +* We just implemented some changes in the way TWBlue handles tweets in order to reduce its RAM memory usage [#380](https://github.com/manuelcortez/TWBlue/pull/380): + * We reduced the tweets size by storing only the tweet fields we currently use. This should reduce tweet's size in memory for every object up to 75%. + * When using the cache database to store your tweets, there is a new setting present in the account settings dialog, in the general tab. This setting allows you to control whether TWBlue will load the whole database into memory (which is the current behaviour) or not. + * Loading the whole database into memory has the advantage of being extremely fast to access any element (for example when moving through tweets in a buffer), but it requires more memory as the tweet buffers grow up. This should, however, use less memory than before thanks to the optimizations performed in tweet objects. If you have a machine with enough memory, this should be a good option for your case. + * If you uncheck this setting, TWBlue will read the whole database from disk. This is significantly slower, but the advantage of this setting is that it will consume almost no extra memory, no matter how big is the tweets dataset. Be ware, though, that TWBlue might start to feel slower when accessing elements (for example when reading tweets) as the buffers grow up. This setting is suggested for computers with low memory or for those people not wanting to keep a really big amount of tweets stored. * Changed the label in the direct message's text control so it will indicate that the user needs to write the text there, without referring to any username in particular. ([#366,](https://github.com/manuelcortez/TWBlue/issues/366)) * TWBlue will take Shift+F10 again as the contextual menu key in the list of items in a buffer. This stopped working after we have migrated to WX 4.1. ([#353,](https://github.com/manuelcortez/TWBlue/issues/353)) * TWBlue should render correctly retweets of quoted tweets. ([#365,](https://github.com/manuelcortez/TWBlue/issues/365)) From 2c75ea50054a3bf153598990cdb01a9b1c0f6dc4 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 26 Jun 2021 01:50:47 -0500 Subject: [PATCH 048/245] Fixed a small issue referencing an user in the old way while retrieving all mentioned users in a tweet --- src/sessions/twitter/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index f74eea5c..a9685212 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -101,7 +101,7 @@ def get_all_mentioned(tweet, conf, field="screen_name"): """ Gets all users that have been mentioned.""" results = [] for i in tweet.entities["user_mentions"]: - if i["screen_name"] != conf["user_name"] and i["screen_name"] != tweet.user.screen_name: + if i["screen_name"] != conf["user_name"] and i["id_str"] != tweet.user: if i.get(field) not in results: results.append(i.get(field)) return results From 5712dd735bf7248fa07cacdd64d14d865ddf4726 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 26 Jun 2021 01:52:07 -0500 Subject: [PATCH 049/245] Added a new setting in account dialog to control whehter we load the cache db into memory or read it from disk --- src/Conf.defaults | 1 + src/controller/settings.py | 2 ++ src/sessions/base.py | 30 +++++++++++++++++++++++------- src/wxUI/dialogs/configuration.py | 4 +--- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Conf.defaults b/src/Conf.defaults index 4396e120..80b28db6 100644 --- a/src/Conf.defaults +++ b/src/Conf.defaults @@ -12,6 +12,7 @@ reverse_timelines = boolean(default=False) announce_stream_status = boolean(default=True) retweet_mode = string(default="ask") persist_size = integer(default=0) +load_cache_in_memory=boolean(default=True) show_screen_names = boolean(default=False) buffer_order = list(default=list('home','mentions', 'dm', 'sent_dm', 'sent_tweets','favorites','followers','friends','blocks','muted','events')) diff --git a/src/controller/settings.py b/src/controller/settings.py index b0c1efd3..b1acceb8 100644 --- a/src/controller/settings.py +++ b/src/controller/settings.py @@ -151,6 +151,7 @@ class accountSettingsController(globalSettingsController): else: self.dialog.set_value("general", "retweet_mode", _(u"Retweet with comments")) self.dialog.set_value("general", "persist_size", str(self.config["general"]["persist_size"])) + self.dialog.set_value("general", "load_cache_in_memory", self.config["general"]["load_cache_in_memory"]) self.dialog.create_reporting() self.dialog.set_value("reporting", "speech_reporting", self.config["reporting"]["speech_reporting"]) self.dialog.set_value("reporting", "braille_reporting", self.config["reporting"]["braille_reporting"]) @@ -193,6 +194,7 @@ class accountSettingsController(globalSettingsController): self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time") self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names") self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall") + self.config["general"]["load_cache_in_memory"] = self.dialog.get_value("general", "load_cache_in_memory") if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"): if self.dialog.get_value("general", "persist_size") == '': self.config["general"]["persist_size"] =-1 diff --git a/src/sessions/base.py b/src/sessions/base.py index b2dba051..816b658b 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -82,12 +82,19 @@ class baseSession(object): if os.path.exists(dbname): os.remove(dbname) return - try: - self.db.commit() - except: - output.speak(_("An exception occurred while saving the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name),True) - log.exception("Exception while saving {}".format(dbname)) - os.remove(dbname) + # Let's check if we need to create a new SqliteDict object or we just need to call to commit in self.db. + if self.settings["general"]["load_cache_in_memory"]: + db=sqlitedict.SqliteDict(dbname, 'c') + for k in self.db.keys(): + db[k] = self.db[k] + db.close() + else: + try: + self.db.commit() + except: + output.speak(_("An exception occurred while saving the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name),True) + log.exception("Exception while saving {}".format(dbname)) + os.remove(dbname) def load_persistent_data(self): """Import data from a database file from user config.""" @@ -100,7 +107,16 @@ class baseSession(object): return # try to load the db file. try: - self.db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), dbname), 'c') + db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), dbname), 'c') + # If load_cache_in_memory is set to true, we will load the whole database into memory for faster access. + # This is going to be faster when retrieving specific objects, at the cost of more memory. + # Setting this to False will read the objects from database as they are needed, which might be slower for bigger datasets. + if self.settings["general"]["load_cache_in_memory"]: + for k in db.keys(): + self.db[k] = db[k] + db.close() + else: + self.db = db if self.db.get("cursors") == None: cursors = dict(direct_messages=-1) self.db["cursors"] = cursors diff --git a/src/wxUI/dialogs/configuration.py b/src/wxUI/dialogs/configuration.py index 147bba1d..1bc5de9c 100644 --- a/src/wxUI/dialogs/configuration.py +++ b/src/wxUI/dialogs/configuration.py @@ -1,7 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -from builtins import range import logging as original_logger import wx import application @@ -127,6 +124,7 @@ class generalAccount(wx.Panel, baseDialog.BaseWXDialog): self.persist_size = wx.TextCtrl(self, -1) sizer.Add(PersistSizeLabel, 0, wx.ALL, 5) sizer.Add(self.persist_size, 0, wx.ALL, 5) + self.load_cache_in_memory = wx.CheckBox(self, wx.NewId(), _("Load cache for tweets in memory (much faster in big datasets but requires more RAM)")) self.SetSizer(sizer) class reporting(wx.Panel, baseDialog.BaseWXDialog): From 35d6010298a48bbc92171a3e192c82a7f351d0fc Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 26 Jun 2021 15:16:50 -0500 Subject: [PATCH 050/245] Save tweets cache by taking into account persist_size --- src/sessions/base.py | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sessions/base.py b/src/sessions/base.py index 816b658b..e4e2999d 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- """ A base class to be derived in possible new sessions for TWBlue and services.""" -from __future__ import absolute_import -from __future__ import unicode_literals -from builtins import str -from builtins import object import os import paths import output @@ -13,11 +9,9 @@ import logging import config_utils import sqlitedict import application -import os from . import session_exceptions as Exceptions log = logging.getLogger("sessionmanager.session") - class baseSession(object): """ toDo: Decorators does not seem to be working when using them in an inherited class.""" @@ -74,22 +68,39 @@ class baseSession(object): def authorise(self): pass + def get_sized_buffer(self, buffer, size, reversed=False): + """ Returns a list with the amount of items specified by size.""" + if isinstance(buffer, list) and size != -1 and len(buffer) > size: + log.debug("Requesting {} items from a list of {} items. Reversed mode: {}".format(size, len(buffer), reversed)) + if reversed == False: + return buffer[size:] + else: + return buffer[:size] + else: + return buffer + def save_persistent_data(self): - """ Save the data to a persistant sqlite backed file. .""" + """ Save the data to a persistent sqlite backed file. .""" dbname=os.path.join(paths.config_path(), str(self.session_id), "cache.db") + log.debug("Saving storage information...") # persist_size set to 0 means not saving data actually. if self.settings["general"]["persist_size"] == 0: if os.path.exists(dbname): os.remove(dbname) return - # Let's check if we need to create a new SqliteDict object or we just need to call to commit in self.db. + # Let's check if we need to create a new SqliteDict object (when loading db in memory) or we just need to call to commit in self (if reading from disk).db. + # If we read from disk, we cannot modify the buffer size here as we could damage the app's integrity. + # We will modify buffer's size (managed by persist_size) upon loading the db into memory in app startup. if self.settings["general"]["load_cache_in_memory"]: + log.debug("Opening database to dump memory contents...") db=sqlitedict.SqliteDict(dbname, 'c') for k in self.db.keys(): - db[k] = self.db[k] + db[k] = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"]) db.close() + log.debug("Data has been saved in the database.") else: try: + log.debug("Syncing new data to disk...") self.db.commit() except: output.speak(_("An exception occurred while saving the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name),True) @@ -98,6 +109,7 @@ class baseSession(object): def load_persistent_data(self): """Import data from a database file from user config.""" + log.debug("Loading storage data...") dbname=os.path.join(paths.config_path(), str(self.session_id), "cache.db") # If persist_size is set to 0, we should remove the db file as we are no longer going to save anything. if self.settings["general"]["persist_size"] == 0: @@ -107,16 +119,24 @@ class baseSession(object): return # try to load the db file. try: + log.debug("Opening database...") db=sqlitedict.SqliteDict(os.path.join(paths.config_path(), dbname), 'c') # If load_cache_in_memory is set to true, we will load the whole database into memory for faster access. # This is going to be faster when retrieving specific objects, at the cost of more memory. # Setting this to False will read the objects from database as they are needed, which might be slower for bigger datasets. if self.settings["general"]["load_cache_in_memory"]: + log.debug("Loading database contents into memory...") for k in db.keys(): self.db[k] = db[k] db.close() + log.debug("Contents were loaded successfully.") else: + log.debug("Instantiating database from disk.") self.db = db + # We must make sure we won't load more than the amount of buffer specified. + log.debug("Checking if we will load all content...") + for k in self.db.keys(): + self.db[k] = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"]) if self.db.get("cursors") == None: cursors = dict(direct_messages=-1) self.db["cursors"] = cursors From c5dadb063a58f082e7a3679a295806e8bca5df8d Mon Sep 17 00:00:00 2001 From: nikola nikola Date: Sun, 27 Jun 2021 04:22:02 +0200 Subject: [PATCH 051/245] Added Serbian documentation and changelog. --- .../sr/lc_messages/twblue-changelog.mo | Bin 0 -> 44869 bytes .../sr/lc_messages/twblue-changelog.po | 1309 ++++++++++++ .../sr/lc_messages/twblue-documentation.mo | Bin 0 -> 71568 bytes .../sr/lc_messages/twblue-documentation.po | 1885 +++++++++++++++++ 4 files changed, 3194 insertions(+) create mode 100644 doc/locales/sr/lc_messages/twblue-changelog.mo create mode 100644 doc/locales/sr/lc_messages/twblue-changelog.po create mode 100644 doc/locales/sr/lc_messages/twblue-documentation.mo create mode 100644 doc/locales/sr/lc_messages/twblue-documentation.po diff --git a/doc/locales/sr/lc_messages/twblue-changelog.mo b/doc/locales/sr/lc_messages/twblue-changelog.mo new file mode 100644 index 0000000000000000000000000000000000000000..005347b963a986980a7acbb10c92b9a6885bbc72 GIT binary patch literal 44869 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 c+w$AC8&-w&-|r@jA+2kxy|DYV3ssi, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" +"PO-Revision-Date: 2021-06-27 04:17+0100\n" +"Last-Translator: Nikola Jović \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 1.6.10\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: sr\n" + +#: ../doc/changelog.py:3 +msgid "TWBlue Changelog" +msgstr "TWBlue lista promena" + +#: ../doc/changelog.py:4 +msgid "## changes in this version" +msgstr "## Promene u ovoj verziji" + +#: ../doc/changelog.py:5 +msgid "" +"* TWBlue can open a Tweet or user directly in Twitter. There is a new option " +"in the context menu for people and tweet buffers, and also, the shortcut " +"control+win+alt+Enter will open the focused item in Twitter." +msgstr "" +"* TWBlue može da otvori tvit ili korisnika direktno na Twitteru. Nova opcija " +"je u kontekstnom meniju za ljude i kanale, i takođe, prečica control+win+alt" +"+Enter otvara fokusiranu stavku na Twitteru." + +#: ../doc/changelog.py:6 +msgid "* Some keystrokes were remapped in the Windows 10 Keymap:" +msgstr "* Neke prečice su promenjene u Windows 10 mapi tasterskih prečica:" + +#: ../doc/changelog.py:7 +msgid "" +" * Read location of a tweet: Ctrl+Win+G. ([#177](https://github.com/" +"manuelcortez/TWBlue/pull/177))" +msgstr "" +" * Čitanje lokacije tvita: Ctrl+Win+G. ([#177](https://github.com/" +"manuelcortez/TWBlue/pull/177))" + +#: ../doc/changelog.py:8 +msgid " * Open global settings dialogue: Ctrl+Win+Alt+O." +msgstr " * Otvaranje dijaloga globalnih podešavanja: Ctrl+Win+Alt+O." + +#: ../doc/changelog.py:9 +msgid " * Mute/unmute current session: Control + Windows + Alt + M." +msgstr "" +" * Utišavanje / uklanjanje utišavanja trenutne sesije: Control + Windows " +"+ Alt + M." + +#: ../doc/changelog.py:10 +msgid "" +"* Fixed an error that was preventing TWBlue to load the direct messages " +"buffer if an user who sent a message has been deleted." +msgstr "" +"* Ispravljena greška koja je sprečavala da TWBlue učita kanal sa direktnim " +"porukama ako je korisnik koji je poslao direktnu poruku obrisan." + +#: ../doc/changelog.py:11 +msgid "" +"* Added support for playing audios posted in [AnyAudio.net](http://anyaudio." +"net) directly from TWBlue. Thanks to [Sam Tupy](http://www.samtupy.com/)" +msgstr "" +"* Dodata podrška za reprodukciju zvučnih zapisa na servisu [AnyAudio.net]" +"(http://anyaudio.net) direktno iz programa TWBlue. Zahvalnost [Sam Tupy]" +"(http://www.samtupy.com/)" + +#: ../doc/changelog.py:12 +msgid "" +"* Custom buffer ordering will not be reset every time the application " +"restarts after an account setting has been modified." +msgstr "" +"* Prilagođen raspored kanala se neće resetovati svaki put kada se aplikacija " +"ponovo pokrene nakon izmenjenog podešavanja naloga." + +#: ../doc/changelog.py:13 +msgid "" +"* When adding or removing an user from a list, it is possible to press enter " +"in the focused list instead of having to search for the \"add\" or \"delete" +"\" button." +msgstr "" +"* Kada dodajete ili uklanjate korisnike iz liste, moguće je da pritisnete " +"enter na fokusiranu listu umesto potrebe da tražite tastere \"dodaj\" ili " +"\"obriši\"." + +#: ../doc/changelog.py:14 +msgid "" +"* Quoted and long tweets are displayed properly in the sent tweets buffer " +"after being send. ([#253](https://github.com/manuelcortez/TWBlue/issues/253))" +msgstr "" +"* Citirani i dugi tvitovi se ispravno prikazuju u kanalima za poslate " +"tvitove nakon što su poslati. ([#253](https://github.com/manuelcortez/TWBlue/" +"issues/253))" + +#: ../doc/changelog.py:15 +msgid "" +"* Fixed an issue that was making the list manager keystroke unable to be " +"shown in the keystroke editor. Now the keystroke is listed properly. ([#260]" +"(https://github.com/manuelcortez/TWBlue/issues/260))" +msgstr "" +"* Ispravljen problem koji je izazvao da se prečica za upravljanje listama ne " +"prikazuje u dijalogu za izmenu tasterskih prečica. Sada se prečica ispravno " +"prikazuje. ([#260](https://github.com/manuelcortez/TWBlue/issues/260))" + +#: ../doc/changelog.py:16 +msgid "" +"* The volume slider, located in the account settings of TWBlue, now should " +"decrease and increase value properly when up and down arrows are pressed. " +"Before it was doing it in inverted order. ([#261](https://github.com/" +"manuelcortez/TWBlue/issues/261))" +msgstr "" +"* Slajder za jačinu, koji se nalazi u podešavanjima naloga za TWBlue, trebao " +"bi da ispravno smanjuje i povećava vrednost kada se koriste strelice gore i " +"dole. Ranije je ovo bilo obrnuto. ([#261](https://github.com/manuelcortez/" +"TWBlue/issues/261))" + +#: ../doc/changelog.py:17 +msgid "" +"* autoreading has been redesigned to work in a similar way for almost all " +"buffers. Needs testing. ([#221](https://github.com/manuelcortez/TWBlue/" +"issues/221))" +msgstr "" +"* Automatsko čitanje je redizajnirano da radi na sličan način za sve kanale. " +"Neophodno je testiranje. ([#221](https://github.com/manuelcortez/TWBlue/" +"issues/221))" + +#: ../doc/changelog.py:18 +msgid "" +"* When displaying tweets or direct messages, a new field has been added to " +"show the date when the item has been posted to Twitter." +msgstr "" +"* Kada se prikazuju tvitovi ili direktne poruke, dodato je novo polje koje " +"će prikazati datum kada je stavka objavljena." + +#: ../doc/changelog.py:19 +msgid "" +"* Added support for deleting direct messages by using the new Twitter API " +"methods." +msgstr "" +"* Dodata podrška za brisanje direktnih poruka korišćenjem novog Twitter API " +"metoda." + +#: ../doc/changelog.py:20 +msgid "" +"* When quoting a retweet, the quote will be made to the original tweet " +"instead of the retweet." +msgstr "" +"* Kada citirate retvit, citiranje će biti izvršeno na izvornom tvitu umesto " +"na retvitu." + +#: ../doc/changelog.py:21 +msgid "" +"* If the sent direct messages buffer is hidden, TWBlue should keep loading " +"everything as expected. ([#246](https://github.com/manuelcortez/TWBlue/" +"issues/246))" +msgstr "" +"* Ako je kanal poslatih direktnih poruka skriven, TWBlue bi trebao da učita " +"sve ostalo kako treba. ([#246](https://github.com/manuelcortez/TWBlue/" +"issues/246))" + +#: ../doc/changelog.py:22 +msgid "" +"* There is a new soundpack, called FreakyBlue (Thanks to [Andre Louis]" +"(https://twitter.com/FreakyFwoof)) as a new option in TWBlue. This pack can " +"be the default in the next stable, so users can take a look and share their " +"opinion in snapshot versions. ([#247](https://github.com/manuelcortez/TWBlue/" +"issues/247))" +msgstr "" +"* Dostupan je novi zvučni paket, koji se zove FreakyBlue (zahvalnost [Andre " +"Louis](https://twitter.com/FreakyFwoof)) kao nova opcija u programu TWBlue. " +"Ovaj paket bi mogao da postane podrazumevani u sledećoj stabilnoj verziji, " +"tako da korisnici mogu da ga probaju i izraze svoje mišljenje u verzijama za " +"testiranje. ([#247](https://github.com/manuelcortez/TWBlue/issues/247))" + +#: ../doc/changelog.py:23 +msgid "" +"* There is a new option in the help menu that allows you to visit the " +"soundpacks section in the TWBlue website. ([#247](https://github.com/" +"manuelcortez/TWBlue/issues/247))" +msgstr "" +"* U meni pomoći je dodata nova opcija koja dozvoljava da posetite deo TWBlue " +"sajta vezan za zvučne pakete. ([#247](https://github.com/manuelcortez/TWBlue/" +"issues/247))" + +#: ../doc/changelog.py:24 +msgid "" +"* When reading location of a geotagged tweet, it will be translated for " +"users of other languages. ([#251](https://github.com/manuelcortez/TWBlue/" +"pull/251))" +msgstr "" +"* Kada čitate lokaciju geografskog tvita, biće preveden za korisnike drugih " +"jezika. ([#251](https://github.com/manuelcortez/TWBlue/pull/251))" + +#: ../doc/changelog.py:25 +msgid "" +"* When there are no more items to retrieve in direct messages and people " +"buffers, a message will announce it." +msgstr "" +"* Kada više nema stavki koje se mogu preuzeti u kanalima sa korisnicima ili " +"sa direktnim porukama, poruka će to označiti." + +#: ../doc/changelog.py:26 +msgid "" +"* Fixed an issue reported by some users that was making them unable to load " +"more items in their direct messages." +msgstr "" +"* Ispravljen problem prijavljen od strane nekih korisnika koji je izazivao " +"nemogućnost preuzimanja dodatnih stavki u kanalu direktnih poruka." + +#: ../doc/changelog.py:27 +msgid "" +"* It is possible to add a tweet to the likes buffer from the menu bar again." +msgstr "* Ponovo je moguće dodati tvit u kanal sviđanja iz trake sa menijima." + +#: ../doc/changelog.py:28 +msgid "" +"* Tweets, replies and retweets will be added to sent tweets right after " +"being posted in Twitter." +msgstr "" +"* Tvitovi, odgovori i retvitovi će biti odmah dodati u kanal poslatih " +"tvitova nakon što se objave na Twitter." + +#: ../doc/changelog.py:29 +msgid "* Extended Tweets should be displayed properly in list buffers." +msgstr "* Dugi tvitovi bi trebalo da se ispravno prikazuju u kanalima lista." + +#: ../doc/changelog.py:30 +msgid "## Changes in version 0.94" +msgstr "## Promene u 0.94 (Engleski )" + +#: ../doc/changelog.py:31 +msgid "" +"* Added an option in the global settings dialog to disable the Streaming " +"features of TWBlue. TWBlue will remove all Streaming features after August " +"16, so this option will give people an idea about how it will be. ([#219]" +"(https://github.com/manuelcortez/TWBlue/issues/219))" +msgstr "" +"* Added an option in the global settings dialog to disable the Streaming " +"features of TWBlue. TWBlue will remove all Streaming features after August " +"16, so this option will give people an idea about how it will be. ([#219]" +"(https://github.com/manuelcortez/TWBlue/issues/219))" + +#: ../doc/changelog.py:32 +msgid "" +"* Due to Twitter API changes, Switched authorisation method to Pin-code " +"based authorisation. When you add new accounts to TWBlue, you will be " +"required to paste a code displayed in the Twitter website in order to grant " +"access to TWBlue. ([#216](https://github.com/manuelcortez/TWBlue/issues/216))" +msgstr "" +"* Due to Twitter API changes, Switched authorisation method to Pin-code " +"based authorisation. When you add new accounts to TWBlue, you will be " +"required to paste a code displayed in the Twitter website in order to grant " +"access to TWBlue. ([#216](https://github.com/manuelcortez/TWBlue/issues/216))" + +#: ../doc/changelog.py:33 +msgid "" +"* In order to comply with latest Twitter changes, TWBlue has switched to the " +"new method used to send and receive direct messages, according to issue " +"[#215.](https://github.com/manuelcortez/twblue/issues/215)" +msgstr "" +"* In order to comply with latest Twitter changes, TWBlue has switched to the " +"new method used to send and receive direct messages, according to issue " +"[#215.](https://github.com/manuelcortez/twblue/issues/215)" + +#: ../doc/changelog.py:34 +msgid "" +" * The new method does not allow direct messages to be processed in real " +"time. Direct messages will be updated periodically." +msgstr "" +" * The new method does not allow direct messages to be processed in real " +"time. Direct messages will be updated periodically." + +#: ../doc/changelog.py:35 +msgid "" +"* After august 16 or when streaming is disabled, the events buffer will no " +"longer be created in TWBlue." +msgstr "" +"* After august 16 or when streaming is disabled, the events buffer will no " +"longer be created in TWBlue." + +#: ../doc/changelog.py:36 +msgid "" +"* You can configure frequency for buffer updates in TWBlue. By default, " +"TWBlue will update all buffers every 2 minutes, but you can change this " +"setting in the global settings dialog. ([#223](https://github.com/" +"manuelcortez/TWBlue/issues/223))" +msgstr "" +"* You can configure frequency for buffer updates in TWBlue. By default, " +"TWBlue will update all buffers every 2 minutes, but you can change this " +"setting in the global settings dialog. ([#223](https://github.com/" +"manuelcortez/TWBlue/issues/223))" + +#: ../doc/changelog.py:37 +msgid "" +"* Added a new tab called feedback, in the account settings dialog. This tab " +"allows you to control whether automatic speech or Braille feedbak in certain " +"events (mentions and direct messages received) is enabled. Take into account " +"that this option will take preference over automatic reading of buffers and " +"any kind of automatic output. ([#203](https://github.com/manuelcortez/TWBlue/" +"issues/203))" +msgstr "" +"* Added a new tab called feedback, in the account settings dialog. This tab " +"allows you to control whether automatic speech or Braille feedbak in certain " +"events (mentions and direct messages received) is enabled. Take into account " +"that this option will take preference over automatic reading of buffers and " +"any kind of automatic output. ([#203](https://github.com/manuelcortez/TWBlue/" +"issues/203))" + +#: ../doc/changelog.py:38 +msgid "" +"* The spell checking dialog now has access keys defined for the most " +"important actions. ([#211](https://github.com/manuelcortez/TWBlue/" +"issues/211))" +msgstr "" +"* The spell checking dialog now has access keys defined for the most " +"important actions. ([#211](https://github.com/manuelcortez/TWBlue/" +"issues/211))" + +#: ../doc/changelog.py:39 +msgid "" +"* TWBlue now Uses WXPython 4.0.1. This will allow us to migrate all " +"important components to Python 3 in the future. ([#207](https://github.com/" +"manuelcortez/TWBlue/issues/207))" +msgstr "" +"* TWBlue now Uses WXPython 4.0.1. This will allow us to migrate all " +"important components to Python 3 in the future. ([#207](https://github.com/" +"manuelcortez/TWBlue/issues/207))" + +#: ../doc/changelog.py:40 +msgid "" +"* When you quote a Tweet, if the original tweet was posted with Twishort, " +"TWBlue should display properly the quoted tweet. Before it was displaying " +"the original tweet only. ([#206](https://github.com/manuelcortez/TWBlue/" +"issues/206))" +msgstr "" +"* When you quote a Tweet, if the original tweet was posted with Twishort, " +"TWBlue should display properly the quoted tweet. Before it was displaying " +"the original tweet only. ([#206](https://github.com/manuelcortez/TWBlue/" +"issues/206))" + +#: ../doc/changelog.py:41 +msgid "" +"* It is possible to filter by retweets, quotes and replies when creating a " +"new filter." +msgstr "" +"* It is possible to filter by retweets, quotes and replies when creating a " +"new filter." + +#: ../doc/changelog.py:42 +msgid "" +"* Added support for playing youtube Links directly from the client. ([#94]" +"(https://github.com/manuelcortez/TWBlue/issues/94))" +msgstr "" +"* Added support for playing youtube Links directly from the client. ([#94]" +"(https://github.com/manuelcortez/TWBlue/issues/94))" + +#: ../doc/changelog.py:43 +msgid "* Replaced Bass with libVLC for playing URL streams." +msgstr "* Replaced Bass with libVLC for playing URL streams." + +#: ../doc/changelog.py:44 +msgid "" +"* the checkbox for indicating whether TWBlue will include everyone in a " +"reply or not, will be unchecked by default." +msgstr "" +"* the checkbox for indicating whether TWBlue will include everyone in a " +"reply or not, will be unchecked by default." + +#: ../doc/changelog.py:45 +msgid "" +"* You can request TWBlue to save the state for two checkboxes: Long tweet " +"and mention all, from the global settings dialogue." +msgstr "" +"* You can request TWBlue to save the state for two checkboxes: Long tweet " +"and mention all, from the global settings dialogue." + +#: ../doc/changelog.py:46 +msgid "" +"* For windows 10 users, some keystrokes in the invisible user interface have " +"been changed or merged:" +msgstr "" +"* For windows 10 users, some keystrokes in the invisible user interface have " +"been changed or merged:" + +#: ../doc/changelog.py:47 +msgid "" +" * control+Windows+alt+F will be used for toggling between adding and " +"removing a tweet to user's likes. This function will execute the needed " +"action based in the current status for the focused tweet." +msgstr "" +" * control+Windows+alt+F will be used for toggling between adding and " +"removing a tweet to user's likes. This function will execute the needed " +"action based in the current status for the focused tweet." + +#: ../doc/changelog.py:48 +msgid "* TWBlue will show an error if something goes wrong in an audio upload." +msgstr "" +"* TWBlue will show an error if something goes wrong in an audio upload." + +#: ../doc/changelog.py:49 +msgid "" +"* And more. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " +msgstr "" +"* And more. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " + +#: ../doc/changelog.py:50 +msgid "## Changes in version 0.93" +msgstr "## Changes in version 0.93" + +#: ../doc/changelog.py:51 +msgid "" +"* A new soundpack has been added to TWBlue. Thanks to [@ValeriaK305](https://" +"twitter.com/ValeriaK305)" +msgstr "" +"* A new soundpack has been added to TWBlue. Thanks to [@ValeriaK305](https://" +"twitter.com/ValeriaK305)" + +#: ../doc/changelog.py:52 +msgid "" +"* In the Windows 10 keymap, we have changed some default keystrokes as " +"windows now uses some previously assigned shortcuts:" +msgstr "" +"* In the Windows 10 keymap, we have changed some default keystrokes as " +"windows now uses some previously assigned shortcuts:" + +#: ../doc/changelog.py:53 +msgid " * For liking a tweet, press Control+Windows+alt+f" +msgstr " * For liking a tweet, press Control+Windows+alt+f" + +#: ../doc/changelog.py:54 +msgid " * for opening a trends buffer, press control+Windows+T" +msgstr " * for opening a trends buffer, press control+Windows+T" + +#: ../doc/changelog.py:55 +msgid "" +"* TWBlue has received improvements in some functions for handling extended " +"tweets, long tweets and quoted retweets. It should render some tweets in a " +"better way." +msgstr "" +"* TWBlue has received improvements in some functions for handling extended " +"tweets, long tweets and quoted retweets. It should render some tweets in a " +"better way." + +#: ../doc/changelog.py:56 +msgid "" +"* In the spell checker module, there is a new button that will allow you to " +"add your own words to your personal dictionary so the module won't mark them " +"as mispelled the next time you will check spelling." +msgstr "" +"* In the spell checker module, there is a new button that will allow you to " +"add your own words to your personal dictionary so the module won't mark them " +"as mispelled the next time you will check spelling." + +#: ../doc/changelog.py:57 +msgid "" +"* Added filtering capabilities to TWBlue. ([#102](https://github.com/" +"manuelcortez/TWBlue/issues/102))" +msgstr "" +"* Added filtering capabilities to TWBlue. ([#102](https://github.com/" +"manuelcortez/TWBlue/issues/102))" + +#: ../doc/changelog.py:58 +msgid "" +" * You can create a filter for the current buffer from the buffer menu in " +"the menu bar. At this moment, invisible interface does not have any shorcut " +"for this." +msgstr "" +" * You can create a filter for the current buffer from the buffer menu in " +"the menu bar. At this moment, invisible interface does not have any shorcut " +"for this." + +#: ../doc/changelog.py:59 +msgid " * You can create filters by word or languages." +msgstr " * You can create filters by word or languages." + +#: ../doc/changelog.py:60 +msgid "" +" * For deleting already created filters, you can go to the filter manager " +"in the buffer menu and delete the filters you won't need." +msgstr "" +" * For deleting already created filters, you can go to the filter manager " +"in the buffer menu and delete the filters you won't need." + +#: ../doc/changelog.py:61 +msgid "" +"* Links should be opened properly in quoted tweets ([#167,](https://github." +"com/manuelcortez/TWBlue/issues/167) [#184](https://github.com/manuelcortez/" +"TWBlue/issues/184))" +msgstr "" +"* Links should be opened properly in quoted tweets ([#167,](https://github." +"com/manuelcortez/TWBlue/issues/167) [#184](https://github.com/manuelcortez/" +"TWBlue/issues/184))" + +#: ../doc/changelog.py:62 +msgid "" +"* Increased display name limit up to 50 characters in update profile dialog." +msgstr "" +"* Increased display name limit up to 50 characters in update profile dialog." + +#: ../doc/changelog.py:63 +msgid "" +"* When authorising an account, you will see a dialogue with a cancel button, " +"in case you want to abort the process. Also, NVDA will not be blocked when " +"the process starts. ([#101](https://github.com/manuelcortez/TWBlue/" +"issues/101))" +msgstr "" +"* When authorising an account, you will see a dialogue with a cancel button, " +"in case you want to abort the process. Also, NVDA will not be blocked when " +"the process starts. ([#101](https://github.com/manuelcortez/TWBlue/" +"issues/101))" + +#: ../doc/changelog.py:64 +msgid "" +"* In the translator module, the list of available languages is fetched " +"automatically from the provider. That means all of these languages will work " +"and there will not be inconsistencies. Also we've removed the first combo " +"box, because the language is detected automatically by Yandex'S API. ([#153]" +"(https://github.com/manuelcortez/TWBlue/issues/153))" +msgstr "" +"* In the translator module, the list of available languages is fetched " +"automatically from the provider. That means all of these languages will work " +"and there will not be inconsistencies. Also we've removed the first combo " +"box, because the language is detected automatically by Yandex'S API. ([#153]" +"(https://github.com/manuelcortez/TWBlue/issues/153))" + +#: ../doc/changelog.py:65 +msgid "" +"* Trending topics, searches and conversation buffers will use mute settings " +"set for the session in wich they were opened. ([#157](https://github.com/" +"manuelcortez/TWBlue/issues/157))" +msgstr "" +"* Trending topics, searches and conversation buffers will use mute settings " +"set for the session in wich they were opened. ([#157](https://github.com/" +"manuelcortez/TWBlue/issues/157))" + +#: ../doc/changelog.py:66 +msgid "" +"* The Tweet limit is now 280 characters lenght instead 140. It means you can " +"tweet longer tweets. ([#172](https://github.com/manuelcortez/TWBlue/" +"issues/172))" +msgstr "" +"* The Tweet limit is now 280 characters lenght instead 140. It means you can " +"tweet longer tweets. ([#172](https://github.com/manuelcortez/TWBlue/" +"issues/172))" + +#: ../doc/changelog.py:67 +msgid "" +"* Per popular request, Status for mention to all and long tweet checkboxes " +"will not be saved in settings. ([#170](https://github.com/manuelcortez/" +"TWBlue/issues/170))" +msgstr "" +"* Per popular request, Status for mention to all and long tweet checkboxes " +"will not be saved in settings. ([#170](https://github.com/manuelcortez/" +"TWBlue/issues/170))" + +#: ../doc/changelog.py:68 +msgid "" +"* Fixed a problem that was making TWBlue unable to start if it was being ran " +"in Windows with Serbian language. ([#175](https://github.com/manuelcortez/" +"TWBlue/issues/175))" +msgstr "" +"* Fixed a problem that was making TWBlue unable to start if it was being ran " +"in Windows with Serbian language. ([#175](https://github.com/manuelcortez/" +"TWBlue/issues/175))" + +#: ../doc/changelog.py:69 +msgid "* Added Danish translation." +msgstr "* Added Danish translation." + +#: ../doc/changelog.py:70 +msgid "" +"* And more. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) " +"[#163,](https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://" +"github.com/manuelcortez/TWBlue/issues/159) [#173,](https://github.com/" +"manuelcortez/TWBlue/issues/173) [#174,](https://github.com/manuelcortez/" +"TWBlue/issues/174) [#176,](https://github.com/manuelcortez/TWBlue/" +"issues/176))" +msgstr "" +"* And more. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) " +"[#163,](https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://" +"github.com/manuelcortez/TWBlue/issues/159) [#173,](https://github.com/" +"manuelcortez/TWBlue/issues/173) [#174,](https://github.com/manuelcortez/" +"TWBlue/issues/174) [#176,](https://github.com/manuelcortez/TWBlue/" +"issues/176))" + +#: ../doc/changelog.py:71 +msgid "## changes in version 0.91 and 0.92" +msgstr "## changes in version 0.91 and 0.92" + +#: ../doc/changelog.py:72 +msgid "" +"* Fixed incorrect unicode handling when copying tweet to clipboard. ([#150]" +"(https://github.com/manuelcortez/TWBlue/issues/150))" +msgstr "" +"* Fixed incorrect unicode handling when copying tweet to clipboard. ([#150]" +"(https://github.com/manuelcortez/TWBlue/issues/150))" + +#: ../doc/changelog.py:73 +msgid "" +"* TWBlue will show an error when trying to open a timeline for a suspended " +"user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))" +msgstr "" +"* TWBlue will show an error when trying to open a timeline for a suspended " +"user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))" + +#: ../doc/changelog.py:74 +msgid "" +"* Removed TwUp as service as it no longer exists. ([#112](https://github.com/" +"manuelcortez/TWBlue/issues/112))" +msgstr "" +"* Removed TwUp as service as it no longer exists. ([#112](https://github.com/" +"manuelcortez/TWBlue/issues/112))" + +#: ../doc/changelog.py:75 +msgid "" +"* Release audio files after uploading them. ([#130](https://github.com/" +"manuelcortez/TWBlue/issues/130))" +msgstr "" +"* Release audio files after uploading them. ([#130](https://github.com/" +"manuelcortez/TWBlue/issues/130))" + +#: ../doc/changelog.py:76 +msgid "" +"* Now TWBlue will use Yandex's translation services instead microsoft " +"translator. ([#132](https://github.com/manuelcortez/TWBlue/issues/132))" +msgstr "" +"* Now TWBlue will use Yandex's translation services instead microsoft " +"translator. ([#132](https://github.com/manuelcortez/TWBlue/issues/132))" + +#: ../doc/changelog.py:77 +msgid "" +"* SndUp users will be able to upload audio in their account by using their " +"API Key again. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" +msgstr "" +"* SndUp users will be able to upload audio in their account by using their " +"API Key again. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" + +#: ../doc/changelog.py:78 +msgid "" +"* old tweets shouldn't be added as new items in buffers. ([#116,](https://" +"github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" +"manuelcortez/TWBlue/issues/133))" +msgstr "" +"* old tweets shouldn't be added as new items in buffers. ([#116,](https://" +"github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" +"manuelcortez/TWBlue/issues/133))" + +#: ../doc/changelog.py:79 +msgid "" +"* All mentionned users should be displayed correctly in Twishort's long " +"tweets. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#135]" +"(https://github.com/manuelcortez/TWBlue/issues/135))" +msgstr "" +"* All mentionned users should be displayed correctly in Twishort's long " +"tweets. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#135]" +"(https://github.com/manuelcortez/TWBlue/issues/135))" + +#: ../doc/changelog.py:80 +msgid "" +"* It is possible to select a language for OCR service from the extras panel, " +"in the account settings dialogue. You can, however, set this to detect " +"automatically. OCR should work better in languages with special characters " +"or non-english symbols. ([#107](https://github.com/manuelcortez/TWBlue/" +"issues/107))" +msgstr "" +"* It is possible to select a language for OCR service from the extras panel, " +"in the account settings dialogue. You can, however, set this to detect " +"automatically. OCR should work better in languages with special characters " +"or non-english symbols. ([#107](https://github.com/manuelcortez/TWBlue/" +"issues/107))" + +#: ../doc/changelog.py:81 +msgid "" +"* Fixed a problem with JAWS for Windows and TWBlue. Now JAWS will work " +"normally in this update. [#100](https://github.com/manuelcortez/twblue/" +"issues/100)" +msgstr "" +"* Fixed a problem with JAWS for Windows and TWBlue. Now JAWS will work " +"normally in this update. [#100](https://github.com/manuelcortez/twblue/" +"issues/100)" + +#: ../doc/changelog.py:82 +msgid "* And more ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" +msgstr "" +"* And more ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" + +#: ../doc/changelog.py:83 +msgid "## Changes in version 0.90" +msgstr "## Changes in version 0.90" + +#: ../doc/changelog.py:84 +msgid "" +"* Fixed a bug in long tweet parsing that was making TWBlue to disconnect the " +"streaming API. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" +msgstr "" +"* Fixed a bug in long tweet parsing that was making TWBlue to disconnect the " +"streaming API. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" + +#: ../doc/changelog.py:85 +msgid "" +"* Now OCR will work in images from retweets. It fixes a bug where TWBlue was " +"detecting images but couldn't apply OCR on them. ([#105](https://github.com/" +"manuelcortez/TWBlue/issues/105))" +msgstr "" +"* Now OCR will work in images from retweets. It fixes a bug where TWBlue was " +"detecting images but couldn't apply OCR on them. ([#105](https://github.com/" +"manuelcortez/TWBlue/issues/105))" + +#: ../doc/changelog.py:86 +msgid "" +"* TWBlue won't try to load tweets already deleted, made with Twishort. " +"Before, if someone posted a long tweet but deleted it in the Twishort's " +"site, TWBlue was trying to load the tweet and it was causing problems in all " +"the client. ([#113](https://github.com/manuelcortez/TWBlue/issues/113))" +msgstr "" +"* TWBlue won't try to load tweets already deleted, made with Twishort. " +"Before, if someone posted a long tweet but deleted it in the Twishort's " +"site, TWBlue was trying to load the tweet and it was causing problems in all " +"the client. ([#113](https://github.com/manuelcortez/TWBlue/issues/113))" + +#: ../doc/changelog.py:87 +msgid "" +"* TWBlue shows an error message when you try to view the profile of an user " +"that does not exist or has been suspended. ([#114,](https://github.com/" +"manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" +"TWBlue/issues/115))" +msgstr "" +"* TWBlue shows an error message when you try to view the profile of an user " +"that does not exist or has been suspended. ([#114,](https://github.com/" +"manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" +"TWBlue/issues/115))" + +#: ../doc/changelog.py:88 +msgid "" +"* The spellchecker module should select the right language when is set to " +"\"user default\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" +msgstr "" +"* The spellchecker module should select the right language when is set to " +"\"user default\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" + +#: ../doc/changelog.py:89 +msgid "" +"* Image description will be displayed in retweets too. ([#119](https://" +"github.com/manuelcortez/TWBlue/issues/119))" +msgstr "" +"* Image description will be displayed in retweets too. ([#119](https://" +"github.com/manuelcortez/TWBlue/issues/119))" + +#: ../doc/changelog.py:90 +msgid "" +"* When reading a long tweet, you shouldn't read strange entities anymore. " +"([#118](https://github.com/manuelcortez/twblue/issues/118))" +msgstr "" +"* When reading a long tweet, you shouldn't read strange entities anymore. " +"([#118](https://github.com/manuelcortez/twblue/issues/118))" + +#: ../doc/changelog.py:91 +msgid "" +"* TWBlue will not try to load timelines if the user is blocking you. ([#125]" +"(https://github.com/manuelcortez/twblue/issues/125))" +msgstr "" +"* TWBlue will not try to load timelines if the user is blocking you. ([#125]" +"(https://github.com/manuelcortez/twblue/issues/125))" + +#: ../doc/changelog.py:92 +msgid "## Changes in version 0.88 and 0.89" +msgstr "## Changes in version 0.88 and 0.89" + +#: ../doc/changelog.py:93 +msgid "* Fixed more issues with streams and reconnections." +msgstr "* Fixed more issues with streams and reconnections." + +#: ../doc/changelog.py:94 +msgid "* newer updates will indicate the release date in the updater." +msgstr "* newer updates will indicate the release date in the updater." + +#: ../doc/changelog.py:95 +msgid "" +"* Changes to keystrokes are reflected in keystroke editor automatically." +msgstr "" +"* Changes to keystrokes are reflected in keystroke editor automatically." + +#: ../doc/changelog.py:96 +msgid "" +"* In replies with multiple users, if the mention to all checkbox is " +"unchecked, you will see a checkbox per user so you will be able to control " +"who will be mentioned in the reply." +msgstr "" +"* In replies with multiple users, if the mention to all checkbox is " +"unchecked, you will see a checkbox per user so you will be able to control " +"who will be mentioned in the reply." + +#: ../doc/changelog.py:97 +msgid "" +"* Fixed a bug that caused duplicated user mentions in replies when the tweet " +"was made with Twishort." +msgstr "" +"* Fixed a bug that caused duplicated user mentions in replies when the tweet " +"was made with Twishort." + +#: ../doc/changelog.py:98 +msgid "" +"* Retweets should be displayed normally again when the originating tweet is " +"a Twishort's long tweet." +msgstr "" +"* Retweets should be displayed normally again when the originating tweet is " +"a Twishort's long tweet." + +#: ../doc/changelog.py:99 +msgid "" +"* Changed the way TWBlue saves user timelines in configuration. Now it uses " +"user IDS instead usernames. With user IDS, if an user changes the username, " +"TWBlue still will create his/her timeline. This was not possible by using " +"usernames." +msgstr "" +"* Changed the way TWBlue saves user timelines in configuration. Now it uses " +"user IDS instead usernames. With user IDS, if an user changes the username, " +"TWBlue still will create his/her timeline. This was not possible by using " +"usernames." + +#: ../doc/changelog.py:100 +msgid "" +"* Added a new setting in the account settings dialogue that makes TWBlue to " +"show twitter usernames instead the full name." +msgstr "" +"* Added a new setting in the account settings dialogue that makes TWBlue to " +"show twitter usernames instead the full name." + +#: ../doc/changelog.py:101 +msgid "" +"* Added OCR in twitter pictures. There is a new item in the tweet menu that " +"allows you to extract and display text in images. Also the keystroke alt+Win" +"+o has been added for the same purpose from the invisible interface." +msgstr "" +"* Added OCR in twitter pictures. There is a new item in the tweet menu that " +"allows you to extract and display text in images. Also the keystroke alt+Win" +"+o has been added for the same purpose from the invisible interface." + +#: ../doc/changelog.py:102 +msgid "* Now TWBlue will play a sound when the focused tweet contains images." +msgstr "" +"* Now TWBlue will play a sound when the focused tweet contains images." + +#: ../doc/changelog.py:103 +msgid "" +"* Your own quoted tweets will not appear in the mentions buffer anymore." +msgstr "" +"* Your own quoted tweets will not appear in the mentions buffer anymore." + +#: ../doc/changelog.py:104 +msgid "" +"* The config file is saved in a different way, it should fix the bug where " +"TWBlue needs to be restarted after the config folder is deleted." +msgstr "" +"* The config file is saved in a different way, it should fix the bug where " +"TWBlue needs to be restarted after the config folder is deleted." + +#: ../doc/changelog.py:105 +msgid "* Mentioning people from friends or followers buffers works again." +msgstr "* Mentioning people from friends or followers buffers works again." + +#: ../doc/changelog.py:106 +msgid "" +"* Support for proxy servers has been improved. Now TWBlue supports http, " +"https, socks4 and socks5 proxies, with and without autentication." +msgstr "" +"* Support for proxy servers has been improved. Now TWBlue supports http, " +"https, socks4 and socks5 proxies, with and without autentication." + +#: ../doc/changelog.py:107 +msgid "## Changes in version 0.87" +msgstr "## Changes in version 0.87" + +#: ../doc/changelog.py:108 +msgid "* Fixed stream connection errors." +msgstr "* Fixed stream connection errors." + +#: ../doc/changelog.py:109 +msgid "" +"* Now TWBlue can handle properly a reply to the sender without including all " +"other mentioned users." +msgstr "" +"* Now TWBlue can handle properly a reply to the sender without including all " +"other mentioned users." + +#: ../doc/changelog.py:110 +msgid "* Updated translations." +msgstr "* Updated translations." + +#: ../doc/changelog.py:111 +msgid "" +"* The status of the mention to all checkbox will be remembered the next time " +"you reply to multiple users." +msgstr "" +"* The status of the mention to all checkbox will be remembered the next time " +"you reply to multiple users." + +#: ../doc/changelog.py:112 +msgid "## Changes in version 0.86" +msgstr "## Changes in version 0.86" + +#: ../doc/changelog.py:113 +msgid "" +"* Fixed a very important security issue. Now TWBlue will send tweets to " +"twishort without using any other server." +msgstr "" +"* Fixed a very important security issue. Now TWBlue will send tweets to " +"twishort without using any other server." + +#: ../doc/changelog.py:114 +msgid "" +"* When you add a comment to a tweet, it will be sent as a quoted tweet, even " +"if your reply plus the original tweet is not exceeding 140 characters." +msgstr "" +"* When you add a comment to a tweet, it will be sent as a quoted tweet, even " +"if your reply plus the original tweet is not exceeding 140 characters." + +#: ../doc/changelog.py:115 +msgid "" +"* Updated windows 10 keymap for reflecting changes made in the last windows " +"10 build." +msgstr "" +"* Updated windows 10 keymap for reflecting changes made in the last windows " +"10 build." + +#: ../doc/changelog.py:116 +msgid "* Added last changes in the twitter API." +msgstr "* Added last changes in the twitter API." + +#: ../doc/changelog.py:117 +msgid "" +"* When replying, it will not show the twitter username in the text box. When " +"you send the tweet, the username will be added automatically." +msgstr "" +"* When replying, it will not show the twitter username in the text box. When " +"you send the tweet, the username will be added automatically." + +#: ../doc/changelog.py:118 +msgid "" +"* When replying to multiple users, you'll have a checkbox instead a button " +"for mentioning all people. If this is checked, twitter usernames will be " +"added automatically when you send your reply." +msgstr "" +"* When replying to multiple users, you'll have a checkbox instead a button " +"for mentioning all people. If this is checked, twitter usernames will be " +"added automatically when you send your reply." + +#: ../doc/changelog.py:119 +msgid "## Changes in version 0.85" +msgstr "## Changes in version 0.85" + +#: ../doc/changelog.py:120 +msgid "* Long and quoted tweets should be displayed properly In lists." +msgstr "* Long and quoted tweets should be displayed properly In lists." + +#: ../doc/changelog.py:121 +msgid "* The connection should be more stable." +msgstr "* The connection should be more stable." + +#: ../doc/changelog.py:122 +msgid "* Added an autostart option in the global settings dialogue." +msgstr "* Added an autostart option in the global settings dialogue." + +#: ../doc/changelog.py:123 +msgid "* Updated translation." +msgstr "* Updated translation." + +#: ../doc/changelog.py:124 +msgid "* Updated russian documentation." +msgstr "* Updated russian documentation." + +#: ../doc/changelog.py:125 +msgid "* Tweets in cached database should be loaded properly." +msgstr "* Tweets in cached database should be loaded properly." + +#: ../doc/changelog.py:126 +msgid "* Added some missed dictionaries for spelling correction." +msgstr "* Added some missed dictionaries for spelling correction." + +#: ../doc/changelog.py:127 +msgid "" +"* Timelines, lists and other buffer should be created in the right order at " +"startup." +msgstr "" +"* Timelines, lists and other buffer should be created in the right order at " +"startup." + +#: ../doc/changelog.py:128 +msgid "## Changes in version 0.84 " +msgstr "## Changes in version 0.84 " + +#: ../doc/changelog.py:129 +msgid "* More improvements in quoted and long tweets." +msgstr "* More improvements in quoted and long tweets." + +#: ../doc/changelog.py:130 +msgid "" +"* Updated translations: Russian, Italian, French, Romanian, Galician and " +"Finnish." +msgstr "" +"* Updated translations: Russian, Italian, French, Romanian, Galician and " +"Finnish." + +#: ../doc/changelog.py:131 +msgid "" +"* Improvements in the audio uploader module: Now it can handle audio with " +"non-english characters." +msgstr "" +"* Improvements in the audio uploader module: Now it can handle audio with " +"non-english characters." + +#: ../doc/changelog.py:132 +msgid "" +"* the title of the window should be updated properly when spellcheck, " +"translate or shorten/unshorten URL buttons are pressed." +msgstr "" +"* the title of the window should be updated properly when spellcheck, " +"translate or shorten/unshorten URL buttons are pressed." + +#: ../doc/changelog.py:133 +msgid "" +"* the bug that changes the selected tweet in the home timeline shouldn't be " +"happening so often." +msgstr "" +"* the bug that changes the selected tweet in the home timeline shouldn't be " +"happening so often." + +#: ../doc/changelog.py:134 +msgid "## Changes in version 0.82 and 0.83" +msgstr "## Changes in version 0.82 and 0.83" + +#: ../doc/changelog.py:135 +msgid "" +"* If the tweet source (client) is an application with unicode characters " +"(example: российская газета) it will not break the tweet displayer." +msgstr "" +"* If the tweet source (client) is an application with unicode characters " +"(example: российская газета) it will not break the tweet displayer." + +#: ../doc/changelog.py:136 +msgid "" +"* Added a new field for image description in tweet displayer. When " +"available, it will show description for images posted in tweets." +msgstr "" +"* Added a new field for image description in tweet displayer. When " +"available, it will show description for images posted in tweets." + +#: ../doc/changelog.py:137 +msgid "" +"* users can add image descriptions to their photos. When uploading an image, " +"a dialog will show for asking a description." +msgstr "" +"* users can add image descriptions to their photos. When uploading an image, " +"a dialog will show for asking a description." + +#: ../doc/changelog.py:138 +msgid "* Redesigned upload image dialog." +msgstr "* Redesigned upload image dialog." + +#: ../doc/changelog.py:139 +msgid "* Fixed photo uploads when posting tweets." +msgstr "* Fixed photo uploads when posting tweets." + +#: ../doc/changelog.py:140 +msgid "" +"* When getting tweets for a conversation, ignores deleted tweets or some " +"errors, now TWBlue will try to get as much tweets as possible, even if some " +"of these are no longer available." +msgstr "" +"* When getting tweets for a conversation, ignores deleted tweets or some " +"errors, now TWBlue will try to get as much tweets as possible, even if some " +"of these are no longer available." + +#: ../doc/changelog.py:141 +msgid "* Added audio playback from soundcloud." +msgstr "* Added audio playback from soundcloud." + +#: ../doc/changelog.py:142 +msgid "* Now the session mute option don't makes the screen reader speaks." +msgstr "* Now the session mute option don't makes the screen reader speaks." + +#: ../doc/changelog.py:143 +msgid "* Fixed the direct message dialog. Now it should be displayed properly." +msgstr "" +"* Fixed the direct message dialog. Now it should be displayed properly." + +#: ../doc/changelog.py:144 +msgid "" +"* when a tweet is deleted in twitter, TWBlue should reflect this change and " +"delete that tweet in every buffer it is displayed." +msgstr "" +"* when a tweet is deleted in twitter, TWBlue should reflect this change and " +"delete that tweet in every buffer it is displayed." + +#: ../doc/changelog.py:145 +msgid "" +"* If your session is broken, TWBlue will be able to remove it automatically " +"instead just crashing." +msgstr "" +"* If your session is broken, TWBlue will be able to remove it automatically " +"instead just crashing." + +#: ../doc/changelog.py:146 +msgid "* audio uploader should display the current progress." +msgstr "* audio uploader should display the current progress." + +#: ../doc/changelog.py:147 +msgid "" +"* users can disable the check for updates feature at startup from the " +"general tab, in the global settings dialogue." +msgstr "" +"* users can disable the check for updates feature at startup from the " +"general tab, in the global settings dialogue." + +#: ../doc/changelog.py:148 +msgid "" +"* The invisible interface and the window should be synchronized when the " +"client reconnects." +msgstr "" +"* The invisible interface and the window should be synchronized when the " +"client reconnects." + +#: ../doc/changelog.py:149 +msgid "* The documentation option in the systray icon should be enabled." +msgstr "* The documentation option in the systray icon should be enabled." + +#: ../doc/changelog.py:150 +msgid "" +"* In trending buffers, you can press enter for posting a tweet about the " +"focused trend." +msgstr "" +"* In trending buffers, you can press enter for posting a tweet about the " +"focused trend." + +#: ../doc/changelog.py:151 +msgid "" +"* Updated russian documentation and main program interface (thanks to " +"Natalia Hedlund (Наталья Хедлунд), [@lifestar_n](https://twitter.com/" +"lifestar_n) in twitter)" +msgstr "" +"* Updated russian documentation and main program interface (thanks to " +"Natalia Hedlund (Наталья Хедлунд), [@lifestar_n](https://twitter.com/" +"lifestar_n) in twitter)" + +#: ../doc/changelog.py:152 +msgid "* updated translations." +msgstr "* updated translations." + +#: ../doc/changelog.py:153 +msgid "## Changes in Version 0.81" +msgstr "## Changes in Version 0.81" + +#: ../doc/changelog.py:154 +msgid "* Updated translations" +msgstr "* Updated translations" + +#: ../doc/changelog.py:155 +msgid "" +"* The updater module has received some improvements. Now it includes a " +"Mirror URL for checking updates if the main URL is not available at the " +"moment. If something is wrong and both locations don't work, the program " +"will start anyway." +msgstr "" +"* The updater module has received some improvements. Now it includes a " +"Mirror URL for checking updates if the main URL is not available at the " +"moment. If something is wrong and both locations don't work, the program " +"will start anyway." + +#: ../doc/changelog.py:156 +msgid "* some GUI elements now use keyboard shortcuts for common actions." +msgstr "* some GUI elements now use keyboard shortcuts for common actions." + +#: ../doc/changelog.py:157 +msgid "* fixed a bug in the geolocation dialog." +msgstr "* fixed a bug in the geolocation dialog." + +#: ../doc/changelog.py:158 +msgid "* the chicken nugget keymap should work properly." +msgstr "* the chicken nugget keymap should work properly." + +#: ../doc/changelog.py:159 +msgid "" +"* Added a new soundpack to the default installation of TWBlue, thanks to " +"[@Deng90](https://twitter.com/deng90)" +msgstr "" +"* Added a new soundpack to the default installation of TWBlue, thanks to " +"[@Deng90](https://twitter.com/deng90)" + +#: ../doc/changelog.py:160 +msgid "* Now the changelog is written in an html File." +msgstr "* Now the changelog is written in an html File." + +#: ../doc/changelog.py:161 +msgid "" +"* Added some missed dictionaries in last version for the spell checking " +"feature." +msgstr "" +"* Added some missed dictionaries in last version for the spell checking " +"feature." + +#: ../doc/changelog.py:162 +msgid "" +"* Trimmed the beginnings of the sounds in the default soundpack. Thanks to " +"[@masonasons](https://github.com/masonasons)" +msgstr "" +"* Trimmed the beginnings of the sounds in the default soundpack. Thanks to " +"[@masonasons](https://github.com/masonasons)" + +#: ../doc/changelog.py:163 +msgid "" +"* Added Opus support for sound playback in TWBlue. Thanks to [@masonasons]" +"(https://github.com/masonasons)" +msgstr "" +"* Added Opus support for sound playback in TWBlue. Thanks to [@masonasons]" +"(https://github.com/masonasons)" + +#: ../doc/changelog.py:164 +msgid "" +"* Added a source field in view tweet dialogue. Thanks to [@masonasons]" +"(https://github.com/masonasons)" +msgstr "" +"* Added a source field in view tweet dialogue. Thanks to [@masonasons]" +"(https://github.com/masonasons)" + +#: ../doc/changelog.py:165 +msgid "" +"* You can load previous items in followers and friend buffers for others." +msgstr "" +"* You can load previous items in followers and friend buffers for others." + +#: ../doc/changelog.py:166 +msgid "" +"* The Spell Checker dialogue should not display an error message when you " +"have set \"default language\" in the global settings dialogue if your " +"language is supported [#168](http://twblue.es/bugs/view.php?id=168)" +msgstr "" +"* The Spell Checker dialogue should not display an error message when you " +"have set \"default language\" in the global settings dialogue if your " +"language is supported [#168](http://twblue.es/bugs/view.php?id=168)" + +#: ../doc/changelog.py:167 +msgid "* Updated romanian translation." +msgstr "* Updated romanian translation." + +#: ../doc/changelog.py:168 +msgid "* Some code cleanups." +msgstr "* Some code cleanups." + +#: ../doc/changelog.py:169 +msgid "* The bug reports feature is fully operational again." +msgstr "* The bug reports feature is fully operational again." + +#: ../doc/changelog.py:170 +msgid "" +"* TWBlue should work again for users that contains special characters in " +"windows usernames." +msgstr "" +"* TWBlue should work again for users that contains special characters in " +"windows usernames." + +#: ../doc/changelog.py:171 +msgid "* Added more options for the tweet searches." +msgstr "* Added more options for the tweet searches." + +#: ../doc/changelog.py:172 +msgid "* Added play_audio to the keymap editor." +msgstr "* Added play_audio to the keymap editor." + +#: ../doc/changelog.py:173 +msgid "* Windows key is no longer required in the keymap editor" +msgstr "* Windows key is no longer required in the keymap editor" + +#: ../doc/changelog.py:174 +msgid "* Switched to the Microsoft translator." +msgstr "* Switched to the Microsoft translator." + +#: ../doc/changelog.py:175 +msgid "" +"* You can update the current buffer by pressing ctrl+win+shift+u in the " +"default keymap or in the buffer menu." +msgstr "" +"* You can update the current buffer by pressing ctrl+win+shift+u in the " +"default keymap or in the buffer menu." + +#: ../doc/changelog.py:176 +msgid "* Changed some keystrokes in the windows 10 default keymap" +msgstr "* Changed some keystrokes in the windows 10 default keymap" + +#: ../doc/changelog.py:177 +msgid "* New followers and friends buffer for user timelines." +msgstr "* New followers and friends buffer for user timelines." + +#: ../doc/changelog.py:178 +msgid "---" +msgstr "---" + +#: ../doc/changelog.py:179 +msgid "Copyright © 2014-2017, Manuel Cortez." +msgstr "Copyright © 2014-2017, Manuel Cortez." diff --git a/doc/locales/sr/lc_messages/twblue-documentation.mo b/doc/locales/sr/lc_messages/twblue-documentation.mo new file mode 100644 index 0000000000000000000000000000000000000000..09645852b04bd260100df7375b7da4d000538db5 GIT binary patch literal 71568 zcmd4437BMQRp%XzirT0w3MeXEs#&TaD{JX)x=FUKrK`HS)~?Lz77A=4Gb1x2GcqEH zC9^USQE)^U7z9N?htXDHY#kL4a6u61ZbclmS{)sC)N#Xc=5y5f5SRIW|8vg!-W!pT z)zv;e-!t{}?UNC4@4KA$?B~4i{r$&%?%Qho``l}4wXXs`{|johi~Rl4$LQNy?Gul$ z)m{Yr1>iII{tKT_s}1!x|UtX*20v2CUtNl9g2=D^%%b!%Msi`*b zTHvb#z5)29e1047(ZG9wbW!_B;M0M>0{k-I-vPf8crE{9Xtiem9|hb8dAph0=p8x6oCw#TH^Gu*VzYzFX;8~#NSC8*s5uaZJd^z906?g#nH^4dI)1O?c zT?d|D4}2S+f0#i{@%czmtKG%tuV+yEfWHA09v%tO*MW}%z6$ty;JbjIe;v;O-wk{o z@KeAGwDVO@tJMzjxeJno=XdkJ8-c$Fq|4ehAc-bw1yJ)l0_4%!%Yk%R`=)^J0SaHA z08Rq`9H@4l_)MSAX`p_8HBjw+H;`Lu9|t}g_!mGu_xRnl+RebD!2Q5i0iOf>5uon- z6X0IpWA`{6z6f}n&#wmF4g7iF?Z9U~%iHe;d?%2fY99lh0)84e0lbMuMIZA((Z@T0 zF9iN7P~&+lH)+1N0QKBF@HXK4fNJlvK;iRg3`*mEIq)XnJArEVLEwvkpGRY7fwuxR zueSm9{m%gp10TsEs=X7y=L35{eyY6}sCD}T;0fT9c$g)t%>!Qmd_7Rl{XFni;9mnj z2D}L(0#&uo0RN74ekzO1P-{=Tp;r4x;8EZO;2{>N3w%597T~oY`*FaNz^~=GuLb@A zpFhH+wEpj6l7c@46rO$)sCJ(K^3=`|;O)Q<0fmoi82nk_6i}bv02IFN1J;562RH!M z`EmpJn?QYk79>0c_&(tKfDZzNr`Iy+Hv@kT2uf;qGKenY{AS>1`TX}F^+~|Ly~Wq_ z(T5zK0RAc8zZSR-T&A%Z;2#3t4t&lLWD@X~fp-I6a1$0=vLlfPVsfC-50})@t7m{21^*0ULKY zeLn7MoDa_ef9!MU52$tzyp%Ns_JI?$-+vjj%IAB&7CHnz66Agw_>aI>0srjfv{eIxr0Y3_SDuenP;HQ9Zp`BlU9sB@Xc)io>@4W%u;P>PImhl1K5Bx@c zKMB#^OMk!gCf1nG8{g{md+%G2ZQS=wZ$$_3{TqNYe6BNz{e1oqkRjLp>}~J{aGpsr z<=T0e?f~!?fWHp>2OvvPyG*B#20jD}kQ@ej)J7zOz>Q3gDB0&jQ{IJPe!zYW?2>{3_tj0iOo^ zH4DdW~3HW^Ahk>)e&j4i)TznUF#OLoo2;I!*=YF^Ib@zK*-hK=y zJp3bY1Nf+W9KII#2|oV=@CCs8Y2<~#M|>Z$jdl(J_wxCZ5YaP$p8?(ge9F81`x&6t z@io9bzz+b0zuyN6um22uCUDPt+`hO2c#zK<0e=vv=YJ3QWZW0`5X6UI&~9o&tUgP|yDt;67mS!~Wbk zpw{gz0e=~&@jdEC{QKL1FX8j+fRn&K0;-+I{;13OmjZY5`Mp4W|69PDflqs{>zkJW z_5E9by6<;^>hJU3=lDJhyp_)bAdl8Q415M~<^9n4Ball#wfCbR;D4<9p95dcpMUW| z+63PIA)oK>0-wm|C;vG8a^G`+zrp9_pYU}*^pnURKG%U-uU7-l0zU%m0KfRB9G|ZO z3ctSq)bF47VYl-x0QKA(flI(o0>2k{{ZAwBfWHBJCGf~cyuY6TzM0Q|06Yfle6&{k zF5riN`+(3wbotly7~#pmAu zZUSHafYZ@$1FwAqWBob4R`B|8rQ}Q+)pC z-*mg|O7Z4QHe(8_>`?vo$U-vKi6YqBuco)xo7}(&xFa0y`XA`)G&mW7= zp9bE*=L3K4`ey;CdHyl*_kf4~!ukIxpZ0N`1b!dwemn3r{C@L)NA{~9;CJx(HUGo! z|BCN8GP zXa3&l|Gxs&@9xjKKKvoz+qwT6{sFs-_P+d|9p4Z9pIYrr+;=xbcL?}b0r!E_<9vPv z@ZH@1lfVz~{N0~(jnT)KJ@Oi}1K$jM?&rYQzyXrnX6cpM2ak=2sqtnLthL zJD+fk*#~cU;x%HE+Bb3O-%Gi!=lU=gC^lW8`M;S<|3IJp6R+ssKXDzkzx;py7V!UY ziB`UrOETyQT;h%WT>p`4g6r8_H*+m=K}seQ-UWOG*SB-s#U;6+f71?39`yKoDL%g; zpujG!ALKf$5Bz%@*E6}E%Y_KFf1ew09(XbS7Wi(iBbCpu=kJ%t=Sd*TQu{G3MC#B# z(W}JFS8{y?*XMD43)f4yKEm~6u1zkjoBsW-1B=Ie9e=~3wV#ado)qxAfY);U7S}tt zew$1G5FaK-^fx4D|NbywC*a+{pWuQ-P4|iKR=7UN^=n+Pmid-n1)Smf2Cl#2dJC8S zopE6PnEpH$pZ_!P4zBOv`ZBKbTtCXCe{Xb<|Nk8R`gN|4aXp_)|Gu6J_ORI1?*L!S zHOHlYw>!xH7Z3eB*OzjAe|-DAfZqXJezY_R`T<_+33fCWTJ%daC?&msXf1wwE|1Z}^xeju@n(H>M^zRS&;{mRJ z#bb+_l*wh|0ntX@5kp)1>6Gu8P}a$?~U*N0eGCN;5yCqt6X2qmHvG-f3&!M zHhnPyAD=#7g~lw zG2iSq=K95Iqt~l1HhPoAiy7!@ebZa%HE4NX!7YvE`nH>kg>GlHXw>JHiVlEHxR6@W0TRV`1o8&lel@9@uR6)xCagTI2K4Sg&X`dwuKm^q}9E zD(+fpf~D0#zu8_adZ3y?O%yYC9c~R8#YU(7%zn{ZiZx}FJ1x>`y~%`Qk)Bty8%;yf zMw7J_nzX+CrFy?uYjk_G+G7>k!V;@+c+j_dW^D&78vPobh;}xjtlKsXRPUdXRTM*2Q?E6 zCeFDKyfjt#Jx=1~O%sK$|6HBn80FjSXB&1)5dIaIYG}Rkas{WTjS-rifV*4pji$8e zMBiwO!RCWu#yqo)&M&mJUc-1d4(TO=1MBn6-dYQuOsIxbf-%JTiE4`aA`~}SyY9N; zNHAYr>l|P7Sp@qNmTdNW`tx|B-RQCq@akM+&A&U*?sq%$1EUb#bF#5H+o^ZwMe^PL z+`#WT#d5ZLa77PsG$(GKN4PMU`A*w9wf1LB+(317(1*7DO9%ksSnSqUnMac!x(juP zL!Dia5Yiua)w^xb_f-DAt~fO4(|5Bcdq;-sMqL= zHr3{J#dI3D(|@C&>op_=_c`6BAr!lhUpTR6{4>q=Is*_9h}>WG&l}}B_-qs5^3;7@yhEKoly4j>Fxus@+MC=+JoryT(@(n zS#~zf+S)yc>)5?ck2#B@oF71|DKpurp7V!iEDj>JIupn-Bpl|G25ukQu_?=r-v*NOEqe)9E$PLR?aXvJJ+E2Ri=s)ZKkOH`9>-&tdvqQfKr<#^e#J!=|U?Yg{OOF5Mn1l<#jc>)L2D^ zbg_ZduFx{H#Ac&(oDvsI`P=d&X{zGCqr#!+c@dPvDB^#Ieu9Y?MwdPzOo7GiWMeBAOJqdangd=BMyVFa}1@&}nsyN?R?LdBJ zxVD-rSk@ve#;oPAzq|F>=G;_q@pNaYzAEeNPzzO6@75vg;?=?!M7b%GfF`(=10UQUbivN@JHCi+B&w^uumC52nMz%(GxZZok09)+h z^kAjgDsJsxYP4Cp@u={YA#v zSk#gnk*qN64c3@k1L53QZ*Is!zKpT>&=$TvI#X}JfpSKGKcrJQJ1vF=*aROk&b)US7u_2EO~FszQwCeUJetqAhJ8~S0YI0~D9S&3uj-B<-x@?Ay8p+d9}LFCUaj^bm;^_AwW`p4FAd6zYs z8t3L6^xN=Lx60g{D$dEEugh8+{`rKf=8%iwJr3V;daAgsDf@%bW3dkZcxH-utgcDV zxxBPN4c~JP`6oqbJi)Rp;O`FKamQ3~$ACLVjhYfg=OyFTAiaIEsNA2dqHsFqp+TA& z4+Wcb%W#KDboxRuzSXt9J3PsV8MjX9sZ!vkMHm*m<*?HeHvBQDNx$C-1<1$0!Yxg$ zd=Ig>IhKY>b+cF0RPQQG(oP=q@a)Tb51pDpfjk6_RBkuTb`)0CV6aROjKzAVH9&G; zliv9B9s98dA(m;Z2V0-{21>SNda6X%Xipc`WP3b}evV8PcQ(=5bDg$?k|~Cr#+113 zN<3E%C{c>TtL47R^B}D_)a`aQrclc32nU3osI@JNz~m6>ekTc0wsR{cUuSVqaWx*6 zvNEx32BO3irdP9#{4LpVQ(XbHarJ2H~(dmxC#MTBJX5kW0nRl zUEI2Y<%96+ba$H9sd&b0Wz)-bf@6)jCVsXX8aqDO!2Ao6IxX`rC~B?SSZ{U)*n3wBUY2&0@8#_!Tky6J=5bI80S zoi(%O%%u~?5 zvKoXVjHEKn6N{BC`cMdf_!WJ}oETV0^kL9t8p2LGef#W;tg53ma(bwdt`Vj*tEWNG z-lVX!#7+~NfeO&aObMHWFwDH$tazBcXFi0%aA7S;ks-yDQF`^t=?Z2{iIrD^34CM5 ziG0*3uU;xVyMRf^#e})qiBt;w(e0oT%p-cqdZ*o7#ZjN`*V~Qz-_*SSb>p3)t+=tV za`50mbE^_pkXOL9LsVdIcFnVPA~Q0Vvo~xqM2KvO$dAXBjCE7)LXiXe!pvWj@+4g3 zEiiA?v^*XbINjc9(bM6eb_7{NnR46wJ_>?toH zd7Gjk&s1o}SmWrBpMeK>345826+2J>&8R1g+X=`=77F}b$LsQ_QcBXK9EjpSJWps& zkt!L3>evLCoIN!u4^WYpbGT9De<#_T(|&3+ zC$B(2kdH5pIKC5`7laB0@l{qtmW*UIrDsF=p2=;>V)$34t;=4&eny95QqHi27IC;Gb~1 z*#@4$8+6U%swO~nUy4=8O!G#ugCi|!}vbXL0>dV?=foaY!?^ zTu_w}_k_!D%wWVyii!AKWSf=Pilnp{3B@9V*X+!x!o!i!j`b%0RoOq0r0^l?GOAZt zR8v?Ov=p9D&Pn63WS3BCUU0SxL8&ztvCizNj+cRV8DwBViyU7_N z>$1JbgqIZfBUsgFVJdX{_uacSUL-1@)o9IeOJi&Qev^r}di$@iLchoZi7}5Xw#-t$(h_rpmYjM z5nzk>r%fdV$`nVXt31*qBq5R>l26TVHVC?N*IbLZjPrFRiJ8M{^Bv1rr-nfiokCF$ z5m{9t+5&(!iX6dBt5GZtCq+xTCP5*RJa*$1ocd$Wxk6+Cv!U(8e0#m!EKc%qfSMjp z%gfwy_e$JiqFB-nfp9#3u%MoBND*=E+Oaf_?b~Bo0$|+XgOTU{;V#!Rlt8PYU zt7Q9GnN_W-v9@~*P`2coNe6eJq1cqPt;9i&iMCzV8<82|dHA1E%*dJ7kX_N);AJW> z_F>U$IK~2;6W5==@7~qT;{2ew1IN!&(lftACiD869Y-FgmS{rKn0{~q%GO|-lZ*mx zQs56x((R5SF@U2<136wNckYJS?E~cG;lX|H>x^HpI|hyZR=wZ4+XiynY%oQ~`wjB# z?P7XviJZs|)9C5PR^x_&KRZl;W3!Jc-6@lrNloS)fiZz5g?vM6R*L{MEenVe4An}v z>f(pU#0^_+Nf}|kcqSuNSy&|8gULC8Y0bI9-$9sLuNy3wf=DEeBw-gkvv@og8C-x+ z37TPEsLo-MuxSL?O&9_X~@39wo$F478`tt>nJDht-Rch#6q-;p5H z6LH6EV^IRCy(kJfL59ZZ{>T!=ByvuQQ;kk>8lGx3$8$idRbTGc$?~{6a>6nPESJ^1 zrJ8`9rmmryK9jp9`#Q}Ui2+luORy^mksJ+4`Jsl(0u#xU)%vC8>R?ss}oo}uT#?RsIEJJk+TKV?>eH2!D80pit>WEpF0;_mEU^82ICu!m3+v zB``PUqY1ne`1PpQ%1jh@cusR7=VK4-x8*wm1*{-e&Zx8uPh%#J!5fH9clo$_yCl=d zfP3|0Qu2yS;~gkZEX!b$Se0xA|JL&%yC%H_8c>;^P#d+7F>4PJ(rM4?)I{W2Bt#N} zPEiPEIZ*H+p@@qC7=kxoN_%r?@v7)x?dxI-khWQDy6&S`e+o^s0x6W6x=d5PjiliB>X~6x7t6W zFNY(PL2Fr6INE(>M0ZGNlX%qcwl*wRG4i~vsuf#lh*l0sMFZdRq1oTG;*D*_x>XAq zfsK^BMf@Sv4kZN|?KT@kRBZxyS+rjHYyl(2IA0F37a@w!e{hK5n#2(}QCVwAJ0CzEDTd6+Ak7*bU}$#9I? zCo}x;q|E+_MX|-EH!qeTI$ObCmL%GD~r*VHOrm zaaS_!M(i7Bv}ESwrdY{s1v~xCHED*;D6pI;_Lsejoo#FuH}E39S@hkCZXt?luAN$! zj&NU~wW+C{MGtFD#1z&*e8=jzQjy|GQIn|uNYw)3{-ID@zSp^1b#+mSVHluA7P728 z>os6P77vk4CtlhC7pe@_*e-D6j)@92HdW6hN?ZeU>1o~v&V9Xnm`Q8}@- zxiUH4x;=+8+gXuuTUsPMe0HAFt(Ic6x8L_u?Iz=!rmU&c+o2WA@OrD!Tu?jb%{{Xk zfOe_}ltN|S12rj{xt3zHID6zg#e;K8ZPMS1h7nDyxhkun-ly7LOTgXw)lYtCR(fcv@FUF4T!hM?~n{O3U)dBqfLG zzuYpzPdOl~vO8ps8@nlItfqW%n-un8rN%}D>jIM0=9}CCtr5;Qtu|aCsiM~G{dM6n2FE9H7*Mpg~*M|4Osc@pC(3tn3%v%&~A zS4=74PL{u!FA4<7%T#%s77zm9GK)u@YW{3cu&q#?q-~5ON}JF!4XT1S#gmkQ5s$*& z3KNL(5RNInXE?VFC*tw+ZMLVpV<94i6H_~-u!`cmz+$Xxr7+UX7)?Ne73Hc~hvG^E ztolQUA~oJ@lLM=pm2^G=W2@{98711JL#)Au3i=dkGg+xDnr2i_k+rGPH1+JztTn6< zzaddKn}a4hLsf@mP%izXs=@e8v>sc66kByBvvwl-AM=aG-9bsowZN1NLYjt9tR7lO z_VsJhb=WF$KD1LTv!@qQR>inXGZvMoZ?9vNkPIRV`X-wv$}wfJ<_T&N5TmhMB=Qu< zCo{%2n;cG#WSZ!v`tU>{*VWcfxTe)t3_3DAf+WowXtLV2+zD-gVJN{>u`ximNq_|b z#R}NNhD~H?+XF4fT5Q|FF+9PhpijJWZifKHg5L#+*L!n=o80uecm|X96Ypf67oh&u z{jVJ_{^ytPMyGUFiHIC9;q9&{8sPG~F2DD|*Ia(@cE4_^KNA6|R; zBbPrgzOhry1xD4s<38jLRt1O=UQ;U(@GC`>?+K~qzT)vL zn`pHgQ9hVF91m|ZJlw?ea@RB0OYu`4NWr+WB{wp9Mm&!KLd?nCH{Fl@?Cj)T<~J$Sq=2@)XQhT`}=AD*DVI5Txyd$0E z+3aN1Dw!iX(w1z$GU8`d3WN+5`0HOoWl#R0F0^6v`vVJR`7=`Zk4g4%Bl?$ z(?XrFT9c#)Tj?M$tKli>V7@8-(z2MxWrA9BO>tV$uSZ!?J_N4*C8_=CwMKmf%p`N; z3ce%aQ@xK(2zq2AWze}Z8;98#DKpvD3Ly$Y5Hf4PzOA;b_+9#9bC=e}9a!ApjmB(` zHJl<$3oK-{U9{5(*6@2=9ooL7S@z0LHhOzx(^VMOLR^wgU0lU=nKo5gG2s{6PL$g1 zrtF-4m__@jI>zE%Y29U=4B84PX^<%fHPca*9VvT{3Z)2#OEgW`+)!q030-4cvUB8U zq=Hm4S?&<-l0uS8U<%7WkcqLnDp_Of@*NIq*%&-5f8|I_1j-?n!-FoX{^I+7dZpJ` z8E;X{>XyxcZZL~tCZ(R;y(yE>hQVrensm6`oz;Yeo#fFVveuYxc6G$UNF}eY5(9)y zSDeAXQmDX-*Db~^U98|SYWCpG`;|b^ZaO>#V%;H(l8g?|2CTO_$xbXOQUfmga@s@5 z%P^Hiy439qQ~`|5!s>MqN7Sapi3pGp0z=*8QL6_iI7Yhrz<&N!21msari-5NNv^4q z-n3_nAUTcaaEc15q~fh<_M+>dNf2S~b7U9uq@4~FYajCFjnJBXqU5u6jtF@%-HLJ` zH)mbV2O1Ox8kZ0q^Qy@Yc?frF)16uPS>}};+HgzNHCVHaTCj$1UnB}@d&=;#TG;E< z+<8DE>?`<+0+@EMrDy;X)1GLnw30{cF&ya{xwoEQEyFl@c%eJ0!~=4f&Hs&+c2VJo z@D_25DqbTB$)rW;Qi4vc?2K99JQ0NnPe0tENq+Jy>)VAa34ZJ(LtUJcF2;r^kqqi0 zF^8pR#ZYD|xGte^#VU#~Sk7z;IT|{&qWtq2>IH4BMnas-dFfZ)5f|At^Gvu1EDl-?x=8bu$ z!11l+VPu34Jcb?|92*EP$nG+Nnlecx>)KXPQw|%a%%cxGutvVF94y-^F*1~vV!pQ9 z#yZhlbZn9N8L3(+!qZwq6Ox`Yk=o^Gm1K09wW;xhe79~qlGL0t%h4ZDNRTc$vc&UX znv04yw>`?hky6eTNYfpQNr* z9u4D4fFuI|k%yr0iE6n4Gf{aD+-0@CFD5R>yJnd~;{cOI%s{9SB#TT)pw2Lvk z%v}p`nycZ4Nj;ft!}C(&+~!3TmtLU@7Ny)%XuSswpN&j$Q0j0yBgBwgLc;8pin}rq zM=zFTpT=cziD3cKoa(DmCUltS-yTimGez}L9O0o!gB0CX%{0-9h47Mk(C==dmOczp z!OBoll97pep{<);rt-2_MnY)&TUCf)hev`z<+#>E6bviZ9GvFzg;9Dm$|cDHyG3)$ zvVv_0w!CP(B*D{cZP}6>@xV`*RmOPsjg(lh60Sv@X7nsJkk{pRD|Kx$3&Pd1W0t=t zd5CVvMu~W-M^ZY_>w6-vCHhUdi)crbtgngAalDu(-OKGUUi*K={Yg4+UTwl{$-(5EU@HoD`*@SP#nD^kq&Qd^cCwK-Sa z2pOOe^j5Wm%xp1j;}rw)(k(f@fh7-+D|{F3zB!>X4b-Wz^FSuA)ol>`_xNzHd8rVm zvpsBgB?t~_`5;7kvSs9DW3O5uP(xBF?4IYTVR`ZhHl5D~jmJ@2M>{#|MT-#cWoHvz20h6`u+u=&C zhhZ3tN{SRe&Ik#SVI|ET0Ktj(Bhy%B^=INZA#0Y+UkZ{=QrJ)3>m^d#+QbvLjvR0q z76KE)N`XF%J4|u7#!4oo*^h?!q~aIk-p1HXtYJ4qAH%_7&vB{&W#P=!Ohrz^H@YJr z;wjq|Mrkz#PW7>js=8?)1PnLCD!J&>?J>jDq{}5yPb#3$nh+7ga@2V#L4=7?%J>|{ z{UT`GXlNFM6{d4cWnp9H}!|(~f4+ zeZ*ouelG>c2d>}C|8AO8jb0_xSsU7?RSn_oE%r~|d~@xX&Y2PeV^hoEGsUiBW9nX2 zf|MsNf>&)6llT@x9*aPBJS4}>Zit6OGBVV0d%`1(rIlbAmF8Wlvkg;DgtUjX>zqQn z)(rDQy&=;rnF`+2gjOnb+_tznY7sQTm=cX?+mv-d1gS>`i_>dPREk1VXFiDv@Zlp_F690xRUp9{%JelB)1yI9ZFHOjh3&Vw3B!eGkC z3*%6PXhj<(i{n-Z0vfVCNwT)gHMg=V3wBuoB8Y+00tuJh1#0}LPh%~0Bi_@%c>-lx z&uu41Go$}#qqm|!>sp8X3|VS|@{w5@m9Pxt7=?ZmEuG{OB?#ChcR||H)}gLQSs4nb zn7S2bURj?bS-&O>#Mvt8zA-+t=4J-Df;{vt!pj}YEE(;%?BrGpFzwKNs2zXO%Vn{9*}7DrPsN&gb%sYuM_M;+=--+6k)5V;=5G6iJq#u6>geOlFj7-+Fo}`YLy!D|`6K0|(3v_Vw7oT)U zrW-gi3XN)|eCNZrp#2CS6OR_9%(4FrEv@1|eGJ*LtYhzz;PtfhMqTCHaGpOOT$;iR zQZ;gJI@*(&4eRQZ=aED$xnLY!=6l}M*Qf}*cuRldrFSd&a&UYmp}*n3?$KB--XiH< z?l0Y;I&S!;JvlyP2Tgk(=%VCpL<6fGr!@G z{^$!O)>Rd%R+TBT#f}{kPaW+})_`sGRGh`VK{Rwa0SvPB<5|KToG314k07~_PB^4m zVJpxS9_8dxf3>xzR+arI)L>$tPGw7gky&!oU6(0=B!O97%Rr;+t)!_mMQvvnMdI!1 zV}0A|L#RvvO<+n=r`1jtN6Em;VigC4y{9x55k^ymK1dTcNh3wsP}#g}EOYNbIbHC{ zPD{f6T=RYJDYV3o>SvWR0z1;9mb?kEv)1Tn!+`ZfVuPd|T&mAFk*u9dEz8GI*F*T)aUH^~E#3>&2S-{1BW$uwujMJ{o?KQkAxf^{ZtW+v zv$(y*(oXPM(FsX-ikfYD!JmAIoIzU;R#&lZ+$h(c!cuyh2`~3XB?E2bonbNsMTJY< zi-+hDMQ>eo-wcltnY>M_J45Xtp<~0SLPIJx6q15~RF! z%Ux*}=7Xp{QFE2BXJp~imB<$H*U7eYE-9V}nP7y;MU!psCIF*~_r(i;4Oa!ZKRXl!#fRx?ATI1`PZwe{U9}sET3cA zY-4m;e`rnpiCk7tL6(arI{HhmgLS3r*m@K-P5>PD@V>#w|+4; zz^V^|-QB8wv(xbHc-BP@1nOyP%YmD(ze!I`Q;G9NLtw| z!eOoi><)OOxv=TK%YP1;Cws!T@05MwAj-Mq%n=#%XQDpW^~q`-rO6eHf#j>iImVOmsJJrzyuH)A@7@$9;Xo_wp7|XPTv%S6 zXVc3p*+&QRg5*x$P;OQuY7XM;nro zQUcWstauZLdl9l=WTASJhtUs7*dsY6blNqbjTV`sJ=F?;cIc~d#{kOEWJZrAH~}tF zs0*q>s>h>l3aO-(m@^MLrWMGPm2a;t!n!|!=*uNiT8S_V4WY9G_N?(-xUq&9-Q#PF z;Pb_okzG;|i;+xm*Dv9A>A{@{lJo8;B}gYS1ioYj!VAzx71IcVa=Jl1I5ESRP6Nmf z8g0C6R3UR>?8!F6k1^u*X7$ygBAtOtZR6oB0UiW!{()JdGWY|#BWw^5o# zBCiM060=Nu^1vA@Osrdej0d&L7TjaB&EH0p7F2=>O_=)|k`(z>O^rIG^-{2yj}gZT zrck!gYMqJ!EO#xIMy?5!!cn|O>xx@MydjGiGk%m!u4Hj7LRYdp2uQYMoRp!5e0P;j zbjzd@8ObU!iR_G!O1l9$%DEqQw6lIyVW);oz2}T=Wa5w|vOyN&OWm4ZU~@amHY`6f zAc$tf3&<=yEZc>aq+%>!&ir9;eVuVD{xFY%-zc(JW!>Z$5V2ywvJcA@%%%@WReFuM zsm#oc;;;k)UoL33eXq07XSWnF9jsk4i_lVO03APbp*Vi-RQicSNRWE)H~pAbbCAe1 zR!6*@Anj#P+`$A}1sSV0jTn8^;P(Da6D?$w!IM2BRp4vLI}Y0St< zBlWbw1?>Ut&2{!#oCZ_OxXgA@SU}dqWuHeO4~0@CYAY5+K0uU#Szy}lE+3eZNU#OStXs@2@O=TcyQ3NlKt|}bD1yPpOyb8D5Dg{hK39~5fjJB-i zX@PU*B4y;|11>b3=OU*NhrA&yIwW~S=+g2YGD(&oaUXN6SitI>K&S^`iHU+qpHH1? zFJ!Od*aV=}b*a2cx2JKi`K6SCbpFsqR&*{=nGU5(c9Zw&ejke6-}aez27q=_#2Z!z zWzs!mhb=~ESWjCGI?x)(OOj0+@m<`C8H~zc0p{shw?K1c66#4s4W9PP>Xs)sSXqM9 zMMgB5Ss}$U4C``aC|LoSgxf8o+5}9 zN8Wmt6XK5uhg7_l8(y2WRHb2?#a94B#As4ssCpz0A55&IM5Kju(-+azICDG<*rXKH zIzy=g)MKcAiZT?MaZT@(85Q#*c1DPan*E_^FSQfa8)HHcnuua(+zfWj}^{WkyGo#5CeIFjZC7gox|1P+T$ zja(3#Zn>L4@R(s@0zX^9Fjf-6(E4lfQ%);AWjO*PR;wM!)Zl``U*hDJ%~&nt(nD(p z;dDD3+b(LhfM0|P;8ZZD?JSDTr2SMfD9z9qN=%ld=x&1Zx-*xGYA(*4J@T^Jxo$@S zfA5L;y?463Jyl$L?(EFoBdnR^+uoxLVoC*m&)vKK`n?BkDh^yfb^Q&`zKxVYfi-vE zJ+`r52PP5f=h40AF?3|O=O+&y*t`EZdk@}J>_0Gd!~SRQXBXzRr-#UdU1Pao$~>T=WkH#W8WM&c>OJl7-}trQ(nk(ek|tR8P0TIsHabyzO@|rfyw>X z9)Ww%7JFxKE7{{p_1ZpEaI^h9X$bak_g`>f=Gfkw%lkA4Xlw7S)OgDTm@01OHPzSp z3vV%Z_a5eSp|wqnH8nQLdt44o-gxcT?2Q{V_;Vdwr2~`CnLM!n+H);-=eG79Lq)K^ zr@dw$doQ^Dd6dZMmly1AKmEY|7rfv=@r-8_`g8wNUvS_+@ghz=<90s3@C66cPtSkB z4f@lb*#CS^M*X_4^GCR6{~n$>z%vK;JTD`LH_LXf)!VTl^p$3}zHG0i*I&ho>L|f# zodnT(r?~%hkde{?taJGrHH{{LrKa@vI?TrVy8BIgEB875#e9dK@%Fabb>8KnXJ{G1 zZ7(;M%%jCk5nM-8(^Fe*K5$QGnJmryZ))`0{I!nFhFiG8pZHS7(LTGtyy@nWw~dR(f9oV)i$PYMYlI9RxQB27Q(vtc!d?OzDfVCnfraK4JI4?~ zE3M`-WLoDib#_E76VvrC3T{~8cfQdhN@cY$WCtLo*B``PDm%6NKruor8gCX`-rHcA zLK8^fLchsypn#KgFx76*F2l7ig~iCitYfM28WyMliL+AQ(y44I;ZA0AdnUa?r_e-dYzyb57i5>!I!>*dD%c}hu?Tl_&TfCXZb`|iCMt&de;^e z?9L)9XcTK(-Lky}B%htfqYq9yC;wK9330@?+_st9qO@Lrt9R~RwE}=p|j9f?g>TqDv=mZ7q0WQv_985Ta;LX zko@v`S&=Df{<=J3rP>yn_rFQP!qXoNrEagR z-&^-r&qH4}IoJX2Y%Mn>c&hi(IP#PCsIXv!IXFuuHD52hiKC2C7E^T?5E)uKJCbzxp}Jt{Sg*rfLiVBvdFxBc+yjka>Y- z;yChamdhLKNu41C;BQ51#3oMQ+R%446o=%O^o1CAD{~&p%W-nF649xP0+V`hfwaI4OdbgHz|5|<$n(i8tywh8sE`jXy6>>T>P&{@F+0ogEH*%*U1y1~pq3@>B+h*?YnP^ey? ztLRo#dsC*6DN35=v*Fr4^OKYpBVTUJ6GPO>k|}2vu$${pd(r)hg31_;wqNo_SgY3> z-2bLJc##3Ya?az;AyfL8dPQS};riE1YQ+}f3PRsz)fc{FGo~u!WEifPb#fJrYjw?9 zlA1GnNTv;D;w-k28<v=@!ea%{->_gR{GhEyb*4fd-EnACI<{Ub)DwV=Mt#eXd;wWWGK83uEbOCDS?}da%-L6}R>;A%Irm+^?P;{8d)O_H++{gadm-1t)Q0Fd6;v zV_<)d0t3R37L6ZYPPfosB;nIow9}othz|TJ$3MchPap%iFfT{TOs*O^0v`-lK&}WGBha8emDtxP*1hp{2gwacQT(d zgg{6xsE2>&G>8jW>2Ja57Bwj{(!kobc;yJf?vTJnh`@^xLkL11x$ivFnO{Uxba{7f z>4w{4m3W=blP*m!o2#4PZW9cTHOY8tR-t2y0&RiOY=PM-kAI|83t_ejaaEMxdvk-X|*|%d*M?NtKi)NJFUyH8>Whv zxZx94&rWypDshH5*ix|5_xvtc=tSnSpJ+7>d;UtgZF9qcf7sJ{_yW2_$;m3MCQ--w z;3>I{+K*Tee!!Z?OLk=aQ`NTIu%#t;t%m%zoiLecle12VOoE&d+6*4(tN+XrrJp8`DF`JTWIac{*g-LBCPs~+MwnUJOhLtl+r zPPgZUbhbH`LM2E{SXO(B2~knEARB!LrIMP0gFMH8lokUG+*z&0tutvql(bE4?qI5H z$7r5M5M*^Cp`0FS9!huBSD53w5MKa>dIo^A?&phSFbcabyLj35^0zO`K~N%IQXngrX{;QM~Z}(+q$?}?r^?j zU7J`rnR8l+P89h4uN&`k5;Cq}JltXws2K~hMQ7oYN z4R*W?el(8-dZ>U|<@KUw0}NIz zyNu)6@I8}ATf@=ZRSQTE3BZlx$I>qMD6zb23W>;+D+wRT>2esJYSb_)#$_cklp6%o za3Is5CW7T4OWdM{$0b@vz8}#n?9|ucxX+U&X%J`1scmI)c=36Jg!qI~r#%dr9XcIL z948c*G$)ZoHyW{!IJ(M0;?`^B!N3!)#@Ti1^*l<7`%1|G860W0dYQHt6)DA9N$e|z zkk%H##SO|5cx3`n6HSL(co9O!ek(Js9bUvqK$T@w?!%~S*bA{xI7v*-QG%o^X)Z}( zw-UuF!Gwc?(j;;M&afJIgh`DNMU_fAr`Z|;P*&KQy#9-DTK2g+>tgRdrw1w%V6;hq zI*}uYF%pFkNZO}W7qnC+%~#SfCoJd>mq6J=DNW%zXTBqVoeW_02ovTGb!aQ&k@+cp z&xwSfGIcH45<`Kqi7Th%9<-Hnf2K;b!Jea@5Rla^{rBB_b$j}SwD7LC`7uWc852id zrs?#jgouJoq>?=_&mf5bQpr0!llKGuzIc-okY4(Uc<;yNtw7( zxYHyG(WH4~e}u}*7$9?0R1})81UqMW>4=CV(jdr|?V<1qy`VAGG_ZbfgjH$CFHd%4 z>{o2dH>;%mHLYVe$_N@4wkRxea_l+y96QEUIM>Pv^mZjlPV(~O0jI5uw*YVxn|HI{ z*>2gRzA>bbVCY}PYgNL5Jm)X}((+0o1m)XJZ6a#DLd1d~QdCRuQv??6Wr`kjhpH{O zE85J`PVJ7AJn=Z`{GhW6sUS$UTwp{D2ov4Qc+dkP2zl@t{|%uPWLimV6YESUM?}p) z!uA3QY0YKILOhtL6hK69w474+whoHibL4`!{rr9Ru5R-7=jINaK1)<}Ugx)7e{eX zZ5U^;g%$N=2GjipyT>>_WNwM9*ACO@>Bm;%hJigjwo)St`Xq2eV_kJ#d#=%{)HRq` zovzE<&mm_DpjNsAm`+rMAR%*y(8zIm>6(Y1!$OMX+8j^l%6>{wZb^Cs(9V)ShKK~A z-pbE9fevyj22@-{Yh#Dq-0&TN;022>Kly(3c*Q$R9b_pv-k8;kh>RYu|Sjgmdk zMDUo5JP{sw9qd1-1mgA@uplH)`?3%#ltQ3SxAAN) zoS|UKlDjg*!}l?gVHJ~x-_cG&d6l!$4i*jz3u_A$paNs}!Cq;;JbjeQ9loV+BA>HK zQE+qHsRXA-+p~9&vrA!6?26L^c456_3$R^>x)JzrHyOf7-j0i7nZAUSq@H(8`jfj@ zKQ~=zfQeesNgloB4Lt=bvx=o>k&q&&$G1@F5-NvTS;p3U6cwJiX1cwx)r6rdl}g^e zYB=~sHe3`U*~^_26EOTxlLx!$9{GNQB5DdIP^c-(%t;a<=O^rSE3!~wvhQ)KnZVuU z3uUt>bn2zUq}wJ6S1l7cgfIcygb0}6*rd!|6Rc~?TRF$>%>fB(YwEmI-WjPs(xdyVzdmJ-yxh?8L=9WxI(bV^_CT8 zHeo6t9!k4SryQI}Kl^1-$y*hmZvNAl57zvxcs5>7Bl000r8!tIW7QN;rFd#PBMssi znw8axk&;3k(E^7RCci(KOjJFAMl0M&RXb*2XHu0opT{uEu8o=4X5+IL47tnW>1O^! z+TyW7_SUYb6`>oJEWf6b0lLTbkcL6||lwr}V=@kEw z(|rhJRgCHt3bhEtbY`~{SZ9uCVKBwmtvbz39QM-CgnW6_X!8EGX?HYuVcwdS4vlI! zNJaNK&YUXCm2uJ}BXtsZv%L)(h1KB03#1#NM|UdwoL7hnNf{fUx;UfHZts9kg>u1O z3g!;2Ww`x*FI}6;g@jGiR71duwIRt_984;?d1j_aVk@?Wct!pTF_j-EF+|Ky7GAJM z3AU9EYL4c|4J}|9J#%zde8q5Om_^D3Q87g~(JLq){YBl{V1|FG&Op(e9Q#0i!ni7& za3Sae=Y~BM1<1I{L3*7dzHpGZ%QV#DNi#CHBi*bsGv8dcC<^3DnDD~FT2QRmHDEj3 z{9qS@Np9{WiC8qCQ6J+7OOF92t2R~WNIg>;fXK&0H23SUYIno7T9X6CObvZdk!uv4 z*tvzBijkZ+e7h*lHtDdnrjdj{VC~UA5r6hw(5YH2>&c*97ItP^ zbtz02MWTI6jcdij>gP|0JKS5z0`qT&pGk6B#Gq2xQq+TXB#g&sERaT9qx)w%^Pmm; zM{S;OAPuc9sZb@k6ADNga=k28in)7*BE-CEpo=cGTDdk$uYC1hpd+wm9TBHU^{Y`n z7V_Om#i+-~Dm|;9r6RFeovd?OKSIolsg_tLGX$lG0;ePM+XpKTY>gGJSsD0F8pfM? z*jAe*-Ve6R*`?jWFBtb?JC=5jN8X}s<-x43%MBke86sBuh7+nyErfA~r+f zwxV8F)Zq1iZUMC=a0osjKVBTK8Jo|%>Ya5_hgczHjSFFrhUlQ>mX>?S&}|4D?9 zL-1ZrYtpAl0;xN1*4f+pGx{bYuh=eBE4@8DRg;b&)NVm+mr;OpyW~!k*s*jLv-9}5 z+wZ0EnL=k^CADIBvFdz=X(M9Sc-Eby;|S8N6MlOzo5eR#) zieo%@A-$ffRK3(a^$UxdJwwfL&@%C;e6J?_BgVfo{2(7oP5qlGAM zWG;ZS$}#$qzEP1L)kMG()C$%;tNnMtKJ%=;eb(5y7=d?4D%30llX z2*X?u#uA#gOytF2&0f8A;`IpSLiTcQm@BGCZwP z#u+hei8u8$KsU?Uw*(Nh$e{BNGC|WXp?(y-Cykf(gh7Mr4Fb!^3(ettG$~b%@o)1@ zt%;PhtArM{x4=#IWSW^H0g7UkiOhRWjMGa%w6iss&HW-LFcs(np@69+e~TfA0yRA6 z{)zz?#(A2{HvU|r*k2Wi^yR~aXzMHWb!kohpD4DpzUX13&4~hQUAYwvf-{w6<{QbI zLB0$ba7P{hQE)W0)GEZNoqVu}t%hNd%zA{0j`8Xf1;I`*o=?1UZikT3g5Sl4_BsdP z-6Wgw;+f{$;1lme>R;fbhSvSB9UnZKU%ngq?5+}_Iv~k!F#wdu<#%0v?}M+o{NBqS ze(;SCzPY&k?#my%`~g0^_VPzAe_(u5r z;Ou#DjOEJn1C{@36RhG%xKrC#F?1x`RS!K1NF=_)`y6L$pR>L0*)2=HttVQ8BJhZkgEic0qDE8Ch^=w0c_a^RKGedJ<3JJ4 z8@m5n*%q=>AyKcxc4Ew#-V#dMEK1D;-ZA25G{YMqM;s&ZnNSKx*}eI$)a(h z@TBKF&Fe;;k%Aj6{K}|XNFYTG65p6puC4BVe_53>yh{oSZ z8n=g*%5bL(09G>v0kS1w99N=`$d8FX(|BIjVH?1hpe=#?M<}A)<0_`@l=uyYoIo@l zrDk3m>X zeMAN0o|vwj8`J|YG=OyE?Qk}M4YwK$OL|)oKpFK`%o)_%H1l~-kR75fh=5T@0;!=& zt%-B5m_oL%WoSq-H?;N?`9sQjHxLJGm?pEoDV?|aKJzU-Nas4sqk%Kk0gB{O>ODPDZvPp_b@$D1y*x@B{q8_aZ3L>3N*7o$MI_HUX25z;%E+I|=K z&P9_U9TcgUK~P8$BzrpIrAgRTWSZ60gis?rM$HEjpJfTt1x=1rSZy#%6dWt(-WR!K z9nC3!nsMNoLA%KyDqW{xN=9Z_qYPP{`rjgE!?@YO9$qA(4uW+ef&$cbT4-dAw+HxA zMdG|F24c*-JCL)7_UGZLwoO*j@V!jI#JNbKjnklq|SJTXd@y*Lcjtp(o@nd|}-NpFyr5k^8oKj+xUT9*SJ@)+U+EpV@Cxa-dY#T?hXyb4iOC(f+Gi0c3(xscu zz*31Qe3f?((^TF(oWm8qjZbkTX%M;hME6wg%cziwdPC99b)(o#rnw09F$P%=M0*4E zQd3g)JN2J3JFMP04=V^kR6tUC#{??gp!hIHDW2qQQcF zV@cL5+ZC>l#QZr;WLo)9>=9P7O*(#?R<5cH@RGzNxH3^wu`g^kDFsEP)T+{(3Vl!m z;7UuO`frEM+>rR8!Lb+sQC7hs!4w7O<6H z8(|TCK3T)SNq2Hef-9?gI1V}0F3Hzl5rtU`%7~V~CE>uK7?h(A=2g)w8p;jH#7fWc zcRGPaBABr#QK2TB-kptj+U1r47&?xOFD%MZik0+0*$oy~Zd*d!Sprd#Sl2~4cr+){ z*((on=xH~?7G;tp7jU?~D$T*lb_|6Qy0BcPxH9-8RN$?70>y&&E{T)-ZpN!?JIMvN z*S#IklNEkhEj`j{H74vi57(8d!&AUOQB5#RGBWA3>WE~Z%R82hP^ugoQ|`KI%KGie zp#Vzsj1<16WTDyj;yJ2RWF1kM(Cg?_O{w8ZYzj`bh=U1kPLJn}nPU>}rJkvdAGKGf z1c(&6=E_EFg64tZ>;uYTr(r*I8@Z&XoqP-tk>eezA)`jF^-I@ zm`GH4R61mno1GxQfeL3aT*XbcRI>OX6lYB%cs+DZ2OPP+V?^PVTE)*8Q!E@QqS_o1 zXdx8p_axt4n}Tdq{h;l&y6&c$l}N-(Vx9#fVrhv>j~dM2vDrRrgqa#bV3;mwQfq?s zqP;cxW%r?+?;x6wTvD&j9;zQi^kQP!>2Hc2=;*UO&tqzblKC5jZt0Xu##>d)9(gj& zY?7z65*22x97I*59CMs}Nd3khk(NJ&Md>y?+rd`+J)gYFQZsg2V;8Qlq?B?<@DJ=9+)Je5EP?k+TPHFGI(!bhCp<0HR*ow6h znV5oCWXX&BNU}P|F(5p$6j7ky>7$IPw0~7$mkSM;Sk5d#BzIeTRrdMrTdO1b7vZ z2QN5;)f16P0))eXGqVW7Km~NC7>)b6gieeH6l3xzjAaV#tT84MPWvjciF0v=m*#>g zNfOaa)LgStZ>#b?^(r$^ww4us${dhz)uzu1ud8wF9X4>awQ=}l=@}^sLno{>>MZlW zm3BzV1pTSiBtdN>43jXCqw3BGSxLf4M?*f|z z7%J{%l>xXg!Br>Y0j(W;cgrXpnK^&TH)ba^*e>n#U>P46+Uo>L!2r$_%c_DHjVUQG zk21y?W@AS+*YCExPwz&$sr+uk-muE9Y1=KH!hbn5hiFcTZ(|HXKdyka#+DhPIw_3K zArDMq&b|DXUgxG7Zv$QG*B3oF7UEZYm7?Q56A47b2fEA)vQ@|fb<0rY@IoFQU61U~ z@<`Qoi2^VA7BC#{+T3b7SCVm_t*Sf%V>O` zjtB4aQqSTxWU$H(q$jlS)XU5@pE}w%9YrDmnlVb@8@WO_3wW@lGZ-!`FOKi5n*-sl zh&D{hOkip9DU@}P=&wKO+1u#$)Q+aKN9bDC-g#N8h+-}G&XfT}({37jTHnZsS|Gws zrF1vIwlTOlC{eZEptzM*O;y6UY=FcD?nAGZJ5<)xG@w5rsbz{uY?zPGO+AKQ&eJSR_v=zg4m*N(Np+hd_rNZ3WpdtVvUs@V;hhIiP(tu1Viw{EJW)_PT z*9S!jVA+qVuzSLoHv*9seHF(_N`(fN)tW2{iy(WH66Mp_Qez=DtplV$7!Ep4dWtIfv6pf{J^OpCguR_0YR%IraauKxTth+iEpro$rXqkaS-aqxe#MT8FJsYRC*UR4&vU2KJuEDGyBk+LPbt>#_t*3sQC5RxmqgDWLf>=_+NsiCc$ zQOSxZDrQdpwvQ5V8k5D(;v{+HPe*1}wihA;GbEqaNE%iMOvii=EKEUhRioR4^*91HxJx={Y`pmnzufa%Q)ZI9REPie(yFm57_O8+Ra%4 zNw?`WioB(MDz_d~0ko&_3iL&_}fbW{i>CiV7` z-+{TqGkSUU(Z&_ft=Eiq7UtO=jQltQUB~(IG6IL3J7ct@D2>j`^sji=Wqe~m5sK38 zQsk*(N%UMQ0^5#AXoY)VOYjxyN@;)x?!hW7yG4~x%Q;O35r3+X&0G_NE-^bKv1+0u zHOmqM7xeXlqjH~p>;^ZE(-7Cq#+?z=a|VK`ip zg5~)gj#ybVCuvWA+L_}mus%fs&NsDoxt&*E3WNoH7oQm-y zFlFNS`4EA9PZFkLw}@3@c+ngF8O$W)OxBKXKc~A~wafv@)_#&L(^mUKXwC2K0~pe2!I*~^T!ACc!N z(ukO#vv6~yK;t|yaa9x_MT*rk&n&I`(|%tViq+RMmBFc03Fa#@Ze)njF{|WbGw!mO ztPFau3Q}|sou6!A$~Aob6(AP%q}ZYoiu9C7YDng0%$Db_o@O_o z#&0Fu$n~%}HFosp9RunmwjUgFhBSo)X>N~cc>~BkDQ&TqNl04(s~lCHfh)bzu2M1t zCe5hTa|8bJ4dw0}!}*|Uh!gaMI?n>t@-E(;%z2`q1VgUogfOajhmeZQ%?+?MSG0EnR8#&#NF55P;}&lleM!J(3Tek;`EXWtzI%>4C_(d1Uu5n?&<-V zG+V!ncqNMIETwIcXok}jPpfWuiUf*o02%l}?hQj%=>?tMH#DwB(?XKit0O_8J z&H)v!h)PSJU;&|MZApMat$E*dtaqI%aHF@`SQ$9{Vm5-R8lb`|Uo$>)o5YJFK@F8f zHfd2iHp(Pe)Em1yRcRQ3%KVhvuw%!SxrHVW6p?I<%ok;fmb{Z+Sm}|`r+N=W4L1TL@0$L zYdr6GkrRMNh(aW~iIL8F*dhhfAymw06&e(bwn&3qNEYNuyJR7#)yghe8==|Fn7uN7 zEWSdgaHk*OkIgO>rhTB=|1V>V4PFFc+4^%!*6dx8rn%P za)BjP;jkniRoRm*esUFaDkv>4O_C&r?Yi%~4x7E}WRNytmaSa~u9 zRmlJ8rI8>2M?i0^+D2GozQTfw@&&lljQ!F`5oe_`IBmq?$U6ovUB|uxv^P_kETfyo z1JIEfd{z4@PchkcvSG3aE*%dEl{kIIwW%LKY`b>68hM0=6+d;ACNBxJ=r||KAxVS? zZ@vuLDd`S{X$9ryjXslMXdz$CWoCmn^$sjSINRv)rebnYsSk1Cd~y8Dh2r?RQ(#K3 zr?j{LQ}*z1y*MaV(Cmh*4lH=0H=E^+RC+s^ACF720q%fEqKy*!k+k-nOvYMr5G&8V z>NO_&mxz6d`8sWmhLej`o&s;darVWSW@ry4JKe>7@mz0Tr!~Jfe^^{=?L9cT--6X> ziKGxDzd6$Ip8mS%d6iP_|F5t!$!#i#qNtY={SgDi9#A|(G=q={Vt~L13!xywh{drs z&bjYZ)wg1aSrpsV-q$zvwYBYhexuzU}>T5A9AhA?MlM$-1F+;?4#X3WfamQmj z-4o?L(JIdYpw4d&oZ^bb23YxEO?+0qTgX|`N1_-Lk1`|j;hgjws1f0y2 z4!Tm!des@nrK;u zm2}B*?x3waiq!0~2cGz#u=lg7?-h15ZoThsjxfI}Dyx#^#o?W@zO*`u+vT>vvaDw2 z&FL459_U6PV98uxI#5s>)!o3Cm;of}To}nCtU-K&1f$vqQ~L~AH;IubWJMEqB5X+; zcgPQ-=*tC15ShRwca$h+iDkp3I{PAsRwkamId_5J@AItAtB%|pYV*vJcxS4V4(XwS zM7ngIhLCF+IbE(WlPAAlXReVxqFJ{nS}`;BKMx0H^VU}ZJ*)%V$=z+VfsXkD&H#v- z@{~4n@7GjumM~7HmO=>DZYx9_zf$ScYeH`F@^0Wm^zjQx>gc91Kt@ex7`a0UaSoNH zP6$qRc|&&LD3#49;!)tv4$auSwT5tgqwSU|41^jS{+RGj2bJeG53zfRuq&B zOI2ujPQFz{_-VtQ<8FW4Y{$(rkQupR z<*{bZc_FXknirCl;Sv4-+$4->lwBGxCyRK8Mqkp2gjT_z1u0OlEb+Q=`netM9pitHmVUoCpw}VISbrTyE hII>RRj!=B^3LHB{jEfd!20Put=Vw3My}kW-_y@T~?zjK| literal 0 HcmV?d00001 diff --git a/doc/locales/sr/lc_messages/twblue-documentation.po b/doc/locales/sr/lc_messages/twblue-documentation.po new file mode 100644 index 00000000..7c302577 --- /dev/null +++ b/doc/locales/sr/lc_messages/twblue-documentation.po @@ -0,0 +1,1885 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" +"PO-Revision-Date: 2021-06-27 01:40+0100\n" +"Last-Translator: Nikola Jović \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 1.6.10\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: sr\n" + +#: ../doc/strings.py:3 +msgid "Documentation for TWBlue - 0.88" +msgstr "Dokumentacija za TWBlue - 0.88" + +#: ../doc/strings.py:4 +msgid "## Table of contents" +msgstr "## Sadržaj" + +#: ../doc/strings.py:5 +msgid "[TOC]" +msgstr "[TOC]" + +#: ../doc/strings.py:6 +msgid "## Warning!" +msgstr "## Upozorenje!" + +#: ../doc/strings.py:7 +msgid "" +"You are reading documentation produced for a program still in development. " +"The object of this manual is to explain some details of the operation of the " +"program. Bear in mind that as the software is in the process of active " +"development, parts of this user guide may change in the near future, so it " +"is advisable to keep checking from time to time to avoid missing important " +"information." +msgstr "" +"Čitate dokumentaciju za program koji je još uvek u razvoju. Cilj ove " +"dokumentacije je da objasni neke detalje funkcionisanja i korišćenja " +"programa. Imajte na umu da je program još u aktivnoj fazi razvoja, pa se " +"zato delovi ovog uputstva mogu promeniti u bliskoj budućnosti, pa je s toga " +"preporučljivo da ga s vremena na vreme proveravate kako bi izbegli " +"propuštanje bitnih informacija." + +#: ../doc/strings.py:8 +msgid "" +"If you want to see what has changed from the previous version, [read the " +"list of updates here.](changes.html)" +msgstr "" +"Ako želite da proverite šta se promenilo od prethodne verzije, [ovde " +"pročitajte listu ažuriranja.](changes.html)" + +#: ../doc/strings.py:9 +msgid "## Introduction" +msgstr "## Uvod" + +#: ../doc/strings.py:10 +msgid "" +"TWBlue is an application to make Twitter simple and fast, while using as few " +"resources as possible. With TWBlue, you can do things like the following:" +msgstr "" +"TWBlue je aplikacija koja čini korišćenje Twittera brzim i jednostavnim, a " +"koristi što je manje moguće resursa. Uz TWBlue, možete raditi sledeće:" + +#: ../doc/strings.py:11 +msgid "* Tweet, reply to, retweet and delete tweets," +msgstr "* Twitovanje, odgovaranje na tvitove, retvitovanje i brisanje tvitova," + +#: ../doc/strings.py:12 +msgid "* Like and unlike a tweet," +msgstr "* označavanje tvita kao sviđa mi se / ne sviđa mi se," + +#: ../doc/strings.py:13 +msgid "* Send and delete direct messages," +msgstr "* slanje i primanje direktnih poruka," + +#: ../doc/strings.py:14 +msgid "* See your friends and followers," +msgstr "* Prikazivanje vaših prijatelja i pratilaca," + +#: ../doc/strings.py:15 +msgid "* Follow, unfollow, report and block a user," +msgstr "" +"* Praćenje, prestanak praćenja, prijavljivanje i blokiranje drugih korisnika," + +#: ../doc/strings.py:16 +msgid "* Open a user's timeline to see their tweets separately," +msgstr "" +"* Otvaranje vremenske linije korisnika kako biste gledali njihove tvitove " +"odvojeno," + +#: ../doc/strings.py:17 +msgid "* Open URLs from a tweet or direct message," +msgstr "* Otvaranje adresa iz tvitova ili direktnih poruka," + +#: ../doc/strings.py:18 +msgid "* Play several types of audio files from addresses," +msgstr "* reprodukcija različitih vrsta zvučnih datoteka sa adresa," + +#: ../doc/strings.py:19 +msgid "* And more." +msgstr "* i još toga." + +#: ../doc/strings.py:20 +msgid "## Usage" +msgstr "## Korišćenje" + +#: ../doc/strings.py:21 +msgid "" +"Twitter is a social networking or micro-blogging tool which allows you to " +"compose short status updates of your activities in 280 characters or less. " +"Twitter is a way for friends, family and co-workers to communicate and stay " +"connected through the exchange of quick, frequent messages. You can restrict " +"delivery of updates to those in your circle of friends or, by default, allow " +"anyone to access them." +msgstr "" +"Twitter je društvena mreža ili alat za mikro blog kojja vam dozvoljava da " +"pišete statuse do 280 znakova. Twitter je način za prijatelje, porodicu ili " +"zaposlene da ostanu u komunikaciji kroz brze, česte poruke. Možete " +"ograničiti ažuriranja na one koji su u vašem krugu prijatelja ili, kako je " +"podrazumevano, dozvoliti svima da im pristupe." + +#: ../doc/strings.py:22 +msgid "" +"You can monitor the status of updates from your friends, family or co-" +"workers (known as following), and they in turn can read any updates you " +"create, (known as followers). The updates are referred to as Tweets. The " +"Tweets are posted to your Twitter profile or Blog and are searchable using " +"Twitter Search." +msgstr "" +"Možete pratiti ažuriranja statusa vaših prijatelja, porodice ili kolega (što " +"je poznatije kao praćenje), i oni takođe mogu da čitaju ažuriranja koja vi " +"pišete, (što znači da su oni vaši pratioci). Ova ažuriranja se zovu tvitovi. " +"Tvitovi će biti postavljeni na vaš Twitter profil ili blog i mogu se pronaći " +"u Twitter pretrazi." + +#: ../doc/strings.py:23 +msgid "" +"In order to use TWBlue, you must first have created an account on the " +"Twitter website. The process for signing up for a Twitter account is very " +"accessible. During the account registration, you will need to choose a " +"Twitter username. This serves two purposes. This is the method through which " +"people will comunicate with you, but most importantly, your username and " +"password will be required to connect TWBlue to your Twitter account. We " +"suggest you choose a username which is memorable both to you and the people " +"you hope will follow you." +msgstr "" +"Da biste koristili TWBlue, prvo morate da napravite nalog na Twitter " +"websajtu. Proces pravljenja naloga je veoma pristupačan. U toku registracije " +"naloga, morate da izaberete Twitter korisničko ime. Ovo korisničko ime ima " +"dve svrhe. Ovo je metod koji će ljudi koristiti da bi komunicirali sa vama, " +"ali naj važnije, vaše korisničko ime i lozinka su neophodni da biste " +"povezali TWBlue sa vašim nalogom. Predlažemo vam da odaberete korisničko ime " +"koje se lako pamti, kako za vas tako i za ljude za koje se nadate da će vas " +"pratiti." + +#: ../doc/strings.py:24 +msgid "" +"We'll start from the premise that you have a Twitter account with its " +"corresponding username and password." +msgstr "" +"Počećemo uz pretpostavku da već imate Twitter nalog sa odgovarajućim " +"korisničkim imenom i lozinkom." + +#: ../doc/strings.py:25 +msgid "### Authorising the application" +msgstr "### Autorizacija aplikacije" + +#: ../doc/strings.py:26 +msgid "" +"First of all, it's necessary to authorise the program so it can access your " +"Twitter account and act on your behalf. The authorisation process is quite " +"simple, and the program never retains data such as your password. In order " +"to authorise the application, you just need to run the main executable file, " +"called TWBlue.exe (on some computers it may appear simply as TWBlue if " +"Windows Explorer is not set to display file extensions). We suggest you may " +"like to place a Windows shortcut on your Desktop pointing to this executable " +"file for quick and easy location." +msgstr "" +"Za početak, neophodno je da autorizujete program kako bi mogao da pristupi " +"vašem nalogu i izvršava radnje u vaše ime. Proces autorizacije je " +"jednostavan, i program nikada ne čuva podatke kao što je vaša lozinka. Kako " +"biste autorizovali aplikaciju, morate samo da pokrenete glavnu izvršnu " +"datoteku, koja se zove TWBlue.exe (na nekim računarima možda će se zvati " +"samo TWBlue ako Windows explorer nije podešen da prikazuje ekstenzije " +"datoteka). Predlažemo vam da podesite prečicu na radnoj površini ka ovoj " +"izvršnoj datoteci radi lakšeg pokretanja." + +#: ../doc/strings.py:27 +msgid "" +"You can log into several Twitter accounts simultaneously. The program refers " +"to each Twitter account you have configured as a \"Session\". If this is the " +"first time you have launched TWBlue, and if no Twitter session exists, you " +"will see the Session Manager. This dialogue box allows you to authorise as " +"many accounts as you wish. If you press the Tab key to reach the \"new " +"account\" button and activate it by pressing the Space Bar, a dialogue box " +"will advise you that your default internet browser will be opened in order " +"to authorise the application and you will be asked if you would like to " +"continue. Activate the \"yes\" Button by pressing the letter \"Y\" so the " +"process may start." +msgstr "" +"Možete da se prijavite na više Twitter naloga u isto vreme. Program će zvati " +"svaki nalog koji podesite kao \"sesija\". Ako je ovo prvi put da pokrećete " +"TWBlue, i ako ne postoji nijedna Twitter sesija, videćete dijalog za " +"upravljanje sesijama. Ovaj dijalog će vam dozvoliti da autorizujete onoliko " +"naloga koliko želite. Ako pritisnete tab dugme da pronađete opciju \"Novi " +"nalog\" i aktivirate je tasterom razmak, dijalog će vam reći da će vaš " +"podrazumevani Web pretraživač biti otvoren kako biste autorizovali " +"aplikaciju i bićete upitani da li želite da nastavite. Aktiviranjem opcije " +"\"Da\" slovom \"D\" proces će započeti." + +#: ../doc/strings.py:28 +msgid "" +"Your default browser will open on the Twitter page to request authorisation. " +"Enter your username and password into the appropriate edit fields if you're " +"not already logged in, select the authorise button, and press it." +msgstr "" +"Vaš podrazumevani Web pretraživač će biti otvoren na Twitter stranici kako " +"bi zahtevao autorizaciju. Upišite vaše korisničko ime i lozinku u " +"odgovarajuća polja ako već niste prijavljeni, izaberite dugme autorizuj, i " +"pritisnite ga." + +#: ../doc/strings.py:29 +msgid "" +"Once you've authorised your twitter account, the website will redirect you " +"to a page which will notify you that TWBlue has been authorised " +"successfully. Now you are able to close the page by pressing ALT+F4 which " +"will return you to the Session Manager. On the session list, you will see a " +"new item temporarily called \"Authorised account x\" -where x is a number. " +"The session name will change once you open that session." +msgstr "" +"Nakon što ste autorizovali vaš Twitter nalog, Websajt će vas preusmeriti na " +"stranicu koja će vas obavestiti da je TWBlue uspešno autorizovan. Sada " +"možete da zatvorite ovu stranicu pritiskanjem tastera ALT+F4 što će vas " +"vratiti na upravljanje sesijama. U listi sesija, videćete novu stavku koja " +"se privremeno zove \"Autorizovan nalog x\" -gde će x biti zamenjen brojem. " +"Ime sesije će se promeniti nakon što je otvorite." + +#: ../doc/strings.py:30 +msgid "" +"To start running TWBlue, press the Ok button in the Session Manager " +"dialogue. By default, the program starts all the configured sessions " +"automatically, however, you can change this behavior." +msgstr "" +"Da biste počeli sa korišćenjem aplikacije TWBlue, u dijalogu upravljanja " +"sesijama pritisnite dugme u redu. Podrazumevano, program automatski pokreće " +"sve podešene sesije, ali, ovo se može promeniti." + +#: ../doc/strings.py:31 +msgid "" +"If all went well, the application will start playing sounds, indicating your " +"data is being updated." +msgstr "" +"Ako je sve u redu, aplikacija će početi sa reprodukcijom zvukova, što znači " +"da se vaši podaci ažuriraju." + +#: ../doc/strings.py:32 +msgid "" +"When the process is finished, by default the program will play another " +"sound, and the screen reader will say \"ready\" (this behaviour can be " +"configured)." +msgstr "" +"Kada se proces završi, po podrazumevanim podešavanjima program će " +"reprodukovati još jedan zvuk, i čitač ekrana će izgovoriti\"spreman\" (ovo " +"se može podesiti )." + +#: ../doc/strings.py:33 +msgid "## General concepts" +msgstr "## Opšti koncepti" + +#: ../doc/strings.py:34 +msgid "" +"Before starting to describe TWBlue's usage, we'll explain some concepts that " +"will be used extensively throughout this manual." +msgstr "" +"Pre nego što počnemo da opisujemo opšte korišćenje programa TWBlue, " +"opisaćemo neke opšte koncepte koji će se često koristiti u ovom uputstvu." + +#: ../doc/strings.py:35 +msgid "### Buffer" +msgstr "### Kanal" + +#: ../doc/strings.py:36 +msgid "" +"A buffer is a list of items to manage the data which arrives from Twitter, " +"after being processed by the application. When you configure a new session " +"on TWBlue and start it, many buffers are created. Each of them may contain " +"some of the items which this program works with: Tweets, direct messages, " +"users, trends or events. According to the buffer you are focusing, you will " +"be able to do different actions with these items." +msgstr "" +"Kanal je lista stavki koja upravlja vrstom podataka koji stižu sa Twittera, " +"nakon što ih aplikacija obradi. Kada podesite novu sesiju u programu TWBlue " +"i pokrenete je, neki kanali su već napravljeni. Svaki može da sadrži neke " +"stavke sa kojima program radi: Tvitovi, direktne poruke, korisnici, teme u " +"trendu ili događaji. U zavisnosti od kanala kojeg fokusirate, možete da " +"izvršavate različite radnje na njemu." + +#: ../doc/strings.py:37 +msgid "" +"The following is a description for every one of TWBlue's buffers and the " +"kind of items they work with." +msgstr "Sledi opis za svaki TWBlue kanal i listu stavki sa kojom on radi." + +#: ../doc/strings.py:38 +msgid "" +"* Home: this shows all the tweets on the main timeline. These are the tweets " +"by users you follow." +msgstr "" +"* Početak: Ovaj kanal prikazuje sve tvitove na glavnoj vremenskoj liniji. " +"Ovo su tvitovi od strane korisnika koje pratite." + +#: ../doc/strings.py:39 +msgid "" +"* Mentions: if a user, whether you follow them or not, mentions you on " +"Twitter, you will find it in this list." +msgstr "" +"* Spominjanja: Ako vas korisnik, bez obzira da li ih pratite ili ne, spomene " +"na Twitteru, to ćete pronaći u ovoj listi." + +#: ../doc/strings.py:40 +msgid "" +"* Direct messages: here you will find the private direct messages you " +"exchange with users who follow you , or with any user, if you allow direct " +"messages from everyone (this setting is configurable from Twitter). This " +"list only shows received messages." +msgstr "" +"* Direktne poruke: Ovde ćete pronaći privatne poruke koje razmenjujete sa " +"korisnicima koji vas prate, ili sa bilo kojim korisnikom, ako dozvolite " +"direktne poruke od svih (ovo podešavanje se menja na Twitteru ). Ova lista " +"prikazuje samo primljene poruke." + +#: ../doc/strings.py:41 +msgid "" +"* Sent direct messages: this buffer shows all the direct messages sent from " +"your account." +msgstr "" +"* Poslate direktne poruke: Ovaj kanal prikazuje sve direktne poruke poslate " +"sa vašeg naloga." + +#: ../doc/strings.py:42 +msgid "* Sent tweets: this shows all the tweets sent from your account." +msgstr "" +"* Poslati tvitovi: Ovaj kanal prikazuje sve tvitove poslate sa vašeg naloga." + +#: ../doc/strings.py:43 +msgid "* Likes: here you will see all the tweets you have liked." +msgstr "* Sviđanja: Ovde ćete videti sve tvitove koje ste označili sviđanjem." + +#: ../doc/strings.py:44 +msgid "" +"* Followers: when users follow you, you'll be able to see them on this " +"buffer, with some of their account details." +msgstr "" +"* Pratioci: Kada vas korisnici prate, možete da ih vidite na ovom kanalu, uz " +"neke detalje o njihovim nalozima." + +#: ../doc/strings.py:45 +msgid "" +"* Friends: the same as the previous buffer, but these are the users you " +"follow." +msgstr "" +"* Prijatelji: Isto kao i prethodni kanal, ali ovo su korisnici koje vi " +"pratite." + +#: ../doc/strings.py:46 +msgid "" +"* User timelines: these are buffers you may create. They contain only the " +"tweets by a specific user. They're used so you can see the tweets by a " +"single person and you don't want to look all over your timeline. You may " +"create as many as you like." +msgstr "" +"* Korisničke vremenske linije: Ovo su kanali koje vi možete da napravite. " +"Oni sadrže tvitove samo određenog korisnika. Oni se koriste kako biste mogli " +"da vidite tvitove samo jedne osobe a ne želite da ih tražite po celoj " +"vremenskoj liniji. Možete da napravite ovakvih kanala onoliko koliko želite." + +#: ../doc/strings.py:47 +msgid "" +"* Events: An event is anything that happens on Twitter, such as when someone " +"follows you, when someone adds or removes one of your tweets from their " +"likes list, or when you subscribe to a list. There are many more, but the " +"program shows the most common ones in the events buffer so that you can " +"easily keep track of what is happening on your account." +msgstr "" +"* Događaji: Događaj je sve ono što se dogodi na Twitteru, na primer kada vas " +"neko prati, kada neko doda ili ukloni vaš tvit sa liste sviđanja, ili kada " +"se prijavite na listu. Ima ih još puno, ali program prikazuje najčešće u " +"ovom kanalu kako biste mogli da pratite šta se dešava na vašem nalogu." + +#: ../doc/strings.py:48 +msgid "" +"* Lists: A list is similar to a user timeline, except that you can configure " +"it to contain tweets from multiple users." +msgstr "" +"* Liste: Lista je slična korisničkoj vremenskoj liniji, osim što možete da " +"je podesite tako da sadrži tvitove više različitih korisnika." + +#: ../doc/strings.py:49 +msgid "* Search: A search buffer contains the results of a search operation." +msgstr "* Pretraga: Kanal pretrage sadrži rezultate izvršene pretrage." + +#: ../doc/strings.py:50 +msgid "" +"* User likes: You can have the program create a buffer containing tweets " +"liked by a particular user." +msgstr "" +"* Korisnička sviđanja: Možete da napravite kanal koji sadrži samo tvitove " +"koji se sviđaju određenom korisniku." + +#: ../doc/strings.py:51 +msgid "" +"* Trending Topics: a trend buffer shows the top ten most used terms in a " +"geographical region. This region may be a country or a city. Trends are " +"updated every five minutes." +msgstr "" +"* Teme u trendu: Kanal tema u trendu sadrži listu 10 termina koji se " +"najčešće koriste u određenoj geografskoj regiji. Ova regija može biti država " +"ili grad. Teme u trendu se ažuriraju na 5 minuta." + +#: ../doc/strings.py:52 +msgid "" +"If a tweet contains a URL, you can press enter in the GUI or Control + " +"Windows + Enter in the invisible interface to open it. If it contains audio, " +"you can press Control + Enter or Control + Windows + Alt + Enter to play it, " +"respectively. TWBlue will play a sound if the tweet contains the \\#audio " +"hashtag, but there may be tweets which contain audio without this. Finally, " +"if a tweet contains geographical information, you can press Control + " +"Windows + G in the invisible interface to retrieve it." +msgstr "" +"Ako tvit sadrži adresu, možete pritisnuti enter u grafičkom interfejsu ili " +"CTRL plus Windows plus enter u nevidljivom interfejsu da je otvorite. Ako " +"sadrži zvučni zapis, možete pritisnuti ctrl plus enter ili ctrl plus windows " +"plus alt plus enter da ga reprodukujete. TWBlue će zvukom označiti tvitove " +"koji sadrže \\#audio hashtag, ali tvitovi mogu imati zvučne zapise i bez " +"ovoga. Konačno, ako tvit sadrži geografske informacije, možete pritisnuti " +"ctrl plus windows plus g da ih preuzmete." + +#: ../doc/strings.py:53 +msgid "### Username fields" +msgstr "### Polja korisničkih imena" + +#: ../doc/strings.py:54 +msgid "" +"These fields accept a Twitter username (without the at sign) as the input. " +"They are present in the send direct message and the user actions dialogue " +"boxes. Those dialogues will be discussed later. The initial value of these " +"fields depends on where they were opened from. They are prepopulated with " +"the username of the sender of the focused tweet (if they were opened from " +"the home and sent timelines, from users' timelines or from lists), the " +"sender of the focused direct message (if from the received or sent direct " +"message buffers) or in the focused user (if from the followers' or friends' " +"buffer). If one of those dialogue boxes is opened from a tweet, and if there " +"are more users mentioned in it, you can use the arrow keys to switch between " +"them. Alternatively, you can also type a username." +msgstr "" +"Ova polja prihvataju Twitter korisnička imena (bez et znaka ) kao unos. Ona " +"se prikazuju u dijalozima za slanje direktnih poruka i za korisničke radnje. " +"Ovi dijalozi će biti opisani kasnije. Prvobitna vrednost ovih polja zavisi " +"od toga gde su otvorena. Podrazumevano je upisano korisničko ime pošiljaoca " +"fokusiranog tvita (ako su otvorena iz početnog kanala ili kanala poslatih " +"stavki, iz korisničkih vremenskih linija ili iz liste), pošiljaocem " +"direktne poruke(ako su otvorena iz kanala primljenih ili poslatih direktnih " +"poruka) ili fokusiranim korisnikom(ako su otvorena iz kanala pratioca ili " +"prijatelja). Ako se jedan od ovih dijaloga otvori iz tvita, i ako je više " +"korisnika spomenuto u njemu, možete koristiti strelice da se prebacujete " +"između njih. U suprotnom, možete takođe da upišete korisničko ime." + +#: ../doc/strings.py:55 +msgid "## The program's interfaces" +msgstr "## Interfejsi programa" + +#: ../doc/strings.py:56 +msgid "### The graphical user interface (GUI)" +msgstr "### Grafički interfejs(GUI)" + +#: ../doc/strings.py:57 +msgid "The graphical user interface of TWBlue consists of a window containing:" +msgstr "Grafički interfejs aplikacije TWBlue sadrži prozor u kojem se nalazi:" + +#: ../doc/strings.py:58 +msgid "" +"* a menu bar accomodating six menus (application, tweet, user, buffer, " +"audio and help);" +msgstr "" +"* Traka menija koja sadrži šest menija (Aplikacija, tvit, korisnik, kanal, " +"audio i pomoć);" + +#: ../doc/strings.py:59 +msgid "* One tree view," +msgstr "* Jedan prikaz stabla," + +#: ../doc/strings.py:60 +msgid "* One list of items" +msgstr "* Jedna lista stavki" + +#: ../doc/strings.py:61 +msgid "" +"* Four buttons in most dialogs: Tweet, retweet , reply and direct message." +msgstr "" +"* 4 dugmeta u većini dijaloga: Tvit, retvituj, odgovori i direktna poruka." + +#: ../doc/strings.py:62 +msgid "The actions that are available for every item will be described later." +msgstr "Radnje koje su dostupne za svaku stavku će kasnije biti opisane." + +#: ../doc/strings.py:63 +msgid "" +"In summary, the GUI contains two core components. These are the controls you " +"will find while pressing the Tab key within the program's interface, and the " +"different elements present on the menu bar." +msgstr "" +"Najkraće opisano, grafički interfejs sadrži dve glavne komponente. To su " +"kontrole koje ćete pronaći kada pritiskate taster Tab u interfejsu programa, " +"i različiti elementi koji se nalaze na traci menija." + +#: ../doc/strings.py:64 +msgid "#### Buttons in the application" +msgstr "#### Dugmići u aplikaciji" + +#: ../doc/strings.py:65 +msgid "" +"* Tweet: this button opens up a dialogue box to write your tweet. Normal " +"tweets must not exceed 280 characters. However you can press the long tweet " +"checkbox and your tweet will be posted throught Twishort, wich will allow " +"you to write longer tweets (10000 characters). If you write past this limit, " +"a sound will play to warn you. Note that the character count is displayed in " +"the title bar. You may use the shorten and expand URL buttons to comply with " +"the character limit. You can upload a picture, check spelling, attach audio " +"or translate your message by selecting one of the available buttons in the " +"dialogue box. In addition, you can autocomplete the entering of users by " +"pressing Alt + C or the button for that purpose if you have the database of " +"users configured. Press enter to send the tweet. If all goes well, you'll " +"hear a sound confirming it. Otherwise, the screen reader will speak an error " +"message in English describing the problem." +msgstr "" +"* Tvit: Ovo dugme otvara dijalog za pisanje vašeg tvita. Standardni tvitovi " +"ne smeju imati više od 280 znakova. Ali možete označiti izborno polje dug " +"tvit i vaš tvit će biti objavljen kroz servis Twishort, što vam dozvoljava " +"da pišete duže tvitove (10000 znakova ). Ako pišete duže od ovog " +"ograničenja, čućete zvuk koji će vas upozoriti. Napomena da se broj znakova " +"takođe prikazuje kao naziv prozora. Možete takođe da koristite tastere " +"skrati vezu i proširi vezu da biste ispoštovali ograničenje znakova. Možete " +"da otpremite sliku, proverite pravopis, priložite zvučnu datoteku ili " +"prevedete tekst korišćenjem dostupnih opcija u ovom dijalogu. Takođe, možete " +"da izvršite automatsko dovršavanje korisničkih imena pritiskanjem prečice " +"alt plus a ili odgovarajućeg dugmeta ako je baza korisnika za automatsko " +"dovršavanje podešena. Pritisnite enter da pošaljete tvit. Ako je sve u redu, " +"čućete zvuk koji ovo potvrđuje. U suprotnom, čitač ekrana će na Engleskom " +"izgovoriti grešku koja opisuje problem." + +#: ../doc/strings.py:66 +msgid "" +"* Retweet: this button retweets the message you're reading. After you press " +"it, if you haven't configured the application not to do so, you'll be asked " +"if you want to add a comment or simply send it as written. If you choose to " +"add a comment, it will post a quoted tweet, that is, the comment with a " +"link to the originating tweet." +msgstr "" +"* Retvituj: Ovo dugme retvituje poruku koju čitate. Nakon što ga pritisnete, " +"ako niste podesili aplikaciju da ovo ne radi, pitaće vas da li želite da " +"dodate komentar ili jednostavno pošaljete retvit onakav kakav je. Ako " +"izaberete da dodate komentar, objaviće citiran tvit, to jest, komentar uz " +"link ka izvornom tvitu." + +#: ../doc/strings.py:67 +msgid "" +"* Reply: when you're viewing a tweet, you can reply to the user who sent it " +"by pressing this button. A dialogue will open up similar to the one for " +"tweeting. If there are more users referred to in the tweet, you can press " +"tab and activate the mention to all checkbox, or enabling checkbox for the " +"users you want to mention separately. When you're on the friends or " +"followers lists, the button will be called mention instead." +msgstr "" +"* Odgovori: Kada gledate tvit, možete odgovoriti korisniku koji ga je poslao " +"aktiviranjem ovog dugmeta. Dijalog će se otvoriti sličan onom za tvitovanje. " +"Ako je više korisnika spomenuto u tvitu, možete pritisnuti tab i označiti " +"izborno polje spomeni sve, ili označiti posebno izborno polje za svakog " +"korisnika kojeg želite da spomenete. Kada ste na listi prijatelja ili " +"pratilaca, umesto ovoga dugme će se zvati spomeni." + +#: ../doc/strings.py:68 +msgid "" +"* Direct message: exactly like sending a tweet, but it's a private message " +"which can only be read by the user you send it to. Press shift-tab twice to " +"see the recipient. If there were other users mentioned in the tweet you were " +"reading, you can arrow up or down to choose which one to send it to, or " +"write the username yourself without the at sign. In addition, you can " +"autocomplete the entering of users by pressing Alt + C or the button for " +"that purpose if you have the database of users configured." +msgstr "" +"* Direktna poruka: Baš kao i slanje tvita, ali ovo je privatna poruka koju " +"može da pročita samo korisnik kome ste je poslali. Pritisnite dva puta šift " +"tab da biste videli primaoca. Ako su drugi korisnici spominjani u tvitu " +"kojeg ste čitali, možete koristiti strelice gore i dole da izaberete kome " +"šaljete poruku, ili sami da upišete korisničko ime bez et znaka. Takođe, " +"možete izvršiti automatsko dovršavanje korisnika prečicom alt plus a ili " +"odgovarajućim dugmetom ako ste podesili bazu podataka za automatsko " +"dovršavanje." + +#: ../doc/strings.py:69 +msgid "" +"Bear in mind that buttons will appear according to which actions are " +"possible on the list you are browsing. For example, on the home timeline, " +"mentions, sent, likes and user timelines you will see the four buttons, " +"while on the direct messages list you'll only get the direct message and " +"tweet buttons, and on friends and followers lists the direct message, tweet, " +"and mention buttons will be available." +msgstr "" +"Imajte na umu da će se dugmići pojavljivati u zavisnosti od toga koje radnje " +"su dostupne na fokusiranoj listi. Na primer, na početnoj vremenskoj liniji, " +"spominjanjima, poslatim tvitovima, sviđanjima i korisničkim vremenskim " +"linijama videćete 4 dugmeta, dok ćete u listama direktnih poruka videti samo " +"dugmiće za direktnu poruku i tvit, i na listama prijatelja i pratilaca biće " +"dostupni dugmići za direktnu poruku, tvitovanje, kao i spominjanje." + +#: ../doc/strings.py:70 +msgid "#### Menus" +msgstr "#### Meniji" + +#: ../doc/strings.py:71 +msgid "" +"Visually, Towards the top of the main application window, can be found a " +"menu bar which contains many of the same functions as listed in the previous " +"section, together with some additional items. To access the menu bar, press " +"the alt key. You will find six menus listed: application, tweet, user, " +"buffer, audio and help. This section describes the items on each one of them." +msgstr "" +"Vizuelno, ka vrhu prozora aplikacije, možete pronaći traku sa menijima koja " +"sadrži dosta funkcija već opisanih iznad, uz neke dodatne stavke. Da biste " +"pristupili traci menija, pritisnite taster alt. Možete primetiti šest " +"opisanih menija: Aplikacija, Tvit, Korisnik, kanal, audio i pomoć. Ova " +"sekcija opisuje stavke svakog od njih." + +#: ../doc/strings.py:72 +msgid "##### Application menu" +msgstr "##### Meni aplikacija" + +#: ../doc/strings.py:73 +msgid "" +"* Manage accounts: Opens a window with all the sessions configured in " +"TWBlue, where you can add new sessions or delete the ones you've already " +"created." +msgstr "" +"* Upravljaj nalozima: Otvara prozor sa svim podešenim sesijama za TWBlue, " +"gde možete da dodate nove sesije ili obrišete već kreirane." + +#: ../doc/strings.py:74 +msgid "" +"* Update profile: opens a dialogue where you can update your information on " +"Twitter: name, location, website and bio. If you have already set this up " +"the fields will be prefilled with the existing information. Also, you can " +"upload a photo to your profile." +msgstr "" +"* Ažuriraj profil: Otvara dijalog gde možete da ažurirate vaše informacije " +"na Twitteru: Ime, mesto, Websajt i biografiju. Ako ste ovo već podesili " +"polja će biti popunjena postojećim informacijama. Takođe, možete otpremiti " +"vašu fotografiju profila." + +#: ../doc/strings.py:75 +msgid "" +"* Hide window: turns off the Graphical User Interface. Read the section on " +"the invisible interface for further details." +msgstr "" +"* Sakrij prozor: Krije grafički interfejs. Pročitajte sekciju o nevidljivom " +"interfejsu za dodatne detalje." + +#: ../doc/strings.py:76 +msgid "" +"* Search: shows a dialogue box where you can search for tweets or users on " +"Twitter." +msgstr "" +"* Pretraži: Prikazuje dijalog u kome možete da pretražujete korisnike i " +"tvitove na Twitteru." + +#: ../doc/strings.py:77 +msgid "" +"* Lists Manager: This dialogue box allows you to manage your Twitter lists. " +"In order to use them, you must first create them. Here, you can view, edit, " +"create, delete or, optionally, open them in buffers similar to user " +"timelines." +msgstr "" +"* Upravljanje listama: Ovaj dijalog vam dozvoljava da upravljate vašim " +"Twitter listama. Da biste ih koristili, prvo morate da ih napravite. Ovde, " +"možete prikazati, urediti, napraviti, obrisati ili, ako to želite, otvorite " +"ih u kanalima slično vremenskim linijama korisnika." + +#: ../doc/strings.py:78 +msgid "" +"* Edit keystrokes: this opens a dialogue where you can see and edit the " +"shortcuts used in the invisible interface." +msgstr "" +"* Izmeni tasterske prečice: Ova opcija otvara dijalog u kome možete " +"pogledati kao i izmeniti prečice koje se koriste u nevidljivom interfejsu." + +#: ../doc/strings.py:79 +msgid "" +"* Account settings: Opens a dialogue box which lets you customize settings " +"for the current account." +msgstr "" +"* Postavke naloga: Otvara dijalog koji vam dozvoljava da podesite " +"podešavanja za trenutni nalog." + +#: ../doc/strings.py:80 +msgid "" +"* Global settings: Opens a dialogue which lets you configure settings for " +"the entire application." +msgstr "" +"* Globalna podešavanja: Otvara dijalog koji vam dozvoljava da podesite " +"podešavanja za celu aplikaciju." + +#: ../doc/strings.py:81 +msgid "" +"* Exit: asks whether you want to exit the program. If the answer is yes, it " +"closes the application. If you do not want to be asked for confirmation " +"before exiting, uncheck the checkbox from the global settings dialogue box." +msgstr "" +"* Izlaz: Upitaće vas da li želite da izađete iz programa. Ako je odgovor da, " +"zatvara aplikaciju. Ako ne želite da budete upitani za potvrdu pre izlaza, " +"Onemogućite ovu opciju u dijalogu globalnih podešavanja." + +#: ../doc/strings.py:82 +msgid "##### Tweet menu" +msgstr "##### Meni tvit" + +#: ../doc/strings.py:83 +msgid "" +"* You will first find the items to tweet, reply and retweet, which are " +"equivalent to the buttons with the same name." +msgstr "" +"* Prvo ćete pronaći stavke da pošaljete tvit, odgovor i retvit, koje imaju " +"istu funkciju kao i dugmići sa ovim imenima." + +#: ../doc/strings.py:84 +msgid "* Like: Adds the tweet you're viewing to your likes list." +msgstr "* Sviđa mi se: Dodaje tvit koji čitate u vašu listu sviđanja." + +#: ../doc/strings.py:85 +msgid "* Unlike: removes the tweet from your likes, but not from Twitter." +msgstr "* Ne sviđa mi se: Uklanja tvit iz vaših sviđanja, ali ne sa Twittera." + +#: ../doc/strings.py:86 +msgid "" +"* Show tweet: opens up a dialogue box where you can read the tweet, direct " +"message, friend or follower which has focus. You can read the text with the " +"arrow keys. It's a similar dialog box as used for composing tweets, without " +"the ability to send the tweet, file attachment and autocompleting " +"capabilities. It does however include a retweets and likes count. If you are " +"in the followers or the friends list, it will only contain a read-only edit " +"box with the information in the focused item and a close button." +msgstr "" +"* Prikaži tvit: Otvara dijalog gde možete da pročitate tvit, direktnu " +"poruku, prijatelja ili pratioca koji je fokusiran. Možete pročitati tekst " +"strelicama. Ovo je sličan dijalog kao onaj koji se koristi za pisanje novog " +"tvita, bez mogućnosti slanja tvita, prilaganja datoteka i mogućnosti " +"automatskog dovršavanja. On ipak uključuje broj retvitova i sviđanja. Ako " +"ste u listi pratilaca ili prijatelja, sadržaće samo polje za čitanje sa " +"informacijama o fokusiranoj stavci i dugme za zatvaranje." + +#: ../doc/strings.py:87 +msgid "" +"* View address: If the selected tweet has geographical information, TWBlue " +"may display a dialogue box where you can read the tweet address. This " +"address is retrieved by sending the geographical coordinates of the tweet to " +"Google maps." +msgstr "" +"* Vidi adresu: Ako odabran tvit ima geografske informacije, TWBlue može " +"prikazati dijalog u kome možete pročitati adresu. Ova adresa se preuzima " +"slanje geografskih koordinata u tvitu na Google mape." + +#: ../doc/strings.py:88 +msgid "" +"* View conversation: If you are focusing a tweet with a mention, it opens a " +"buffer where you can view the whole conversation." +msgstr "" +"* Vidi razgovor: Ako ste fokusirani na tvit sa spominjanjem, otvara kanal u " +"kojem možete da vidite čitav razgovor." + +#: ../doc/strings.py:89 +msgid "" +"* Read text in pictures: Attempt to apply OCR technology to the image " +"attached to the tweet. The result will be displayed in another dialog." +msgstr "" +"* Čitaj tekst u slici: Pokušava da primeni OCR tehnologije na sliku koja je " +"priložena u tvit. Rezultat će biti prikazan u drugom dijalogu." + +#: ../doc/strings.py:90 +msgid "" +"* Delete: permanently removes the tweet or direct message which has focus " +"from Twitter and from your lists. Bear in mind that Twitter only allows you " +"to delete tweets you have posted yourself." +msgstr "" +"* Izbriši: Trajno uklanja fokusiran tvit ili direktnu poruku sa Twittera i " +"iz vaših lista. Imajte na umu da vam Twitter dozvoljava brisanje samo " +"tvitova koje ste vi poslali." + +#: ../doc/strings.py:91 +msgid "##### User menu" +msgstr "##### Meni korisnik" + +#: ../doc/strings.py:92 +msgid "" +"* Actions: Opens a dialogue where you can interact with a user. This " +"dialogue box will be populated with the user who sent the tweet or direct " +"message in focus or the selected user in the friends or followers buffer. " +"You can edit it or leave it as is and choose one of the following actions:" +msgstr "" +"* Radnje: Otvara dijalog u kojem možete da vršite interakciju sa korisnikom. " +"Ovaj dijalog će imati već upisano ime korisnika koji je poslao tvit ili " +"direktnu poruku, ili sa imenom fokusiranog korisnika u kanalima prijatelja i " +"pratilaca. Možete ga izmeniti ili ga ostaviti i izabrati jednu od sledećih " +"radnji:" + +#: ../doc/strings.py:93 +msgid "" +" * Follow: Follows a user. This means you'll see his/her tweets on your home " +"timeline, and if he/she also follows you, you'll be able to exchange direct " +"messages. You may also send / receive direct messages from each other if you " +"have configured the option to allow direct messages from anyone." +msgstr "" +" * Prati: Prati korisnika. Ovo znači da ćete njihove tvitove videti na vašoj " +"početnoj vremenskoj liniji, i ako vas oni takođe prate, možete da " +"razmenjujete direktne poruke. Takođe možete da razmenjujete direktne poruke " +"ako ste dozvolili razmenu direktnih poruka sa svima u Twitter podešavanjima." + +#: ../doc/strings.py:94 +msgid "" +" * Unfollow: Stops following a user, which causes you not being able to see " +"his/her tweets on your main timeline neither exchanging direct messages, " +"unless they have enabled receiving direct messages from anyone." +msgstr "" +" * Otprati: Prestaje sa praćenjem korisnika, što će onemogućiti praćenje " +"njihovih tvitova na vašoj vremenskoj liniji kao i razmenu direktnih poruka, " +"osim ako su omogućili primanje direktnih poruka od svih." + +#: ../doc/strings.py:95 +msgid "" +" * Mute: While muting someone, TWBlue won't show you nor his/her tweets on " +"your main timeline; neither will you see that person's mentions. But you " +"both will be able to exchange direct messages. The muted user is not " +"informed of this action." +msgstr "" +" * Utišaj: Kada nekoga utišate, TWBlue vam neće prikazivati njihove tvitove " +"na vremenskoj liniji; niti ćete videti njihova spominjanja. Možete da " +"razmenjujete direktne poruke. Utišan korisnik neće dobiti informaciju o ovoj " +"radnji." + +#: ../doc/strings.py:96 +msgid "" +" * Unmute: this option allows TWBlue to display the user's tweets and " +"mentions again." +msgstr "" +" * Ukloni utišavanje: Ova opcija dozvoljava da TWBlue ponovo prikazuje " +"tvitove i spominjanja korisnika." + +#: ../doc/strings.py:97 +msgid " * Block: Blocks a user. This forces the user to unfollow you ." +msgstr "" +" * Blokiraj: Blokira korisnika. Ovo će naterati korisnika da prestane da vas " +"prati." + +#: ../doc/strings.py:98 +msgid " * Unblock: Stops blocking a user." +msgstr " * Odblokiraj: Prestaje sa blokiranjem korisnika." + +#: ../doc/strings.py:99 +msgid "" +" * Report as spam: this option sends a message to Twitter suggesting the " +"user is performing prohibited practices on the social network." +msgstr "" +" * Prijavi kao neželjeno: Ova opcija šalje poruku Twitteru koja obaveštava " +"da korisnik izvršava zabranjene radnje." + +#: ../doc/strings.py:100 +msgid "" +" * Ignore tweets from this client: Adds the client from which the focused " +"tweet was sent to the ignored clients list." +msgstr "" +" * Zanemari tvitove iz ovog klijenta: Dodaje klijent iz kog je tvit poslat u " +"listu klijenata iz kojih se tvitovi zanemaruju." + +#: ../doc/strings.py:101 +msgid "" +"* View timeline: Lets you open a user's timeline by choosing the user in a " +"dialog box. It is created when you press enter. If you invoke this option " +"relative to a user that has no tweets, the operation will fail. If you try " +"creating an existing timeline the program will warn you and will not create " +"it again." +msgstr "" +"* Vidi vremensku liniju: Dozvoljava vam da otvorite vremensku liniju " +"korisnikaizborom korisnika u dijalogu. Pravi se kada pritisnete enter. Ako " +"aktivirate ovu opciju za korisnika koji nema tvitove, radnja neće uspeti. " +"Ako pokušate da napravite vremensku liniju koja već postoji program će vas " +"upozoriti i ona neće ponovo biti napravljena." + +#: ../doc/strings.py:102 +msgid "* Direct message: same action as the button." +msgstr "* Direktna poruka: Ista radnja kao i već opisano dugme." + +#: ../doc/strings.py:103 +msgid "" +"* Add to List: In order to see someone's tweets in one or more of your " +"lists, you must add them first. In the dialogue box that opens after " +"selecting the user, you will be asked to select the list you wish to add the " +"user to. Thereafter, the list will contain a new member and their tweets " +"will be displayed there." +msgstr "" +"* Dodaj na listu: Kako biste videli nečije tvitove u jednoj ili više lista, " +"prvo ih morate dodati. U dijalogu koji se otvara nakon što izaberete " +"korisnika, bićete upitani da izaberete listu na koju će korisnik biti dodat. " +"Nakon toga, lista će imati novog člana i njihovi tvitovi će biti prikazani u " +"njoj." + +#: ../doc/strings.py:104 +msgid "* Remove from list: lets you remove a user from a list." +msgstr "* Ukloni sa liste: Dozvoljava vam da uklonite korisnika sa liste." + +#: ../doc/strings.py:105 +msgid "* View lists: Shows the lists created by a specified user." +msgstr "* Vidi liste: Prikazuje liste koje je izabrani korisnik napravio." + +#: ../doc/strings.py:106 +msgid "" +"* Show user profile: opens a dialogue with the profile of the specified user." +msgstr "" +"* Prikaži profil korisnika: Otvara dijalog sa profilom izabranog korisnika." + +#: ../doc/strings.py:107 +msgid "" +"* View likes: Opens a buffer where you can see the tweets which have been " +"liked by a particular user." +msgstr "" +"* Vidi sviđanja: Otvara kanal u kojem možete videti tvitove koje je izabrani " +"korisnik označio sviđanjem." + +#: ../doc/strings.py:108 +msgid "##### Buffer menu" +msgstr "##### Meni kanal" + +#: ../doc/strings.py:109 +msgid "" +"* New trending topics buffer: This opens a buffer to get the worlwide " +"trending topics or those of a country or a city. You'll be able to select " +"from a dialogue box if you wish to retrieve countries' trends, cities' " +"trends or worldwide trends (this option is in the cities' list) and choose " +"one from the selected list. The trending topics buffer will be created once " +"the \"OK\" button has been activated within the dialogue box. Remember this " +"kind of buffer will be updated every five minutes." +msgstr "" +"* Novi kanal sa temama u trendu: Ova opcija otvara kanal za preuzimanje tema " +"u trendu širom sveta, za određenu državu ili za određeni grad. Nakon " +"aktiviranja opcije možete da izaberete da li želite da vidite teme u trendu " +"za državu, teme u trendu za grad ili teme u trendu širom sveta (ova opcija " +"se nalazi u listi gradova) i možete da izaberete jedan iz izabrane liste. " +"Kanal sa temama u trendu će biti napravljen kada aktivirate dugme \"u redu\" " +"u dijalogu. Zapamtite da će se ovaj kanal ažurirati na 5 minuta." + +#: ../doc/strings.py:110 +msgid "" +"* Load previous items: This allows more items to be loaded for the specified " +"buffer." +msgstr "" +"* Učitaj prethodne stavke: Ova opcija dozvoljava da učitate dodatne stavke " +"za izabrani kanal." + +#: ../doc/strings.py:111 +msgid "" +"* Mute: Mutes notifications of a particular buffer so you will not hear when " +"new tweets arrive." +msgstr "" +"* Utišaj: Utišava obaveštenja za trenutni kanal tako da nećete čuti kada " +"stignu novi tvitovi." + +#: ../doc/strings.py:112 +msgid "" +"* autoread: When enabled, the screen reader or SAPI 5 Text to Speech voice " +"(if enabled) will read the text of incoming tweets. Please note that this " +"could get rather chatty if there are a lot of incoming tweets." +msgstr "" +"* Automatski čitaj: Kada je ova opcija omogućena, čitač ekrana ili SAPI 5 " +"glas (ako je omogućen ) pročitaće tekst dolaznih tvitova. Imajte na umu da " +"bi ovo moglo da bude prilično često ako ima puno novih tvitova." + +#: ../doc/strings.py:113 +msgid "* Clear buffer: Deletes all items from the buffer." +msgstr "* Očisti kanal: Briše sve stavke sa kanala." + +#: ../doc/strings.py:114 +msgid "* Destroy: dismisses the list you're on." +msgstr "* Izbriši: Briše kanal na kojem ste." + +#: ../doc/strings.py:115 +msgid "##### Audio menu" +msgstr "##### Meni audio" + +#: ../doc/strings.py:116 +msgid "" +"* Play/pause: try to play audio for the selected item (if available), or " +"stop the currently played audio." +msgstr "" +"* Reprodukuj / zaustavi: Pokušava da reprodukuje zvučni zapis za izabranu " +"stavku (ako je dostupan ), ili zaustavlja zapis koji se trenutno reprodukuje." + +#: ../doc/strings.py:117 +msgid "" +"* Seek back 5 seconds: If an audio is being played, seek 5 seconds back in " +"the playback. This will work only in audio files. This feature cannot be " +"used in radio stations or other streamed files." +msgstr "" +"* Premotaj unazad za 5 sekundi: Ako se zvučni zapis reprodukuje, premotava " +"reprodukciju nazad 5 sekundi. Ovo će raditi samo u zvučnim datotekama. Ova " +"opcija se ne može koristiti na radio stanicama ili drugim strimovima." + +#: ../doc/strings.py:118 +msgid "" +"* Seek forward 5 seconds: If an audio is being played, seek 5 seconds " +"forward in the playback. This feature cannot be used in radio stations or " +"other streamed files." +msgstr "" +"* Premotaj unapred za 5 sekundi: Ako se zvučni zapis reprodukuje, premotava " +"reprodukciju za 5 sekundi unapred. Ova opcija se ne može koristiti sa radio " +"stanicama ili drugim strimovima." + +#: ../doc/strings.py:119 +msgid "##### Help menu" +msgstr "##### Meni pomoć" + +#: ../doc/strings.py:120 +msgid "" +"* Documentation: opens up this file, where you can read some useful program " +"concepts." +msgstr "" +"* Dokumentacija: Otvara ovu datoteku, u kojoj možete pročitati neke korisne " +"koncepte programa." + +#: ../doc/strings.py:121 +msgid "" +"* Sounds tutorial: Opens a dialog box where you can familiarize yourself " +"with the different sounds of the program." +msgstr "" +"* Zvučna uputstva: Otvara dijalog u kojem se možete upoznati sa različitim " +"zvukovima programa." + +#: ../doc/strings.py:122 +msgid "" +"* What's new in this version?: opens up a document with the list of changes " +"from the current version to the earliest." +msgstr "" +"* Šta je novo u ovoj verziji?: Otvara dokument sa listom promena od trenutne " +"verzije do naj starije." + +#: ../doc/strings.py:123 +msgid "" +"* Check for updates: every time you open the program it automatically checks " +"for new versions. If an update is available, it will ask you if you want to " +"download the update. If you accept, the updating process will commence. When " +"complete, TWBlue will be restarted. This item checks for new updates without " +"having to restart the application." +msgstr "" +"* Proveri da li postoje nadogradnje: Svaki put kada otvorite program " +"automatski će proveriti dostupnost nove verzije. Ako je ažuriranje dostupno, " +"upitaće vas da li želite da preuzmete ažuriranje. Ako prihvatite, proces " +"ažuriranja će započeti. Kada se završi, TWBlue će biti ponovo pokrenut. Ova " +"opcija proverava dostupnost ažuriranja bez potrebe za ponovnim pokretanjem " +"aplikacije." + +#: ../doc/strings.py:124 +msgid "" +"* TWBlue's website: visit our [home page](http://twblue.es) where you can " +"find all relevant information and downloads for TWBlue and become a part of " +"the community." +msgstr "" +"* TWBlue's websajt: Posetite našu[početnu stranicu](http://twblue.es) gde " +"možete pronaći sve bitne TWBlue informacije i preuzimanja za TWBlue kao i " +"postati deo zajednice." + +#: ../doc/strings.py:125 +msgid "* About TWBlue: shows the credits of the program." +msgstr "* O TWBlue: Prikazuje zahvalnosti i informacije o programu." + +#: ../doc/strings.py:126 +msgid "### The invisible user interface" +msgstr "### Nevidljivi korisnički interfejs" + +#: ../doc/strings.py:127 +msgid "" +"The invisible interface, as its name suggests, has no graphical window and " +"works directly with screen readers such as JAWS for Windows, NVDA and System " +"Access. This interface is disabled by default, but you can enable it by " +"pressing Control + M. It works similarly to TheQube and Chicken Nugget. Its " +"shortcuts are similar to those found in these two clients. In addition, the " +"program has builtin support for the keymaps for these applications, " +"configurable through the global settings dialogue. By default, you cannot " +"use this interface's shortcuts in the GUI, but you can configure this in the " +"global settings dialogue." +msgstr "" +"Nevidljivi interfejs, kao što samo ime govori, nema grafičkog prozora i radi " +"direktno sa čitačima ekrana kao što su JAWS za Windows, NVDA i System " +"Access. Ovaj interfejs je podrazumevano onemogućen, ali možete ga omogućiti " +"pritiskanjem prečice Control + M. Radi slično klijentima TheQube i Chicken " +"Nugget. Njegove prečice su slične onima koje se nalaze u ova dva klijenta. " +"Takođe, program ima ugrađenu podršku za mape prečica za ove aplikacije, koje " +"se podešavaju u dijalogu globalnih podešavanja. Po podrazumevanim " +"podešavanjima, ne možete koristiti prečice ovog interfejsa dok je prikazan " +"grafički interfejs, ali možete ovo podesiti u dijalogu globalnih podešavanja." + +#: ../doc/strings.py:128 +msgid "" +"The next section contains a list of keyboard shortcuts for both interfaces. " +"Bear in mind that we will only describe the default keymap." +msgstr "" +"Sledeća lista sadrži listu prečica za oba interfejsa. Imajte na umu da ćemo " +"opisati samo podrazumevanu mapu prečica." + +#: ../doc/strings.py:129 +msgid "## Keyboard shortcuts" +msgstr "## Tasterske prečice" + +#: ../doc/strings.py:130 +msgid "### Shortcuts of the graphical user interface (GUI)" +msgstr "### prečice grafičkog interfejsa (GUI-a)" + +#: ../doc/strings.py:131 +msgid "* Enter: Open URL." +msgstr "* Enter: Otvara adresu." + +#: ../doc/strings.py:132 +msgid "* Control + Enter: Play audio." +msgstr "* Control + Enter: Reprodukuje zvučni zapis." + +#: ../doc/strings.py:133 +msgid "* Control + M: Hide the GUI." +msgstr "* Control + M: Krije grafički interfejs." + +#: ../doc/strings.py:134 +msgid "* Control + N: Compose a new tweet." +msgstr "* Control + N: Piše novi tvit." + +#: ../doc/strings.py:135 +msgid "* Control + R: Reply / mention." +msgstr "* Control + R: Odgovor / spominjanje." + +#: ../doc/strings.py:136 +msgid "* Control + Shift + R: Retweet." +msgstr "* Control + Shift + R: Retvit." + +#: ../doc/strings.py:137 +msgid "* Control + D: Send a direct message." +msgstr "* Control + D: Šalje direktnu poruku." + +#: ../doc/strings.py:138 +msgid "* control + F: Add tweet to likes." +msgstr "* control + F: Dodavanje tvita u sviđanja." + +#: ../doc/strings.py:139 +msgid "* Control + Shift + F: Remove a tweet from likes." +msgstr "* Control + Shift + F: Uklanja tvit iz sviđanja." + +#: ../doc/strings.py:140 +msgid "* Control + S: Open the user actions dialogue." +msgstr "* Control + S: Otvara dijalog korisničkih radnji." + +#: ../doc/strings.py:141 +msgid "* Control + Shift + V: Show tweet." +msgstr "* Control + Shift + V: Prikazuje tvit." + +#: ../doc/strings.py:142 +msgid "* Control + Q: Quit this program." +msgstr "* Control + Q: Izlazi iz ovog programa." + +#: ../doc/strings.py:143 +msgid "* Control + I: Open user timeline." +msgstr "* Control + I: Otvara vremensku liniju korisnika." + +#: ../doc/strings.py:144 +msgid "* Control + Shift + i: Destroy buffer." +msgstr "* Control + Shift + i: Briše kanal." + +#: ../doc/strings.py:145 +msgid "* F5: Increase volume by 5%." +msgstr "* F5: Pojačava jačinu za 5 %." + +#: ../doc/strings.py:146 +msgid "* F6: Decrease volume by 5%." +msgstr "* F6: Smanjuje jačinu za 5%." + +#: ../doc/strings.py:147 +msgid "* Control + P: Edit your profile." +msgstr "* Control + P: Uređivanje vašeg profila." + +#: ../doc/strings.py:148 +msgid "* Control + Delete: Delete a tweet or direct message." +msgstr "* Control + Delete: Briše tvit ili direktnu poruku." + +#: ../doc/strings.py:149 +msgid "* Control + Shift + Delete: Empty the current buffer." +msgstr "* Control + Shift + Delete: Prazni trenutni kanal." + +#: ../doc/strings.py:150 +msgid "### Shortcuts of the invisible interface (default keymap)" +msgstr "### Prečice nevidljivog interfejsa (podrazumevana mapa prečica )" + +#: ../doc/strings.py:151 +msgid "" +"The invisible interface of TWBlue can be customised by using a keymap. Every " +"keymap defines a set of keystrokes to be used along with the invisible " +"interface. You can change the keymap in the global settings dialogue, under " +"the application menu in the menu bar, and check or edit keystrokes for the " +"selected keymap in the keystroke editor, also available in the application " +"menu." +msgstr "" +"Nevidljivi interfejs programa TWBlue se može prilagoditi korišćenjem mape " +"prečica. Svaka mapa prečica definiše listu prečica koje će se koristiti u " +"nevidljivom interfejsu. Možete promeniti mapu prečica u dijalogu globalnih " +"podešavanja, u meniju aplikacija u traci sa menijima, kao i da proverite ili " +"izmenite prečice izabrane mape opcijom izmeni tasterske prečice, koja se " +"takođe nalazi u meniju aplikacija." + +#: ../doc/strings.py:152 +msgid "" +"* Control + Windows + Up Arrow: moves to the previous item in the buffer." +msgstr "" +"* Control + Windows + strelica gore: Prelazi na prethodnu stavku u kanalu." + +#: ../doc/strings.py:153 +msgid "* Control + Windows + Down Arrow: moves to the next item in the buffer." +msgstr "" +"* Control + Windows + strelica dole: Prelazi na sledeću stavku u kanalu." + +#: ../doc/strings.py:154 +msgid "* Control + Windows + Left Arrow: Move to the previous buffer." +msgstr "* Control + Windows + strelica levo: Prelazi na sledeći kanal." + +#: ../doc/strings.py:155 +msgid "* Control + Windows + Right Arrow: Move to the next buffer." +msgstr "* Control + Windows + strelica desno: Prelazi na sledeći kanal." + +#: ../doc/strings.py:156 +msgid "* Control + Windows + Shift + Left: Focus the previous session." +msgstr "" +"* Control + Windows + Shift + strelica levo: Fokusiranje prethodne sesije." + +#: ../doc/strings.py:157 +msgid "* Control + Windows + Shift + Right: Focus the next session." +msgstr "" +"* Control + Windows + Shift + strelica desno: Fokusiranje sledeće sesije." + +#: ../doc/strings.py:158 +msgid "* Control + Windows + C: View conversation." +msgstr "* Control + Windows + C: Prikazuje razgovor." + +#: ../doc/strings.py:159 +msgid "* Control + Windows + Enter: Open URL." +msgstr "* Control + Windows + Enter: Otvara adresu." + +#: ../doc/strings.py:160 +msgid "* Control + Windows + ALT + Enter: Play audio." +msgstr "* Control + Windows + ALT + Enter: Reprodukuje zvučni zapis." + +#: ../doc/strings.py:161 +msgid "* Control + Windows + M: Show or hide the GUI." +msgstr "* Control + Windows + M: Prikazuje ili krije grafički interfejs." + +#: ../doc/strings.py:162 +msgid "* Control + Windows + N: New tweet." +msgstr "* Control + Windows + N: Novi tvit." + +#: ../doc/strings.py:163 +msgid "* Control + Windows + R: Reply / Mention." +msgstr "* Control + Windows + R: Odgovor / spominjanje." + +#: ../doc/strings.py:164 +msgid "* Control + Windows + Shift + R: Retweet." +msgstr "* Control + Windows + Shift + R: Retvit." + +#: ../doc/strings.py:165 +msgid "* Control + Windows + D: Send direct message." +msgstr "* Control + Windows + D: Slanje direktne poruke." + +#: ../doc/strings.py:166 +msgid "* Windows+ Alt + F: Like a tweet." +msgstr "* Windows+ Alt + F: Označite da vam se tvit sviđa." + +#: ../doc/strings.py:167 +msgid "* Alt + Windows + Shift + F: Remove from likes." +msgstr "* Alt + Windows + Shift + F: Uklanjanje iz liste sviđanja." + +#: ../doc/strings.py:168 +msgid "* Control + Windows + S: Open the user actions dialogue." +msgstr "* Control + Windows + S: Otvara dijalog korisničkih radnji." + +#: ../doc/strings.py:169 +msgid "* Control + Windows + Alt + N: See user details." +msgstr "* Control + Windows + Alt + N: Prikazuje korisničke detalje." + +#: ../doc/strings.py:170 +msgid "* Control + Windows + V: Show tweet." +msgstr "* Control + Windows + V: Prikazuje tvit." + +#: ../doc/strings.py:171 +msgid "* Control + Windows + F4: Quit TWBlue." +msgstr "* Control + Windows + F4: Zatvara TWBlue." + +#: ../doc/strings.py:172 +msgid "* Control + Windows + I: Open user timeline." +msgstr "* Control + Windows + I: Otvara vremensku liniju korisnika." + +#: ../doc/strings.py:173 +msgid "* Control + Windows + Shift + I: Destroy buffer." +msgstr "* Control + Windows + Shift + I: Briše kanal." + +#: ../doc/strings.py:174 +msgid "* Control + Windows + Alt + Up: Increase volume by 5%." +msgstr "* Control + Windows + Alt + strelica gore: Pojačava jačinu za 5%." + +#: ../doc/strings.py:175 +msgid "* Control + Windows + Alt + Down: Decrease volume by 5%." +msgstr "* Control + Windows + Alt + strelica dole: smanjuje jačinu za 5%." + +#: ../doc/strings.py:176 +msgid "" +"* Control + Windows + Home: Jump to the first element of the current buffer." +msgstr "" +"* Control + Windows + Home: Prebacuje se na prvi element trenutnog kanala." + +#: ../doc/strings.py:177 +msgid "" +"* Control + Windows + End: Jump to the last element of the current buffer." +msgstr "" +"* Control + Windows + End: Prebacuje se na poslednji element trenutnog " +"kanala." + +#: ../doc/strings.py:178 +msgid "" +"* Control + Windows + PageUp: Jump 20 elements up in the current buffer." +msgstr "" +"* Control + Windows + PageUp: Skače 20 elemenata gore u trenutnom kanalu." + +#: ../doc/strings.py:179 +msgid "" +"* Control + Windows + PageDown: Jump 20 elements down in the current buffer." +msgstr "" +"* Control + Windows + PageDown: Skače 20 elemenata dole u trenutnom kanalu." + +#: ../doc/strings.py:180 +msgid "* Windows + Alt + P: Edit profile." +msgstr "* Windows + Alt + P: Uređivanje profila." + +#: ../doc/strings.py:181 +msgid "* Control + Windows + Delete: Delete a tweet or direct message." +msgstr "* Control + Windows + Delete: Briše tvit ili direktnu poruku." + +#: ../doc/strings.py:182 +msgid "* Control + Windows + Shift + Delete: Empty the current buffer." +msgstr "* Control + Windows + Shift + Delete: Prazni trenutni kanal." + +#: ../doc/strings.py:183 +msgid "* Control + Windows + Space: Repeat last item." +msgstr "* Control + Windows + razmak: Ponavlja poslednju stavku." + +#: ../doc/strings.py:184 +msgid "* Control + Windows + Shift + C: Copy to clipboard." +msgstr "* Control + Windows + Shift + C: Kopira u privremenu memoriju." + +#: ../doc/strings.py:185 +msgid "* Control + Windows+ A: Add user to list." +msgstr "* Control + Windows+ A: Dodaje korisnika na listu." + +#: ../doc/strings.py:186 +msgid "* Control + Windows + Shift + A: Remove user from list." +msgstr "* Control + Windows + Shift + A: Uklanja korisnika sa liste." + +#: ../doc/strings.py:187 +msgid "* Control + Windows + Shift + M: Mute / unmute the current buffer." +msgstr "" +"* Control + Windows + Shift + M: Utišava ili uklanja utišavanje trenutnog " +"kanala." + +#: ../doc/strings.py:188 +msgid "* Windows + Alt + M: Mute / unmute the current session." +msgstr "* Windows + Alt + M: Utišava ili uklanja utišavanje trenutne sesije." + +#: ../doc/strings.py:189 +msgid "" +"* Control + Windows + E: Toggle the automatic reading of incoming tweets in " +"the current buffer." +msgstr "" +"* Control + Windows + E: Uključuje ili isključuje automatsko čitanje tvitova " +"za trenutni kanal." + +#: ../doc/strings.py:190 +msgid "* Control + Windows + -: Search on Twitter." +msgstr "* Control + Windows + -: Pretraga Twittera." + +#: ../doc/strings.py:191 +msgid "* Control + Windows + K: Show the keystroke editor." +msgstr "" +"* Control + Windows + K: Prikazuje dijalog za menjanje tasterskih prečica." + +#: ../doc/strings.py:192 +msgid "* Control + Windows + L: Show lists for a specified user." +msgstr "* Control + Windows + L: Prikazuje liste za izabranog korisnika." + +#: ../doc/strings.py:193 +msgid "* Windows + Alt + PageUp: Load previous items for the current buffer." +msgstr "* Windows + Alt + PageUp: Učitava prethodne stavke za trenutni kanal." + +#: ../doc/strings.py:194 +msgid "* Control + Windows + G: Get geolocation." +msgstr "* Control + Windows + G: Preuzima geografske podatke." + +#: ../doc/strings.py:195 +msgid "" +"* Control + Windows + Shift + G: Display the tweet's geolocation in a " +"dialogue." +msgstr "" +"* Control + Windows + Shift + G: Prikazuje geografske podatke o lokaciji " +"tvita u dijalogu." + +#: ../doc/strings.py:196 +msgid "* Control + Windows + T: Create a trending topics' buffer." +msgstr "* Control + Windows + T: Pravi kanal tema u trendu." + +#: ../doc/strings.py:197 +msgid "* Control + Windows + {: Find a string in the current buffer." +msgstr "* Control + Windows + {: Pretraga teksta u trenutnom kanalu." + +#: ../doc/strings.py:198 +msgid "" +"* Alt + Windows + O: Extracts text from the picture and display the result " +"in a dialog." +msgstr "" +"* Alt + Windows + O: Izvlači tekst iz slike i prikazuje rezultat u dijalogu." + +#: ../doc/strings.py:199 +msgid "## Configuration" +msgstr "## Podešavanja" + +#: ../doc/strings.py:200 +msgid "" +"As described above, this application has two configuration dialogues, the " +"global settings dialogue and the account settings dialogue." +msgstr "" +"Kao što je iznad opisano, ova aplikacija ima dva dijaloga podešavanja, " +"dijalog globalnih podešavanja i dijalog postavki naloga." + +#: ../doc/strings.py:201 +msgid "### The account settings dialogue" +msgstr "### Dijalog podešavanja naloga" + +#: ../doc/strings.py:202 +msgid "#### General tab" +msgstr "#### Kartica opšte" + +#: ../doc/strings.py:203 +msgid "" +"* Autocompletion settings: Allows you to configure the autocompletion " +"database. You can add users manually or let TWBlue add your followers, " +"friends or both." +msgstr "" +"* Postavke automatskog dovršavanja: Dozvoljava vam da podesite bazu " +"automatskog dovršavanja. Možete ručno podesiti bazu ili dozvoliti da TWBlue " +"doda vaše pratioce, prijatelje ili i jedne i druge." + +#: ../doc/strings.py:204 +msgid "" +"* Relative timestamps: Allows you to configure whether the application will " +"calculate the time the tweet or direct message was sent or received based on " +"the current time, or simply say the time it was received or sent." +msgstr "" +"* Relativne vremenske oznake: Dozvoljava da podesite da li će aplikacija " +"računati vreme u koje je direktna poruka ili tvit poslat ili primljen u " +"zavisnosti od trenutnog vremena, ili jednostavno reći vreme kada je stavka " +"primljena ili poslata." + +#: ../doc/strings.py:205 +msgid "" +"* API calls: Allows you to adjust the number of API calls to be made to " +"Twitter by this program." +msgstr "" +"* API pozivi: Dozvoljava da promenite broj API poziva Twitteru od strane " +"programa." + +#: ../doc/strings.py:206 +msgid "" +"* Items on each API call: Allows you to specify how many items should be " +"retrieved from Twitter for each API call (default and maximum is 200)." +msgstr "" +"* Stavke po svakom API pozivu: Dozvoljava da odredite koliko stavki treba da " +"se preuzme sa Twittera za svaki API poziv (podrazumevano i maksimalno je " +"200)." + +#: ../doc/strings.py:207 +msgid "" +"* Inverted buffers: Allows you to specify whether the buffers should be " +"inverted, which means that the oldest items will show at the end of them and " +"the newest at the beginning." +msgstr "" +"* Okreni kanal: Dozvoljava da odredite da li će kanali biti obrnuti, što " +"znači da će se starije stavke prikazivati na dnu a novije na vrhu." + +#: ../doc/strings.py:208 +msgid "" +"* Retweet mode: Allows you to specify the behaviour when posting a retweet: " +"you can choose between retweeting with a comment, retweeting without comment " +"or being asked." +msgstr "" +"* Način retvitovanja: Dozvoljava vam da odredite ponašanje kada šaljete " +"retvit: Možete izabrati između opcija retvituj sa komentarima, retvituj bez " +"komentara ili da vas aplikacija uvek pita." + +#: ../doc/strings.py:209 +msgid "" +"* Number of items per buffer to cache in database: This allows you to " +"specify how many items TWBlue should cache in a database. You can type any " +"number, 0 to cache all items, or leave blank to disable caching entirely." +msgstr "" +"* Broj stavki po kanalu za čuvanje u bazi: Ova opcija vam dozvoljava da " +"odredite koliko stavki će TWBlue čuvati u svojoj bazi. Možete upisati bilo " +"koji broj, 0 da se sve stavke čuvaju, ili ostavite polje praznim da se " +"čuvanje u potpunosti onemogući." + +#: ../doc/strings.py:210 +msgid "#### buffers tab" +msgstr "#### Kartica kanali" + +#: ../doc/strings.py:211 +msgid "" +"This tab displays a list for each buffer you have available in TWBlue, " +"except for searches, timelines, likes' timelines and lists. You can show, " +"hide and move them." +msgstr "" +"Ova kartica prikazuje sve kanale koje imate u aplikaciji TWBlue, osim " +"pretraga, vremenskih linija, vremenskih linija sviđanja i listi. Možete ih " +"prikazati, sakriti i premeštati." + +#: ../doc/strings.py:212 +msgid "#### The ignored clients tab" +msgstr "#### Kartica zanemareni klijenti" + +#: ../doc/strings.py:213 +msgid "" +"In this tab, you can add and remove clients to be ignored by the program." +msgstr "" +"U ovoj kartici, možete dodati i ukloniti klijente koje će program zanemariti." + +#: ../doc/strings.py:214 +msgid "#### Sound tab" +msgstr "#### Kartica zvuk" + +#: ../doc/strings.py:215 +msgid "" +"In this tab, you can adjust the sound volume, select the input and output " +"device and set the soundpack used by the program." +msgstr "" +"U ovoj kartici, možete promeniti jačinu zvuka, izabrati ulazni i izlazni " +"uređaj kao i zvučni paket koji će program koristiti." + +#: ../doc/strings.py:216 +msgid "#### Audio service tab" +msgstr "#### Kartica audio servis" + +#: ../doc/strings.py:217 +msgid "" +"In this tab, you can enter your SndUp API key (if you have one) to upload " +"audio to SndUp with your account. Note that if account credentials are not " +"specified you will upload anonimously." +msgstr "" +"U ovoj kartici, možete upisati vaš SndUp API ključ (ako ga imate ) da biste " +"otpremili zvučne datoteke na servis SndUp vašim nalogom. Napomena da ako ne " +"odredite podatke naloga otpremaćete datoteke anonimno." + +#: ../doc/strings.py:218 +msgid "### Global settings" +msgstr "### Globalna podešavanja" + +#: ../doc/strings.py:219 +msgid "" +"This dialogue allows you to configure some settings which will affect the " +"entire application." +msgstr "" +"Ovaj dijalog vam dozvoljava da podesite određena podešavanja koja će uticati " +"na čitavu aplikaciju." + +#: ../doc/strings.py:220 +msgid "#### General tab {#general-tab_1}" +msgstr "#### Kartica opšte {#general-tab_1}" + +#: ../doc/strings.py:221 +msgid "" +"* Language: This allows you to change the language of this program. " +"Currently supported languages are arabic, Catalan, German, English, Spanish, " +"Basque, Finnish, French, Galician, Croatian, Hungarian, Italian, Polish, " +"Portuguese, Russian and Turkish." +msgstr "" +"* Jezik: Dozvoljava promenu jezika programa. Trenutno podržani jezici su " +"Arapski, Katalonski, Nemački, Engleski, Španski, Baskijski, Finski, " +"Francuski, Galski, Hrvatski, Mađarski, Italijanski, Poljski, Portugalski, " +"Ruski, Srpski i Turski." + +#: ../doc/strings.py:222 +msgid "" +"* Ask before exiting TWBlue: This checkbox allows you to control whetherthe " +"program will ask for confirmation before exiting." +msgstr "" +"* Pitaj pre zatvaranja TWBlue: Ovo izborno polje dozvoljava da podesite da " +"li će program zahtevati potvrdu pre izlaza." + +#: ../doc/strings.py:223 +msgid "" +"* Play a sound when TWBlue launches: This checkbox allows you to configure " +"whether the application will play a sound when it has finished loading the " +"buffers." +msgstr "" +"* Reprodukuj zvuk kada se TWBlue pokrene: Ovo izborno polje dozvoljava da " +"odredite da li će aplikacija reprodukovati zvuk nakon što završi učitavanje " +"kanala." + +#: ../doc/strings.py:224 +msgid "" +"* Speak a message when TWBlue launches: This is the same as the previous " +"option, but this checkbox configures whether the screen reader will say " +"\"ready\"." +msgstr "" +"* Izgovori poruku kada se TWBlue pokrene: Ova opcija je ista kao i " +"prethodna, ali ovo izborno polje kontroliše da li će čitač ekrana reći " +"\"spreman\"." + +#: ../doc/strings.py:225 +msgid "" +"* Use the invisible interface's shortcuts in the GUI: As the invisible " +"interface and the Graphical User Interface have their own shortcuts, you may " +"want to use the invisible interface's keystrokes all the time. If this " +"option is checked, the invisible interface's shortcuts will be usable in the " +"GUI." +msgstr "" +"* Koristi prečice nevidljivog okruženja dok je grafičko okruženje prikazano: " +"Budući da nevidljivi i grafički interfejs imaju svoje prečice, možda ćete " +"želeti da uvek koristite prečice nevidljivog interfejsa. Ako je ova opcija " +"označena, prečice nevidljivog interfejsa se mogu koristiti u grafičkom " +"interfejsu." + +#: ../doc/strings.py:226 +msgid "" +"* Activate SAPI5 when any other screen reader is not being run: This " +"checkbox allows to activate SAPI 5 TTS when no other screen reader is being " +"run." +msgstr "" +"* Aktiviraj SAPI5 u slučaju da nijedan čitač ekrana nije pokrenut: Ova " +"opcija dozvoljava da koristite SAPI 5 glasove kada nijedan čitač ekrana nije " +"pokrenut." + +#: ../doc/strings.py:227 +msgid "" +"* Hide GUI on launch: This allows you to configure whether TWBlue will start " +"with the GUI or the invisible interface." +msgstr "" +"* Sakrij grafičko okruženje prilikom pokretanja: Ovo izborno polje " +"dozvoljava da podesite da li će se TWBlue pokrenuti u grafičkom ili " +"nevidljivom interfejsu." + +#: ../doc/strings.py:228 +msgid "" +"* Keymap: This option allows you to change the keymap used by the program in " +"the invisible interface. The shipped keymaps are Default, Qwitter, Windows " +"10 and Chicken Nugget. The keymaps are in the \"keymaps\" folder, and you " +"can create new ones. Just create a new \".keymap\" file and change the " +"keystrokes associated with the actions, as it is done in the shipped keymaps." +msgstr "" +"* Tasterske prečice: Ovaj izborni okvir vam dozvoljava da promenite mapu " +"prečica koju koristi program u nevidljivom interfejsu. Podrazumevane mape " +"prečica su default - podrazumevana, Qwitter, Windows 10 i Chicken Nugget. " +"Mape prečica su u folderu \"keymaps\", i možete napraviti nove. Samo " +"napravite novu \".keymap\" datoteku i promenite prečice za radnje, kako je i " +"urađeno u već postojećim mapama." + +#: ../doc/strings.py:229 +msgid "#### Proxi tab" +msgstr "#### Kartica proksi" + +#: ../doc/strings.py:230 +msgid "" +"In this tab you can configure TWBlue to use a Proxy server by completing the " +"fields displayed (type, server, port, user and password)." +msgstr "" +"U ovoj kartici možete podesiti TWBlue da koristi proksi server popunjavanjem " +"prikazanih polja (vrsta, server, port, korisnik i lozinka)." + +#: ../doc/strings.py:231 +msgid "## License, source code and donations" +msgstr "## Licenca, izvorni kod i donacije" + +#: ../doc/strings.py:232 +msgid "" +"Tw Blue is free software, licensed under the GNU GPL license, either version " +"2 or, at your option, any later version. You can view the license in the " +"file named license.txt, or online at ." +msgstr "" +"Tw Blue je besplatan program, pod GNU GPL licencom, ili verzija 2 ili, u " +"zavisnosti od vaših mogućnosti, bilo koja novija verzija. Možete videti " +"licencu u datoteci license.txt, ili onlajn na lokaciji ." + +#: ../doc/strings.py:233 +msgid "" +"The source code of the program is available on GitHub at ." +msgstr "" +"Izvorni kod programa je dostupan na Githubu ." + +#: ../doc/strings.py:234 +msgid "" +"If you want to donate to the project, you can do so at . Thank you for your support!" +msgstr "" +"Ako želite da donirate za razvoj projekta, to možete uraditi na adresi " +". Hvala vam na podršci!" + +#: ../doc/strings.py:235 +msgid "## Contact" +msgstr "## Kontakt" + +#: ../doc/strings.py:236 +msgid "" +"If you still have questions after reading this document, if you wish to " +"collaborate to the project in some other way, or if you simply want to get " +"in touch with the application developer, follow the Twitter account [@tw" +"\\_blue2](https://twitter.com/tw_blue2) or [@manuelcortez00.](https://" +"twitter.com/manuelcortez00) You can also visit [our website](https://twblue." +"es)" +msgstr "" +"Ako imate još pitanja nakon što ste pročitali ovaj dokument, ako želite da " +"pomognete projektu na neki drugi način, ili ako jednostavno želite da se " +"obratite programeru aplikacije, pratite Twitter nalog [@tw\\_blue2](https://" +"twitter.com/tw_blue2) ili [@manuelcortez00.](https://twitter.com/" +"manuelcortez00) takođe možete da posetite [naš websajt](https://twblue.es)" + +#: ../doc/strings.py:237 +msgid "## Credits" +msgstr "## Zahvalnost" + +#: ../doc/strings.py:238 +msgid "" +"TWBlue is developed and maintained by [Manuel Cortéz](https://twitter.com/" +"manuelcortez00) and [José Manuel Delicado](https://twitter.com/jmdaweb)." +msgstr "" +"TWBlue programiraju i održavaju [Manuel Cortéz](https://twitter.com/" +"manuelcortez00) i [José Manuel Delicado](https://twitter.com/jmdaweb)." + +#: ../doc/strings.py:239 +msgid "" +"We would also like to thank the translators of TWBlue, who have allowed the " +"spreading of the application." +msgstr "" +"Takođe bismo želeli da se zahvalimo prevodiocima aplikacije TWBlue, koji su " +"dozvolili da se aplikacija proširi." + +#: ../doc/strings.py:240 +msgid "" +"* Arabic: [Mohammed Al Shara,](https://twitter.com/mohammed0204) [Hatoun " +"Felemban](https://twitter.com/HatounFelemban)" +msgstr "" +"* Arapski: [Mohammed Al Shara,](https://twitter.com/mohammed0204) [Hatoun " +"Felemban](https://twitter.com/HatounFelemban)" + +#: ../doc/strings.py:241 +msgid "* Basque: [Sukil Etxenike](https://twitter.com/sukil2011)." +msgstr "* Baskijski: [Sukil Etxenike](https://twitter.com/sukil2011)." + +#: ../doc/strings.py:242 +msgid "* Catalan: [Francisco Torres](https://twitter.com/ftgalleg)" +msgstr "* Katalonski: [Francisco Torres](https://twitter.com/ftgalleg)" + +#: ../doc/strings.py:243 +msgid "* Croatian: [Zvonimir Stanečić](https://twitter.com/zvonimirek222)." +msgstr "* Hrvatski: [Zvonimir Stanečić](https://twitter.com/zvonimirek222)." + +#: ../doc/strings.py:244 +msgid "* English: [Manuel Cortéz](https://twitter.com/manuelcortez00)." +msgstr "* Engleski: [Manuel Cortéz](https://twitter.com/manuelcortez00)." + +#: ../doc/strings.py:245 +msgid "* Finnish: [Jani Kinnunen](https://twitter.com/jani_kinnunen)." +msgstr "* Finski: [Jani Kinnunen](https://twitter.com/jani_kinnunen)." + +#: ../doc/strings.py:246 +msgid "* French: [Rémy Ruiz](https://twitter.com/blindhelp38)." +msgstr "* Francuski: [Rémy Ruiz](https://twitter.com/blindhelp38)." + +#: ../doc/strings.py:247 +msgid "* Galician: [Juan Buño](https://twitter.com/Quetzatl_)." +msgstr "* Galski: [Juan Buño](https://twitter.com/Quetzatl_)." + +#: ../doc/strings.py:248 +msgid "* German: [Steffen Schultz](https://twitter.com/schulle4u)." +msgstr "* Nemački: [Steffen Schultz](https://twitter.com/schulle4u)." + +#: ../doc/strings.py:249 +msgid "* Hungarian: Robert Osztolykan." +msgstr "* Mađarski: Robert Osztolykan." + +#: ../doc/strings.py:250 +msgid "* Italian: [Christian Leo Mameli](https://twitter.com/llajta2012)." +msgstr "* Italijanski: [Christian Leo Mameli](https://twitter.com/llajta2012)." + +#: ../doc/strings.py:251 +msgid "* Japanese: [Riku](https://twitter.com/_riku02)" +msgstr "* Japanski: [Riku](https://twitter.com/_riku02)" + +#: ../doc/strings.py:252 +msgid "* Polish: [Pawel Masarczyk.](https://twitter.com/Piciok)" +msgstr "* Poljski: [Pawel Masarczyk.](https://twitter.com/Piciok)" + +#: ../doc/strings.py:253 +msgid "* Portuguese: [Odenilton Júnior Santos.](https://twitter.com/romaleif)" +msgstr "" +"* Portugalski: [Odenilton Júnior Santos.](https://twitter.com/romaleif)" + +#: ../doc/strings.py:254 +msgid "" +"* Romanian: [Florian Ionașcu](https://twitter.com/florianionascu7) and " +"[Nicușor Untilă](https://twitter.com/dj_storm2001)" +msgstr "" +"* Rumunski: [Florian Ionașcu](https://twitter.com/florianionascu7) i " +"[Nicușor Untilă](https://twitter.com/dj_storm2001)" + +#: ../doc/strings.py:255 +msgid "" +"* Russian: [Наталья Хедлунд](https://twitter.com/Lifestar_n) and [Валерия " +"Кузнецова](https://twitter.com/ValeriaK305)." +msgstr "" +"* Ruski: [Наталья Хедлунд](https://twitter.com/Lifestar_n) i [Валерия " +"Кузнецова](https://twitter.com/ValeriaK305)." + +#: ../doc/strings.py:256 +msgid "* Serbian: [Aleksandar Đurić](https://twitter.com/sokodtreshnje)" +msgstr "* Srpski: [Aleksandar Đurić](https://twitter.com/sokodtreshnje)" + +#: ../doc/strings.py:257 +msgid "* Spanish: [Manuel Cortéz](https://twitter.com/manuelcortez00)." +msgstr "* Španski: [Manuel Cortéz](https://twitter.com/manuelcortez00)." + +#: ../doc/strings.py:258 +msgid "* Turkish: [Burak Yüksek](https://twitter.com/burakyuksek)." +msgstr "* Turski: [Burak Yüksek](https://twitter.com/burakyuksek)." + +#: ../doc/strings.py:259 +msgid "" +"Many thanks also to the people who worked on the documentation. Initially, " +"[Manuel Cortez](https://twitter.com/manuelcortez00) did the documentation in " +"Spanish, and translated to English by [Bryner Villalobos](https://twitter." +"com/Bry_StarkCR), [Robert Spangler](https://twitter.com/glasscity1837), " +"[Sussan Rey](https://twitter.com/sussanrey17), [Anibal Hernandez](https://" +"twitter.com/AnimalMetal), and [Holly Scott-Gardner](https://twitter.com/" +"CatchTheseWords). It was updated by [Sukil Etxenike](https://twitter.com/" +"sukil2011), with some valuable corrections by [Brian Hartgen](https://" +"twitter.com/brianhartgen) and [Bill Dengler](https://twitter.com/codeofdusk)." +msgstr "" +"Velika zahvalnost takođe svima koji su radili na dokumentaciji. Prvobitno, " +"[Manuel Cortez](https://twitter.com/manuelcortez00) je napisao dokumentaciju " +"na Španskom, i na Engleski su preveli [Bryner Villalobos](https://twitter." +"com/Bry_StarkCR), [Robert Spangler](https://twitter.com/glasscity1837), " +"[Sussan Rey](https://twitter.com/sussanrey17), [Anibal Hernandez](https://" +"twitter.com/AnimalMetal), i [Holly Scott-Gardner](https://twitter.com/" +"CatchTheseWords). Ažurirao ju je [Sukil Etxenike](https://twitter.com/" +"sukil2011), uz neke značajne ispravke od strane [Brian Hartgen](https://" +"twitter.com/brianhartgen) i [Bill Dengler](https://twitter.com/codeofdusk)." + +#: ../doc/strings.py:260 +msgid "------------------------------------------------------------------------" +msgstr "------------------------------------------------------------------------" + +#: ../doc/strings.py:261 +msgid "Copyright © 2013-2017. Manuel Cortéz" +msgstr "Autorsko pravo © 2013-2017. Manuel Cortéz" From 0612c653b88e0b7297c3be31017a4a7aaff82f5e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 02:32:28 -0500 Subject: [PATCH 052/245] Make TWBlue to respect persist_size when loading the cache database. Added tests for both reading from disk and loading in memory caches --- src/run_tests.py | 18 ++++ src/sessions/base.py | 19 ++-- src/test/__init__.py | 1 + src/test/test_cache.py | 194 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 src/run_tests.py create mode 100644 src/test/__init__.py create mode 100644 src/test/test_cache.py diff --git a/src/run_tests.py b/src/run_tests.py new file mode 100644 index 00000000..41842347 --- /dev/null +++ b/src/run_tests.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +import unittest + +testmodules = ["test.test_cache"] + +suite = unittest.TestSuite() + +for t in testmodules: + try: + # If the module defines a suite() function, call it to get the suite. + mod = __import__(t, globals(), locals(), ['suite']) + suitefn = getattr(mod, 'suite') + suite.addTest(suitefn()) + except (ImportError, AttributeError): + # else, just load all the test cases from the module. + suite.addTest(unittest.defaultTestLoader.loadTestsFromName(t)) + +unittest.TextTestRunner(verbosity=2).run(suite) \ No newline at end of file diff --git a/src/sessions/base.py b/src/sessions/base.py index e4e2999d..63ee5142 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -72,10 +72,10 @@ class baseSession(object): """ Returns a list with the amount of items specified by size.""" if isinstance(buffer, list) and size != -1 and len(buffer) > size: log.debug("Requesting {} items from a list of {} items. Reversed mode: {}".format(size, len(buffer), reversed)) - if reversed == False: - return buffer[size:] - else: + if reversed == True: return buffer[:size] + else: + return buffer[len(buffer)-size:] else: return buffer @@ -91,17 +91,20 @@ class baseSession(object): # Let's check if we need to create a new SqliteDict object (when loading db in memory) or we just need to call to commit in self (if reading from disk).db. # If we read from disk, we cannot modify the buffer size here as we could damage the app's integrity. # We will modify buffer's size (managed by persist_size) upon loading the db into memory in app startup. - if self.settings["general"]["load_cache_in_memory"]: + if self.settings["general"]["load_cache_in_memory"] and isinstance(self.db, dict): log.debug("Opening database to dump memory contents...") db=sqlitedict.SqliteDict(dbname, 'c') for k in self.db.keys(): - db[k] = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"]) + sized_buff = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"]) + db[k] = sized_buff + db.commit(blocking=True) db.close() log.debug("Data has been saved in the database.") else: try: log.debug("Syncing new data to disk...") - self.db.commit() + if hasattr(self.db, "commit"): + self.db.commit() except: output.speak(_("An exception occurred while saving the {app} database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the {app} developers.").format(app=application.name),True) log.exception("Exception while saving {}".format(dbname)) @@ -128,6 +131,7 @@ class baseSession(object): log.debug("Loading database contents into memory...") for k in db.keys(): self.db[k] = db[k] + db.commit(blocking=True) db.close() log.debug("Contents were loaded successfully.") else: @@ -136,7 +140,8 @@ class baseSession(object): # We must make sure we won't load more than the amount of buffer specified. log.debug("Checking if we will load all content...") for k in self.db.keys(): - self.db[k] = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"]) + sized_buffer = self.get_sized_buffer(self.db[k], self.settings["general"]["persist_size"], self.settings["general"]["reverse_timelines"]) + self.db[k] = sized_buffer if self.db.get("cursors") == None: cursors = dict(direct_messages=-1) self.db["cursors"] = cursors diff --git a/src/test/__init__.py b/src/test/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/src/test/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/test/test_cache.py b/src/test/test_cache.py new file mode 100644 index 00000000..af5e1c4d --- /dev/null +++ b/src/test/test_cache.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8 -*- +""" Test case to check some of the scenarios we might face when storing tweets in cache, both loading into memory or rreading from disk. """ +import unittest +import os +import paths +import sqlitedict +import shutil +# The base session module requires sound as a dependency, and this needs libVLC to be locatable. +os.environ['PYTHON_VLC_MODULE_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", "x86")) +os.environ['PYTHON_VLC_LIB_PATH']=os.path.abspath(os.path.join(paths.app_path(), "..", "windows-dependencies", "x86", "libvlc.dll")) +from sessions import base + +class cacheTestCase(unittest.TestCase): + + def setUp(self): + """ Configures a fake session to check caching objects here. """ + self.session = base.baseSession("testing") + if os.path.exists(os.path.join(paths.config_path(), "testing")) == False: + os.mkdir(os.path.join(paths.config_path(), "testing")) + self.session.get_configuration() + + def tearDown(self): + """ Removes the previously configured session. """ + session_folder = os.path.join(paths.config_path(), "testing") + if os.path.exists(session_folder): + shutil.rmtree(session_folder) + + def generate_dataset(self): + """ Generates a sample dataset""" + dataset = dict(home_timeline=["message" for i in range(10000)], mentions_timeline=["mention" for i in range(20000)]) + return dataset + + ### Testing database being read from disk. + + def test_cache_in_disk_unlimited_size(self): + """ Tests cache database being read from disk, storing the whole datasets. """ + dataset = self.generate_dataset() + self.session.settings["general"]["load_cache_in_memory"] = False + self.session.settings["general"]["persist_size"] = -1 + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + self.session.save_persistent_data() + self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(len(self.session.db.get("home_timeline")), 10000) + self.assertEquals(len(self.session.db.get("mentions_timeline")), 20000) + self.session.db.close() + + + def test_cache_in_disk_limited_dataset(self): + """ Tests wether the cache stores only the amount of items we ask it to store. """ + dataset = self.generate_dataset() + self.session.settings["general"]["load_cache_in_memory"] = False + self.session.settings["general"]["persist_size"] = 100 + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + # We need to save and load the db again because we cannot modify buffers' size while the database is opened. + # As TWBlue reads directly from db when reading from disk, an attempt to modify buffers size while Blue is reading the db + # Might cause an out of sync error between the GUI lists and the database. + # So we perform the changes to buffer size when loading data during app startup if the DB is read from disk. + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(len(self.session.db.get("home_timeline")), 100) + self.assertEquals(len(self.session.db.get("mentions_timeline")), 100) + self.session.db.close() + + def test_cache_in_disk_limited_dataset_unreversed(self): + """Test if the cache is saved properly in unreversed buffers, when newest items are at the end of the list. """ + dataset = dict(home_timeline=[i for i in range(20)], mentions_timeline=[i for i in range(20)]) + self.session.settings["general"]["load_cache_in_memory"] = False + self.session.settings["general"]["persist_size"] = 10 + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + # We need to save and load the db again because we cannot modify buffers' size while the database is opened. + # As TWBlue reads directly from db when reading from disk, an attempt to modify buffers size while Blue is reading the db + # Might cause an out of sync error between the GUI lists and the database. + # So we perform the changes to buffer size when loading data during app startup if the DB is read from disk. + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(self.session.db.get("home_timeline")[0], 10) + self.assertEquals(self.session.db.get("mentions_timeline")[0], 10) + self.assertEquals(self.session.db.get("home_timeline")[-1], 19) + self.assertEquals(self.session.db.get("mentions_timeline")[-1], 19) + self.session.db.close() + + def test_cache_in_disk_limited_dataset_reversed(self): + """Test if the cache is saved properly in reversed buffers, when newest items are at the start of the list. """ + dataset = dict(home_timeline=[i for i in range(19, -1, -1)], mentions_timeline=[i for i in range(19, -1, -1)]) + self.session.settings["general"]["load_cache_in_memory"] = False + self.session.settings["general"]["persist_size"] = 10 + self.session.settings["general"]["reverse_timelines"] = True + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + # We need to save and load the db again because we cannot modify buffers' size while the database is opened. + # As TWBlue reads directly from db when reading from disk, an attempt to modify buffers size while Blue is reading the db + # Might cause an out of sync error between the GUI lists and the database. + # So we perform the changes to buffer size when loading data during app startup if the DB is read from disk. + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(self.session.db.get("home_timeline")[0], 19) + self.assertEquals(self.session.db.get("mentions_timeline")[0], 19) + self.assertEquals(self.session.db.get("home_timeline")[-1], 10) + self.assertEquals(self.session.db.get("mentions_timeline")[-1], 10) + self.session.db.close() + + ### Testing database being loaded into memory. Those tests should give the same results than before + ### but as we have different code depending whether we load db into memory or read it from disk, + ### We need to test this anyways. + def test_cache_in_memory_unlimited_size(self): + """ Tests cache database being loaded in memory, storing the whole datasets. """ + dataset = self.generate_dataset() + self.session.settings["general"]["load_cache_in_memory"] = True + self.session.settings["general"]["persist_size"] = -1 + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, dict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(len(self.session.db.get("home_timeline")), 10000) + self.assertEquals(len(self.session.db.get("mentions_timeline")), 20000) + + def test_cache_in_memory_limited_dataset(self): + """ Tests wether the cache stores only the amount of items we ask it to store, when loaded in memory. """ + dataset = self.generate_dataset() + self.session.settings["general"]["load_cache_in_memory"] = True + self.session.settings["general"]["persist_size"] = 100 + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, dict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(len(self.session.db.get("home_timeline")), 100) + self.assertEquals(len(self.session.db.get("mentions_timeline")), 100) + + def test_cache_in_memory_limited_dataset_unreversed(self): + """Test if the cache is saved properly when loaded in memory in unreversed buffers, when newest items are at the end of the list. """ + dataset = dict(home_timeline=[i for i in range(20)], mentions_timeline=[i for i in range(20)]) + self.session.settings["general"]["load_cache_in_memory"] = True + self.session.settings["general"]["persist_size"] = 10 + self.session.load_persistent_data() + self.assertTrue(len(self.session.db)==1) + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, dict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(self.session.db.get("home_timeline")[0], 10) + self.assertEquals(self.session.db.get("mentions_timeline")[0], 10) + self.assertEquals(self.session.db.get("home_timeline")[-1], 19) + self.assertEquals(self.session.db.get("mentions_timeline")[-1], 19) + + def test_cache_in_memory_limited_dataset_reversed(self): + """Test if the cache is saved properly in reversed buffers, when newest items are at the start of the list. This test if for db read into memory. """ + dataset = dict(home_timeline=[i for i in range(19, -1, -1)], mentions_timeline=[i for i in range(19, -1, -1)]) + self.session.settings["general"]["load_cache_in_memory"] = True + self.session.settings["general"]["persist_size"] = 10 + self.session.settings["general"]["reverse_timelines"] = True + self.session.load_persistent_data() + self.session.db["home_timeline"] = dataset["home_timeline"] + self.session.db["mentions_timeline"] = dataset["mentions_timeline"] + self.session.save_persistent_data() + self.session.load_persistent_data() + self.assertIsInstance(self.session.db, dict) + self.assertTrue(self.session.db.get("home_timeline") != None) + self.assertTrue(self.session.db.get("mentions_timeline") != None) + self.assertEquals(self.session.db.get("home_timeline")[0], 19) + self.assertEquals(self.session.db.get("mentions_timeline")[0], 19) + self.assertEquals(self.session.db.get("home_timeline")[-1], 10) + self.assertEquals(self.session.db.get("mentions_timeline")[-1], 10) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 002e1ccb5560d2481bf73061bed5dbe68beee900 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 16:03:36 -0500 Subject: [PATCH 053/245] If get_user is called with a full user object as an argument, logs it and changes the object to be only the user_id --- src/sessions/twitter/session.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 4e3278cf..030d29e8 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -398,6 +398,9 @@ class Session(base.baseSession): """ Returns an user object associated with an ID. id str: User identifier, provided by Twitter. returns a tweepy user object.""" + if hasattr(id, "id_str"): + log.error("Called get_user function by passing a full user id as a parameter.") + id = id.id_str if ("users" in self.db) == False or (str(id) in self.db["users"]) == False: log.debug("Requesting user id {} as it is not present in the users database.".format(id)) try: From 4b60a79e492081aa4e5dc1df293d5029880dc82c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 18:04:26 -0500 Subject: [PATCH 054/245] Made get_all_mentioned to take into account sometimes tweets might have no entities defined --- src/sessions/twitter/utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index a9685212..10ba9c37 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -100,10 +100,11 @@ def is_media(tweet): def get_all_mentioned(tweet, conf, field="screen_name"): """ Gets all users that have been mentioned.""" results = [] - for i in tweet.entities["user_mentions"]: - if i["screen_name"] != conf["user_name"] and i["id_str"] != tweet.user: - if i.get(field) not in results: - results.append(i.get(field)) + if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): + for i in tweet.entities["user_mentions"]: + if i["screen_name"] != conf["user_name"] and i["id_str"] != tweet.user: + if i.get(field) not in results: + results.append(i.get(field)) return results def get_all_users(tweet, session): From 1b9062d86f39a941f3a3b96d68aa80014727494a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 18:05:35 -0500 Subject: [PATCH 055/245] aHandles deleted users for direct messages without wasting too many API calls --- src/sessions/twitter/session.py | 48 ++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 030d29e8..e33d1019 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -119,6 +119,12 @@ class Session(base.baseSession): self.reconnection_function_active = False self.counter = 0 self.lists = [] + # As users are cached for accessing them with not too many twitter calls, + # there could be a weird situation where a deleted user who sent direct messages to the current account will not be able to be retrieved at twitter. + # So we need to store an "user deleted" object in the cache, but have the ID of the deleted user in a local reference. + # This will be especially useful because if the user reactivates their account later, TWblue will try to retrieve such user again at startup. + # If we wouldn't implement this approach, TWBlue would save permanently the "deleted user" object. + self.deleted_users = {} # @_require_configuration def login(self, verify_credentials=True): @@ -401,16 +407,25 @@ class Session(base.baseSession): if hasattr(id, "id_str"): log.error("Called get_user function by passing a full user id as a parameter.") id = id.id_str + # Check if the user has been added to the list of deleted users previously. + if id in self.deleted_users: + log.debug("Returning user {} from the list of deleted users.".format(id)) + return self.deleted_users[id] if ("users" in self.db) == False or (str(id) in self.db["users"]) == False: log.debug("Requesting user id {} as it is not present in the users database.".format(id)) try: user = self.twitter.get_user(id=id) - except ValueError as err: + except TweepError as err: user = UserModel(None) user.screen_name = "deleted_user" user.id = id user.name = _("Deleted account") - return user + if hasattr(err, "api_code") and err.api_code == 50: + self.deleted_users[id] = user + return user + else: + log.exception("Error when attempting to retrieve an user from Twitter.") + return user users = self.db["users"] users[user.id_str] = user self.db["users"] = users @@ -443,18 +458,33 @@ class Session(base.baseSession): if len(user_ids) == 0: return log.debug("Received %d user IDS to be added in the database." % (len(user_ids))) - users_to_retrieve = [user_id for user_id in user_ids if user_id not in self.db["users"]] + users_to_retrieve = [user_id for user_id in user_ids if (user_id not in self.db["users"] and user_id not in self.deleted_users)] # Remove duplicates users_to_retrieve = list(dict.fromkeys(users_to_retrieve)) if len(users_to_retrieve) == 0: return log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) - users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") - users_db = self.db["users"] - for user in users: - users_db[user.id_str] = user - log.debug("Added %d new users" % (len(users))) - self.db["users"] = users_db + try: + users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") + users_db = self.db["users"] + for user in users: + users_db[user.id_str] = user + log.debug("Added %d new users" % (len(users))) + self.db["users"] = users_db + except TweepError as err: + if hasattr(err, "api_code") and err.api_code == 17: # Users not found. + log.error("The specified users {} were not found in twitter.".format(user_ids)) + # Creates a deleted user object for every user_id not found here. + # This will make TWBlue to not waste Twitter API calls when attempting to retrieve those users again. + # As deleted_users is not saved across restarts, when restarting TWBlue, it will retrieve the correct users if they enabled their accounts. + for id in users_to_retrieve: + user = UserModel(None) + user.screen_name = "deleted_user" + user.id = id + user.name = _("Deleted account") + self.deleted_users[id] = user + else: + log.exception("An exception happened while attempting to retrieve a list of users from direct messages in Twitter.") def add_users_from_results(self, data): users = self.db["users"] From 8db14a95c12ea5ed4a0f59557ba452181a562946 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 18:07:56 -0500 Subject: [PATCH 056/245] Call reduce.reduce_tweet and session.save_users when retrieving previous items for a buffer --- src/controller/buffers/twitterBuffers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index d44d0b1d..03657e7c 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -19,7 +19,7 @@ import languageHandler import logging from audio_services import youtube_utils from controller.buffers import baseBuffers -from sessions.twitter import compose, utils +from sessions.twitter import compose, utils, reduce from mysc.thread_utils import call_threaded from tweepy.error import TweepError from tweepy.cursor import Cursor @@ -231,8 +231,10 @@ class baseBufferController(baseBuffers.buffer): if items == None: return items_db = self.session.db[self.name] + self.session.add_users_from_results(items) for i in items: if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i.id, self.session.db[self.name]) == None: + i = reduce.reduce_tweet(i) i = self.session.check_quoted_status(i) i = self.session.check_long_tweet(i) elements.append(i) From 3ebfdbc48bf793cf1b5a1b5b66a9f41a71d52972 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 19:09:21 -0500 Subject: [PATCH 057/245] Request for a restart when switching memory cache --- src/controller/mainController.py | 1 + src/controller/settings.py | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 0dfe9039..b405b3b2 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -617,6 +617,7 @@ class Controller(object): if d.needs_restart == True: commonMessageDialogs.needs_restart() buff.session.settings.write() + buff.session.save_persistent_data() restart.restart_program() def report_error(self, *args, **kwargs): diff --git a/src/controller/settings.py b/src/controller/settings.py index b1acceb8..84040d2e 100644 --- a/src/controller/settings.py +++ b/src/controller/settings.py @@ -1,7 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals -from builtins import str -from builtins import object import os import webbrowser import sound_lib @@ -194,7 +191,9 @@ class accountSettingsController(globalSettingsController): self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time") self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names") self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall") - self.config["general"]["load_cache_in_memory"] = self.dialog.get_value("general", "load_cache_in_memory") + if self.config["general"]["load_cache_in_memory"] != self.dialog.get_value("general", "load_cache_in_memory"): + self.config["general"]["load_cache_in_memory"] = self.dialog.get_value("general", "load_cache_in_memory") + self.needs_restart = True if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"): if self.dialog.get_value("general", "persist_size") == '': self.config["general"]["persist_size"] =-1 From a59ba5ef78f926e8f46d5d73294454e4310af50d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 19:09:49 -0500 Subject: [PATCH 058/245] Reset cache every time we call to save_persistent_data in tests --- src/test/test_cache.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/test_cache.py b/src/test/test_cache.py index af5e1c4d..6337c3b2 100644 --- a/src/test/test_cache.py +++ b/src/test/test_cache.py @@ -48,7 +48,6 @@ class cacheTestCase(unittest.TestCase): self.assertEquals(len(self.session.db.get("mentions_timeline")), 20000) self.session.db.close() - def test_cache_in_disk_limited_dataset(self): """ Tests wether the cache stores only the amount of items we ask it to store. """ dataset = self.generate_dataset() @@ -62,6 +61,7 @@ class cacheTestCase(unittest.TestCase): # Might cause an out of sync error between the GUI lists and the database. # So we perform the changes to buffer size when loading data during app startup if the DB is read from disk. self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) self.assertTrue(self.session.db.get("home_timeline") != None) @@ -83,6 +83,7 @@ class cacheTestCase(unittest.TestCase): # Might cause an out of sync error between the GUI lists and the database. # So we perform the changes to buffer size when loading data during app startup if the DB is read from disk. self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) self.assertTrue(self.session.db.get("home_timeline") != None) @@ -107,6 +108,7 @@ class cacheTestCase(unittest.TestCase): # Might cause an out of sync error between the GUI lists and the database. # So we perform the changes to buffer size when loading data during app startup if the DB is read from disk. self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, sqlitedict.SqliteDict) self.assertTrue(self.session.db.get("home_timeline") != None) @@ -129,6 +131,7 @@ class cacheTestCase(unittest.TestCase): self.session.db["home_timeline"] = dataset["home_timeline"] self.session.db["mentions_timeline"] = dataset["mentions_timeline"] self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, dict) self.assertTrue(self.session.db.get("home_timeline") != None) @@ -145,6 +148,7 @@ class cacheTestCase(unittest.TestCase): self.session.db["home_timeline"] = dataset["home_timeline"] self.session.db["mentions_timeline"] = dataset["mentions_timeline"] self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, dict) self.assertTrue(self.session.db.get("home_timeline") != None) @@ -162,6 +166,7 @@ class cacheTestCase(unittest.TestCase): self.session.db["home_timeline"] = dataset["home_timeline"] self.session.db["mentions_timeline"] = dataset["mentions_timeline"] self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, dict) self.assertTrue(self.session.db.get("home_timeline") != None) @@ -181,6 +186,7 @@ class cacheTestCase(unittest.TestCase): self.session.db["home_timeline"] = dataset["home_timeline"] self.session.db["mentions_timeline"] = dataset["mentions_timeline"] self.session.save_persistent_data() + self.session.db = dict() self.session.load_persistent_data() self.assertIsInstance(self.session.db, dict) self.assertTrue(self.session.db.get("home_timeline") != None) From 9dfccd2bd0f8b408d77f4092457c518ef127e972 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 20:55:16 -0500 Subject: [PATCH 059/245] Updated documentation generators --- doc/documentation_importer.py | 4 ++-- doc/generator.py | 31 ++++++++++++++++--------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/doc/documentation_importer.py b/doc/documentation_importer.py index 7fc927aa..9210a28a 100644 --- a/doc/documentation_importer.py +++ b/doc/documentation_importer.py @@ -16,9 +16,9 @@ def prepare_documentation_in_file(fileSource, fileDest): if "\n" == i: newvar = "\"\"," elif "\n" == i[-1]: - newvar = "_(u\"\"\"%s\"\"\"),\n" % (i[:-1]) + newvar = "\"\"\"%s\"\"\",\n" % (i[:-1]) else: - newvar = "_(u\"\"\"%s\"\"\"),\n" % (i) + newvar = "\"\"\"%s\"\"\",\n" % (i) f2.write(newvar) f1.close() f2.write("]") diff --git a/doc/generator.py b/doc/generator.py index e26f7b75..3bc6bb4e 100644 --- a/doc/generator.py +++ b/doc/generator.py @@ -8,10 +8,11 @@ import shutil from codecs import open as _open from importlib import reload -def change_language(name, language): - global _ - os.environ["lang"] = language - _ = gettext.install(name, os.path.join(paths.app_path(), "locales")) +def get_translation_function(name, language): + if language == "en": + return gettext.NullTranslations() + translation_function = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[language]) + return translation_function # the list of supported language codes of TW Blue languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da"] @@ -19,17 +20,15 @@ languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", " def generate_document(language, document_type="documentation"): if document_type == "documentation": translation_file = "twblue-documentation" - change_language(translation_file, language) - reload(strings) - markdown_file = markdown.markdown("\n".join(strings.documentation[1:]), extensions=["markdown.extensions.toc"]) - title = strings.documentation[0] + translation_function = get_translation_function(translation_file, language) + markdown_file = markdown.markdown("\n".join([translation_function.gettext(s[:-1]) if s != "\n" else s for s in strings.documentation[1:]]), extensions=["markdown.extensions.toc"]) + title = translation_function.gettext(strings.documentation[0][:-1]) filename = "manual.html" elif document_type == "changelog": translation_file = "twblue-changelog" - change_language(translation_file, language) - reload(changelog) - markdown_file = markdown.markdown("\n".join(changelog.documentation[1:]), extensions=["markdown.extensions.toc"]) - title = changelog.documentation[0] + translation_function = get_translation_function(translation_file, language) + markdown_file = markdown.markdown("\n".join([translation_function.gettext(s[:-1]) if s != "\n" else s for s in changelog.documentation[1:]]), extensions=["markdown.extensions.toc"]) + title = translation_function.gettext(changelog.documentation[0][:-1]) filename = "changelog.html" first_html_block = """ @@ -56,11 +55,13 @@ def create_documentation(): shutil.copy(os.path.join("..", "license.txt"), os.path.join("documentation", "license.txt")) for i in languages: print("Creating documentation for: %s" % (i,)) - generate_document(i) - generate_document(i, "changelog") + try: + generate_document(i) + generate_document(i, "changelog") + except: + continue print("Done") -change_language("twblue-documentation", "en") import strings import changelog create_documentation() \ No newline at end of file From fbbe7852c2a2a5320c3ab7f56cb57bae228c0220 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 20:57:13 -0500 Subject: [PATCH 060/245] Added serbian to generate documentation --- doc/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/generator.py b/doc/generator.py index 3bc6bb4e..b48374ad 100644 --- a/doc/generator.py +++ b/doc/generator.py @@ -15,7 +15,7 @@ def get_translation_function(name, language): return translation_function # the list of supported language codes of TW Blue -languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da"] +languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da", "sr"] def generate_document(language, document_type="documentation"): if document_type == "documentation": From 64a14c831be619164c2cd9fb0686203899c038f8 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 27 Jun 2021 21:40:22 -0500 Subject: [PATCH 061/245] Added initial support for playback of Twitter videos (only works in tweets so far) --- src/controller/buffers/twitterBuffers.py | 2 +- src/sessions/twitter/utils.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index 03657e7c..b88fbe43 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -553,7 +553,7 @@ class baseBufferController(baseBuffers.buffer): return sound.URLPlayer.stop_audio() tweet = self.get_tweet() if tweet == None: return - urls = utils.find_urls(tweet) + urls = utils.find_urls(tweet, twitter_media=True) if len(urls) == 1: url=urls[0] elif len(urls) > 1: diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 10ba9c37..ce0ae47b 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -21,8 +21,15 @@ bad_chars = '\'\\\n.,[](){}:;"' def find_urls_in_text(text): return url_re2.findall(text) -def find_urls (tweet): +def find_urls (tweet, twitter_media=False): urls = [] + if twitter_media and hasattr(tweet, "extended_entities"): + for mediaItem in tweet.extended_entities["media"]: + if mediaItem["type"] == "video": + for variant in mediaItem["video_info"]["variants"]: + if variant["content_type"] == "video/mp4": + urls.append(variant["url"]) + break # Let's add URLS from tweet entities. if hasattr(tweet, "message_create"): entities = tweet.message_create["message_data"]["entities"] @@ -63,6 +70,11 @@ def find_list(name, lists): if lists[i].name == name: return lists[i].id def is_audio(tweet): + # Checks firstly for Twitter videos and audios. + if hasattr(tweet, "extended_entities"): + for mediaItem in tweet.extended_entities["media"]: + if mediaItem["type"] == "video": + return True try: if len(find_urls(tweet)) < 1: return False From 02d94fcea09305dbbfcd314df9bcab13f965759f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 00:36:53 -0500 Subject: [PATCH 062/245] Fixed a small issue when loading a conversation buffer --- src/controller/buffers/twitterBuffers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitterBuffers.py index b88fbe43..3e09243f 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitterBuffers.py @@ -1230,6 +1230,8 @@ class conversationBufferController(searchBufferController): self.statuses.append(self.tweet) self.ids.append(self.tweet.id) tweet = self.tweet + if not hasattr(tweet, "in_reply_to_status_id"): + tweet.in_reply_to_status_id = None while tweet.in_reply_to_status_id != None: try: tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") From 7f401ba789a199f241fc604217637496dbbe5e96 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 00:39:45 -0500 Subject: [PATCH 063/245] Removed unneeded locales --- ... Kinnunen's conflicted copy 2019-03-25).po | 4187 ---------------- ... Kinnunen's conflicted copy 2019-03-25).mo | Bin 49494 -> 0 bytes ... Kinnunen's conflicted copy 2019-03-25).po | 3371 ------------- ... Kinnunen's conflicted copy 2019-03-25).po | 4190 ----------------- src/locales/it/LC_MESSAGES/twblue.po | 4157 ---------------- 5 files changed, 15905 deletions(-) delete mode 100644 src/locales/ca/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po delete mode 100644 src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).mo delete mode 100644 src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po delete mode 100644 src/locales/gl/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po delete mode 100644 src/locales/it/LC_MESSAGES/twblue.po diff --git a/src/locales/ca/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po b/src/locales/ca/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po deleted file mode 100644 index 00ed6817..00000000 --- a/src/locales/ca/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po +++ /dev/null @@ -1,4187 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2018-08-08 18:22+0200\n" -"Last-Translator: Manuel Cortez \n" -"Language-Team: Fran Torres Gallego \n" -"Language: ca\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.1.1\n" -"X-Poedit-KeywordsList: _;gettext;gettext_noop\n" -"X-Poedit-Basepath: .\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-SourceCharset: UTF-8\n" - -#: ../src\controller\attach.py:23 -msgid "Photo" -msgstr "Foto" - -#: ../src\controller\buffers\baseBuffers.py:95 -msgid "This action is not supported for this buffer" -msgstr "El buffer actual no suporta aquesta acció" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 -msgid "Home" -msgstr "Principal" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 -msgid "Mentions" -msgstr "Mencions" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 -msgid "Direct messages" -msgstr "Missatges directes" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 -msgid "Sent direct messages" -msgstr "Missatges directes enviats" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 -msgid "Sent tweets" -msgstr "Tuits enviats" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 -msgid "Likes" -msgstr "Tuits que m'agraden." - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 -msgid "Followers" -msgstr "Seguidors" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "Amics" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 -msgid "Blocked users" -msgstr "Usuaris bloquejats" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 -msgid "Muted users" -msgstr "Usuaris silenciats" - -#: ../src\controller\buffers\twitterBuffers.py:75 -#, fuzzy -msgid "{username}'s timeline" -msgstr "Obrir línia temporal" - -#: ../src\controller\buffers\twitterBuffers.py:77 -msgid "{username}'s likes" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:79 -msgid "{username}'s followers" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:81 -msgid "{username}'s friends" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:83 -#, fuzzy -msgid "Unknown buffer" -msgstr "Desconegut" - -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 -msgid "Tweet" -msgstr "Tuit" - -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 -msgid "Write the tweet here" -msgstr "Escriu el tuit aquí" - -#: ../src\controller\buffers\twitterBuffers.py:194 -#, fuzzy -msgid "New tweet in {0}" -msgstr "Tuit nou" - -#: ../src\controller\buffers\twitterBuffers.py:197 -#, fuzzy -msgid "{0} new tweets in {1}." -msgstr "@{0} Ha citat el teu tuit: {1}" - -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 -msgid "%s items retrieved" -msgstr "%s elements descarregats" - -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "Aquest buffer no es una liniatemporal; no es pot eliminar." - -#: ../src\controller\buffers\twitterBuffers.py:402 -msgid "Reply to {arg0}" -msgstr "Respondre a {arg0}" - -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 -msgid "Reply" -msgstr "Respondre" - -#: ../src\controller\buffers\twitterBuffers.py:405 -msgid "Reply to %s" -msgstr "Respondre a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Missatge directe a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 -msgid "New direct message" -msgstr "Nou missatge directe" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Add your comment to the tweet" -msgstr "Afegeix el teu comentari al tuit" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Quote" -msgstr "citar" - -#: ../src\controller\buffers\twitterBuffers.py:572 -msgid "Opening URL..." -msgstr "Obrint URL..." - -#: ../src\controller\buffers\twitterBuffers.py:607 -msgid "User details" -msgstr "Detalls de l'usuari" - -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 -msgid "Opening item in web browser..." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -msgid "Mention to %s" -msgstr "Mencionar a %s" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 -msgid "Mention" -msgstr "Menció" - -#: ../src\controller\buffers\twitterBuffers.py:728 -#, fuzzy -msgid "{0} new direct messages." -msgstr "Nou missatge directe" - -#: ../src\controller\buffers\twitterBuffers.py:731 -#, fuzzy -msgid "This action is not supported in the buffer yet." -msgstr "El buffer actual no suporta aquesta acció" - -#: ../src\controller\buffers\twitterBuffers.py:741 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy -msgid "{0} new followers." -msgstr "Nou seguidor." - -#: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy -msgid "This action is not supported in the buffer, yet." -msgstr "El buffer actual no suporta aquesta acció" - -#: ../src\controller\mainController.py:273 -msgid "Ready" -msgstr "Llest." - -#: ../src\controller\mainController.py:345 -msgid "Timelines" -msgstr "Línies temporals" - -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 -msgid "Timeline for {}" -msgstr "Línia temporal per a {}" - -#: ../src\controller\mainController.py:352 -msgid "Likes timelines" -msgstr "Línies temporals de tuits que m'agraden" - -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 -msgid "Likes for {}" -msgstr "Tuits que agraden a {}" - -#: ../src\controller\mainController.py:359 -msgid "Followers' Timelines" -msgstr "Línies temporals de seguidors." - -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 -msgid "Followers for {}" -msgstr "Seguidors de {}" - -#: ../src\controller\mainController.py:366 -msgid "Friends' Timelines" -msgstr "Línies temporals d'amics" - -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 -msgid "Friends for {}" -msgstr "Amics de {}" - -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 -msgid "Lists" -msgstr "Llistes" - -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 -msgid "List for {}" -msgstr "Llista per {}" - -#: ../src\controller\mainController.py:381 -msgid "Searches" -msgstr "Recerques" - -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 -msgid "Search for {}" -msgstr "Cercar per {}" - -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 -msgid "Trending topics for %s" -msgstr "Tendències de %s" - -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "" -"No hi ha cap sessió en el focus. Focalitza una sessió amb les dreceres " -"d'anterior o següent sessió." - -#: ../src\controller\mainController.py:465 -msgid "Empty buffer." -msgstr "Buidar buffer." - -#: ../src\controller\mainController.py:472 -msgid "{0} not found." -msgstr "{0} no s'ha trobat." - -#: ../src\controller\mainController.py:482 -msgid "Filters cannot be applied on this buffer" -msgstr "No es poden aplicar filtres a aquest bufer" - -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 -msgid "Select the user" -msgstr "Selecciona l'usuari" - -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy -msgid "MMM D, YYYY. H:m" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\controller\mainController.py:934 -msgid "Conversation with {0}" -msgstr "Conversa amb {0}" - -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 -msgid "There are no coordinates in this tweet" -msgstr "En aquest tuit no hi ha coordenades." - -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "No hi ha resultats per a les coordenades d'aquest tuit." - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 -msgid "Error decoding coordinates. Try again later." -msgstr "Error decodificant les coordenades. Si et plau, prova-ho més tard." - -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 -msgid "%s, %s of %s" -msgstr "%s, %s de %s" - -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 -msgid "%s. Empty" -msgstr "%s. buit" - -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 -msgid "{0}: This account is not logged into Twitter." -msgstr "{0}: No s'ha iniciat sessió a Twitter amb aquest compte" - -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 -msgid "%s. %s, %s of %s" -msgstr "%s. %s, %s de %s" - -#: ../src\controller\mainController.py:1170 -msgid "{0}: This account is not logged into twitter." -msgstr "{0}: No s'ha iniciat sessió a Twitter amb aquest compte" - -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Esdeveniments" - -#: ../src\controller\mainController.py:1393 -msgid "This list is already opened" -msgstr "Aquesta llista ja està oberta." - -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 -#, fuzzy -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "" -"Alguna cosa inesperada ha passat quan s'intentaba reportar el teu problema. " -"Si et plau, prova-ho de nou més tard." - -#: ../src\controller\mainController.py:1475 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "La lectura automàtica de tuits per a aquest buffer està activada." - -#: ../src\controller\mainController.py:1478 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "La lectura automàtica de tuits per a aquest buffer està desactivada." - -#: ../src\controller\mainController.py:1485 -msgid "Session mute on" -msgstr "Silenci de sessió activat" - -#: ../src\controller\mainController.py:1488 -msgid "Session mute off" -msgstr "Silenci de sessió desactivat." - -#: ../src\controller\mainController.py:1496 -msgid "Buffer mute on" -msgstr "Silenci de buffer activat" - -#: ../src\controller\mainController.py:1499 -msgid "Buffer mute off" -msgstr "Silenci de buffer desactivat" - -#: ../src\controller\mainController.py:1522 -msgid "Copied" -msgstr "Copiat" - -#: ../src\controller\mainController.py:1549 -msgid "Unable to update this buffer." -msgstr "No es pot actualitzar aquest buffer." - -#: ../src\controller\mainController.py:1552 -msgid "Updating buffer..." -msgstr "Actualitzant buffer..." - -#: ../src\controller\mainController.py:1555 -msgid "{0} items retrieved" -msgstr "{0} elements descarregats." - -#: ../src\controller\mainController.py:1572 -msgid "Invalid buffer" -msgstr "Bufer invàlid." - -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "Aquest twit no contè imatges." - -#: ../src\controller\mainController.py:1579 -msgid "Picture {0}" -msgstr "Imatge de {0}" - -#: ../src\controller\mainController.py:1580 -msgid "Select the picture" -msgstr "Selecciona una imatge." - -#: ../src\controller\mainController.py:1596 -msgid "Unable to extract text" -msgstr "No es pot extreure el text." - -#: ../src\controller\messages.py:54 -msgid "Translated" -msgstr "Traduït" - -#: ../src\controller\messages.py:61 -msgid "There's no URL to be shortened" -msgstr "No hi ha cap adreça per escurçar." - -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 -msgid "URL shortened" -msgstr "Adreça escurçada." - -#: ../src\controller\messages.py:80 -msgid "There's no URL to be expanded" -msgstr "No hi ha cap adreça per expandir." - -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 -msgid "URL expanded" -msgstr "Adreça expandida" - -#: ../src\controller\messages.py:104 -msgid "%s - %s of %d characters" -msgstr "%s - %s de %d caracters" - -#: ../src\controller\messages.py:108 -msgid "%s - %s characters" -msgstr "%s - %s caracters" - -#: ../src\controller\messages.py:262 -msgid "View item" -msgstr "&Veure Element" - -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Conexió directa." - -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Ask" -msgstr "Pregunta" - -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet without comments" -msgstr "Retuiteja sense comentaris" - -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet with comments" -msgstr "Retuiteja amb comentaris" - -#: ../src\controller\settings.py:184 -msgid "Account settings for %s" -msgstr "Configuració del compte per a %s" - -#: ../src\controller\settings.py:284 -msgid "Direct Messages" -msgstr "missatges directes" - -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 -msgid "Error" -msgstr "Error" - -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 -msgid "That user does not exist" -msgstr "Aquest 'usuari no existeix" - -#: ../src\controller\user.py:30 -msgid "User has been suspended" -msgstr "L'usuari ha estat suspès" - -#: ../src\controller\user.py:36 -msgid "Information for %s" -msgstr "Detalls per a %s" - -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 -msgid "Discarded" -msgstr "Descartat" - -#: ../src\controller\user.py:95 -msgid "Username: @%s\n" -msgstr "Nom d'usuari: @%s\n" - -#: ../src\controller\user.py:96 -msgid "Name: %s\n" -msgstr "Nom: %s\n" - -#: ../src\controller\user.py:98 -msgid "Location: %s\n" -msgstr "Localització: %s\n" - -#: ../src\controller\user.py:100 -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: ../src\controller\user.py:102 -msgid "Bio: %s\n" -msgstr "Descripció: %s\n" - -#: ../src\controller\user.py:103 ../src\controller\user.py:118 -msgid "Yes" -msgstr "Sí" - -#: ../src\controller\user.py:104 ../src\controller\user.py:119 -msgid "No" -msgstr "No" - -#: ../src\controller\user.py:105 -msgid "Protected: %s\n" -msgstr "Protegit: %s\n" - -#: ../src\controller\user.py:110 -msgid "You follow {0}. " -msgstr "Ja segueixes a {0}. " - -#: ../src\controller\user.py:113 -msgid "{0} is following you." -msgstr "{0} et segueix" - -#: ../src\controller\user.py:117 -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"Seguidors: %s\n" -" Amics: %s\n" - -#: ../src\controller\user.py:120 -msgid "Verified: %s\n" -msgstr "Verificat: %s\n" - -#: ../src\controller\user.py:121 -msgid "Tweets: %s\n" -msgstr "Tuits: %s\n" - -#: ../src\controller\user.py:122 -msgid "Likes: %s" -msgstr "m'agraden" - -#: ../src\controller\userActionsController.py:75 -msgid "You can't ignore direct messages" -msgstr "No pots ignorar els missatges directes." - -#: ../src\extra\AudioUploader\audioUploader.py:54 -msgid "Attaching..." -msgstr "Adjuntant..." - -#: ../src\extra\AudioUploader\audioUploader.py:71 -msgid "Pause" -msgstr "Pausa" - -#: ../src\extra\AudioUploader\audioUploader.py:73 -msgid "&Resume" -msgstr "&Continúa" - -#: ../src\extra\AudioUploader\audioUploader.py:74 -msgid "Resume" -msgstr "Continúa" - -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 -msgid "&Pause" -msgstr "&Pausa" - -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 -msgid "&Stop" -msgstr "&Aturar" - -#: ../src\extra\AudioUploader\audioUploader.py:92 -msgid "Recording" -msgstr "Grabant" - -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 -msgid "Stopped" -msgstr "Aturat" - -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 -msgid "&Record" -msgstr "&Grabar" - -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 -msgid "Playing..." -msgstr "Reproduïnt..." - -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 -msgid "&Play" -msgstr "&Reproduir" - -#: ../src\extra\AudioUploader\audioUploader.py:156 -msgid "Recoding audio..." -msgstr "Recodificant audio..." - -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 -msgid "Error in file upload: {0}" -msgstr "Error al carregar el fitxer: {0}" - -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 -msgid "%d day, " -msgstr "%d dia, " - -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 -msgid "%d days, " -msgstr "%d dies, " - -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 -msgid "%d hour, " -msgstr "%d hora, " - -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 -msgid "%d hours, " -msgstr "%d hores, " - -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 -msgid "%d minute, " -msgstr "%d minut, " - -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 -msgid "%d minutes, " -msgstr "%d minuts, " - -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 -msgid "%s second" -msgstr "%s segon" - -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 -msgid "%s seconds" -msgstr "%s segons" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 -msgid "File" -msgstr "Fitxer" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 -msgid "Transferred" -msgstr "Transferit" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 -msgid "Total file size" -msgstr "Mida total del fitxer" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 -msgid "Transfer rate" -msgstr "Velocitat de transferencia" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 -msgid "Time left" -msgstr "Temps restant" - -#: ../src\extra\AudioUploader\wx_ui.py:28 -msgid "Attach audio" -msgstr "Adjuntar audio" - -#: ../src\extra\AudioUploader\wx_ui.py:40 -msgid "&Add an existing file" -msgstr "&Afegir un fitxer existent" - -#: ../src\extra\AudioUploader\wx_ui.py:41 -msgid "&Discard" -msgstr "&Descartar" - -#: ../src\extra\AudioUploader\wx_ui.py:43 -msgid "Upload to" -msgstr "Enviar a:" - -#: ../src\extra\AudioUploader\wx_ui.py:48 -msgid "Attach" -msgstr "Adjuntar" - -#: ../src\extra\AudioUploader\wx_ui.py:50 -msgid "&Cancel" -msgstr "&Cancel·lar" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "Arxius d'audio (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Select the audio file to be uploaded" -msgstr "Selecciona el fitxer d'audio que vols carregar" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 -msgid "Audio tweet." -msgstr "Tuit d'audio" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "User timeline buffer created." -msgstr "S'ha creat el buffer de la linia temporal de l'usuari" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "Buffer destroied." -msgstr "Buffer eliminat" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Direct message received." -msgstr "Missatge directe rebut." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message sent." -msgstr "Missatge directe enviat." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Error." -msgstr "Error." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Tweet liked." -msgstr "Tuit marcat com m'agrada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Likes buffer updated." -msgstr "Buffer de tuits que m'agraden actualitzat" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Geotweet." -msgstr "Geotuit" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Tweet contains one or more images" -msgstr "El twit contè una o més imatges." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Boundary reached." -msgstr "No hi ha més elements" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "List updated." -msgstr "Llista actualitzada" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "Too many characters." -msgstr "Massa caracters" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Mention received." -msgstr "Menció rebuda" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "New event." -msgstr "Esdeveniment nou." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "{0} is ready." -msgstr "{0} és a punt." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -msgid "Mention sent." -msgstr "Menció enviada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Tweet retweeted." -msgstr "Tuit retuitejat." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Search buffer updated." -msgstr "Buffer de recerca actualitzat" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Tweet received." -msgstr "Tuit rebut." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet sent." -msgstr "Tuit enviat." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Trending topics buffer updated." -msgstr "Búfer de tendències actualitzat" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "New tweet in user timeline buffer." -msgstr "Tuit nou a la línia temporal de l'usuari." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New follower." -msgstr "Nou seguidor." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "Volume changed." -msgstr "Volum canviat" - -#: ../src\extra\SoundsTutorial\wx_ui.py:8 -msgid "Sounds tutorial" -msgstr "Tutorial de sons" - -#: ../src\extra\SoundsTutorial\wx_ui.py:11 -msgid "Press enter to listen to the sound for the selected event" -msgstr "Prem enter per escoltar el so per al esdeveniment seleccionat." - -#: ../src\extra\SpellChecker\spellchecker.py:57 -msgid "Misspelled word: %s" -msgstr "Paraula mal escrita: %s" - -#: ../src\extra\SpellChecker\wx_ui.py:27 -msgid "Misspelled word" -msgstr "Paraula mal escrita" - -#: ../src\extra\SpellChecker\wx_ui.py:32 -msgid "Context" -msgstr "Context" - -#: ../src\extra\SpellChecker\wx_ui.py:37 -msgid "Suggestions" -msgstr "Sugeriments" - -#: ../src\extra\SpellChecker\wx_ui.py:42 -msgid "&Ignore" -msgstr "&Ignorar" - -#: ../src\extra\SpellChecker\wx_ui.py:43 -msgid "I&gnore all" -msgstr "I&gnorar tot" - -#: ../src\extra\SpellChecker\wx_ui.py:44 -msgid "&Replace" -msgstr "R&eemplaçar" - -#: ../src\extra\SpellChecker\wx_ui.py:45 -msgid "R&eplace all" -msgstr "Reemplaçar t&ots." - -#: ../src\extra\SpellChecker\wx_ui.py:46 -msgid "&Add to personal dictionary" -msgstr "A&fegir al diccionari personal" - -#: ../src\extra\SpellChecker\wx_ui.py:79 -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "" -"Hi ha hagut un problema. No hi ha diccionaris disponibles per a l'idioma " -"seleccionat a {0}." - -#: ../src\extra\SpellChecker\wx_ui.py:82 -msgid "Spell check complete." -msgstr "Comprovació d'ortografia finalitzada" - -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 -msgid "You have to start writing" -msgstr "Has de començar a escriure." - -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 -msgid "There are no results in your users database" -msgstr "No hi ha resultats a la teva base de dades d'usuaris." - -#: ../src\extra\autocompletionUsers\completion.py:33 -msgid "Autocompletion only works for users." -msgstr "l'autocompletat només funciona per a usuaris." - -#: ../src\extra\autocompletionUsers\settings.py:27 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"Actualitzant la base de dades... Pots tancar aquesta finestra, un nissatge " -"t'avisarà quan el procés hagi acabat." - -#: ../src\extra\autocompletionUsers\wx_manage.py:8 -msgid "Manage Autocompletion database" -msgstr "Gestionar la base de dades d'autocompletar." - -#: ../src\extra\autocompletionUsers\wx_manage.py:11 -msgid "Editing {0} users database" -msgstr "Editant la base de dades d'usuaris de {0}." - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Username" -msgstr "Nom d'usuari." - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "Nom." - -#: ../src\extra\autocompletionUsers\wx_manage.py:15 -msgid "Add user" -msgstr "Afegir usuari." - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Remove user" -msgstr "Esborrar usuari." - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Add user to database" -msgstr "Afegir usuari a la base de dades." - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Twitter username" -msgstr "Nom d'usuari de Twitter." - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -msgid "The user does not exist" -msgstr "L'usuari no existeix" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "Error!" -msgstr "Error!" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "Configuració d'autocompletar usuaris" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "Afegir usuaris des del buffer de seguidors." - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "Afegir usuaris des del buffer d'amics" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "Gestionar base de dades..." - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "Fet" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "La base de dades d'usuaris de {0} s'ha actualitzat" - -#: ../src\extra\ocr\OCRSpace.py:5 -msgid "Detect automatically" -msgstr "Detecció automàtica" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 -msgid "Danish" -msgstr "Danès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 -msgid "Dutch" -msgstr "olandès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 -msgid "English" -msgstr "Anglès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 -msgid "Finnish" -msgstr "Finès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 -msgid "French" -msgstr "Francès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 -msgid "German" -msgstr "Alemany" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 -msgid "Hungarian" -msgstr "Hongarès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 -msgid "Italian" -msgstr "Italià" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 -msgid "Japanese" -msgstr "Japonès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 -msgid "Korean" -msgstr "Coreà" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 -msgid "Polish" -msgstr "Polac" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 -msgid "Portuguese" -msgstr "Portuguès" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 -msgid "Russian" -msgstr "Rus" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 -msgid "Spanish" -msgstr "Espanyol" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 -msgid "Turkish" -msgstr "Turc" - -#: ../src\extra\translator\translator.py:12 -msgid "Afrikaans" -msgstr "Africà" - -#: ../src\extra\translator\translator.py:13 -msgid "Albanian" -msgstr "Albanès" - -#: ../src\extra\translator\translator.py:14 -msgid "Amharic" -msgstr "Amharic" - -#: ../src\extra\translator\translator.py:15 -msgid "Arabic" -msgstr "Àrab" - -#: ../src\extra\translator\translator.py:16 -msgid "Armenian" -msgstr "Armeni" - -#: ../src\extra\translator\translator.py:17 -msgid "Azerbaijani" -msgstr "Acerbajà" - -#: ../src\extra\translator\translator.py:18 -msgid "Basque" -msgstr "vasc" - -#: ../src\extra\translator\translator.py:19 -msgid "Belarusian" -msgstr "Bielorús" - -#: ../src\extra\translator\translator.py:20 -msgid "Bengali" -msgstr "Bengali" - -#: ../src\extra\translator\translator.py:21 -msgid "Bihari" -msgstr "Bihari" - -#: ../src\extra\translator\translator.py:22 -msgid "Bulgarian" -msgstr "Bùlgar" - -#: ../src\extra\translator\translator.py:23 -msgid "Burmese" -msgstr "Birmà" - -#: ../src\extra\translator\translator.py:24 -msgid "Catalan" -msgstr "Català" - -#: ../src\extra\translator\translator.py:25 -msgid "Cherokee" -msgstr "Cheroqui" - -#: ../src\extra\translator\translator.py:26 -msgid "Chinese" -msgstr "xinès" - -#: ../src\extra\translator\translator.py:27 -msgid "Chinese_simplified" -msgstr "xinèss simplificat" - -#: ../src\extra\translator\translator.py:28 -msgid "Chinese_traditional" -msgstr "xinés tradicional" - -#: ../src\extra\translator\translator.py:29 -msgid "Croatian" -msgstr "Croat" - -#: ../src\extra\translator\translator.py:30 -msgid "Czech" -msgstr "Txec" - -#: ../src\extra\translator\translator.py:32 -msgid "Dhivehi" -msgstr "Dhivehi" - -#: ../src\extra\translator\translator.py:35 -msgid "Esperanto" -msgstr "Esperanto" - -#: ../src\extra\translator\translator.py:36 -msgid "Estonian" -msgstr "Estonià" - -#: ../src\extra\translator\translator.py:37 -msgid "Filipino" -msgstr "Filipí" - -#: ../src\extra\translator\translator.py:40 -msgid "Galician" -msgstr "Gallec" - -#: ../src\extra\translator\translator.py:41 -msgid "Georgian" -msgstr "Georgià" - -#: ../src\extra\translator\translator.py:43 -msgid "Greek" -msgstr "Grec" - -#: ../src\extra\translator\translator.py:44 -msgid "Guarani" -msgstr "Guaraní" - -#: ../src\extra\translator\translator.py:45 -msgid "Gujarati" -msgstr "Guiaratí" - -#: ../src\extra\translator\translator.py:46 -msgid "Hebrew" -msgstr "Hebreu" - -#: ../src\extra\translator\translator.py:47 -msgid "Hindi" -msgstr "Hindi" - -#: ../src\extra\translator\translator.py:49 -msgid "Icelandic" -msgstr "Islandès" - -#: ../src\extra\translator\translator.py:50 -msgid "Indonesian" -msgstr "Indonesi" - -#: ../src\extra\translator\translator.py:51 -msgid "Inuktitut" -msgstr "Inuktitut" - -#: ../src\extra\translator\translator.py:52 -msgid "Irish" -msgstr "Irlandès" - -#: ../src\extra\translator\translator.py:55 -msgid "Kannada" -msgstr "Canarès" - -#: ../src\extra\translator\translator.py:56 -msgid "Kazakh" -msgstr "Kazakh" - -#: ../src\extra\translator\translator.py:57 -msgid "Khmer" -msgstr "Camboià" - -#: ../src\extra\translator\translator.py:59 -msgid "Kurdish" -msgstr "Kurd" - -#: ../src\extra\translator\translator.py:60 -msgid "Kyrgyz" -msgstr "Kirguís" - -#: ../src\extra\translator\translator.py:61 -msgid "Laothian" -msgstr "Lao" - -#: ../src\extra\translator\translator.py:62 -msgid "Latvian" -msgstr "Letó" - -#: ../src\extra\translator\translator.py:63 -msgid "Lithuanian" -msgstr "Lituà" - -#: ../src\extra\translator\translator.py:64 -msgid "Macedonian" -msgstr "Macedoni" - -#: ../src\extra\translator\translator.py:65 -msgid "Malay" -msgstr "Malai" - -#: ../src\extra\translator\translator.py:66 -msgid "Malayalam" -msgstr "Malayalam" - -#: ../src\extra\translator\translator.py:67 -msgid "Maltese" -msgstr "Maltès" - -#: ../src\extra\translator\translator.py:68 -msgid "Marathi" -msgstr "Maratí" - -#: ../src\extra\translator\translator.py:69 -msgid "Mongolian" -msgstr "Mongol" - -#: ../src\extra\translator\translator.py:70 -msgid "Nepali" -msgstr "Nepalí" - -#: ../src\extra\translator\translator.py:71 -msgid "Norwegian" -msgstr "Noruec" - -#: ../src\extra\translator\translator.py:72 -msgid "Oriya" -msgstr "Oriia" - -#: ../src\extra\translator\translator.py:73 -msgid "Pashto" -msgstr "Pastú" - -#: ../src\extra\translator\translator.py:74 -msgid "Persian" -msgstr "Persa" - -#: ../src\extra\translator\translator.py:77 -msgid "Punjabi" -msgstr "Paniabí" - -#: ../src\extra\translator\translator.py:78 -msgid "Romanian" -msgstr "Romanè" - -#: ../src\extra\translator\translator.py:80 -msgid "Sanskrit" -msgstr "Sànstrit" - -#: ../src\extra\translator\translator.py:81 -msgid "Serbian" -msgstr "Serbi" - -#: ../src\extra\translator\translator.py:82 -msgid "Sindhi" -msgstr "Sindhi" - -#: ../src\extra\translator\translator.py:83 -msgid "Sinhalese" -msgstr "Cingalès" - -#: ../src\extra\translator\translator.py:84 -msgid "Slovak" -msgstr "Eslovac" - -#: ../src\extra\translator\translator.py:85 -msgid "Slovenian" -msgstr "Esloveni" - -#: ../src\extra\translator\translator.py:87 -msgid "Swahili" -msgstr "Suahili" - -#: ../src\extra\translator\translator.py:88 -msgid "Swedish" -msgstr "Suec" - -#: ../src\extra\translator\translator.py:89 -msgid "Tajik" -msgstr "Tajik" - -#: ../src\extra\translator\translator.py:90 -msgid "Tamil" -msgstr "Tamil" - -#: ../src\extra\translator\translator.py:91 -msgid "Tagalog" -msgstr "Tagal" - -#: ../src\extra\translator\translator.py:92 -msgid "Telugu" -msgstr "Telugú" - -#: ../src\extra\translator\translator.py:93 -msgid "Thai" -msgstr "Tailandès" - -#: ../src\extra\translator\translator.py:94 -msgid "Tibetan" -msgstr "tibetà" - -#: ../src\extra\translator\translator.py:96 -msgid "Ukrainian" -msgstr "Ucraïnès" - -#: ../src\extra\translator\translator.py:97 -msgid "Urdu" -msgstr "Urdu" - -#: ../src\extra\translator\translator.py:98 -msgid "Uzbek" -msgstr "Uzbec" - -#: ../src\extra\translator\translator.py:99 -msgid "Uighur" -msgstr "Uigur" - -#: ../src\extra\translator\translator.py:100 -msgid "Vietnamese" -msgstr "Vietnamita" - -#: ../src\extra\translator\translator.py:101 -msgid "Welsh" -msgstr "Galès" - -#: ../src\extra\translator\translator.py:102 -msgid "Yiddish" -msgstr "Yiddish" - -#: ../src\extra\translator\wx_ui.py:44 -msgid "Translate message" -msgstr "Traduir missatge" - -#: ../src\extra\translator\wx_ui.py:47 -msgid "Target language" -msgstr "Llengua de destinació" - -#: ../src\issueReporter\issueReporter.py:30 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 -msgid "General" -msgstr "General" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "always" -msgstr "Sempre" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "have not tried" -msgstr "No s'ha provat." - -#: ../src\issueReporter\issueReporter.py:31 -msgid "random" -msgstr "aleatori" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "sometimes" -msgstr "a vegades" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "unable to duplicate" -msgstr "Impossible duplicar." - -#: ../src\issueReporter\issueReporter.py:32 -msgid "block" -msgstr "bloquejar" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "crash" -msgstr "error" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "feature" -msgstr "característica" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "major" -msgstr "major" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "minor" -msgstr "menor" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "text" -msgstr "text" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "trivial" -msgstr "Trivial" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "tweak" -msgstr "configuració" - -#: ../src\issueReporter\wx_ui.py:25 -msgid "Report an error" -msgstr "Reportar un problema" - -#: ../src\issueReporter\wx_ui.py:28 -msgid "Select a category" -msgstr "selecciona una categoria" - -#: ../src\issueReporter\wx_ui.py:36 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "" -"Descriu en poques paraules el que ha passat. Desprès podràs explicar-ho més " -"profundament" - -#: ../src\issueReporter\wx_ui.py:45 -msgid "Here, you can describe the bug in detail" -msgstr "Aquí pots descriure amb detall el problema" - -#: ../src\issueReporter\wx_ui.py:55 -msgid "how often does this bug happen?" -msgstr "Amb quina freqüència té lloc aquest error?" - -#: ../src\issueReporter\wx_ui.py:62 -msgid "Select the importance that you think this bug has" -msgstr "Selecciona la importància que creus que té aquest bug del programa" - -#: ../src\issueReporter\wx_ui.py:69 -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"Entenc que el sistema de bugs de {0} obtindrà el meu nom d'usuari per " -"contactar-me i solucionar el bug ràpidament." - -#: ../src\issueReporter\wx_ui.py:72 -msgid "Send report" -msgstr "Enviar report" - -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 -msgid "Cancel" -msgstr "Cancel·lar" - -#: ../src\issueReporter\wx_ui.py:83 -msgid "You must fill out both fields" -msgstr "Has d'omplir els dos camps" - -#: ../src\issueReporter\wx_ui.py:86 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"Cal que marquis la casella per facilitar-nos el teu nom d'usuari de Twitter, " -"per poder-te contactar si és necessari." - -#: ../src\issueReporter\wx_ui.py:89 -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"Gracies per reportar aquest problema! Tant de bó puguis veure'l entre la " -"llista de millores de pròximes versions. Has reportat el problema nombre %i" - -#: ../src\issueReporter\wx_ui.py:89 -msgid "reported" -msgstr "Reportat" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "Error while reporting" -msgstr "Error reportant" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"Alguna cosa inesperada ha passat quan s'intentaba reportar el teu problema. " -"Si et plau, prova-ho de nou més tard." - -#: ../src\keystrokeEditor\constants.py:3 -msgid "Go up in the current buffer" -msgstr "Va amunt en el bufer actual" - -#: ../src\keystrokeEditor\constants.py:4 -msgid "Go down in the current buffer" -msgstr "Va avall en el buffer actual" - -#: ../src\keystrokeEditor\constants.py:5 -msgid "Go to the previous buffer" -msgstr "Anar al buffer anterior" - -#: ../src\keystrokeEditor\constants.py:6 -msgid "Go to the next buffer" -msgstr "Anar al bufer següent" - -#: ../src\keystrokeEditor\constants.py:7 -msgid "Focus the next session" -msgstr "Focalitza la sessió següent." - -#: ../src\keystrokeEditor\constants.py:8 -msgid "Focus the previous session" -msgstr "Focalitza la sessió anterior." - -#: ../src\keystrokeEditor\constants.py:9 -msgid "Show or hide the GUI" -msgstr "Veure o amagar la GUI" - -#: ../src\keystrokeEditor\constants.py:10 -msgid "New tweet" -msgstr "Tuit nou" - -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 -msgid "Retweet" -msgstr "Retuit" - -#: ../src\keystrokeEditor\constants.py:13 -msgid "Send direct message" -msgstr "Enviar Missatge Directe" - -#: ../src\keystrokeEditor\constants.py:14 -msgid "Like a tweet" -msgstr "t'agrada el tuit." - -#: ../src\keystrokeEditor\constants.py:15 -msgid "Like/unlike a tweet" -msgstr "t'agrada/ja no t'agrada el twit" - -#: ../src\keystrokeEditor\constants.py:16 -msgid "Unlike a tweet" -msgstr "Ja no t'agrada el tuit." - -#: ../src\keystrokeEditor\constants.py:17 -msgid "Open the user actions dialogue" -msgstr "Obrir el diàleg d'accions d'usuari" - -#: ../src\keystrokeEditor\constants.py:18 -msgid "See user details" -msgstr "Veure detalls de l'usuari" - -#: ../src\keystrokeEditor\constants.py:19 -msgid "Show tweet" -msgstr "Mostra el tuit" - -#: ../src\keystrokeEditor\constants.py:20 -msgid "Quit" -msgstr "Sortir" - -#: ../src\keystrokeEditor\constants.py:21 -msgid "Open user timeline" -msgstr "Obrir línia temporal" - -#: ../src\keystrokeEditor\constants.py:22 -msgid "Destroy buffer" -msgstr "Elimina el bufer." - -#: ../src\keystrokeEditor\constants.py:23 -msgid "Interact with the currently focused tweet." -msgstr "Interactua amb el tuit seleccionat." - -#: ../src\keystrokeEditor\constants.py:24 -msgid "Open URL" -msgstr "Obre adreça." - -#: ../src\keystrokeEditor\constants.py:25 -#, fuzzy -msgid "View in Twitter" -msgstr "Cerca a Twitter" - -#: ../src\keystrokeEditor\constants.py:26 -msgid "Increase volume by 5%" -msgstr "Augmentar Volum 5%" - -#: ../src\keystrokeEditor\constants.py:27 -msgid "Decrease volume by 5%" -msgstr "Baixar Volum 5%" - -#: ../src\keystrokeEditor\constants.py:28 -msgid "Jump to the first element of a buffer" -msgstr "Vés al primer element del bufer actual." - -#: ../src\keystrokeEditor\constants.py:29 -msgid "Jump to the last element of the current buffer" -msgstr "Vés a l'últim element del buffer actual." - -#: ../src\keystrokeEditor\constants.py:30 -msgid "Jump 20 elements up in the current buffer" -msgstr "Vés 20 elements amunt en el buffer actual." - -#: ../src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements down in the current buffer" -msgstr "Vés 20 elements avall en el bufer actual." - -#: ../src\keystrokeEditor\constants.py:32 -msgid "Edit profile" -msgstr "Editar perfil" - -#: ../src\keystrokeEditor\constants.py:33 -msgid "Delete a tweet or direct message" -msgstr "Elimina un tuit o missatge directe." - -#: ../src\keystrokeEditor\constants.py:34 -msgid "Empty the current buffer" -msgstr "Buidar el buffer actual" - -#: ../src\keystrokeEditor\constants.py:35 -msgid "Repeat last item" -msgstr "Repeteix l'últim ítem" - -#: ../src\keystrokeEditor\constants.py:36 -msgid "Copy to clipboard" -msgstr "Copiar al portapapers" - -#: ../src\keystrokeEditor\constants.py:37 -msgid "Add to list" -msgstr "Afegir a llista" - -#: ../src\keystrokeEditor\constants.py:38 -msgid "Remove from list" -msgstr "Eliminar de llista" - -#: ../src\keystrokeEditor\constants.py:39 -msgid "Mute/unmute the active buffer" -msgstr "Activar o desactivar el silenci al buffer actual" - -#: ../src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the current session" -msgstr "Activa o desactiva el silenci de la sessió actual" - -#: ../src\keystrokeEditor\constants.py:41 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "Commutar la lectura automàtica de tuits nous per a aquest buffer" - -#: ../src\keystrokeEditor\constants.py:42 -msgid "Search on twitter" -msgstr "Cerca a Twitter" - -#: ../src\keystrokeEditor\constants.py:43 -msgid "Find a string in the currently focused buffer" -msgstr "Troba una cadena en el buffer focalitzat." - -#: ../src\keystrokeEditor\constants.py:44 -msgid "Show the keystroke editor" -msgstr "Mostrar l'editor de combinacions de teclat" - -#: ../src\keystrokeEditor\constants.py:45 -msgid "Show lists for a specified user" -msgstr "Veure llistes de l'usuari específic" - -#: ../src\keystrokeEditor\constants.py:46 -msgid "load previous items" -msgstr "Carrega elements anteriors" - -#: ../src\keystrokeEditor\constants.py:47 -msgid "Get geolocation" -msgstr "Obtenir la geolocalització" - -#: ../src\keystrokeEditor\constants.py:48 -msgid "Display the tweet's geolocation in a dialog" -msgstr "Mostra en un diàleg la localització geográfica del tuit." - -#: ../src\keystrokeEditor\constants.py:49 -msgid "Create a trending topics buffer" -msgstr "Crear un buffer de tendències" - -#: ../src\keystrokeEditor\constants.py:50 -msgid "View conversation" -msgstr "Veure conversa." - -#: ../src\keystrokeEditor\constants.py:51 -msgid "Check and download updates" -msgstr "Cerca i descarrega actualitzacions" - -#: ../src\keystrokeEditor\constants.py:52 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"Obre el gestor de llistes, que et permetrà crear, editar, eliminar i obrir " -"llistes en buffers." - -#: ../src\keystrokeEditor\constants.py:53 -msgid "Opens the global settings dialogue" -msgstr "Obre el diàleg de configuració global." - -#: ../src\keystrokeEditor\constants.py:54 -#, fuzzy -msgid "Opens the list manager" -msgstr "Gestor de llistes" - -#: ../src\keystrokeEditor\constants.py:55 -msgid "Opens the account settings dialogue" -msgstr "Obre el diàleg de configuració del compte." - -#: ../src\keystrokeEditor\constants.py:56 -msgid "Try to play an audio file" -msgstr "Provar de reproduir un arxiu d'audio" - -#: ../src\keystrokeEditor\constants.py:57 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "Actualitza el buffer i carrega possibles elements perduts." - -#: ../src\keystrokeEditor\constants.py:58 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "Extreure el text d'una imatge i mostra'l en un diàleg." - -#: ../src\keystrokeEditor\wx_ui.py:8 -msgid "Keystroke editor" -msgstr "Editor de combinacions de teclat" - -#: ../src\keystrokeEditor\wx_ui.py:12 -msgid "Select a keystroke to edit" -msgstr "Selecciona una combinació de teclat per editar-la" - -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "Combinació de teclat" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 -msgid "Action" -msgstr "Acció" - -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 -msgid "Edit" -msgstr "Editar" - -#: ../src\keystrokeEditor\wx_ui.py:20 -msgid "Execute action" -msgstr "Executar acció" - -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 -msgid "Close" -msgstr "Tancar" - -#: ../src\keystrokeEditor\wx_ui.py:48 -msgid "Editing keystroke" -msgstr "Editant combinació de tecles" - -#: ../src\keystrokeEditor\wx_ui.py:51 -msgid "Control" -msgstr "Control" - -#: ../src\keystrokeEditor\wx_ui.py:52 -msgid "Alt" -msgstr "Alt" - -#: ../src\keystrokeEditor\wx_ui.py:53 -msgid "Shift" -msgstr "Shift" - -#: ../src\keystrokeEditor\wx_ui.py:54 -msgid "Windows" -msgstr "Finestres" - -#: ../src\keystrokeEditor\wx_ui.py:60 -msgid "Key" -msgstr "Tecla" - -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 -msgid "OK" -msgstr "Acceptar" - -#: ../src\keystrokeEditor\wx_ui.py:78 -msgid "You need to use the Windows key" -msgstr "Necessites utilitzar la tecla Windows" - -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 -msgid "Invalid keystroke" -msgstr "Combinació de teclat invàlida" - -#: ../src\keystrokeEditor\wx_ui.py:81 -msgid "You must provide a character for the keystroke" -msgstr "Has de triar una lletra per a la cominació ràpida de teclat" - -#: ../src\languageHandler.py:99 -msgid "User default" -msgstr "Usuari per defecte" - -#: ../src\main.py:105 -msgid "https://twblue.es/donate" -msgstr "https://twblue.es/donate" - -#: ../src\main.py:122 -msgid "" -"{0} is already running. Close the other instance before starting this one. " -"If you're sure that {0} isn't running, try deleting the file at {1}. If " -"you're unsure of how to do this, contact the {0} developers." -msgstr "" - -#: ../src\sessionmanager\wxUI.py:8 -msgid "Session manager" -msgstr "Gestor de sessions" - -#: ../src\sessionmanager\wxUI.py:11 -msgid "Accounts list" -msgstr "Llista de comptes" - -#: ../src\sessionmanager\wxUI.py:13 -msgid "Account" -msgstr "Compte" - -#: ../src\sessionmanager\wxUI.py:17 -msgid "New account" -msgstr "Compte nou." - -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 -msgid "Remove account" -msgstr "Esborrar compte." - -#: ../src\sessionmanager\wxUI.py:19 -msgid "Global Settings" -msgstr "Configuració global" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "Account Error" -msgstr "Problema de compte" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "You need to configure an account." -msgstr "Necessites configurar un compte" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "Authorization" -msgstr "Autorització" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "" -"The request to authorize your Twitter account will be opened in your " -"browser. You only need to do this once. Would you like to continue?" -msgstr "" -"La sol·licitud per autoritzar el teu compte de twitter sobrirà en el teu " -"navegador. Només has de fer això una vegada. Vols continuar?" - -#: ../src\sessionmanager\wxUI.py:52 -msgid "Authorized account %d" -msgstr "Compte autoritzat %d" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "Invalid user token" -msgstr "Token d'usuari invàlid" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "" -"Your access token is invalid or the authorization has failed. Please try " -"again." -msgstr "" -"El codi d'autorització no és vàlid o el procés d'atorització ha fallat. Si " -"et plau, prova-ho més tard." - -#: ../src\sessionmanager\wxUI.py:64 -msgid "Do you really want to delete this account?" -msgstr "Realment vols eliminar aquest compte?" - -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 -msgid "dddd, MMMM D, YYYY H:m:s" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 -msgid "Dm to %s " -msgstr "dm a %s" - -#: ../src\sessions\twitter\compose.py:141 -msgid "{0}. Quoted tweet from @{1}: {2}" -msgstr "{0}. Tuit citat de @{1}: {2}" - -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 -msgid "Unavailable" -msgstr "No disponible" - -#: ../src\sessions\twitter\compose.py:166 -msgid "" -"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " -"Twitter %s" -msgstr "" -"%s (@%s). %s seguidors, %s amics, %s tuits. Últim tuit %s. Es va unir a " -"Twitter %s" - -#: ../src\sessions\twitter\compose.py:170 -msgid "No description available" -msgstr "No hi ha descripció disponible" - -#: ../src\sessions\twitter\compose.py:174 -msgid "private" -msgstr "Privat" - -#: ../src\sessions\twitter\compose.py:175 -msgid "public" -msgstr "Públic" - -#: ../src\sessions\twitter\session.py:169 -#, fuzzy -msgid "There are no more items to retrieve in this buffer." -msgstr "En aquest tuit no hi ha coordenades." - -#: ../src\sessions\twitter\session.py:215 -msgid "%s failed. Reason: %s" -msgstr "%s ha fallat. Raó: %s" - -#: ../src\sessions\twitter\session.py:221 -msgid "%s succeeded." -msgstr "%s amb èxit" - -#: ../src\sessions\twitter\utils.py:225 -msgid "Sorry, you are not authorised to see this status." -msgstr "Ho sentim, no estas autoritzat per veure aquest estat" - -#: ../src\sessions\twitter\utils.py:227 -msgid "No status found with that ID" -msgstr "No s'ha trobat cap estat amb aquest ID" - -#: ../src\sessions\twitter\utils.py:229 -msgid "Error code {0}" -msgstr "Codi d'error {0}" - -#: ../src\sessions\twitter\wxUI.py:6 -msgid "Authorising account..." -msgstr "Autoritzant el compte..." - -#: ../src\sessions\twitter\wxUI.py:9 -msgid "Enter your PIN code here" -msgstr "Introdueix el PIN aqui" - -#: ../src\sound.py:159 -msgid "Stopped." -msgstr "Aturat." - -#: ../src\update\wxUpdater.py:10 -msgid "New version for %s" -msgstr "Nova versió de %s" - -#: ../src\update\wxUpdater.py:10 -msgid "" -"There's a new %s version available, released on %s. Would you like to " -"download it now?\n" -"\n" -" %s version: %s\n" -"\n" -"Changes:\n" -"%s" -msgstr "" -"Hi ha una nova versió de %s disponible. T'agradaria descaregar-la ara?\n" -"\n" -" %s versió: %s\n" -"\n" -"Canvis:\n" -"%s" - -#: ../src\update\wxUpdater.py:18 -msgid "Download in Progress" -msgstr "Descàrrega en progrés" - -#: ../src\update\wxUpdater.py:18 -msgid "Downloading the new version..." -msgstr "Descarregant la nova versió" - -#: ../src\update\wxUpdater.py:28 -msgid "Updating... %s of %s" -msgstr "Actualitzant... %s of %s" - -#: ../src\update\wxUpdater.py:31 -msgid "Done!" -msgstr "Fet!" - -#: ../src\update\wxUpdater.py:31 -msgid "" -"The update has been downloaded and installed successfully. Press OK to " -"continue." -msgstr "" -"L'actualització s'ha descarregat i instal·lat correctament. Prem Acceptar " -"per continuar." - -#: ../src\wxUI\buffers\base.py:11 -msgid "Client" -msgstr "Client" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Text" -msgstr "Text" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 -msgid "Date" -msgstr "data" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 -msgid "User" -msgstr "Usuari" - -#: ../src\wxUI\buffers\base.py:27 -msgid "Direct message" -msgstr "Missatge directe" - -#: ../src\wxUI\buffers\events.py:13 -msgid "Event" -msgstr "Esdeveniment" - -#: ../src\wxUI\buffers\events.py:15 -msgid "Remove event" -msgstr "Eliminar esdeveniment" - -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 -msgid "Login" -msgstr "connectar-se" - -#: ../src\wxUI\buffers\panels.py:13 -msgid "Log in automatically" -msgstr "Iniciar sessió automàticament" - -#: ../src\wxUI\buffers\panels.py:21 -msgid "Logout" -msgstr "Desconnectar-se" - -#: ../src\wxUI\buffers\trends.py:8 -msgid "Trending topic" -msgstr "Trending topic" - -#: ../src\wxUI\buffers\trends.py:18 -msgid "Tweet about this trend" -msgstr "Tuit sobre aquesta tendència" - -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 -msgid "Search topic" -msgstr "Cerca missatge" - -#: ../src\wxUI\commonMessageDialogs.py:6 -msgid "" -"This retweet is over 140 characters. Would you like to post it as a mention " -"to the poster with your comments and a link to the original tweet?" -msgstr "" -"Aquest tuit excedeix els 140 caracters. Vols publicar-lo com una menció a " -"l'usuari original amb els teus comentaris i un enllaç al twit original?" - -#: ../src\wxUI\commonMessageDialogs.py:9 -msgid "Would you like to add a comment to this tweet?" -msgstr "T'agradaria afegirun comentari a aquest tuit?" - -#: ../src\wxUI\commonMessageDialogs.py:12 -msgid "" -"Do you really want to delete this tweet? It will be deleted from Twitter as " -"well." -msgstr "" -"Estàs segur que vols eliminar aquest tuit? també s'eliminarà de Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 -msgid "Delete" -msgstr "Eliminar" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Do you really want to close {0}?" -msgstr "Estàs segur que vols tancar {0}?" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Exit" -msgstr "Sortir" - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid " {0} must be restarted for these changes to take effect." -msgstr " {0} S'ha de reiniciar perquè els canvis facin efecte." - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid "Restart {0} " -msgstr "Reiniciar {0} " - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "" -"Are you sure you want to delete this user from the database? This user will " -"not appear in autocomplete results anymore." -msgstr "" -"Estàs segur de que vols eliminar aquest usuari de la base de dades? l'usuari " -"no apareixerà més als resultats d'autocompletar." - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "Confirm" -msgstr "Confirma" - -#: ../src\wxUI\commonMessageDialogs.py:25 -msgid "Enter the name of the client : " -msgstr "Introdueix el nom del client : " - -#: ../src\wxUI\commonMessageDialogs.py:25 -#: ../src\wxUI\dialogs\configuration.py:246 -msgid "Add client" -msgstr "Afegir client" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "" -"Do you really want to empty this buffer? It's items will be removed from " -"the list but not from Twitter" -msgstr "" -"Estàs segur de que vols buidar aquest buffer? Els tuits seràn eliminats de " -"la llista, però no de Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "Empty buffer" -msgstr "Buidar buffer" - -#: ../src\wxUI\commonMessageDialogs.py:35 -msgid "Do you really want to destroy this buffer?" -msgstr "Realment vols eliminar aquest buffer?" - -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Attention" -msgstr "Alerta" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "A timeline for this user already exists. You can't open another" -msgstr "" -"Ja hi ha una línia temporal per aquest usuari. No pots obrirne una altra." - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "Existing timeline" -msgstr "Linea temporal existent" - -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "This user has no tweets, so you can't open a timeline for them." -msgstr "" -"Aquest usuari no té tuits, per tant no pots obrir-ne una línia temporal." - -#: ../src\wxUI\commonMessageDialogs.py:47 -msgid "" -"This is a protected Twitter user, which means you can't open a timeline " -"using the Streaming API. The user's tweets will not update due to a twitter " -"policy. Do you want to continue?" -msgstr "" -"Aquest usuari està protegit, per tant no es pot obrir la seva línia temporal " -"utilitant la API de streaming. Els tuits de l'usuari no s'actualitzaran " -"degut a la política de Twitter. Vols continuar?" - -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "Warning" -msgstr "Avís" - -#: ../src\wxUI\commonMessageDialogs.py:50 -msgid "" -"This is a protected user account, you need to follow this user to view their " -"tweets or likes." -msgstr "" -"El compte d'aquest usuari està protegit, necessites seguir-lo per veure els " -"seus tuits o els tuits que li agraden." - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "" -"If you like {0} we need your help to keep it going. Help us by donating to " -"the project. This will help us pay for the server, the domain and some other " -"things to ensure that {0} will be actively maintained. Your donation will " -"give us the means to continue the development of {0}, and to keep {0} free. " -"Would you like to donate now?" -msgstr "" -"Si t'agrada {0}, necessitem la teva col·laboració perquè continui " -"funcionant, ens pots ajudar donant una quantitat al projecte. Això ens " -"ajudarà a pagar el servidor, el domini i altres aspectes que asseguraran un " -"manteniment més actiu de {0}. La teva donació ens empeny a continuar el " -"desenvolupament de {0}, i per fent que {0} sigui gratuit. Vols fer una " -"donació ara?" - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "We need your help" -msgstr "Necessitem la teva ajuda" - -#: ../src\wxUI\commonMessageDialogs.py:57 -msgid "This user has no tweets. {0} can't create a timeline." -msgstr "Aquest usuari no té tuits. {0} no pot obrir la seva línia temporal." - -#: ../src\wxUI\commonMessageDialogs.py:60 -msgid "This user has no favorited tweets. {0} can't create a timeline." -msgstr "" -"Aquest usuari no té tuits favorits. {0} no pot obrir la seva línia temporal." - -#: ../src\wxUI\commonMessageDialogs.py:63 -msgid "This user has no followers. {0} can't create a timeline." -msgstr "Aquest usuari no té seguidors, {0} no pot obrir la línia temporal." - -#: ../src\wxUI\commonMessageDialogs.py:66 -msgid "This user has no friends. {0} can't create a timeline." -msgstr "Aquest usuari no té amics, {0} no pot obrir la línia temporal." - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geo data for this tweet" -msgstr "Dades geogràfiques en aquest tuit." - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geolocation data: {0}" -msgstr "Dades geográfiques: {0}. " - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "Information" -msgstr "Informació" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "" -"TWBlue has detected that you're running windows 10 and has changed the " -"default keymap to the Windows 10 keymap. It means that some keyboard " -"shorcuts could be different. Please check the keystroke editor by pressing " -"Alt+Win+K to see all available keystrokes for this keymap." -msgstr "" -"TWBlue ha detectat que s'està executant Windows 10 i ha cambiat el mapa de " -"tecles per defecte al mapa de tecles Windows 10." - -#: ../src\wxUI\commonMessageDialogs.py:76 -msgid "You have been blocked from viewing this content" -msgstr "Vosté ha estat bloquejat per veure aquest contingut." - -#: ../src\wxUI\commonMessageDialogs.py:79 -msgid "" -"You have been blocked from viewing someone's content. In order to avoid " -"conflicts with the full session, TWBlue will remove the affected timeline." -msgstr "" -"Vostè ha estat bloquejat per veure alguns continguts. A la petició hi ha " -"confictes que afecten completament a la sessió. TWBlue eliminarà el fil " -"temporal afectat." - -#: ../src\wxUI\commonMessageDialogs.py:82 -msgid "" -"TWBlue cannot load this timeline because the user has been suspended from " -"Twitter." -msgstr "" -"TWBlue no pot carregar aquest time-line ja que l'usuari ha estat suspès de " -"twitter." - -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Do you really want to delete this filter?" -msgstr "Realment vols eliminar aquest filtre?" - -#: ../src\wxUI\commonMessageDialogs.py:88 -msgid "This filter already exists. Please use a different title" -msgstr "Aquest filtre ja existeix. Si us plau, utilitzeu un altre titol." - -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "" -"{0} quit unexpectedly the last time it was run. If the problem persists, " -"please report it to the {0} developers." -msgstr "" - -#: ../src\wxUI\dialogs\attach.py:9 -msgid "Add an attachment" -msgstr "Afegir adjunts" - -#: ../src\wxUI\dialogs\attach.py:12 -msgid "Attachments" -msgstr "Adjunts" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Title" -msgstr "Titol" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Type" -msgstr "Tipus" - -#: ../src\wxUI\dialogs\attach.py:18 -msgid "Add attachments" -msgstr "Afegir un adjunt" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "&Photo" -msgstr "&Foto" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "Remove attachment" -msgstr "esborrar l'adjunt" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "Fitxers d'imatge (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Select the picture to be uploaded" -msgstr "Selecciona la fotografia per carregar." - -#: ../src\wxUI\dialogs\attach.py:43 -msgid "please provide a description" -msgstr "Si et plau, proveeix d'una descripció" - -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 -msgid "Description" -msgstr "Descripció" - -#: ../src\wxUI\dialogs\configuration.py:16 -msgid "Language" -msgstr "Idioma" - -#: ../src\wxUI\dialogs\configuration.py:23 -msgid "Run {0} at Windows startup" -msgstr "executar {0} quan Windows inicii" - -#: ../src\wxUI\dialogs\configuration.py:24 -msgid "ask before exiting {0}" -msgstr "Preguntar abans de sortir de {0}" - -#: ../src\wxUI\dialogs\configuration.py:27 -msgid "Disable Streaming functions" -msgstr "Desactivar les funcions de streaming" - -#: ../src\wxUI\dialogs\configuration.py:30 -msgid "Buffer update interval, in minutes" -msgstr "actualització del bufer, en minuts" - -#: ../src\wxUI\dialogs\configuration.py:36 -msgid "Play a sound when {0} launches" -msgstr "Reprodueix un so quan {0} s'inicii." - -#: ../src\wxUI\dialogs\configuration.py:38 -msgid "Speak a message when {0} launches" -msgstr "verbalitza un missatge quan {0} s'inicii." - -#: ../src\wxUI\dialogs\configuration.py:40 -msgid "Use invisible interface's keyboard shortcuts while GUI is visible" -msgstr "" -"Utilitzar les combinacions de tecles de la interfície invisible mentre la " -"guia està visible." - -#: ../src\wxUI\dialogs\configuration.py:42 -msgid "Activate Sapi5 when any other screen reader is not being run" -msgstr "Activar Sapi5 quan no hi ha un altre lector de pantalla funcionant" - -#: ../src\wxUI\dialogs\configuration.py:44 -msgid "Hide GUI on launch" -msgstr "Amagar guia al iniciar" - -#: ../src\wxUI\dialogs\configuration.py:46 -msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" -msgstr "" -"Lectura completa de tuits llargs (Pot disminuir la velocitat del " -"funcionament del client)." - -#: ../src\wxUI\dialogs\configuration.py:48 -msgid "Remember state for mention all and long tweet" -msgstr "Recordar l'estat de menció a tots en els twits llargs" - -#: ../src\wxUI\dialogs\configuration.py:51 -msgid "Keymap" -msgstr "Mapa de teclat" - -#: ../src\wxUI\dialogs\configuration.py:56 -msgid "Check for updates when {0} launches" -msgstr "Comprobar actualitzacións quan {0} s'inicii" - -#: ../src\wxUI\dialogs\configuration.py:66 -msgid "Proxy type: " -msgstr "Tipus de proxi." - -#: ../src\wxUI\dialogs\configuration.py:73 -msgid "Proxy server: " -msgstr "Servidor proxi: " - -#: ../src\wxUI\dialogs\configuration.py:79 -msgid "Port: " -msgstr "Port: " - -#: ../src\wxUI\dialogs\configuration.py:85 -msgid "User: " -msgstr "Usuari: " - -#: ../src\wxUI\dialogs\configuration.py:91 -msgid "Password: " -msgstr "Contrasenya: " - -#: ../src\wxUI\dialogs\configuration.py:103 -msgid "Autocompletion settings..." -msgstr "Configuració d'autocompletat..." - -#: ../src\wxUI\dialogs\configuration.py:105 -msgid "Relative timestamps" -msgstr "Temps relatius" - -#: ../src\wxUI\dialogs\configuration.py:108 -msgid "Items on each API call" -msgstr "Elements per cada trucada a la API" - -#: ../src\wxUI\dialogs\configuration.py:114 -msgid "" -"Inverted buffers: The newest tweets will be shown at the beginning while the " -"oldest at the end" -msgstr "" -"Buffers invertits: els nous tuits es mostraràn al inici de les llistes y els " -"antics al final" - -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet mode" -msgstr "Mode de Retuit" - -#: ../src\wxUI\dialogs\configuration.py:122 -msgid "Show screen names instead of full names" -msgstr "Mostrar el nom de pantalla dins del nom complert." - -#: ../src\wxUI\dialogs\configuration.py:124 -msgid "" -"Number of items per buffer to cache in database (0 to disable caching, blank " -"for unlimited)" -msgstr "" -"Nombre d'elements per bufer que s'emmagatzemaran a la base de dades (0 per " -"deshabilitar l'emagatzematge, en blanc per a ilimitat)." - -#: ../src\wxUI\dialogs\configuration.py:134 -msgid "Enable automatic speech feedback" -msgstr "Activar missatges parlats" - -#: ../src\wxUI\dialogs\configuration.py:136 -msgid "Enable automatic Braille feedback" -msgstr "Activar missatges en braille" - -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "Estat" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Buffer" -msgstr "Bufer" - -#: ../src\wxUI\dialogs\configuration.py:147 -msgid "Show/hide" -msgstr "Mostra/amaga" - -#: ../src\wxUI\dialogs\configuration.py:148 -msgid "Move up" -msgstr "Moure amunt" - -#: ../src\wxUI\dialogs\configuration.py:149 -msgid "Move down" -msgstr "Moure avall" - -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 -msgid "Show" -msgstr "Mostra" - -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 -msgid "Hide" -msgstr "Amaga" - -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 -msgid "Select a buffer first." -msgstr "Primer has de seleccionar un buffer." - -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 -msgid "The buffer is hidden, show it first." -msgstr "El buffer està amagat, primer l'has de mostrar." - -#: ../src\wxUI\dialogs\configuration.py:175 -msgid "The buffer is already at the top of the list." -msgstr "El buffer ja és al capdamunt de la llista." - -#: ../src\wxUI\dialogs\configuration.py:199 -msgid "The buffer is already at the bottom of the list." -msgstr "El buffer ja es al capdavall de la llista." - -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 -msgid "Ignored clients" -msgstr "Clients ignorats" - -#: ../src\wxUI\dialogs\configuration.py:247 -msgid "Remove client" -msgstr "Esborrar client" - -#: ../src\wxUI\dialogs\configuration.py:271 -msgid "Volume" -msgstr "Volum." - -#: ../src\wxUI\dialogs\configuration.py:282 -msgid "Session mute" -msgstr "Silenci de sessió" - -#: ../src\wxUI\dialogs\configuration.py:284 -msgid "Output device" -msgstr "Dispositiu de sortida" - -#: ../src\wxUI\dialogs\configuration.py:291 -msgid "Input device" -msgstr "Dispositiu d'entrada" - -#: ../src\wxUI\dialogs\configuration.py:299 -msgid "Sound pack" -msgstr "Paquet de sons" - -#: ../src\wxUI\dialogs\configuration.py:305 -msgid "Indicate audio tweets with sound" -msgstr "Indica un twit d'audio mitjançant un só." - -#: ../src\wxUI\dialogs\configuration.py:307 -msgid "Indicate geotweets with sound" -msgstr "Indica un GeoTwit amb un só." - -#: ../src\wxUI\dialogs\configuration.py:309 -msgid "Indicate tweets containing images with sound" -msgstr "Indica els twits que continguin imatges amb un só." - -#: ../src\wxUI\dialogs\configuration.py:332 -msgid "Language for OCR" -msgstr "Idioma de l'OCR" - -#: ../src\wxUI\dialogs\configuration.py:338 -msgid "API Key for SndUp" -msgstr "Clau API per SndUp." - -#: ../src\wxUI\dialogs\configuration.py:353 -msgid "{0} preferences" -msgstr "Preferències de {0} " - -#: ../src\wxUI\dialogs\configuration.py:364 -msgid "Proxy" -msgstr "Proxi" - -#: ../src\wxUI\dialogs\configuration.py:373 -msgid "Feedback" -msgstr "Retroalimentació" - -#: ../src\wxUI\dialogs\configuration.py:377 -msgid "Buffers" -msgstr "Buffers" - -#: ../src\wxUI\dialogs\configuration.py:385 -msgid "Sound" -msgstr "So" - -#: ../src\wxUI\dialogs\configuration.py:389 -msgid "Extras" -msgstr "Extres." - -#: ../src\wxUI\dialogs\configuration.py:394 -msgid "Save" -msgstr "Desar" - -#: ../src\wxUI\dialogs\filterDialogs.py:15 -msgid "Create a filter for this buffer" -msgstr "Crear un filtre per aquest bufer" - -#: ../src\wxUI\dialogs\filterDialogs.py:16 -msgid "Filter title" -msgstr "Titol del filtre." - -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by word" -msgstr "Filtrar per paraula" - -#: ../src\wxUI\dialogs\filterDialogs.py:26 -msgid "Ignore tweets wich contain the following word" -msgstr "Ignorar els twits amb la següent paraula" - -#: ../src\wxUI\dialogs\filterDialogs.py:27 -msgid "Ignore tweets without the following word" -msgstr "Ignorar els twits que no contenguin la següent paraula" - -#: ../src\wxUI\dialogs\filterDialogs.py:32 -msgid "word" -msgstr "paraula" - -#: ../src\wxUI\dialogs\filterDialogs.py:37 -msgid "Allow retweets" -msgstr "Permetre retwits" - -#: ../src\wxUI\dialogs\filterDialogs.py:38 -msgid "Allow quoted tweets" -msgstr "Permetre twits citats" - -#: ../src\wxUI\dialogs\filterDialogs.py:39 -msgid "Allow replies" -msgstr "Permetre respostes" - -#: ../src\wxUI\dialogs\filterDialogs.py:47 -msgid "Use this term as a regular expression" -msgstr "utilizar aquest termini com una expresió regular." - -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by language" -msgstr "filtrar per idioma" - -#: ../src\wxUI\dialogs\filterDialogs.py:50 -msgid "Load tweets in the following languages" -msgstr "carregar els twits amb els següents idiomes" - -#: ../src\wxUI\dialogs\filterDialogs.py:51 -msgid "Ignore tweets in the following languages" -msgstr "Ignorar els twits amb els següents idiomes" - -#: ../src\wxUI\dialogs\filterDialogs.py:52 -msgid "Don't filter by language" -msgstr "No filtrar per idioma" - -#: ../src\wxUI\dialogs\filterDialogs.py:63 -msgid "Supported languages" -msgstr "Idiomes soporrtats" - -#: ../src\wxUI\dialogs\filterDialogs.py:68 -msgid "Add selected language to filter" -msgstr "Afegir l'idioma seleccionat a filtrar" - -#: ../src\wxUI\dialogs\filterDialogs.py:72 -msgid "Selected languages" -msgstr "Idiomes seleccionats" - -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 -msgid "Remove" -msgstr "Esborrar" - -#: ../src\wxUI\dialogs\filterDialogs.py:122 -msgid "Manage filters" -msgstr "Gestionar filtresGestionar compte" - -#: ../src\wxUI\dialogs\filterDialogs.py:124 -msgid "Filters" -msgstr "Filtres" - -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter" -msgstr "Filtre" - -#: ../src\wxUI\dialogs\find.py:12 -msgid "Find in current buffer" -msgstr "Troba en el buffer actual." - -#: ../src\wxUI\dialogs\find.py:13 -msgid "String" -msgstr "cadena" - -#: ../src\wxUI\dialogs\lists.py:10 -msgid "Lists manager" -msgstr "Gestor de llistes" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "List" -msgstr "Llista" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Members" -msgstr "Membres" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Owner" -msgstr "Propietari" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "mode" -msgstr "Manera" - -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 -msgid "Create a new list" -msgstr "Crear una nova llista" - -#: ../src\wxUI\dialogs\lists.py:21 -msgid "Open in buffer" -msgstr "Obrir en buffer" - -#: ../src\wxUI\dialogs\lists.py:51 -msgid "Viewing lists for %s" -msgstr "Veient les llistes de %s" - -#: ../src\wxUI\dialogs\lists.py:52 -msgid "Subscribe" -msgstr "Donar-se d'alta" - -#: ../src\wxUI\dialogs\lists.py:53 -msgid "Unsubscribe" -msgstr "Donar-se de baixa" - -#: ../src\wxUI\dialogs\lists.py:64 -msgid "Name (20 characters maximun)" -msgstr "Nom (màxim vint caràcters)" - -#: ../src\wxUI\dialogs\lists.py:74 -msgid "Mode" -msgstr "Manera" - -#: ../src\wxUI\dialogs\lists.py:75 -msgid "Public" -msgstr "Públic" - -#: ../src\wxUI\dialogs\lists.py:76 -msgid "Private" -msgstr "Privat" - -#: ../src\wxUI\dialogs\lists.py:96 -msgid "Editing the list %s" -msgstr "Editant la llista %s" - -#: ../src\wxUI\dialogs\lists.py:107 -msgid "Select a list to add the user" -msgstr "Selecciona una llista per a afegir a l'usuari" - -#: ../src\wxUI\dialogs\lists.py:108 -msgid "Add" -msgstr "Afegir" - -#: ../src\wxUI\dialogs\lists.py:130 -msgid "Select a list to remove the user" -msgstr "Selecciona una llista per esborrar a l'usuari" - -#: ../src\wxUI\dialogs\lists.py:148 -msgid "Do you really want to delete this list?" -msgstr "Realment vols eliminar aquesta llista?" - -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "&Tuit llarg" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "&Carregar imatge..." - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 -msgid "Check &spelling..." -msgstr "Comprova &l'ortografia." - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "&Adjuntar audio..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "&Escurçar adreça" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 -msgid "&Expand URL" -msgstr "&Expandir adreça" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 -msgid "&Translate..." -msgstr "&Traduir..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "&Autocompletar usuaris" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "&enviar" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 -msgid "C&lose" -msgstr "&Tancar" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "&Destinatari" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "&Mencionar a tothom" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Tuit - %i caràcters" - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Descripció de la imatge" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "Retuit." - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Tuits que m'agraden: " - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Font: " - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -#, fuzzy -msgid "Date: " -msgstr "data" - -#: ../src\wxUI\dialogs\message.py:405 -msgid "View" -msgstr "veure" - -#: ../src\wxUI\dialogs\message.py:407 -msgid "Item" -msgstr "Element" - -#: ../src\wxUI\dialogs\search.py:13 -msgid "Search on Twitter" -msgstr "Cerca a Twitter" - -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 -msgid "&Search" -msgstr "&Cerca" - -#: ../src\wxUI\dialogs\search.py:21 -msgid "Tweets" -msgstr "Tuits" - -#: ../src\wxUI\dialogs\search.py:22 -msgid "Users" -msgstr "Usuaris" - -#: ../src\wxUI\dialogs\search.py:29 -msgid "&Language for results: " -msgstr "&idioma dels resultats: " - -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 -msgid "any" -msgstr "Cap" - -#: ../src\wxUI\dialogs\search.py:37 -msgid "Results &type: " -msgstr "&Tipus de resultats: " - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 -msgid "Mixed" -msgstr "Barrejat" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 -msgid "Recent" -msgstr "Recent" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 -msgid "Popular" -msgstr "Popular" - -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 -msgid "&OK" -msgstr "&Acceptar" - -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 -msgid "&Close" -msgstr "&Tancar" - -#: ../src\wxUI\dialogs\show_user.py:11 -msgid "Details" -msgstr "Detalls" - -#: ../src\wxUI\dialogs\show_user.py:16 -msgid "&Go to URL" -msgstr "&Anar a l'adreça" - -#: ../src\wxUI\dialogs\trends.py:12 -msgid "View trending topics" -msgstr "Noves tendències." - -#: ../src\wxUI\dialogs\trends.py:13 -msgid "Trending topics by" -msgstr "Trending topics per" - -#: ../src\wxUI\dialogs\trends.py:15 -msgid "Country" -msgstr "País" - -#: ../src\wxUI\dialogs\trends.py:16 -msgid "City" -msgstr "Ciutat" - -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 -msgid "&Location" -msgstr "&Localització" - -#: ../src\wxUI\dialogs\update_profile.py:9 -msgid "Update your profile" -msgstr "Actualitzar el teu perfil" - -#: ../src\wxUI\dialogs\update_profile.py:11 -msgid "&Name (50 characters maximum)" -msgstr "&Nom (màxim 50 caràcters)" - -#: ../src\wxUI\dialogs\update_profile.py:22 -msgid "&Website" -msgstr "&Lloc web" - -#: ../src\wxUI\dialogs\update_profile.py:27 -msgid "&Bio (160 characters maximum)" -msgstr "&Biografia (màxim 160 caràcters)" - -#: ../src\wxUI\dialogs\update_profile.py:33 -msgid "Upload a &picture" -msgstr "Carregar una &fotografia" - -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 -msgid "&Update profile" -msgstr "&Actualitzar perfil" - -#: ../src\wxUI\dialogs\update_profile.py:76 -msgid "Upload a picture" -msgstr "Carregar una fotografia" - -#: ../src\wxUI\dialogs\update_profile.py:78 -msgid "Discard image" -msgstr "Descartar imatge" - -#: ../src\wxUI\dialogs\urlList.py:5 -msgid "Select URL" -msgstr "Selecciona adreça" - -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 -msgid "&User" -msgstr "&Usuari" - -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 -msgid "&Autocomplete users" -msgstr "&Autocompletar usuaris." - -#: ../src\wxUI\dialogs\userActions.py:19 -msgid "&Follow" -msgstr "&Seguir" - -#: ../src\wxUI\dialogs\userActions.py:20 -msgid "U&nfollow" -msgstr "&Deixar de seguir" - -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 -msgid "&Mute" -msgstr "&Silenciar" - -#: ../src\wxUI\dialogs\userActions.py:22 -msgid "Unmu&te" -msgstr "&Dessilenciar" - -#: ../src\wxUI\dialogs\userActions.py:23 -msgid "&Block" -msgstr "&Bloquejar" - -#: ../src\wxUI\dialogs\userActions.py:24 -msgid "Unbl&ock" -msgstr "&Desbloquejar" - -#: ../src\wxUI\dialogs\userActions.py:25 -msgid "&Report as spam" -msgstr "&Reportar com a spam" - -#: ../src\wxUI\dialogs\userActions.py:26 -msgid "&Ignore tweets from this client" -msgstr "&Ignorar tuits d'aquest client" - -#: ../src\wxUI\dialogs\userSelection.py:9 -msgid "Timeline for %s" -msgstr "Línia temporal de %s" - -#: ../src\wxUI\dialogs\userSelection.py:18 -msgid "Buffer type" -msgstr "Tipus de bufer." - -#: ../src\wxUI\dialogs\userSelection.py:19 -msgid "&Tweets" -msgstr "&Tuits" - -#: ../src\wxUI\dialogs\userSelection.py:20 -msgid "&Likes" -msgstr "&Tuits que m'agraden." - -#: ../src\wxUI\dialogs\userSelection.py:21 -msgid "&Followers" -msgstr "&Seguidors" - -#: ../src\wxUI\dialogs\userSelection.py:22 -msgid "F&riends" -msgstr "&Amics" - -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 -msgid "&Retweet" -msgstr "&Retuit" - -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 -msgid "Re&ply" -msgstr "&Respondre" - -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 -msgid "&Like" -msgstr "&m'agrada" - -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 -msgid "&Unlike" -msgstr "&Ja no m'agrada" - -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 -msgid "&Open URL" -msgstr "&Obrir URL..." - -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -#, fuzzy -msgid "&Open in Twitter" -msgstr "Cerca a Twitter" - -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 -msgid "&Play audio" -msgstr "&Reproduir audio" - -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 -msgid "&Show tweet" -msgstr "&Veure tuit" - -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 -msgid "&Copy to clipboard" -msgstr "&Copiar al portapapers" - -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 -msgid "&Delete" -msgstr "&Eliminar" - -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 -msgid "&User actions..." -msgstr "&accions d'usuari..." - -#: ../src\wxUI\menus.py:39 -msgid "&Show direct message" -msgstr "&Mostrar missatge directe" - -#: ../src\wxUI\menus.py:67 -msgid "&Show event" -msgstr "&Veure esdeveniment." - -#: ../src\wxUI\menus.py:77 -msgid "Direct &message" -msgstr "Missatge &directe" - -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 -msgid "&View lists" -msgstr "&Veure llistes" - -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 -msgid "Show user &profile" -msgstr "&Veure perfil de l'usuari" - -#: ../src\wxUI\menus.py:84 -msgid "&Show user" -msgstr "&Veure usuari." - -#: ../src\wxUI\menus.py:98 -msgid "&Tweet about this trend" -msgstr "Tuit sobre aquesta tendència." - -#: ../src\wxUI\menus.py:100 -msgid "&Show item" -msgstr "Mostrar item." - -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 -msgid "&Global settings" -msgstr "&Configuració global" - -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 -msgid "Account se&ttings" -msgstr "&Configuració del compte" - -#: ../src\wxUI\sysTrayIcon.py:37 -msgid "Update &profile" -msgstr "&Actualitzar perfil" - -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "&Show / hide" -msgstr "&Veure/ amagar" - -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 -msgid "&Documentation" -msgstr "&Documentació" - -#: ../src\wxUI\sysTrayIcon.py:40 -msgid "Check for &updates" -msgstr "&Cercar actualitzacions" - -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "&Exit" -msgstr "&Sortir" - -#: ../src\wxUI\view.py:16 -msgid "&Manage accounts" -msgstr "&gestionar compte" - -#: ../src\wxUI\view.py:18 -msgid "&Hide window" -msgstr "&Amagar finestra" - -#: ../src\wxUI\view.py:20 -msgid "&Lists manager" -msgstr "&Gestor de llistes" - -#: ../src\wxUI\view.py:21 -msgid "&Edit keystrokes" -msgstr "&Editar combinacions de tecles" - -#: ../src\wxUI\view.py:24 -msgid "E&xit" -msgstr "&Sortir" - -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 -msgid "&Tweet" -msgstr "&Tuit" - -#: ../src\wxUI\view.py:34 -msgid "View &address" -msgstr "Veure &Adreça" - -#: ../src\wxUI\view.py:35 -msgid "View conversa&tion" -msgstr "Veure &conversa" - -#: ../src\wxUI\view.py:36 -msgid "Read text in picture" -msgstr "Llegir el text dintre d'una imatge." - -#: ../src\wxUI\view.py:41 -msgid "&Actions..." -msgstr "&Accions..." - -#: ../src\wxUI\view.py:42 -msgid "&View timeline..." -msgstr "&Veure línia temporal..." - -#: ../src\wxUI\view.py:43 -msgid "Direct me&ssage" -msgstr "Missatge directe" - -#: ../src\wxUI\view.py:44 -msgid "&Add to list" -msgstr "&Afegir a llista" - -#: ../src\wxUI\view.py:45 -msgid "R&emove from list" -msgstr "&Eliminar de llista" - -#: ../src\wxUI\view.py:48 -msgid "V&iew likes" -msgstr "&Veure tuits que agraden" - -#: ../src\wxUI\view.py:52 -msgid "&Update buffer" -msgstr "&Actualitzar buffer" - -#: ../src\wxUI\view.py:53 -msgid "New &trending topics buffer..." -msgstr "Nou &bufer de tendències" - -#: ../src\wxUI\view.py:54 -msgid "Create a &filter" -msgstr "Crear un nou &filtreCrear una nova llista" - -#: ../src\wxUI\view.py:55 -msgid "&Manage filters" -msgstr "&gestionar filtres" - -#: ../src\wxUI\view.py:56 -msgid "Find a string in the currently focused buffer..." -msgstr "Troba una cadena en el buffer focalitzat..." - -#: ../src\wxUI\view.py:57 -msgid "&Load previous items" -msgstr "&carregar twits més antics" - -#: ../src\wxUI\view.py:60 -msgid "&Autoread" -msgstr "&lectura automàtica" - -#: ../src\wxUI\view.py:61 -msgid "&Clear buffer" -msgstr "&Netejar buffer" - -#: ../src\wxUI\view.py:62 -msgid "&Destroy" -msgstr "&elimina" - -#: ../src\wxUI\view.py:66 -msgid "&Seek back 5 seconds" -msgstr "enrere 5 se&gons" - -#: ../src\wxUI\view.py:67 -msgid "&Seek forward 5 seconds" -msgstr "avan&çar 5 segons" - -#: ../src\wxUI\view.py:72 -msgid "Sounds &tutorial" -msgstr "&Tutorial de sons" - -#: ../src\wxUI\view.py:73 -msgid "&What's new in this version?" -msgstr "&Què hi ha de nou en aquesta versió?" - -#: ../src\wxUI\view.py:74 -msgid "&Check for updates" -msgstr "&Cercar actualitzacions" - -#: ../src\wxUI\view.py:75 -msgid "&Report an error" -msgstr "&Reportar un problema" - -#: ../src\wxUI\view.py:76 -msgid "{0}'s &website" -msgstr "&Pàgina web de {0} " - -#: ../src\wxUI\view.py:77 -msgid "Get soundpacks for TWBlue" -msgstr "" - -#: ../src\wxUI\view.py:78 -msgid "About &{0}" -msgstr "Sobre &{0}" - -#: ../src\wxUI\view.py:81 -msgid "&Application" -msgstr "&Aplicació" - -#: ../src\wxUI\view.py:84 -msgid "&Buffer" -msgstr "&Bufer" - -#: ../src\wxUI\view.py:85 -msgid "&Audio" -msgstr "&Audio" - -#: ../src\wxUI\view.py:86 -msgid "&Help" -msgstr "&Ajuda" - -#: ../src\wxUI\view.py:172 -msgid "Address" -msgstr "Adreça" - -#: ../src\wxUI\view.py:203 -msgid "Update" -msgstr "Actualitzat" - -#: ../src\wxUI\view.py:203 -msgid "Your {0} version is up to date" -msgstr "La teva {0} versió ja està actualitzada." - -#~ msgid "Empty" -#~ msgstr "Buit" - -#~ msgid "One mention from %s " -#~ msgstr "Una menció de %s" - -#~ msgid "One tweet from %s" -#~ msgstr "Un tuit de %s" - -#~ msgid "You've blocked %s" -#~ msgstr "Has bloquejat a %s" - -#~ msgid "You've unblocked %s" -#~ msgstr "has desbloquejat %s" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "%s(@%s) ha començat a seguirte" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "Has seguit a %s(@%s)" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "Has deixat de seguir a %s(@%s)" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "Has marcat que t'agrada: %s, %s" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "%s(@%s) ha marcat que li agrada: %s" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "Has marcat que ja no t'agrada: %s, %s" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "%s(@%s) ha marcat que ja no li agrada: %s" - -#~ msgid "You've created the list %s" -#~ msgstr "Has creat la llista %s" - -#~ msgid "You've deleted the list %s" -#~ msgstr "Has esborrat la llista %s" - -#~ msgid "You've updated the list %s" -#~ msgstr "Has actualitzat la lista %s" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "Has afegit a %s(@%s) a la llista %s" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "%s(@%s) t'a afegit a la llista %s" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "Has esborrat a %s(@%s) de la llista %s" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "%s(@%s) t'ha eliminat de la llista %s" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "T'has subscrit a la llista %s, propietat de %s(@%s)" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "%s - %s caracters." - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "T'has donat de baixa de la llista %s, propietat de %s(@%s)" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Has sigut donat de baixa de la llista %s, propietat de %s(@%s)" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "Has retuitat un tuit de %s(@%s): %s" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "%s(@%s) ha retuitat el teu retuit: %s" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "Trucades a la API (una trucada equival a 200 tuits, 2 a 400 tuits, etc):" - -#~ msgid "Unable to upload the audio" -#~ msgstr "Impossible carregar l'audio" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "Esperant per l'autorització..." - -#~ msgid "autodetect" -#~ msgstr "Autodetectar" - -#~ msgid "" -#~ "There's a new %s version available. Would you like to download it now?\n" -#~ "\n" -#~ " %s version: %s\n" -#~ "\n" -#~ "Changes:\n" -#~ "%s" -#~ msgstr "" -#~ "Hi ha una nova versió de %s disponible. T'agradaria descaregar-la ara?\n" -#~ "\n" -#~ " %s versió: %s\n" -#~ "\n" -#~ "Canvis:\n" -#~ "%s" - -#~ msgid "Start {0} after logging in windows" -#~ msgstr "Iniciar {0} després d'iniciar Windows." - -#~ msgid "" -#~ "If you have a SndUp account, enter your API Key here. If your API Key is " -#~ "invalid, {0} will fail to upload. If there is no API Key here, {0} will " -#~ "upload annonymously." -#~ msgstr "" -#~ "Si tens un compte a SndUp, introdueix el teu API Key aquí. Si l'API Key " -#~ "és incorrecte, {0} no podrá enviar res al servidor. Si no hi ha API Key " -#~ "aqí, {0} carregarà de manera anònima" - -#~ msgid "Disconnect your Pocket account" -#~ msgstr "Desconnectar el teu compte de Pocket" - -#~ msgid "Connect your Pocket account" -#~ msgstr "Connectar compte de pocket" - -#~ msgid "Pocket Authorization" -#~ msgstr "Autorització de Pocket" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. You only need " -#~ "to do this once. Do you want to continue?" -#~ msgstr "" -#~ "La sol·licitud s'obrirà en el teu navegador. Només necessites fer això " -#~ "una vegada. Vols continuar?" - -#~ msgid "Error during authorization. Try again later." -#~ msgstr "Error durant l'autorització. Si et plau, prova-ho més tard." - -#~ msgid "Services" -#~ msgstr "Serveis" - -#~ msgid "Contains" -#~ msgstr "conté" - -#~ msgid "Doesn't contain" -#~ msgstr "no conté" - -#~ msgid "" -#~ "You have successfully logged into Twitter with {0}. You can close this " -#~ "window now." -#~ msgstr "" -#~ "S'ha iniciat correctament la sessió a twitter amb {0}. Ara ja es pot " -#~ "tancar aquesta finestra." - -#~ msgid "&Send" -#~ msgstr "&Enviar" - -#~ msgid "Spelling correction" -#~ msgstr "Correcció d'escriptura." - -#~ msgid "Shorten URL" -#~ msgstr "Escurçar adreça" - -#~ msgid "Expand URL" -#~ msgstr "Expandir adreça" - -#~ msgid "Send" -#~ msgstr "Enviar" - -#~ msgid "unavailable" -#~ msgstr "No disponible." - -#~ msgid "Search" -#~ msgstr "Cerca" - -#~ msgid "Update profile" -#~ msgstr "Actualitzar perfil" - -#~ msgid "Follow" -#~ msgstr "Seguir" - -#~ msgid "Mute" -#~ msgstr "Silenciar" - -#~ msgid "Block" -#~ msgstr "Bloquejar" - -#~ msgid "Report as spam" -#~ msgstr "Reportar com a spam" - -#~ msgid "Favourites" -#~ msgstr "Favorits" - -#~ msgid "Favourites timeline for {}" -#~ msgstr "Línies temporals dels favorits de " - -#~ msgid "Tweet favourited." -#~ msgstr "Tuit marcat com a favorit." - -#~ msgid "Mark as favourite" -#~ msgstr "Marcar com a favorit" - -#~ msgid "Remove from favourites" -#~ msgstr "Esborrar de favorits" - -#~ msgid "You've added to favourites: %s, %s" -#~ msgstr "Has afegit a favorits: %s, %s" - -#~ msgid "%s(@%s) has marked as favourite: %s" -#~ msgstr "%s(@%s) ha marcat com a favorit: %s" - -#~ msgid "You've removed from favourites: %s, %s" -#~ msgstr "Has esborrat delsteus favorits: %s, %s" - -#~ msgid "%s(@%s) has removed from favourites: %s" -#~ msgstr "%s(@%s) ha esborrat dels seus favorits: %s" - -#~ msgid "Favourites: " -#~ msgstr "Favorits: " - -#~ msgid "Add to &favourites" -#~ msgstr "&Afegir a favorit" - -#~ msgid "Remove from favo&urites" -#~ msgstr "&Esborrar de favorits" - -#~ msgid "V&iew favourites" -#~ msgstr "&Veure favorits" - -#~ msgid "Opening media..." -#~ msgstr "Obrint media..." - -#~ msgid "Add a new ignored client" -#~ msgstr "Afegir un nou client ignorat " - -#~ msgid "Do you really want to delete this timeline?" -#~ msgstr "Realment vols eliminar aquesta línia temporal?" - -#~ msgid "Autocomplete users\\342\\200\\231 settings" -#~ msgstr "Autocompletar usuaris\\342\\200\\231 configuració" - -#~ msgid "Set the autocomplete function" -#~ msgstr "Configurar la funció d'autocompletat" - -#~ msgid "Relative times" -#~ msgstr "Temps relatius" - -#~ msgid "" -#~ "API calls when the stream is started (One API call equals to 200 tweetts, " -#~ "two API calls equals 400 tweets, etc):" -#~ msgstr "" -#~ "Trucades a la API quan el stream s'inicïi (una trucada equival a 200 " -#~ "tuits, 2 a 400 tuits, etc):" - -#~ msgid "" -#~ "Inverted buffers: The newest tweets will be shown at the beginning of the " -#~ "lists while the oldest at the end" -#~ msgstr "" -#~ "Buffers invertits: els nous tuits es mostraràn al inici de les llistes y " -#~ "els antics al final" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. Copy the code " -#~ "from Dropbox and paste it into the text box which will appear. You only " -#~ "need to do this once." -#~ msgstr "" -#~ "La sol·licitud d'autorització s'obrirà en el teu navegador. Copia i " -#~ "enganxa el codi al quadre de text que apareixerà tot seguit. Només has de " -#~ "fer això una vegada." - -#~ msgid "Verification code" -#~ msgstr "Codi de verificació" - -#~ msgid "Error during authorisation. Try again later." -#~ msgstr "Error durant l'autorització. Si et plau, prova-ho més tard." - -#~ msgid "TW Blue preferences" -#~ msgstr "Preferències de TW Blue" - -#~ msgid "Show other buffers" -#~ msgstr "Mostrar altres buffers" - -#~ msgid "JPG images" -#~ msgstr "Imatges JPG" - -#~ msgid "GIF images" -#~ msgstr "Imatges Gif" - -#~ msgid "PNG Images" -#~ msgstr "Imatges PNG" - -#~ msgid "Select an URL" -#~ msgstr "Selecciona una adreça" - -#~ msgid "Not actionable." -#~ msgstr "No hi ha accions associades a aquest tuit" - -#~ msgid "This account is not logged in twitter." -#~ msgstr "No s'ha iniciat sessió a Twitter amb aquest compte" - -#~ msgid "{0}: This account is not logged in twitter." -#~ msgstr "{0}: No s'ha iniciat sessió a twitter amb aquest comte" - -#~ msgid "Global mute off" -#~ msgstr "Silenci global desactivat" - -#~ msgid "User-defined buffer created." -#~ msgstr "Creat el buffer de l'usuari definit" - -#~ msgid "User-defined buffer destroied." -#~ msgstr "Esborrat el buffer de l'usuari definit" - -#, fuzzy -#~ msgid "Someone's favourites have been updated." -#~ msgstr "Els favorits d'algú s'han actualitzat." - -#~ msgid "A trending topic buffer has been updated." -#~ msgstr "Un buffer de tendències s'ha actualitzat." - -#~ msgid "New tweet in user-defined buffer." -#~ msgstr "Un tuit nou al buffer de l'usuari definit" - -#~ msgid "Mis-spelled word: %s" -#~ msgstr "Paraula mal escrita: %s" - -#~ msgid "Mis-spelled word" -#~ msgstr "Paraula mal escrita" - -#~ msgid "Finished" -#~ msgstr "Finalitzat" - -#~ msgid "The spelling review has finished." -#~ msgstr "La revisió d'escriptura s'ha finalitzat." - -#~ msgid "" -#~ "Do you really want to delete this message? It will be eliminated from " -#~ "Twitter as well." -#~ msgstr "" -#~ "Estàs segur de que vols esborrar aquest missatge? Tambè s'esborrarà de " -#~ "Twitter." - -#~ msgid "Show followers" -#~ msgstr "Veure seguidors" - -#~ msgid "Show friends" -#~ msgstr "Veure amics" - -#~ msgid "Show favourites" -#~ msgstr "Veure favorits" - -#~ msgid "Show blocked users" -#~ msgstr "Veure usuaris bloquejats" - -#~ msgid "Show muted users" -#~ msgstr "Veure usuaris silenciats" - -#~ msgid "Show events" -#~ msgstr "Veure esdeveniments." - -#~ msgid "" -#~ "The authorisation request will be shown on your browser. Copy the code " -#~ "tat Dropbox will provide and, in the text box that will appear on TW " -#~ "Blue, paste it. This code is necessary to continue. You only need to do " -#~ "it once." -#~ msgstr "" -#~ "La sol·licitud d'autorització apareixerà al teu navegador. Copia el codi " -#~ "que dropbox et facilitarà i, en el camp de text que apareixerà a TW Blue, " -#~ "enganxa'l. Aquest codi es necessari per continuar. Només ho has de fer " -#~ "una vegada." - -#~ msgid "Authorisation" -#~ msgstr "Autorització" - -#, fuzzy -#~ msgid "Change to the next account" -#~ msgstr "Anar a la pestanya següent" - -#, fuzzy -#~ msgid "Change to the previous account" -#~ msgstr "Anar a la pestanya anterior" - -#~ msgid "Remove buffer" -#~ msgstr "Esborrar buffer" - -#~ msgid "" -#~ "Open URL on the current tweet, or further information for a friend or " -#~ "follower" -#~ msgstr "" -#~ "Obrir adreça al twit actual, o sol·licitar més informació a buffers " -#~ "d'usuaris" - -#~ msgid "Go to the first element on the list" -#~ msgstr "Anar al primer element DE LA LLISTA" - -#~ msgid "Go to the last element on the list" -#~ msgstr "Anar al darrer element de la llista" - -#~ msgid "Move 20 elements up on the current list" -#~ msgstr "Moure's 20 elements cap amunt en la llista actual" - -#~ msgid "Move 20 elements down on the current list" -#~ msgstr "Moure's 20 elements cap avall en la llista actual" - -#~ msgid "Remove a tweet or direct message" -#~ msgstr "Esborrar un tuit o missatge directe" - -#, fuzzy -#~ msgid "Globally mute/unmute the current account" -#~ msgstr "Activar o desactivar el silenci global de TW Blue" - -#, fuzzy -#~ msgid "load previous items to any buffer" -#~ msgstr "&carregar twits més antics a qualsevol buffer" - -#, fuzzy -#~ msgid "" -#~ "The request for the required Twitter authorisation to continue will be " -#~ "opened on your browser. You only need to do it once. Would you like to " -#~ "autorhise a new account now?" -#~ msgstr "" -#~ "La Sol·licitud per a l'autorització del teu compte de Twitter s'obrirá al " -#~ "navigador. Només has de fer això una vegada. Vols autoritzar un compte de " -#~ "Twitter ara?" - -#~ msgid "" -#~ "Your access token is invalid or the authorisation has failed. Please try " -#~ "again." -#~ msgstr "" -#~ "El teu token d'accés és invàlid o l'autorització ha fallat. Si et plau, " -#~ "prova-ho de nou." - -#~ msgid "" -#~ "%s (@%s). %s followers, %s friends, %s tweets. Last tweet on %s. Joined " -#~ "Twitter on %s" -#~ msgstr "" -#~ "%s (@%s). %s seguidors, %s amics, %s tuits. Últim tuit el %s. Es va unir " -#~ "a Twitter el %s" - -#~ msgid "" -#~ "The application requires to be restarted to save these changes. Press OK " -#~ "to do it now." -#~ msgstr "" -#~ "El programa necessita reiniciar perquè els canvis facin efecte. Prem " -#~ "acceptar per fer-ho ara." - -#~ msgid "" -#~ "Dropbox will open in your browser. After you log into Dropbox, an " -#~ "authorization code will be generated. Please paste it into the field " -#~ "which will appear. You only need to do this once." -#~ msgstr "" -#~ "Dropbox s'obrirà en el teu navegador. Una vegada hagis iniciat sessió a " -#~ "Dropox, apareixerà un codi d'autorització que hauràs d'enganxar. Només " -#~ "hauràs de fer això una vegada." - -#~ msgid "View &trending topics" -#~ msgstr "Veure &Trending topics" - -#~ msgid "&Unfollow" -#~ msgstr "&Deixar de seguir" - -#~ msgid "U&nmute" -#~ msgstr "&Dessilenciar" - -#~ msgid "Unb&lock" -#~ msgstr "&Desbloquejar" - -#~ msgid "&Timeline" -#~ msgstr "&Línia temporal" - -#~ msgid "&Autoread tweets for this buffer" -#~ msgstr "&Llegir automàticament els tuits d'aquest buffer." - -#~ msgid "&Remove buffer" -#~ msgstr "&Esborrar buffer" - -#~ msgid "Stop recording" -#~ msgstr "Aturar grabació" - -#~ msgid "The tweet may contain a playable audio" -#~ msgstr "El tuit pot contenir un audio reproduible." - -#~ msgid "A timeline has been created" -#~ msgstr "La línia temporal s'ha creat" - -#~ msgid "A timeline has been deleted" -#~ msgstr "La línia temporal s'ha esborrat" - -#~ msgid "You've received a direct message" -#~ msgstr "Has rebut un missatge directe" - -#~ msgid "You've sent a direct message" -#~ msgstr "Has enviat un missatge directe." - -#~ msgid "A bug has happened" -#~ msgstr "Hi ha hagut un problema." - -#~ msgid "You've added a tweet to your favourites" -#~ msgstr "Has afegit un tuit als favorits." - -#~ msgid "The tweet has coordinates to determine its location" -#~ msgstr "El tuit té coordenades per determinar la seva localització." - -#~ msgid "There are no more tweets to read" -#~ msgstr "No hi ha més twits per llegir" - -#~ msgid "A list has a new tweet" -#~ msgstr "Una llista té un nou twit" - -#~ msgid "You can't add any more characters on the tweet" -#~ msgstr "No pots afegir més caràcters al tuit." - -#~ msgid "You've been mentioned " -#~ msgstr "Has sigut mencionat" - -#~ msgid "A new event has happened" -#~ msgstr "hi ha hagut un nou esdeveniment." - -#~ msgid "You've replied" -#~ msgstr "Has contestat" - -#~ msgid "You've sent a tweet" -#~ msgstr "Has enviat un tuit" - -#~ msgid "There's a new tweet in a timeline" -#~ msgstr "Hi ha un nou tuit a una línia temporal." - -#~ msgid "You have a new follower" -#~ msgstr "Tens un nou seguidor." - -#~ msgid "You've turned the volume up or down" -#~ msgstr "Has apujat o abaixat el volum." - -#~ msgid "" -#~ "It seems as though the currently used sound pack needs an update. %i " -#~ "fails are still be required to use this function. Make sure to obtain the " -#~ "needed lacking sounds or to contact with the sound pack developer." -#~ msgstr "" -#~ "Sembla que el paquet de sons actualment utilitzat necessita una " -#~ "actualització. %i fitxers son necesaris per a fer aquesta funció. " -#~ "Asegurat de aconseguir els sons necessaris o contacta amb el creador del " -#~ "paquet." - -#~ msgid "See the users list" -#~ msgstr "Veure la llista d'usuaris." - -#~ msgid "Do you really want to delete this message?" -#~ msgstr "Realment vols eliminar aquest missatge?" - -#~ msgid "Unable to play audio." -#~ msgstr "Impossible reproduir audio" - -#~ msgid "Do you really want to delete this favourites timeline?" -#~ msgstr "Realment vols eliminar aquesta líniade favorits?" - -#~ msgid "&Mention" -#~ msgstr "&Menció" - -#~ msgid "Announce" -#~ msgstr "Anuncia" - -#~ msgid "" -#~ "Do you really want to empty this buffer? It's items will be removed from " -#~ "the list" -#~ msgstr "" -#~ "Estàs segur de que vols buidar aquest buffer? Els tuits seràn eliminats " -#~ "de la llista." - -#~ msgid "Do you really want to delete this search term?" -#~ msgstr "Segur que vols esborrar aquest terme de cerca?" - -#~ msgid "ask before exiting TwBlue?" -#~ msgstr "Preguntar abans de sortir de Tw Blue?" - -#~ msgid "Activate the auto-start of the invisible interface" -#~ msgstr "Activar l'inici automàtic de la interfície invisible" - -#~ msgid "Global mute" -#~ msgstr "Silenci global" - -#~ msgid "friends" -#~ msgstr "Amics" - -#~ msgid "Favorites" -#~ msgstr "Favorits" - -#~ msgid "You've muted to %s" -#~ msgstr "Has silenciat a %s" - -#~ msgid "You've unmuted to %s" -#~ msgstr "Has dessilenciat a %s" - -#~ msgid "This list is arready opened." -#~ msgstr "Aquesta llista ja està oberta" - -#~ msgid "List for %s" -#~ msgstr "Llista %s" - -#~ msgid "Uploading..." -#~ msgstr "Carregant..." - -#~ msgid "Men&tion all" -#~ msgstr "Men&cionar a tots" - -#~ msgid "This user does not exist on Twitter" -#~ msgstr "Aquest usuari no existeix a Twitter." - -#~ msgid "S&witch account" -#~ msgstr "&Canviar de compte" - -#~ msgid "&Preferences" -#~ msgstr "&Preferències" - -#~ msgid "About &TW Blue" -#~ msgstr "&Sobre TW Blue" - -#~ msgid "" -#~ "An error occurred while looking for an update. It may be due to any " -#~ "problem either on our server or on your DNS servers. Please, try again " -#~ "later." -#~ msgstr "" -#~ "Hi ha hagut un error cercant actualitzacions. Pot ser per un problema amb " -#~ "el nostre servidor o en el teu servidor DNS. Si et plau, prova-ho més " -#~ "tard." - -#~ msgid "Sent" -#~ msgstr "Enviats" - -#~ msgid "%s favourites from %s" -#~ msgstr "%s favorits de %s" - -#~ msgid "Streams disconnected. TW Blue will try to reconnect in a minute." -#~ msgstr "Streams desconnectats. TW Blue provarà de connectar-se en un minut." - -#~ msgid "Reconnecting streams..." -#~ msgstr "Reconectant els streams..." - -#~ msgid "search users for %s" -#~ msgstr "Cercar usuaris per %s" - -#~ msgid "Do you really want to close TW Blue?" -#~ msgstr "Estàs segur de que vols sortir de TW Blue?" - -#~ msgid "Exiting..." -#~ msgstr "Sortint..." - -#~ msgid "Error while adding to favourites." -#~ msgstr "Error afegint a favorit" - -#~ msgid "Error while removing from favourites." -#~ msgstr "Error esborrant de favorits" - -#~ msgid "Individual timeline" -#~ msgstr "Línia temporal individual" - -#~ msgid "List of favourites" -#~ msgstr "Llista de favorits" - -#~ msgid "Existing list" -#~ msgstr "Llista existent" - -#~ msgid "" -#~ "There's already a list of favourites for this user. You can't create " -#~ "another." -#~ msgstr "" -#~ "Ja hi ha una llista de favorits d'aquest usuari. No pots crear-ne una " -#~ "altra." - -#~ msgid "" -#~ "This user has no favourites. You can't create a list of favourites for " -#~ "this user." -#~ msgstr "" -#~ "Aquest usuari no té tuits favorits. No pots obrir una llista dels seus " -#~ "tuits favorits." - -#~ msgid "%s" -#~ msgstr "%s" - -#~ msgid "Documentation" -#~ msgstr "Documentació" - -#~ msgid "Translation" -#~ msgstr "Traducció." - -#~ msgid "Move up one tweet in the conversation" -#~ msgstr "Anar un tuit amunt a la conversa" - -#~ msgid "Move down one tweet in the conversation" -#~ msgstr "Anar un tuit avall a la conversa" - -#~ msgid "Show the graphical interface" -#~ msgstr "Activar la visualització gràfica" - -#~ msgid "Reply to a tweet" -#~ msgstr "Respondre un twit." - -#~ msgid "Empty the buffer removing all the elements" -#~ msgstr "Buidar buffer, eliminant tos els elements" - -#~ msgid "Listen the current message" -#~ msgstr "Escoltar el missatge actual" - -#~ msgid "Get location of any tweet" -#~ msgstr "Esbrinar la localització de qualsevol tuit." - -#~ msgid "Creates a buffer for displaying trends for a desired place" -#~ msgstr "Crea un buffer per mostrar tendències d'un lloc concret." - -#~ msgid "Select a twitter account to start TW Blue" -#~ msgstr "Selecciona un compte de Twitter per començar a TWBlue" - -#~ msgid "Remove session" -#~ msgstr "Eliminar sessió." - -#~ msgid "One tweet from %s in the list %s" -#~ msgstr "Un tuit de %s en la llista %s" - -#~ msgid "One direct message" -#~ msgstr "Un missatge directe" - -#~ msgid "About a week ago" -#~ msgstr "Fa una setmana" - -#~ msgid "About {} weeks ago" -#~ msgstr "Fa {} setmanes" - -#~ msgid "A month ago" -#~ msgstr "Fa un mes" - -#~ msgid "About {} months ago" -#~ msgstr "Fa {} messos" - -#~ msgid "About a year ago" -#~ msgstr "Fa un any" - -#~ msgid "About {} years ago" -#~ msgstr "Fa {} anys" - -#~ msgid "About 1 day ago" -#~ msgstr "Fa un dia" - -#~ msgid "About {} days ago" -#~ msgstr "Fa {} dies" - -#~ msgid "just now" -#~ msgstr "Ara mateix" - -#~ msgid "{} seconds ago" -#~ msgstr "Fa {} segons" - -#~ msgid "1 minute ago" -#~ msgstr "Fa 1 minut" - -#~ msgid "{} minutes ago" -#~ msgstr "Fa {} minuts" - -#~ msgid "About 1 hour ago" -#~ msgstr "Fa una hora" - -#~ msgid "About {} hours ago" -#~ msgstr "Fa {} hores" - -#~ msgid "January" -#~ msgstr "Jener" - -#~ msgid "February" -#~ msgstr "Febrer" - -#~ msgid "March" -#~ msgstr "Març" - -#~ msgid "April" -#~ msgstr "Abril" - -#~ msgid "June" -#~ msgstr "Juny" - -#~ msgid "July" -#~ msgstr "Juliol" - -#~ msgid "August" -#~ msgstr "Agost" - -#~ msgid "September" -#~ msgstr "Setembre" - -#~ msgid "October" -#~ msgstr "Octubre" - -#~ msgid "November" -#~ msgstr "Novembre" - -#~ msgid "December" -#~ msgstr "Decembre" - -#~ msgid "Sunday" -#~ msgstr "Diumenge" - -#~ msgid "Monday" -#~ msgstr "Dilluns" - -#~ msgid "Tuesday" -#~ msgstr "Dimars" - -#~ msgid "Wednesday" -#~ msgstr "Dimecres" - -#~ msgid "Thursday" -#~ msgstr "Dijous" - -#~ msgid "Friday" -#~ msgstr "Divendres" - -#~ msgid "Saturday" -#~ msgstr "Disabte" - -#~ msgid "sun" -#~ msgstr "Diumenge" - -#~ msgid "mon" -#~ msgstr "Dilluns" - -#~ msgid "tue" -#~ msgstr "Dimarts" - -#~ msgid "wed" -#~ msgstr "Dimecres" - -#~ msgid "thu" -#~ msgstr "Dijous" - -#~ msgid "fri" -#~ msgstr "Divendres" - -#~ msgid "sat" -#~ msgstr "Dissabte" - -#~ msgid "jan" -#~ msgstr "Jener" - -#~ msgid "feb" -#~ msgstr "Febrer" - -#~ msgid "mar" -#~ msgstr "Març" - -#~ msgid "apr" -#~ msgstr "Abril" - -#~ msgid "may" -#~ msgstr "Maig" - -#~ msgid "jun" -#~ msgstr "Juny" - -#~ msgid "jul" -#~ msgstr "Juliol" - -#~ msgid "aug" -#~ msgstr "Agost" - -#~ msgid "sep" -#~ msgstr "Setembre" - -#~ msgid "oct" -#~ msgstr "Octubre" - -#~ msgid "nov" -#~ msgstr "Novembre" - -#~ msgid "dec" -#~ msgstr "Decembre" - -#~ msgid "%A, %B %d, %Y at %I:%M:%S %p" -#~ msgstr "%A, %d de %B del %Y a les %I:%M:%S %p" - -#~ msgid "Your TW Blue version is up to date" -#~ msgstr "La teva versió de TWBlue està actualitzada" - -#~ msgid "Connection error. Try again later." -#~ msgstr "Error de connexió. Si et plau, prova-ho més tard." - -#~ msgid "View members" -#~ msgstr "¿¿¿Veure membres" - -#~ msgid "View subscribers" -#~ msgstr "Veure subscriptors" - -#~ msgid "Ouner" -#~ msgstr "propietari" - -#~ msgid "Successfully following %s" -#~ msgstr "Èxit seguint a %s" - -#~ msgid "%s has been reported as spam" -#~ msgstr "%s ha sigut reportat com spam" - -#~ msgid "%s has been blocked" -#~ msgstr "%s ha sigut bloquejat" - -#~ msgid "User's information" -#~ msgstr "Detalls de l'usuari" - -#~ msgid "You've unblock %s" -#~ msgstr "Has desbloquejat a %s" - -#~ msgid "Clear" -#~ msgstr "Limpiar" diff --git a/src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).mo b/src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).mo deleted file mode 100644 index b7b41c9f6516ea6d1bb6c1982118df4dc76ee3a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49494 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 VW_DC#n|5tdpcQW#=)brd{vXl!R(Svb diff --git a/src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po b/src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po deleted file mode 100644 index d3113de0..00000000 --- a/src/locales/da/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po +++ /dev/null @@ -1,3371 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2019-03-09 23:36+0100\n" -"Last-Translator: Nicolai Svendsen \n" -"Language-Team: \n" -"Language: da\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.2\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../src\controller\attach.py:23 -msgid "Photo" -msgstr "Billede" - -#: ../src\controller\buffers\baseBuffers.py:95 -msgid "This action is not supported for this buffer" -msgstr "Denne handling understøttes ikke for denne buffer" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 -msgid "Home" -msgstr "Hjem" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 -msgid "Mentions" -msgstr "Omtale" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 -msgid "Direct messages" -msgstr "Direkte beskeder" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 -msgid "Sent direct messages" -msgstr "Sendte direkte beskeder" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 -msgid "Sent tweets" -msgstr "Sendte tweets" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 -msgid "Likes" -msgstr "Synes godt om" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 -msgid "Followers" -msgstr "Følgere" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "Venner" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 -msgid "Blocked users" -msgstr "Blokerede brugere" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 -msgid "Muted users" -msgstr "Dæmpede brugere" - -#: ../src\controller\buffers\twitterBuffers.py:75 -#, fuzzy -msgid "{username}'s timeline" -msgstr "Åbn brugerens tidslinje" - -#: ../src\controller\buffers\twitterBuffers.py:77 -msgid "{username}'s likes" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:79 -msgid "{username}'s followers" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:81 -msgid "{username}'s friends" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:83 -#, fuzzy -msgid "Unknown buffer" -msgstr "Ukendt" - -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 -msgid "Tweet" -msgstr "Tweet" - -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 -msgid "Write the tweet here" -msgstr "Skriv et tweet her" - -#: ../src\controller\buffers\twitterBuffers.py:194 -#, fuzzy -msgid "New tweet in {0}" -msgstr "Nyt Tweet" - -#: ../src\controller\buffers\twitterBuffers.py:197 -#, fuzzy -msgid "{0} new tweets in {1}." -msgstr "@{0} citerede dit tweet: {1}" - -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 -msgid "%s items retrieved" -msgstr "%s elementer hentet" - -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "Denne buffer er ikke en tidslinje; Den kan ikke slettes." - -#: ../src\controller\buffers\twitterBuffers.py:402 -msgid "Reply to {arg0}" -msgstr "Svare {arg0}" - -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 -msgid "Reply" -msgstr "Svar" - -#: ../src\controller\buffers\twitterBuffers.py:405 -msgid "Reply to %s" -msgstr "Svar %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Direkte besked til %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 -msgid "New direct message" -msgstr "Ny direkte besked" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Add your comment to the tweet" -msgstr "tilføj din kommentar til dette tweet" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Quote" -msgstr "Citat" - -#: ../src\controller\buffers\twitterBuffers.py:572 -msgid "Opening URL..." -msgstr "Åbner URL…" - -#: ../src\controller\buffers\twitterBuffers.py:607 -msgid "User details" -msgstr "Brugerdetaljer" - -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 -msgid "Opening item in web browser..." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -msgid "Mention to %s" -msgstr "Omtale til %s" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 -msgid "Mention" -msgstr "Omtale" - -#: ../src\controller\buffers\twitterBuffers.py:728 -#, fuzzy -msgid "{0} new direct messages." -msgstr "Ny direkte besked" - -#: ../src\controller\buffers\twitterBuffers.py:731 -#, fuzzy -msgid "This action is not supported in the buffer yet." -msgstr "Denne handling understøttes ikke for denne buffer" - -#: ../src\controller\buffers\twitterBuffers.py:741 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy -msgid "{0} new followers." -msgstr "Ny følger." - -#: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy -msgid "This action is not supported in the buffer, yet." -msgstr "Denne handling understøttes ikke for denne buffer" - -#: ../src\controller\mainController.py:273 -msgid "Ready" -msgstr "Klar" - -#: ../src\controller\mainController.py:345 -msgid "Timelines" -msgstr "Tidslinjer" - -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 -msgid "Timeline for {}" -msgstr "Tidslinje for {}" - -#: ../src\controller\mainController.py:352 -msgid "Likes timelines" -msgstr "Tidslinjer for synes godt om" - -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 -msgid "Likes for {}" -msgstr "Synes godt om for {}" - -#: ../src\controller\mainController.py:359 -msgid "Followers' Timelines" -msgstr "Tidslinjer for følgere" - -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 -msgid "Followers for {}" -msgstr "Følgere for {}" - -#: ../src\controller\mainController.py:366 -msgid "Friends' Timelines" -msgstr "Venners tidslinjer" - -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 -msgid "Friends for {}" -msgstr "Venner for {}" - -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 -msgid "Lists" -msgstr "Lister" - -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 -msgid "List for {}" -msgstr "Liste for {}" - -#: ../src\controller\mainController.py:381 -msgid "Searches" -msgstr "Søgninger" - -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 -msgid "Search for {}" -msgstr "Søg efter {}" - -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 -msgid "Trending topics for %s" -msgstr "Trends for {}" - -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "" -"Ingen session er på nuværende tidspunkt i fokus. Skift fokus til en aktiv " -"session ved brug af tastaturgenvejen der skifter mellem forrige og næste " -"session" - -#: ../src\controller\mainController.py:465 -msgid "Empty buffer." -msgstr "Tøm buffer" - -#: ../src\controller\mainController.py:472 -msgid "{0} not found." -msgstr "{0} ikke fundet." - -#: ../src\controller\mainController.py:482 -msgid "Filters cannot be applied on this buffer" -msgstr "Filtre understøttes ikke for denne buffer" - -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 -msgid "Select the user" -msgstr "Vælg bruger" - -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy -msgid "MMM D, YYYY. H:m" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\controller\mainController.py:934 -msgid "Conversation with {0}" -msgstr "Samtale med {0}" - -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 -msgid "There are no coordinates in this tweet" -msgstr "Der er ingen koordinater i denne tweet" - -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "Der er ingen resultater for koordinaterne i denne tweet" - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 -msgid "Error decoding coordinates. Try again later." -msgstr "Fejl under afkodning af koordinater. Prøv igen senere." - -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 -msgid "%s, %s of %s" -msgstr "%s, %s af %s" - -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 -msgid "%s. Empty" -msgstr "%s. Tom" - -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 -msgid "{0}: This account is not logged into Twitter." -msgstr "{0}: Denne konto er ikke logget ind på Twitter." - -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 -msgid "%s. %s, %s of %s" -msgstr "%s. %s, %s af %s" - -#: ../src\controller\mainController.py:1170 -msgid "{0}: This account is not logged into twitter." -msgstr "{0}: Denne konto er ikke logget ind på Twitter." - -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Begivenheder" - -#: ../src\controller\mainController.py:1393 -msgid "This list is already opened" -msgstr "Denne liste er allerede åbnet" - -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 -#, fuzzy -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "" -"Noget uventet opstod under forsøg på at rapportere fejlen. Prøv igen senere." - -#: ../src\controller\mainController.py:1475 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "Auto-læsning af ny tweets er aktiveret for denne buffer" - -#: ../src\controller\mainController.py:1478 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "Auto-læsning af ny tweets er deaktiveret for denne buffer" - -#: ../src\controller\mainController.py:1485 -msgid "Session mute on" -msgstr "Session dæmpning slået til" - -#: ../src\controller\mainController.py:1488 -msgid "Session mute off" -msgstr "Session dæmpning slået fra" - -#: ../src\controller\mainController.py:1496 -msgid "Buffer mute on" -msgstr "Buffer dæmpning slået til" - -#: ../src\controller\mainController.py:1499 -msgid "Buffer mute off" -msgstr "Buffer dæmpning slået fra" - -#: ../src\controller\mainController.py:1522 -msgid "Copied" -msgstr "Kopieret" - -#: ../src\controller\mainController.py:1549 -msgid "Unable to update this buffer." -msgstr "Ikke i stand til at opdatere denne buffer." - -#: ../src\controller\mainController.py:1552 -msgid "Updating buffer..." -msgstr "Opdaterer buffer…" - -#: ../src\controller\mainController.py:1555 -msgid "{0} items retrieved" -msgstr "{0} emner hentet" - -#: ../src\controller\mainController.py:1572 -msgid "Invalid buffer" -msgstr "Ugyldig buffer" - -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "Dette tweet indeholder ingen billeder." - -#: ../src\controller\mainController.py:1579 -msgid "Picture {0}" -msgstr "Billede {0}" - -#: ../src\controller\mainController.py:1580 -msgid "Select the picture" -msgstr "Vælg billedet" - -#: ../src\controller\mainController.py:1596 -msgid "Unable to extract text" -msgstr "Ikke i stand til at genkende tekst" - -#: ../src\controller\messages.py:54 -msgid "Translated" -msgstr "Oversat" - -#: ../src\controller\messages.py:61 -msgid "There's no URL to be shortened" -msgstr "Der er ingen URL der kan forkortes" - -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 -msgid "URL shortened" -msgstr "URL forkortet" - -#: ../src\controller\messages.py:80 -msgid "There's no URL to be expanded" -msgstr "Der er ingen URL der kan udvides" - -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 -msgid "URL expanded" -msgstr "URL udvidet" - -#: ../src\controller\messages.py:104 -msgid "%s - %s of %d characters" -msgstr "%s - %s af %d tegn" - -#: ../src\controller\messages.py:108 -msgid "%s - %s characters" -msgstr "%s - %s tegn" - -#: ../src\controller\messages.py:262 -msgid "View item" -msgstr "Vis element" - -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Direkte forbindelse" - -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Ask" -msgstr "Spørg" - -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet without comments" -msgstr "Retweet uden kommentar" - -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet with comments" -msgstr "Retweet med en kommentar" - -#: ../src\controller\settings.py:184 -msgid "Account settings for %s" -msgstr "Kontoindstillinger for %s" - -#: ../src\controller\settings.py:284 -msgid "Direct Messages" -msgstr "Direkte Beskeder" - -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 -msgid "Error" -msgstr "Fejl" - -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 -msgid "That user does not exist" -msgstr "Denne bruger eksisterer ikke" - -#: ../src\controller\user.py:30 -msgid "User has been suspended" -msgstr "Brugeren er suspenderet" - -#: ../src\controller\user.py:36 -msgid "Information for %s" -msgstr "Information om %s" - -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 -msgid "Discarded" -msgstr "Kasseret" - -#: ../src\controller\user.py:95 -msgid "Username: @%s\n" -msgstr "Brugernavn: @%s\n" - -#: ../src\controller\user.py:96 -msgid "Name: %s\n" -msgstr "Navn: %s\n" - -#: ../src\controller\user.py:98 -msgid "Location: %s\n" -msgstr "Lokalitet: %s\n" - -#: ../src\controller\user.py:100 -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: ../src\controller\user.py:102 -msgid "Bio: %s\n" -msgstr "Bio: %s\n" - -#: ../src\controller\user.py:103 ../src\controller\user.py:118 -msgid "Yes" -msgstr "Ja" - -#: ../src\controller\user.py:104 ../src\controller\user.py:119 -msgid "No" -msgstr "Nej" - -#: ../src\controller\user.py:105 -msgid "Protected: %s\n" -msgstr "Beskyttet: %s\n" - -#: ../src\controller\user.py:110 -msgid "You follow {0}. " -msgstr "Du følger {0}. " - -#: ../src\controller\user.py:113 -msgid "{0} is following you." -msgstr "{0} følger dig." - -#: ../src\controller\user.py:117 -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"Følgere: %s\n" -" Venner: %s\n" - -#: ../src\controller\user.py:120 -msgid "Verified: %s\n" -msgstr "Verificeret:%s\n" - -#: ../src\controller\user.py:121 -msgid "Tweets: %s\n" -msgstr "Tweets: %s\n" - -#: ../src\controller\user.py:122 -msgid "Likes: %s" -msgstr "Synes godt om: %s" - -#: ../src\controller\userActionsController.py:75 -msgid "You can't ignore direct messages" -msgstr "Du kan ikke ignorere direkte beskeder" - -#: ../src\extra\AudioUploader\audioUploader.py:54 -msgid "Attaching..." -msgstr "Vedhæfter…" - -#: ../src\extra\AudioUploader\audioUploader.py:71 -msgid "Pause" -msgstr "Pause" - -#: ../src\extra\AudioUploader\audioUploader.py:73 -msgid "&Resume" -msgstr "&Genoptag" - -#: ../src\extra\AudioUploader\audioUploader.py:74 -msgid "Resume" -msgstr "Genoptag" - -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 -msgid "&Pause" -msgstr "&Pause" - -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 -msgid "&Stop" -msgstr "&Stop" - -#: ../src\extra\AudioUploader\audioUploader.py:92 -msgid "Recording" -msgstr "Optager" - -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 -msgid "Stopped" -msgstr "Stoppet" - -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 -msgid "&Record" -msgstr "&Optag" - -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 -msgid "Playing..." -msgstr "Afspiller." - -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 -msgid "&Play" -msgstr "&Afspil" - -#: ../src\extra\AudioUploader\audioUploader.py:156 -msgid "Recoding audio..." -msgstr "Genkoder lyd..." - -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 -msgid "Error in file upload: {0}" -msgstr "Fejl under upload af fil: {0}" - -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 -msgid "%d day, " -msgstr "%d dag, " - -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 -msgid "%d days, " -msgstr "%d dage, " - -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 -msgid "%d hour, " -msgstr "%d time, " - -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 -msgid "%d hours, " -msgstr "%d timer, " - -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 -msgid "%d minute, " -msgstr "%d minut, " - -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 -msgid "%d minutes, " -msgstr "%d minutter, " - -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 -msgid "%s second" -msgstr "%s sekund" - -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 -msgid "%s seconds" -msgstr "%s sekunder" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 -msgid "File" -msgstr "Fil" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 -msgid "Transferred" -msgstr "Overført" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 -msgid "Total file size" -msgstr "Total filstørrelse" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 -msgid "Transfer rate" -msgstr "Overførselshastighed" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 -msgid "Time left" -msgstr "Tid tilbage" - -#: ../src\extra\AudioUploader\wx_ui.py:28 -msgid "Attach audio" -msgstr "Vedhæft lyd" - -#: ../src\extra\AudioUploader\wx_ui.py:40 -msgid "&Add an existing file" -msgstr "&Tilføj en eksisterende fil" - -#: ../src\extra\AudioUploader\wx_ui.py:41 -msgid "&Discard" -msgstr "&Kassér" - -#: ../src\extra\AudioUploader\wx_ui.py:43 -msgid "Upload to" -msgstr "Overfør til" - -#: ../src\extra\AudioUploader\wx_ui.py:48 -msgid "Attach" -msgstr "Vedhæft" - -#: ../src\extra\AudioUploader\wx_ui.py:50 -msgid "&Cancel" -msgstr "&Annuller" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "Lydfiler (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Select the audio file to be uploaded" -msgstr "Vælg den lydfil, der skal uploades" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 -msgid "Audio tweet." -msgstr "Lyd tweet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "User timeline buffer created." -msgstr "Bruger tidslinjebuffer oprettet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "Buffer destroied." -msgstr "Buffer slettet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Direct message received." -msgstr "Direkte besked modtaget." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message sent." -msgstr "Direkte besked sendt." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Error." -msgstr "Fejl." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Tweet liked." -msgstr "Synes godt om tweet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Likes buffer updated." -msgstr "Buffer synes godt om opdateret." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Geotweet." -msgstr "Geotweet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Tweet contains one or more images" -msgstr "Tweet indeholder et eller flere billeder" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Boundary reached." -msgstr "Grænse nået." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "List updated." -msgstr "Liste opdateret." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "Too many characters." -msgstr "For mange tegn." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Mention received." -msgstr "Omtale modtaget." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "New event." -msgstr "Nyt begivenhed." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "{0} is ready." -msgstr "{0} er klar." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -msgid "Mention sent." -msgstr "Omtale sendt." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Tweet retweeted." -msgstr "Tweet retweetet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Search buffer updated." -msgstr "Søgebuffer opdateret." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Tweet received." -msgstr "Tweet modtaget." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet sent." -msgstr "Tweet sendt." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Trending topics buffer updated." -msgstr "Trending emner buffer opdateret." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "New tweet in user timeline buffer." -msgstr "Ny tweet i bruger tidslinje buffer." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New follower." -msgstr "Ny følger." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "Volume changed." -msgstr "Lydstyrke ændret." - -#: ../src\extra\SoundsTutorial\wx_ui.py:8 -msgid "Sounds tutorial" -msgstr "Hør lyde" - -#: ../src\extra\SoundsTutorial\wx_ui.py:11 -msgid "Press enter to listen to the sound for the selected event" -msgstr "Tryk på enter for at lytte til lyden for den valgte begivenhed" - -#: ../src\extra\SpellChecker\spellchecker.py:57 -msgid "Misspelled word: %s" -msgstr "Fejlstavede ord: %s" - -#: ../src\extra\SpellChecker\wx_ui.py:27 -msgid "Misspelled word" -msgstr "Fejlstavet ord" - -#: ../src\extra\SpellChecker\wx_ui.py:32 -msgid "Context" -msgstr "Kontekst" - -#: ../src\extra\SpellChecker\wx_ui.py:37 -msgid "Suggestions" -msgstr "Forslag" - -#: ../src\extra\SpellChecker\wx_ui.py:42 -msgid "&Ignore" -msgstr "&Ignorér" - -#: ../src\extra\SpellChecker\wx_ui.py:43 -msgid "I&gnore all" -msgstr "&Ignorér alle" - -#: ../src\extra\SpellChecker\wx_ui.py:44 -msgid "&Replace" -msgstr "&Erstat" - -#: ../src\extra\SpellChecker\wx_ui.py:45 -msgid "R&eplace all" -msgstr "E&rstat alle" - -#: ../src\extra\SpellChecker\wx_ui.py:46 -msgid "&Add to personal dictionary" -msgstr "&Tilføj til personlig ordbog" - -#: ../src\extra\SpellChecker\wx_ui.py:79 -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "" -"Der opstod en fejl. Der findes ingen ordbøger til det valgte sprog på {0}" - -#: ../src\extra\SpellChecker\wx_ui.py:82 -msgid "Spell check complete." -msgstr "Stavekontrol gennemført." - -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 -msgid "You have to start writing" -msgstr "Du skal begynde at skrive" - -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 -msgid "There are no results in your users database" -msgstr "Der er ingen resultater i din bruger database" - -#: ../src\extra\autocompletionUsers\completion.py:33 -msgid "Autocompletion only works for users." -msgstr "Autofuldførelse fungerer kun for brugere." - -#: ../src\extra\autocompletionUsers\settings.py:27 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"Opdaterer database... Du kan lukke dette vindue nu. En meddelelse vil " -"fortælle dig, hvornår processen er færdig." - -#: ../src\extra\autocompletionUsers\wx_manage.py:8 -msgid "Manage Autocompletion database" -msgstr "Administrer autofuldførelsesdatabase" - -#: ../src\extra\autocompletionUsers\wx_manage.py:11 -msgid "Editing {0} users database" -msgstr "Redigerer {0} brugers database" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Username" -msgstr "Brugernavn" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "Navn" - -#: ../src\extra\autocompletionUsers\wx_manage.py:15 -msgid "Add user" -msgstr "Tilføj bruger" - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Remove user" -msgstr "Fjern bruger" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Add user to database" -msgstr "Tilføj bruger til database" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Twitter username" -msgstr "Twitter brugernavn" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -msgid "The user does not exist" -msgstr "Denne bruger eksisterer ikke" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "Error!" -msgstr "Fejl!" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "Indstillinger for autofuldførelse af brugere" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "Tilføj brugere fra bufferen følgere" - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "Tilføj brugere fra bufferen venner" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "Administrer database…" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "Færdig" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "{0}s database over brugere er blevet opdateret." - -#: ../src\extra\ocr\OCRSpace.py:5 -msgid "Detect automatically" -msgstr "Opdag automatisk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 -msgid "Danish" -msgstr "Dansk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 -msgid "Dutch" -msgstr "Hollandsk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 -msgid "English" -msgstr "Engelsk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 -msgid "Finnish" -msgstr "Finsk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 -msgid "French" -msgstr "Fransk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 -msgid "German" -msgstr "Tysk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 -msgid "Hungarian" -msgstr "Ungarsk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 -msgid "Italian" -msgstr "Italiensk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 -msgid "Japanese" -msgstr "Japansk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 -msgid "Korean" -msgstr "Koreansk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 -msgid "Polish" -msgstr "Polsk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 -msgid "Portuguese" -msgstr "Portugisisk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 -msgid "Russian" -msgstr "Russisk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 -msgid "Spanish" -msgstr "Spansk" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 -msgid "Turkish" -msgstr "Tyrkisk" - -#: ../src\extra\translator\translator.py:12 -msgid "Afrikaans" -msgstr "Afrikaans" - -#: ../src\extra\translator\translator.py:13 -msgid "Albanian" -msgstr "Albansk" - -#: ../src\extra\translator\translator.py:14 -msgid "Amharic" -msgstr "Amharisk" - -#: ../src\extra\translator\translator.py:15 -msgid "Arabic" -msgstr "Arabisk" - -#: ../src\extra\translator\translator.py:16 -msgid "Armenian" -msgstr "Armensk" - -#: ../src\extra\translator\translator.py:17 -msgid "Azerbaijani" -msgstr "Azerbaijansk" - -#: ../src\extra\translator\translator.py:18 -msgid "Basque" -msgstr "Baskisk " - -#: ../src\extra\translator\translator.py:19 -msgid "Belarusian" -msgstr "Hviderussisk " - -#: ../src\extra\translator\translator.py:20 -msgid "Bengali" -msgstr "Bengali" - -#: ../src\extra\translator\translator.py:21 -msgid "Bihari" -msgstr "Bihari" - -#: ../src\extra\translator\translator.py:22 -msgid "Bulgarian" -msgstr "Bulgarsk" - -#: ../src\extra\translator\translator.py:23 -msgid "Burmese" -msgstr "Burmesisk" - -#: ../src\extra\translator\translator.py:24 -msgid "Catalan" -msgstr "Catalansk" - -#: ../src\extra\translator\translator.py:25 -msgid "Cherokee" -msgstr "Cherokee" - -#: ../src\extra\translator\translator.py:26 -msgid "Chinese" -msgstr "Kinesisk" - -#: ../src\extra\translator\translator.py:27 -msgid "Chinese_simplified" -msgstr "Kinesisk (Forenklet)" - -#: ../src\extra\translator\translator.py:28 -msgid "Chinese_traditional" -msgstr "Kinesisk (Traditionelt)" - -#: ../src\extra\translator\translator.py:29 -msgid "Croatian" -msgstr "Kroatisk" - -#: ../src\extra\translator\translator.py:30 -msgid "Czech" -msgstr "Tjekkisk" - -#: ../src\extra\translator\translator.py:32 -msgid "Dhivehi" -msgstr "Dhivehi" - -#: ../src\extra\translator\translator.py:35 -msgid "Esperanto" -msgstr "Esperanto" - -#: ../src\extra\translator\translator.py:36 -msgid "Estonian" -msgstr "Estisk" - -#: ../src\extra\translator\translator.py:37 -msgid "Filipino" -msgstr "Filippinsk" - -#: ../src\extra\translator\translator.py:40 -msgid "Galician" -msgstr "Galicisk" - -#: ../src\extra\translator\translator.py:41 -msgid "Georgian" -msgstr "Georgisk" - -#: ../src\extra\translator\translator.py:43 -msgid "Greek" -msgstr "Græsk" - -#: ../src\extra\translator\translator.py:44 -msgid "Guarani" -msgstr "Guaraní" - -#: ../src\extra\translator\translator.py:45 -msgid "Gujarati" -msgstr "Gujarati" - -#: ../src\extra\translator\translator.py:46 -msgid "Hebrew" -msgstr "Hebraisk" - -#: ../src\extra\translator\translator.py:47 -msgid "Hindi" -msgstr "Hindi" - -#: ../src\extra\translator\translator.py:49 -msgid "Icelandic" -msgstr "Islandsk" - -#: ../src\extra\translator\translator.py:50 -msgid "Indonesian" -msgstr "Indonesisk" - -#: ../src\extra\translator\translator.py:51 -msgid "Inuktitut" -msgstr "Inuktitut" - -#: ../src\extra\translator\translator.py:52 -msgid "Irish" -msgstr "Irsk" - -#: ../src\extra\translator\translator.py:55 -msgid "Kannada" -msgstr "Kannada" - -#: ../src\extra\translator\translator.py:56 -msgid "Kazakh" -msgstr "Kasakhisk" - -#: ../src\extra\translator\translator.py:57 -msgid "Khmer" -msgstr "Khmer" - -#: ../src\extra\translator\translator.py:59 -msgid "Kurdish" -msgstr "Kurdisk" - -#: ../src\extra\translator\translator.py:60 -msgid "Kyrgyz" -msgstr "Kirgisisk" - -#: ../src\extra\translator\translator.py:61 -msgid "Laothian" -msgstr "Laotisk" - -#: ../src\extra\translator\translator.py:62 -msgid "Latvian" -msgstr "Lettisk" - -#: ../src\extra\translator\translator.py:63 -msgid "Lithuanian" -msgstr "Litauisk" - -#: ../src\extra\translator\translator.py:64 -msgid "Macedonian" -msgstr "Makedonsk" - -#: ../src\extra\translator\translator.py:65 -msgid "Malay" -msgstr "Malaysisk" - -#: ../src\extra\translator\translator.py:66 -msgid "Malayalam" -msgstr "Malayalam" - -#: ../src\extra\translator\translator.py:67 -msgid "Maltese" -msgstr "Maltesisk" - -#: ../src\extra\translator\translator.py:68 -msgid "Marathi" -msgstr "Marathi" - -#: ../src\extra\translator\translator.py:69 -msgid "Mongolian" -msgstr "Mongolsk" - -#: ../src\extra\translator\translator.py:70 -msgid "Nepali" -msgstr "Nepalesisk" - -#: ../src\extra\translator\translator.py:71 -msgid "Norwegian" -msgstr "Norsk" - -#: ../src\extra\translator\translator.py:72 -msgid "Oriya" -msgstr "Oriya" - -#: ../src\extra\translator\translator.py:73 -msgid "Pashto" -msgstr "Pashto" - -#: ../src\extra\translator\translator.py:74 -msgid "Persian" -msgstr "Persisk" - -#: ../src\extra\translator\translator.py:77 -msgid "Punjabi" -msgstr "Panjabi" - -#: ../src\extra\translator\translator.py:78 -msgid "Romanian" -msgstr "Rumænsk" - -#: ../src\extra\translator\translator.py:80 -msgid "Sanskrit" -msgstr "Sanskrit" - -#: ../src\extra\translator\translator.py:81 -msgid "Serbian" -msgstr "Serbisk" - -#: ../src\extra\translator\translator.py:82 -msgid "Sindhi" -msgstr "Sindhi" - -#: ../src\extra\translator\translator.py:83 -msgid "Sinhalese" -msgstr "Sinhalesisk" - -#: ../src\extra\translator\translator.py:84 -msgid "Slovak" -msgstr "Slovakisk" - -#: ../src\extra\translator\translator.py:85 -msgid "Slovenian" -msgstr "Slovensk" - -#: ../src\extra\translator\translator.py:87 -msgid "Swahili" -msgstr "Swahili" - -#: ../src\extra\translator\translator.py:88 -msgid "Swedish" -msgstr "Svensk" - -#: ../src\extra\translator\translator.py:89 -msgid "Tajik" -msgstr "Tadsjikisk" - -#: ../src\extra\translator\translator.py:90 -msgid "Tamil" -msgstr "Tamil" - -#: ../src\extra\translator\translator.py:91 -msgid "Tagalog" -msgstr "Tagalog" - -#: ../src\extra\translator\translator.py:92 -msgid "Telugu" -msgstr "Telugu" - -#: ../src\extra\translator\translator.py:93 -msgid "Thai" -msgstr "Thaisk" - -#: ../src\extra\translator\translator.py:94 -msgid "Tibetan" -msgstr "Tibetansk" - -#: ../src\extra\translator\translator.py:96 -msgid "Ukrainian" -msgstr "Ukrainsk" - -#: ../src\extra\translator\translator.py:97 -msgid "Urdu" -msgstr "Urdu" - -#: ../src\extra\translator\translator.py:98 -msgid "Uzbek" -msgstr "Usbekisk" - -#: ../src\extra\translator\translator.py:99 -msgid "Uighur" -msgstr "Uighur" - -#: ../src\extra\translator\translator.py:100 -msgid "Vietnamese" -msgstr "Vietnamesisk" - -#: ../src\extra\translator\translator.py:101 -msgid "Welsh" -msgstr "Walisisk" - -#: ../src\extra\translator\translator.py:102 -msgid "Yiddish" -msgstr "Jiddisch" - -#: ../src\extra\translator\wx_ui.py:44 -msgid "Translate message" -msgstr "Oversæt besked" - -#: ../src\extra\translator\wx_ui.py:47 -msgid "Target language" -msgstr "Målsprog" - -#: ../src\issueReporter\issueReporter.py:30 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 -msgid "General" -msgstr "Generelt" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "always" -msgstr "altid" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "have not tried" -msgstr "Har ikke prøvet" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "random" -msgstr "tilfældigt" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "sometimes" -msgstr "somme tider" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "unable to duplicate" -msgstr "Kan ikke duplikere" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "block" -msgstr "blokér" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "crash" -msgstr "sammenbrud" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "feature" -msgstr "funktion" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "major" -msgstr "stor" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "minor" -msgstr "mindre" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "text" -msgstr "tekst" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "trivial" -msgstr "trivielt" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "tweak" -msgstr "tweak" - -#: ../src\issueReporter\wx_ui.py:25 -msgid "Report an error" -msgstr "Rapportér en fejl" - -#: ../src\issueReporter\wx_ui.py:28 -msgid "Select a category" -msgstr "Vælg en katogori" - -#: ../src\issueReporter\wx_ui.py:36 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "" -"Beskriv kort, hvad der skete. Du vil blive i stand til at forklare det " -"grundigt senere" - -#: ../src\issueReporter\wx_ui.py:45 -msgid "Here, you can describe the bug in detail" -msgstr "Her kan du beskrive fejlen i detaljer" - -#: ../src\issueReporter\wx_ui.py:55 -msgid "how often does this bug happen?" -msgstr "Hvor ofte sker denne fejl?" - -#: ../src\issueReporter\wx_ui.py:62 -msgid "Select the importance that you think this bug has" -msgstr "Vælg den betydning, du mener, at denne fejl har" - -#: ../src\issueReporter\wx_ui.py:69 -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"Jeg ved at {0} fejlsystemet vil modtage mit Twitter brugernavn til at " -"kontakte mig og rette fejlen hurtigt" - -#: ../src\issueReporter\wx_ui.py:72 -msgid "Send report" -msgstr "Send rapport" - -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 -msgid "Cancel" -msgstr "Annuller" - -#: ../src\issueReporter\wx_ui.py:83 -msgid "You must fill out both fields" -msgstr "Du skal udfylde begge felter" - -#: ../src\issueReporter\wx_ui.py:86 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"Du skal markere checkboksen for at give os dit twitter brugernavn så vi kan " -"kontakte dig, hvis det er nødvendigt." - -#: ../src\issueReporter\wx_ui.py:89 -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"Tak for at du rapporterede denne fejl! I fremtidige versioner kan du " -"muligvis finde denne fejlrettelse i listen over ændringer. Din rapport har " -"fejlnummeret %i" - -#: ../src\issueReporter\wx_ui.py:89 -msgid "reported" -msgstr "rapporteret" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "Error while reporting" -msgstr "Fejl under rapportering" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"Noget uventet opstod under forsøg på at rapportere fejlen. Prøv igen senere." - -#: ../src\keystrokeEditor\constants.py:3 -msgid "Go up in the current buffer" -msgstr "Gå op i den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:4 -msgid "Go down in the current buffer" -msgstr "Gå ned i den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:5 -msgid "Go to the previous buffer" -msgstr "Gå til den forrige buffer" - -#: ../src\keystrokeEditor\constants.py:6 -msgid "Go to the next buffer" -msgstr "Gå til den næste buffer" - -#: ../src\keystrokeEditor\constants.py:7 -msgid "Focus the next session" -msgstr "Bring fokus til næste session" - -#: ../src\keystrokeEditor\constants.py:8 -msgid "Focus the previous session" -msgstr "Bring fokus til forrige session" - -#: ../src\keystrokeEditor\constants.py:9 -msgid "Show or hide the GUI" -msgstr "Vis eller skjul brugergrænsefladen" - -#: ../src\keystrokeEditor\constants.py:10 -msgid "New tweet" -msgstr "Nyt Tweet" - -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 -msgid "Retweet" -msgstr "Retweet" - -#: ../src\keystrokeEditor\constants.py:13 -msgid "Send direct message" -msgstr "Send direkte besked" - -#: ../src\keystrokeEditor\constants.py:14 -msgid "Like a tweet" -msgstr "Synes godt om en tweet" - -#: ../src\keystrokeEditor\constants.py:15 -msgid "Like/unlike a tweet" -msgstr "Synes godt om/synes ikke godt om en tweet" - -#: ../src\keystrokeEditor\constants.py:16 -msgid "Unlike a tweet" -msgstr "Synes ikke godt om en tweet" - -#: ../src\keystrokeEditor\constants.py:17 -msgid "Open the user actions dialogue" -msgstr "Åbn dialogboksen Brugerhandlinger" - -#: ../src\keystrokeEditor\constants.py:18 -msgid "See user details" -msgstr "Se brugerdetaljer" - -#: ../src\keystrokeEditor\constants.py:19 -msgid "Show tweet" -msgstr "Vis tweet" - -#: ../src\keystrokeEditor\constants.py:20 -msgid "Quit" -msgstr "Afslut" - -#: ../src\keystrokeEditor\constants.py:21 -msgid "Open user timeline" -msgstr "Åbn brugerens tidslinje" - -#: ../src\keystrokeEditor\constants.py:22 -msgid "Destroy buffer" -msgstr "Ødelæg buffer" - -#: ../src\keystrokeEditor\constants.py:23 -msgid "Interact with the currently focused tweet." -msgstr "Interager med den aktuelt fokuserede tweet." - -#: ../src\keystrokeEditor\constants.py:24 -msgid "Open URL" -msgstr "Åbn URL" - -#: ../src\keystrokeEditor\constants.py:25 -#, fuzzy -msgid "View in Twitter" -msgstr "Søg på Twitter" - -#: ../src\keystrokeEditor\constants.py:26 -msgid "Increase volume by 5%" -msgstr "Forøg lydstyrke med 5%" - -#: ../src\keystrokeEditor\constants.py:27 -msgid "Decrease volume by 5%" -msgstr "Formindsk lydstyrke med 5%" - -#: ../src\keystrokeEditor\constants.py:28 -msgid "Jump to the first element of a buffer" -msgstr "Hop til det første element i en buffer" - -#: ../src\keystrokeEditor\constants.py:29 -msgid "Jump to the last element of the current buffer" -msgstr "Hop til det sidste element i den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:30 -msgid "Jump 20 elements up in the current buffer" -msgstr "Spring 20 elementer op i den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements down in the current buffer" -msgstr "Spring 20 elementer ned i den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:32 -msgid "Edit profile" -msgstr "Redigér profil" - -#: ../src\keystrokeEditor\constants.py:33 -msgid "Delete a tweet or direct message" -msgstr "Slet et tweet eller en direkte besked" - -#: ../src\keystrokeEditor\constants.py:34 -msgid "Empty the current buffer" -msgstr "Tøm den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:35 -msgid "Repeat last item" -msgstr "Gentag sidste emne" - -#: ../src\keystrokeEditor\constants.py:36 -msgid "Copy to clipboard" -msgstr "Kopiér til udklipsholder" - -#: ../src\keystrokeEditor\constants.py:37 -msgid "Add to list" -msgstr "Tilføj til liste" - -#: ../src\keystrokeEditor\constants.py:38 -msgid "Remove from list" -msgstr "Fjern fra liste" - -#: ../src\keystrokeEditor\constants.py:39 -msgid "Mute/unmute the active buffer" -msgstr "Slå dæmpning til eller fra på den aktuelle buffer" - -#: ../src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the current session" -msgstr "Slå dæmpning til eller fra på den aktuelle session" - -#: ../src\keystrokeEditor\constants.py:41 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "" -"Slå automatisk læsning af indkommende tweets til og fra for den aktive buffer" - -#: ../src\keystrokeEditor\constants.py:42 -msgid "Search on twitter" -msgstr "Søg på twitter" - -#: ../src\keystrokeEditor\constants.py:43 -msgid "Find a string in the currently focused buffer" -msgstr "Find en streng i den aktuelt fokuserede buffer" - -#: ../src\keystrokeEditor\constants.py:44 -msgid "Show the keystroke editor" -msgstr "Vis tastetrykredigering" - -#: ../src\keystrokeEditor\constants.py:45 -msgid "Show lists for a specified user" -msgstr "Vis tilhørende lister for en bestemt bruger" - -#: ../src\keystrokeEditor\constants.py:46 -msgid "load previous items" -msgstr "Indlæs tidligere elementer" - -#: ../src\keystrokeEditor\constants.py:47 -msgid "Get geolocation" -msgstr "Få geolokalitet" - -#: ../src\keystrokeEditor\constants.py:48 -msgid "Display the tweet's geolocation in a dialog" -msgstr "Vis tweetens geolokalitet i en dialog" - -#: ../src\keystrokeEditor\constants.py:49 -msgid "Create a trending topics buffer" -msgstr "Opret en buffer med trending emner" - -#: ../src\keystrokeEditor\constants.py:50 -msgid "View conversation" -msgstr "Se samtale" - -#: ../src\keystrokeEditor\constants.py:51 -msgid "Check and download updates" -msgstr "Tjek og download opdateringer" - -#: ../src\keystrokeEditor\constants.py:52 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"Åbner listemanageren, som giver dig mulighed for at oprette, redigere, " -"slette og åbne lister i buffere." - -#: ../src\keystrokeEditor\constants.py:53 -msgid "Opens the global settings dialogue" -msgstr "Åbner dialogen med globale indstillinger" - -#: ../src\keystrokeEditor\constants.py:54 -#, fuzzy -msgid "Opens the list manager" -msgstr "Listemanager" - -#: ../src\keystrokeEditor\constants.py:55 -msgid "Opens the account settings dialogue" -msgstr "Åbner dialogen med kontoindstillinger" - -#: ../src\keystrokeEditor\constants.py:56 -msgid "Try to play an audio file" -msgstr "Forsøg at afspille en lydfil" - -#: ../src\keystrokeEditor\constants.py:57 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "Opdaterer bufferen og henter mulige tabte emner der." - -#: ../src\keystrokeEditor\constants.py:58 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "Uddrager teksten fra et billede og viser resultatet i en dialog." - -#: ../src\keystrokeEditor\wx_ui.py:8 -msgid "Keystroke editor" -msgstr "Tastetrykredigering" - -#: ../src\keystrokeEditor\wx_ui.py:12 -msgid "Select a keystroke to edit" -msgstr "Vælg et tastetryk for at redigere" - -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "tastetryk" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 -msgid "Action" -msgstr "Handling" - -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 -msgid "Edit" -msgstr "Rediger" - -#: ../src\keystrokeEditor\wx_ui.py:20 -msgid "Execute action" -msgstr "Kør handling" - -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 -msgid "Close" -msgstr "Luk" - -#: ../src\keystrokeEditor\wx_ui.py:48 -msgid "Editing keystroke" -msgstr "Redigerer tastetryk" - -#: ../src\keystrokeEditor\wx_ui.py:51 -msgid "Control" -msgstr "Kontrol" - -#: ../src\keystrokeEditor\wx_ui.py:52 -msgid "Alt" -msgstr "Alt" - -#: ../src\keystrokeEditor\wx_ui.py:53 -msgid "Shift" -msgstr "Skift" - -#: ../src\keystrokeEditor\wx_ui.py:54 -msgid "Windows" -msgstr "Windows" - -#: ../src\keystrokeEditor\wx_ui.py:60 -msgid "Key" -msgstr "Tast" - -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 -msgid "OK" -msgstr "OK" - -#: ../src\keystrokeEditor\wx_ui.py:78 -msgid "You need to use the Windows key" -msgstr "Du skal bruge Windows-tasten" - -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 -msgid "Invalid keystroke" -msgstr "Ugyldigt tastetryk" - -#: ../src\keystrokeEditor\wx_ui.py:81 -msgid "You must provide a character for the keystroke" -msgstr "Du skal angive et tegn til tastetrykket" - -#: ../src\languageHandler.py:99 -msgid "User default" -msgstr "Brugerstandard" - -#: ../src\main.py:105 -msgid "https://twblue.es/donate" -msgstr "https://twblue.es/donate" - -#: ../src\main.py:122 -msgid "" -"{0} is already running. Close the other instance before starting this one. " -"If you're sure that {0} isn't running, try deleting the file at {1}. If " -"you're unsure of how to do this, contact the {0} developers." -msgstr "" - -#: ../src\sessionmanager\wxUI.py:8 -msgid "Session manager" -msgstr "Sessionmanager" - -#: ../src\sessionmanager\wxUI.py:11 -msgid "Accounts list" -msgstr "Konti liste" - -#: ../src\sessionmanager\wxUI.py:13 -msgid "Account" -msgstr "Konto" - -#: ../src\sessionmanager\wxUI.py:17 -msgid "New account" -msgstr "Ny konto" - -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 -msgid "Remove account" -msgstr "Fjern konto" - -#: ../src\sessionmanager\wxUI.py:19 -msgid "Global Settings" -msgstr "Globale Indstillinger" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "Account Error" -msgstr "Kontofejl" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "You need to configure an account." -msgstr "Du skal konfigurere en konto." - -#: ../src\sessionmanager\wxUI.py:48 -msgid "Authorization" -msgstr "Godkendelse" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "" -"The request to authorize your Twitter account will be opened in your " -"browser. You only need to do this once. Would you like to continue?" -msgstr "" -"Anmodningen om at godkende din Twitter-konto åbnes i din browser. Du behøver " -"kun at gøre dette en gang. Vil du fortsætte?" - -#: ../src\sessionmanager\wxUI.py:52 -msgid "Authorized account %d" -msgstr "Autoriseret konto %d" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "Invalid user token" -msgstr "Ugyldigt brugertoken" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "" -"Your access token is invalid or the authorization has failed. Please try " -"again." -msgstr "" -"Dit adgangstoken er ugyldigt, eller godkendelsen er mislykket. Prøv igen." - -#: ../src\sessionmanager\wxUI.py:64 -msgid "Do you really want to delete this account?" -msgstr "Vil du slette denne konto?" - -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 -msgid "dddd, MMMM D, YYYY H:m:s" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 -msgid "Dm to %s " -msgstr "DB til %s " - -#: ../src\sessions\twitter\compose.py:141 -msgid "{0}. Quoted tweet from @{1}: {2}" -msgstr "{0}. Citeret tweet fra @{1}: {2}" - -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 -msgid "Unavailable" -msgstr "Utilgængelig" - -#: ../src\sessions\twitter\compose.py:166 -msgid "" -"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " -"Twitter %s" -msgstr "" -"%s (@%s). %s følgere, %s venner, %s tweets. Sidst tweetedt %s. Tilmeldt " -"Twitter %s" - -#: ../src\sessions\twitter\compose.py:170 -msgid "No description available" -msgstr "Ingen beskrivelse tilgængelig" - -#: ../src\sessions\twitter\compose.py:174 -msgid "private" -msgstr "privat" - -#: ../src\sessions\twitter\compose.py:175 -msgid "public" -msgstr "offentlig" - -#: ../src\sessions\twitter\session.py:169 -#, fuzzy -msgid "There are no more items to retrieve in this buffer." -msgstr "Der er ingen koordinater i denne tweet" - -#: ../src\sessions\twitter\session.py:215 -msgid "%s failed. Reason: %s" -msgstr "%s mislykkedes. Grund: %s" - -#: ../src\sessions\twitter\session.py:221 -msgid "%s succeeded." -msgstr "%s lykkedes." - -#: ../src\sessions\twitter\utils.py:225 -msgid "Sorry, you are not authorised to see this status." -msgstr "Beklager, du har ikke tilladelse til at se denne status." - -#: ../src\sessions\twitter\utils.py:227 -msgid "No status found with that ID" -msgstr "Ingen status fundet med det ID" - -#: ../src\sessions\twitter\utils.py:229 -msgid "Error code {0}" -msgstr "Fejlkode {0}" - -#: ../src\sessions\twitter\wxUI.py:6 -msgid "Authorising account..." -msgstr "Godkender konto..." - -#: ../src\sessions\twitter\wxUI.py:9 -msgid "Enter your PIN code here" -msgstr "Indtast din PIN-kode her" - -#: ../src\sound.py:159 -msgid "Stopped." -msgstr "Stoppet." - -#: ../src\update\wxUpdater.py:10 -msgid "New version for %s" -msgstr "Ny version for %s" - -#: ../src\update\wxUpdater.py:10 -msgid "" -"There's a new %s version available, released on %s. Would you like to " -"download it now?\n" -"\n" -" %s version: %s\n" -"\n" -"Changes:\n" -"%s" -msgstr "" -"Der er en ny %s version tilgængelig, udgivet den %s. Vil du hente den nu?\n" -"\n" -" %s version: %s\n" -"\n" -"Ændringer:\n" -"%s" - -#: ../src\update\wxUpdater.py:18 -msgid "Download in Progress" -msgstr "Download i gang" - -#: ../src\update\wxUpdater.py:18 -msgid "Downloading the new version..." -msgstr "Henter den nye version..." - -#: ../src\update\wxUpdater.py:28 -msgid "Updating... %s of %s" -msgstr "Opdaterer... %s af %s" - -#: ../src\update\wxUpdater.py:31 -msgid "Done!" -msgstr "Færdig!" - -#: ../src\update\wxUpdater.py:31 -msgid "" -"The update has been downloaded and installed successfully. Press OK to " -"continue." -msgstr "" -"Opdateringen er blevet downloadet og installeret med succes. Tryk på OK for " -"at fortsætte." - -#: ../src\wxUI\buffers\base.py:11 -msgid "Client" -msgstr "Klient" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Text" -msgstr "Tekst" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 -msgid "Date" -msgstr "Dato" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 -msgid "User" -msgstr "Bruger" - -#: ../src\wxUI\buffers\base.py:27 -msgid "Direct message" -msgstr "Direkte besked" - -#: ../src\wxUI\buffers\events.py:13 -msgid "Event" -msgstr "Begivenhed" - -#: ../src\wxUI\buffers\events.py:15 -msgid "Remove event" -msgstr "Fjern Begivenhed" - -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 -msgid "Login" -msgstr "Log ind" - -#: ../src\wxUI\buffers\panels.py:13 -msgid "Log in automatically" -msgstr "Log ind automatisk" - -#: ../src\wxUI\buffers\panels.py:21 -msgid "Logout" -msgstr "Log ud" - -#: ../src\wxUI\buffers\trends.py:8 -msgid "Trending topic" -msgstr "Trending emne" - -#: ../src\wxUI\buffers\trends.py:18 -msgid "Tweet about this trend" -msgstr "Tweet om denne trend" - -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 -msgid "Search topic" -msgstr "Søg emne" - -#: ../src\wxUI\commonMessageDialogs.py:6 -msgid "" -"This retweet is over 140 characters. Would you like to post it as a mention " -"to the poster with your comments and a link to the original tweet?" -msgstr "" -"Dette retweet er over 140 tegn. Vil du sende det som en omtale til den " -"oprindelige sender med dine kommentarer og et link til det oprindelige tweet?" - -#: ../src\wxUI\commonMessageDialogs.py:9 -msgid "Would you like to add a comment to this tweet?" -msgstr "Vil du gerne tilføje en kommentar til dette tweet?" - -#: ../src\wxUI\commonMessageDialogs.py:12 -msgid "" -"Do you really want to delete this tweet? It will be deleted from Twitter as " -"well." -msgstr "" -"Vil du virkelig slette dette tweet? Den bliver også slettet fra Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 -msgid "Delete" -msgstr "Slet" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Do you really want to close {0}?" -msgstr "Vil du virkelig lukke {0}?" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Exit" -msgstr "Afslut" - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid " {0} must be restarted for these changes to take effect." -msgstr "{0} skal genstartes for at disse ændringer træder i kraft." - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid "Restart {0} " -msgstr "Genstart {0}" - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "" -"Are you sure you want to delete this user from the database? This user will " -"not appear in autocomplete results anymore." -msgstr "" -"Er du sikker på, at du vil slette denne bruger fra databasen? Denne bruger " -"vil ikke længere blive vist i autofuldførende resultater." - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "Confirm" -msgstr "Bekræft" - -#: ../src\wxUI\commonMessageDialogs.py:25 -msgid "Enter the name of the client : " -msgstr "Indtast klientens navn:" - -#: ../src\wxUI\commonMessageDialogs.py:25 -#: ../src\wxUI\dialogs\configuration.py:246 -msgid "Add client" -msgstr "Tilføj klient" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "" -"Do you really want to empty this buffer? It's items will be removed from " -"the list but not from Twitter" -msgstr "" -"Vil du virkelig tømme denne buffer? Bufferens emner vil blive fjernet fra " -"listen, men ikke fra Twitter" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "Empty buffer" -msgstr "Tøm buffer" - -#: ../src\wxUI\commonMessageDialogs.py:35 -msgid "Do you really want to destroy this buffer?" -msgstr "Vil du virkelig ødelægge denne buffer?" - -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Attention" -msgstr "Bemærk" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "A timeline for this user already exists. You can't open another" -msgstr "" -"En tidslinje for denne bruger eksisterer allerede. Du kan ikke åbne en anden." - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "Existing timeline" -msgstr "Eksisterende tidslinje" - -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "This user has no tweets, so you can't open a timeline for them." -msgstr "" -"Denne bruger har ingen tweets, så du kan ikke åbne en tidslinje for dem." - -#: ../src\wxUI\commonMessageDialogs.py:47 -msgid "" -"This is a protected Twitter user, which means you can't open a timeline " -"using the Streaming API. The user's tweets will not update due to a twitter " -"policy. Do you want to continue?" -msgstr "" -"Dette er en beskyttet Twitter-bruger, hvilket betyder, at du ikke kan åbne " -"en tidslinje ved hjælp af Streaming API. Brugerens tweets opdateres ikke på " -"grund af en Twitter-politik. Vil du fortsætte?" - -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "Warning" -msgstr "Advarsel" - -#: ../src\wxUI\commonMessageDialogs.py:50 -msgid "" -"This is a protected user account, you need to follow this user to view their " -"tweets or likes." -msgstr "" -"Dette er en beskyttet brugerkonto, du skal følge denne bruger for at se " -"deres tweets eller synes godt om." - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "" -"If you like {0} we need your help to keep it going. Help us by donating to " -"the project. This will help us pay for the server, the domain and some other " -"things to ensure that {0} will be actively maintained. Your donation will " -"give us the means to continue the development of {0}, and to keep {0} free. " -"Would you like to donate now?" -msgstr "" -"Hvis du kan lide {0}, har vi brug for din hjælp til at holde projektet i " -"gang. Hjælp os ved at donere til projektet. Dette vil hjælpe os med at " -"betale for serveren, domænet og nogle andre ting for at sikre, at {0} bliver " -"aktivt vedligeholdt. Din donation vil give os midler til at fortsætte " -"udviklingen af {0} og sikre, at {0} forbliver gratis. Vil du gerne donere nu?" - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "We need your help" -msgstr "Vi har brug for din hjælp" - -#: ../src\wxUI\commonMessageDialogs.py:57 -msgid "This user has no tweets. {0} can't create a timeline." -msgstr "Denne bruger har ingen tweets. {0} kan ikke oprette en tidslinje." - -#: ../src\wxUI\commonMessageDialogs.py:60 -msgid "This user has no favorited tweets. {0} can't create a timeline." -msgstr "" -"Denne bruger har ingen foretrukne tweets. {0} kan ikke oprette en tidslinje." - -#: ../src\wxUI\commonMessageDialogs.py:63 -msgid "This user has no followers. {0} can't create a timeline." -msgstr "Denne bruger har ingen følgere. {0} kan ikke oprette en tidslinje." - -#: ../src\wxUI\commonMessageDialogs.py:66 -msgid "This user has no friends. {0} can't create a timeline." -msgstr "Denne bruger har ingen venner. {0} kan ikke oprette en tidslinje." - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geo data for this tweet" -msgstr "Geo data for denne tweet" - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geolocation data: {0}" -msgstr "Data for geolokalitet: {0}" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "Information" -msgstr "Information" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "" -"TWBlue has detected that you're running windows 10 and has changed the " -"default keymap to the Windows 10 keymap. It means that some keyboard " -"shorcuts could be different. Please check the keystroke editor by pressing " -"Alt+Win+K to see all available keystrokes for this keymap." -msgstr "" -"TWBlue har opdaget, at du kører Windows 10 og har skiftet " -"standardtastaturkommandoerne til Windows 10 keymap. Det betyder, at nogle " -"tastaturgenveje kan være forskellige. Tjek venligst de tilgængelige " -"tastetryk ved at trykke på ALT+WIN+K for at se alle tilgængelige tastetryk " -"for dette sæt af tastaturgenveje." - -#: ../src\wxUI\commonMessageDialogs.py:76 -msgid "You have been blocked from viewing this content" -msgstr "Du er blevet blokeret for at se dette indhold" - -#: ../src\wxUI\commonMessageDialogs.py:79 -msgid "" -"You have been blocked from viewing someone's content. In order to avoid " -"conflicts with the full session, TWBlue will remove the affected timeline." -msgstr "" -"Du er blevet blokeret fra at se en persons indhold. For at undgå konflikter " -"med den fulde session fjerner TWBlue den berørte tidslinje." - -#: ../src\wxUI\commonMessageDialogs.py:82 -msgid "" -"TWBlue cannot load this timeline because the user has been suspended from " -"Twitter." -msgstr "" -"TWBlue kan ikke indlæse denne tidslinje, fordi brugeren er blevet " -"suspenderet fra Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Do you really want to delete this filter?" -msgstr "Er du sikker på, at du vil slette dette filter?" - -#: ../src\wxUI\commonMessageDialogs.py:88 -msgid "This filter already exists. Please use a different title" -msgstr "Dette filter findes allerede. Benyt venligst en anden titel." - -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "" -"{0} quit unexpectedly the last time it was run. If the problem persists, " -"please report it to the {0} developers." -msgstr "" - -#: ../src\wxUI\dialogs\attach.py:9 -msgid "Add an attachment" -msgstr "Tilføj et bilag" - -#: ../src\wxUI\dialogs\attach.py:12 -msgid "Attachments" -msgstr "Bilag" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Title" -msgstr "Titel" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Type" -msgstr "Type" - -#: ../src\wxUI\dialogs\attach.py:18 -msgid "Add attachments" -msgstr "Tilføj bilag" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "&Photo" -msgstr "&Billede" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "Remove attachment" -msgstr "Fjern bilag" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "Billedfiler (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Select the picture to be uploaded" -msgstr "Vælg det billede, der skal uploades" - -#: ../src\wxUI\dialogs\attach.py:43 -msgid "please provide a description" -msgstr "Giv en kort beskrivelse" - -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 -msgid "Description" -msgstr "beskrivelse" - -#: ../src\wxUI\dialogs\configuration.py:16 -msgid "Language" -msgstr "Sprog" - -#: ../src\wxUI\dialogs\configuration.py:23 -msgid "Run {0} at Windows startup" -msgstr "Kør {0} når Windows starter" - -#: ../src\wxUI\dialogs\configuration.py:24 -msgid "ask before exiting {0}" -msgstr "Spørg før du afslutter {0}" - -#: ../src\wxUI\dialogs\configuration.py:27 -msgid "Disable Streaming functions" -msgstr "Deaktivér streaming-funktionalitet" - -#: ../src\wxUI\dialogs\configuration.py:30 -msgid "Buffer update interval, in minutes" -msgstr "Buffer-opdateringsinterval, i minutter" - -#: ../src\wxUI\dialogs\configuration.py:36 -msgid "Play a sound when {0} launches" -msgstr "Afspil en lyd, når {0} starter" - -#: ../src\wxUI\dialogs\configuration.py:38 -msgid "Speak a message when {0} launches" -msgstr "Sig en besked, når {0} starter" - -#: ../src\wxUI\dialogs\configuration.py:40 -msgid "Use invisible interface's keyboard shortcuts while GUI is visible" -msgstr "" -"Brug tastaturgenveje for den usynlige grænseflade, mens brugergrænsefladen " -"er synlig" - -#: ../src\wxUI\dialogs\configuration.py:42 -msgid "Activate Sapi5 when any other screen reader is not being run" -msgstr "Aktivér Sapi5, når en anden skærmlæser ikke køres" - -#: ../src\wxUI\dialogs\configuration.py:44 -msgid "Hide GUI on launch" -msgstr "Skjul brugergrænsefladen ved opstart" - -#: ../src\wxUI\dialogs\configuration.py:46 -msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" -msgstr "Brug Codeofdusks longtweet handlers (kan reducere klientens ydeevne)" - -#: ../src\wxUI\dialogs\configuration.py:48 -msgid "Remember state for mention all and long tweet" -msgstr "Husk indstilling for \"omtal alle\" og \"lang tweet\"" - -#: ../src\wxUI\dialogs\configuration.py:51 -msgid "Keymap" -msgstr "Sæt af tastaturkommandoer" - -#: ../src\wxUI\dialogs\configuration.py:56 -msgid "Check for updates when {0} launches" -msgstr "Søg efter opdateringer, når {0} starter" - -#: ../src\wxUI\dialogs\configuration.py:66 -msgid "Proxy type: " -msgstr "Proxy- type:" - -#: ../src\wxUI\dialogs\configuration.py:73 -msgid "Proxy server: " -msgstr "Proxyserver:" - -#: ../src\wxUI\dialogs\configuration.py:79 -msgid "Port: " -msgstr "Port:" - -#: ../src\wxUI\dialogs\configuration.py:85 -msgid "User: " -msgstr "Bruger:" - -#: ../src\wxUI\dialogs\configuration.py:91 -msgid "Password: " -msgstr "Adgangskode:" - -#: ../src\wxUI\dialogs\configuration.py:103 -msgid "Autocompletion settings..." -msgstr "Autofuldførelsesindstillinger..." - -#: ../src\wxUI\dialogs\configuration.py:105 -msgid "Relative timestamps" -msgstr "Relative tidsstempler" - -#: ../src\wxUI\dialogs\configuration.py:108 -msgid "Items on each API call" -msgstr "Emner ved hvert API-opkald" - -#: ../src\wxUI\dialogs\configuration.py:114 -msgid "" -"Inverted buffers: The newest tweets will be shown at the beginning while the " -"oldest at the end" -msgstr "" -"Inverterede buffere: De nyeste tweets vil blive vist i toppen, mens de " -"ældste vises i bunden" - -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet mode" -msgstr "Retweet-tilstand" - -#: ../src\wxUI\dialogs\configuration.py:122 -msgid "Show screen names instead of full names" -msgstr "Vis skærmnavne i stedet for fulde navne" - -#: ../src\wxUI\dialogs\configuration.py:124 -msgid "" -"Number of items per buffer to cache in database (0 to disable caching, blank " -"for unlimited)" -msgstr "" -"Antal emner pr. Buffer til cache i databasen (0 for at deaktivere caching, " -"blank for ubegrænset)" - -#: ../src\wxUI\dialogs\configuration.py:134 -msgid "Enable automatic speech feedback" -msgstr "Aktivér automatisk talefeedback" - -#: ../src\wxUI\dialogs\configuration.py:136 -msgid "Enable automatic Braille feedback" -msgstr "Aktiver automatisk punktfeedback" - -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "Status" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Buffer" -msgstr "Buffer" - -#: ../src\wxUI\dialogs\configuration.py:147 -msgid "Show/hide" -msgstr "Vis/skjul" - -#: ../src\wxUI\dialogs\configuration.py:148 -msgid "Move up" -msgstr "Flyt op" - -#: ../src\wxUI\dialogs\configuration.py:149 -msgid "Move down" -msgstr "Flyt ned" - -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 -msgid "Show" -msgstr "Vis" - -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 -msgid "Hide" -msgstr "Skjul" - -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 -msgid "Select a buffer first." -msgstr "Vælg først en buffer." - -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 -msgid "The buffer is hidden, show it first." -msgstr "Bufferen er skjult, vis den først." - -#: ../src\wxUI\dialogs\configuration.py:175 -msgid "The buffer is already at the top of the list." -msgstr "Bufferen er allerede øverst på listen." - -#: ../src\wxUI\dialogs\configuration.py:199 -msgid "The buffer is already at the bottom of the list." -msgstr "Bufferen er allerede nederst på listen." - -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 -msgid "Ignored clients" -msgstr "Ignorerede klienter" - -#: ../src\wxUI\dialogs\configuration.py:247 -msgid "Remove client" -msgstr "Fjern klient" - -#: ../src\wxUI\dialogs\configuration.py:271 -msgid "Volume" -msgstr "Lydstyrke" - -#: ../src\wxUI\dialogs\configuration.py:282 -msgid "Session mute" -msgstr "Sessiondæmpning" - -#: ../src\wxUI\dialogs\configuration.py:284 -msgid "Output device" -msgstr "Output- enhed" - -#: ../src\wxUI\dialogs\configuration.py:291 -msgid "Input device" -msgstr "Input- enhed" - -#: ../src\wxUI\dialogs\configuration.py:299 -msgid "Sound pack" -msgstr "Lydpakke" - -#: ../src\wxUI\dialogs\configuration.py:305 -msgid "Indicate audio tweets with sound" -msgstr "Angiv lydtweets med en lyd" - -#: ../src\wxUI\dialogs\configuration.py:307 -msgid "Indicate geotweets with sound" -msgstr "Angiv geotweets med en lyd" - -#: ../src\wxUI\dialogs\configuration.py:309 -msgid "Indicate tweets containing images with sound" -msgstr "Angiv tweets der indeholder billeder med en lyd" - -#: ../src\wxUI\dialogs\configuration.py:332 -msgid "Language for OCR" -msgstr "Sprog til tekstgenkendelse" - -#: ../src\wxUI\dialogs\configuration.py:338 -msgid "API Key for SndUp" -msgstr "API-nøgle til SndUp" - -#: ../src\wxUI\dialogs\configuration.py:353 -msgid "{0} preferences" -msgstr "{0} indstillinger" - -#: ../src\wxUI\dialogs\configuration.py:364 -msgid "Proxy" -msgstr "Proxy" - -#: ../src\wxUI\dialogs\configuration.py:373 -msgid "Feedback" -msgstr "Feedback" - -#: ../src\wxUI\dialogs\configuration.py:377 -msgid "Buffers" -msgstr "Buffere" - -#: ../src\wxUI\dialogs\configuration.py:385 -msgid "Sound" -msgstr "Lyd" - -#: ../src\wxUI\dialogs\configuration.py:389 -msgid "Extras" -msgstr "Ekstra" - -#: ../src\wxUI\dialogs\configuration.py:394 -msgid "Save" -msgstr "Gem" - -#: ../src\wxUI\dialogs\filterDialogs.py:15 -msgid "Create a filter for this buffer" -msgstr "Opret et filter for denne buffer" - -#: ../src\wxUI\dialogs\filterDialogs.py:16 -msgid "Filter title" -msgstr "Filtrér titel" - -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by word" -msgstr "Filtrér efter ord" - -#: ../src\wxUI\dialogs\filterDialogs.py:26 -msgid "Ignore tweets wich contain the following word" -msgstr "Ignorer tweets der indeholder følgende ord" - -#: ../src\wxUI\dialogs\filterDialogs.py:27 -msgid "Ignore tweets without the following word" -msgstr "Ignorer tweets uden følgende ord" - -#: ../src\wxUI\dialogs\filterDialogs.py:32 -msgid "word" -msgstr "ord" - -#: ../src\wxUI\dialogs\filterDialogs.py:37 -msgid "Allow retweets" -msgstr "Tillad retweets" - -#: ../src\wxUI\dialogs\filterDialogs.py:38 -msgid "Allow quoted tweets" -msgstr "Tillad citerede tweets" - -#: ../src\wxUI\dialogs\filterDialogs.py:39 -msgid "Allow replies" -msgstr "Tillad svar" - -#: ../src\wxUI\dialogs\filterDialogs.py:47 -msgid "Use this term as a regular expression" -msgstr "Brug dette udtryk som et regulært udtryk" - -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by language" -msgstr "Filtrer efter sprog" - -#: ../src\wxUI\dialogs\filterDialogs.py:50 -msgid "Load tweets in the following languages" -msgstr "Indlæs tweets i de følgende sprog" - -#: ../src\wxUI\dialogs\filterDialogs.py:51 -msgid "Ignore tweets in the following languages" -msgstr "Ignorer tweets i de følgende sprog" - -#: ../src\wxUI\dialogs\filterDialogs.py:52 -msgid "Don't filter by language" -msgstr "Filtrér ikke efter sprog" - -#: ../src\wxUI\dialogs\filterDialogs.py:63 -msgid "Supported languages" -msgstr "Understøttede sprog" - -#: ../src\wxUI\dialogs\filterDialogs.py:68 -msgid "Add selected language to filter" -msgstr "Tilføj valge sprog til filter" - -#: ../src\wxUI\dialogs\filterDialogs.py:72 -msgid "Selected languages" -msgstr "Valgte sprog" - -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 -msgid "Remove" -msgstr "Fjern" - -#: ../src\wxUI\dialogs\filterDialogs.py:122 -msgid "Manage filters" -msgstr "Administrer filtre" - -#: ../src\wxUI\dialogs\filterDialogs.py:124 -msgid "Filters" -msgstr "Filtre" - -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter" -msgstr "Filter" - -#: ../src\wxUI\dialogs\find.py:12 -msgid "Find in current buffer" -msgstr "Find i den aktuelle buffer" - -#: ../src\wxUI\dialogs\find.py:13 -msgid "String" -msgstr "Streng" - -#: ../src\wxUI\dialogs\lists.py:10 -msgid "Lists manager" -msgstr "Listemanager" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "List" -msgstr "Liste" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Members" -msgstr "Medlemmer" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Owner" -msgstr "Ejer" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "mode" -msgstr "tilstand" - -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 -msgid "Create a new list" -msgstr "Opret en ny liste" - -#: ../src\wxUI\dialogs\lists.py:21 -msgid "Open in buffer" -msgstr "Åbn i buffer" - -#: ../src\wxUI\dialogs\lists.py:51 -msgid "Viewing lists for %s" -msgstr "Viser lister for %s" - -#: ../src\wxUI\dialogs\lists.py:52 -msgid "Subscribe" -msgstr "Tilmeld" - -#: ../src\wxUI\dialogs\lists.py:53 -msgid "Unsubscribe" -msgstr "Afmeld" - -#: ../src\wxUI\dialogs\lists.py:64 -msgid "Name (20 characters maximun)" -msgstr "Navn (maks. 20 tegn)" - -#: ../src\wxUI\dialogs\lists.py:74 -msgid "Mode" -msgstr "Tilstand" - -#: ../src\wxUI\dialogs\lists.py:75 -msgid "Public" -msgstr "Offentlig" - -#: ../src\wxUI\dialogs\lists.py:76 -msgid "Private" -msgstr "Privat" - -#: ../src\wxUI\dialogs\lists.py:96 -msgid "Editing the list %s" -msgstr "Redigerer listen %s" - -#: ../src\wxUI\dialogs\lists.py:107 -msgid "Select a list to add the user" -msgstr "Vælg en liste for at tilføje brugeren" - -#: ../src\wxUI\dialogs\lists.py:108 -msgid "Add" -msgstr "Tilføj" - -#: ../src\wxUI\dialogs\lists.py:130 -msgid "Select a list to remove the user" -msgstr "Vælg en liste for at fjerne brugeren" - -#: ../src\wxUI\dialogs\lists.py:148 -msgid "Do you really want to delete this list?" -msgstr "Er du sikker på, at du vil slette denne liste ?" - -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "&Lang tweet" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "&Upload billede" - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 -msgid "Check &spelling..." -msgstr "Kontroller &stavning…" - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "&Vedhæft lyd..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "Fork&ort URL" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 -msgid "&Expand URL" -msgstr "&Udvid URL" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 -msgid "&Translate..." -msgstr "&Oversæt…" - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "Auto&fuldfør brugere" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "Sen&d" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 -msgid "C&lose" -msgstr "&Luk" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "&Modtager" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "&Omtal alle" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Tweet - %i tegn" - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Billedbeskrivelse" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "retweets:" - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Synes godt om:" - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Kilde:" - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -#, fuzzy -msgid "Date: " -msgstr "Dato" - -#: ../src\wxUI\dialogs\message.py:405 -msgid "View" -msgstr "Vis" - -#: ../src\wxUI\dialogs\message.py:407 -msgid "Item" -msgstr "Emne" - -#: ../src\wxUI\dialogs\search.py:13 -msgid "Search on Twitter" -msgstr "Søg på Twitter" - -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 -msgid "&Search" -msgstr "&Søg" - -#: ../src\wxUI\dialogs\search.py:21 -msgid "Tweets" -msgstr "Tweets" - -#: ../src\wxUI\dialogs\search.py:22 -msgid "Users" -msgstr "Brugere" - -#: ../src\wxUI\dialogs\search.py:29 -msgid "&Language for results: " -msgstr "&Sprog for resultater:" - -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 -msgid "any" -msgstr "alle" - -#: ../src\wxUI\dialogs\search.py:37 -msgid "Results &type: " -msgstr "Resultat&typer: " - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 -msgid "Mixed" -msgstr "Blandet" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 -msgid "Recent" -msgstr "Seneste" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 -msgid "Popular" -msgstr "Populær" - -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 -msgid "&OK" -msgstr "&OK" - -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 -msgid "&Close" -msgstr "&Luk" - -#: ../src\wxUI\dialogs\show_user.py:11 -msgid "Details" -msgstr "Detaljer" - -#: ../src\wxUI\dialogs\show_user.py:16 -msgid "&Go to URL" -msgstr "&Gå til URL" - -#: ../src\wxUI\dialogs\trends.py:12 -msgid "View trending topics" -msgstr "Se trending emner" - -#: ../src\wxUI\dialogs\trends.py:13 -msgid "Trending topics by" -msgstr "Trends for" - -#: ../src\wxUI\dialogs\trends.py:15 -msgid "Country" -msgstr "Land" - -#: ../src\wxUI\dialogs\trends.py:16 -msgid "City" -msgstr "By" - -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 -msgid "&Location" -msgstr "&Lokalitet" - -#: ../src\wxUI\dialogs\update_profile.py:9 -msgid "Update your profile" -msgstr "Opdater din profil" - -#: ../src\wxUI\dialogs\update_profile.py:11 -msgid "&Name (50 characters maximum)" -msgstr "&Navn (50 tegn max)" - -#: ../src\wxUI\dialogs\update_profile.py:22 -msgid "&Website" -msgstr "&Webside" - -#: ../src\wxUI\dialogs\update_profile.py:27 -msgid "&Bio (160 characters maximum)" -msgstr "&Bio (maks. 160 tegn)" - -#: ../src\wxUI\dialogs\update_profile.py:33 -msgid "Upload a &picture" -msgstr "Upload et &billede" - -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 -msgid "&Update profile" -msgstr "&Opdater profil" - -#: ../src\wxUI\dialogs\update_profile.py:76 -msgid "Upload a picture" -msgstr "Upload et billede" - -#: ../src\wxUI\dialogs\update_profile.py:78 -msgid "Discard image" -msgstr "Kassér billede" - -#: ../src\wxUI\dialogs\urlList.py:5 -msgid "Select URL" -msgstr "Vælg URL" - -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 -msgid "&User" -msgstr "&Bruger" - -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 -msgid "&Autocomplete users" -msgstr "&Autofuldfør brugere" - -#: ../src\wxUI\dialogs\userActions.py:19 -msgid "&Follow" -msgstr "&Følg" - -#: ../src\wxUI\dialogs\userActions.py:20 -msgid "U&nfollow" -msgstr "&Stop med at følge" - -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 -msgid "&Mute" -msgstr "&Dæmp" - -#: ../src\wxUI\dialogs\userActions.py:22 -msgid "Unmu&te" -msgstr "&Dæmp ikke" - -#: ../src\wxUI\dialogs\userActions.py:23 -msgid "&Block" -msgstr "&Blokér" - -#: ../src\wxUI\dialogs\userActions.py:24 -msgid "Unbl&ock" -msgstr "&Fjern blokering" - -#: ../src\wxUI\dialogs\userActions.py:25 -msgid "&Report as spam" -msgstr "&Rapporter som spam" - -#: ../src\wxUI\dialogs\userActions.py:26 -msgid "&Ignore tweets from this client" -msgstr "&Ignorer tweets fra denne klient" - -#: ../src\wxUI\dialogs\userSelection.py:9 -msgid "Timeline for %s" -msgstr "Tidslinje for %s" - -#: ../src\wxUI\dialogs\userSelection.py:18 -msgid "Buffer type" -msgstr "Buffertype" - -#: ../src\wxUI\dialogs\userSelection.py:19 -msgid "&Tweets" -msgstr "&Tweets" - -#: ../src\wxUI\dialogs\userSelection.py:20 -msgid "&Likes" -msgstr "&Synes godt om" - -#: ../src\wxUI\dialogs\userSelection.py:21 -msgid "&Followers" -msgstr "&Følgere" - -#: ../src\wxUI\dialogs\userSelection.py:22 -msgid "F&riends" -msgstr "&Venner" - -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 -msgid "&Retweet" -msgstr "&Retweet" - -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 -msgid "Re&ply" -msgstr "&Svar" - -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 -msgid "&Like" -msgstr "S&ynes godt om" - -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 -msgid "&Unlike" -msgstr "Fjern Synes &godt om" - -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 -msgid "&Open URL" -msgstr "Åbn &URL" - -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -#, fuzzy -msgid "&Open in Twitter" -msgstr "Søg på Twitter" - -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 -msgid "&Play audio" -msgstr "&Afspil lyd" - -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 -msgid "&Show tweet" -msgstr "&Vis tweet" - -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 -msgid "&Copy to clipboard" -msgstr "&Kopiér til udklipsholder" - -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 -msgid "&Delete" -msgstr "&Slet" - -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 -msgid "&User actions..." -msgstr "&Brugerhandlinger…" - -#: ../src\wxUI\menus.py:39 -msgid "&Show direct message" -msgstr "&Vis direkte besked" - -#: ../src\wxUI\menus.py:67 -msgid "&Show event" -msgstr "&Vis begivenhed" - -#: ../src\wxUI\menus.py:77 -msgid "Direct &message" -msgstr "Direkte &besked" - -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 -msgid "&View lists" -msgstr "&Vis lister" - -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 -msgid "Show user &profile" -msgstr "Vis bruger&profil" - -#: ../src\wxUI\menus.py:84 -msgid "&Show user" -msgstr "Vis &bruger" - -#: ../src\wxUI\menus.py:98 -msgid "&Tweet about this trend" -msgstr "&Tweet om denne trend" - -#: ../src\wxUI\menus.py:100 -msgid "&Show item" -msgstr "&Vis emne" - -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 -msgid "&Global settings" -msgstr "&Globale indstillinger" - -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 -msgid "Account se&ttings" -msgstr "&Kontoindstillinger" - -#: ../src\wxUI\sysTrayIcon.py:37 -msgid "Update &profile" -msgstr "Opdater &profil" - -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "&Show / hide" -msgstr "vis/skjul" - -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 -msgid "&Documentation" -msgstr "&Dokumentation" - -#: ../src\wxUI\sysTrayIcon.py:40 -msgid "Check for &updates" -msgstr "&Søg efter opdateringer" - -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "&Exit" -msgstr "&Afslut" - -#: ../src\wxUI\view.py:16 -msgid "&Manage accounts" -msgstr "&Kontihåndtering" - -#: ../src\wxUI\view.py:18 -msgid "&Hide window" -msgstr "&Skjul vindue" - -#: ../src\wxUI\view.py:20 -msgid "&Lists manager" -msgstr "&Listemanager" - -#: ../src\wxUI\view.py:21 -msgid "&Edit keystrokes" -msgstr "&Rediger tastetryk" - -#: ../src\wxUI\view.py:24 -msgid "E&xit" -msgstr "&Afslut" - -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 -msgid "&Tweet" -msgstr "&Tweet" - -#: ../src\wxUI\view.py:34 -msgid "View &address" -msgstr "Vis &adresse" - -#: ../src\wxUI\view.py:35 -msgid "View conversa&tion" -msgstr "Vis sa&&tale" - -#: ../src\wxUI\view.py:36 -msgid "Read text in picture" -msgstr "Læs tekst på billedet" - -#: ../src\wxUI\view.py:41 -msgid "&Actions..." -msgstr "&Handlinger..." - -#: ../src\wxUI\view.py:42 -msgid "&View timeline..." -msgstr "&Vis tidslinje..." - -#: ../src\wxUI\view.py:43 -msgid "Direct me&ssage" -msgstr "Direkte &besked" - -#: ../src\wxUI\view.py:44 -msgid "&Add to list" -msgstr "&Tilføj til liste" - -#: ../src\wxUI\view.py:45 -msgid "R&emove from list" -msgstr "&Fjern fra liste" - -#: ../src\wxUI\view.py:48 -msgid "V&iew likes" -msgstr "V&is synes godt om" - -#: ../src\wxUI\view.py:52 -msgid "&Update buffer" -msgstr "&Opdater buffer" - -#: ../src\wxUI\view.py:53 -msgid "New &trending topics buffer..." -msgstr "Ny &trending emner buffer..." - -#: ../src\wxUI\view.py:54 -msgid "Create a &filter" -msgstr "Opret et nyt &filter" - -#: ../src\wxUI\view.py:55 -msgid "&Manage filters" -msgstr "&Administrer filtre" - -#: ../src\wxUI\view.py:56 -msgid "Find a string in the currently focused buffer..." -msgstr "Find en streng i den aktuelt fokuserede buffer..." - -#: ../src\wxUI\view.py:57 -msgid "&Load previous items" -msgstr "&Indlæs tidligere emner" - -#: ../src\wxUI\view.py:60 -msgid "&Autoread" -msgstr "&Automatisk læsning" - -#: ../src\wxUI\view.py:61 -msgid "&Clear buffer" -msgstr "&Ryd buffer" - -#: ../src\wxUI\view.py:62 -msgid "&Destroy" -msgstr "&Ødelæg" - -#: ../src\wxUI\view.py:66 -msgid "&Seek back 5 seconds" -msgstr "&Søg tilbage 5 sekunder" - -#: ../src\wxUI\view.py:67 -msgid "&Seek forward 5 seconds" -msgstr "&Søg fremad 5 sekunder" - -#: ../src\wxUI\view.py:72 -msgid "Sounds &tutorial" -msgstr "&Hør lyde" - -#: ../src\wxUI\view.py:73 -msgid "&What's new in this version?" -msgstr "&Hvad er nyt i denne version?" - -#: ../src\wxUI\view.py:74 -msgid "&Check for updates" -msgstr "&Søg efter opdateringer" - -#: ../src\wxUI\view.py:75 -msgid "&Report an error" -msgstr "&Rapporter en fejl" - -#: ../src\wxUI\view.py:76 -msgid "{0}'s &website" -msgstr "{0}s &websted" - -#: ../src\wxUI\view.py:77 -msgid "Get soundpacks for TWBlue" -msgstr "" - -#: ../src\wxUI\view.py:78 -msgid "About &{0}" -msgstr "&Om {0}" - -#: ../src\wxUI\view.py:81 -msgid "&Application" -msgstr "&Applikation" - -#: ../src\wxUI\view.py:84 -msgid "&Buffer" -msgstr "&Buffer" - -#: ../src\wxUI\view.py:85 -msgid "&Audio" -msgstr "&Lyd" - -#: ../src\wxUI\view.py:86 -msgid "&Help" -msgstr "&Hjælp" - -#: ../src\wxUI\view.py:172 -msgid "Address" -msgstr "Adresse" - -#: ../src\wxUI\view.py:203 -msgid "Update" -msgstr "Opdatér" - -#: ../src\wxUI\view.py:203 -msgid "Your {0} version is up to date" -msgstr "Din {0} version er opdateret" - -#~ msgid "Empty" -#~ msgstr "Tom" - -#~ msgid "One mention from %s " -#~ msgstr "En omtale fra %s" - -#~ msgid "One tweet from %s" -#~ msgstr "Et tweet fra %s" - -#~ msgid "You've blocked %s" -#~ msgstr "Du har blokeret %s" - -#~ msgid "You've unblocked %s" -#~ msgstr "Du har fjernet blokeringen af %s" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "%s (@%s) har fulgt dig" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "Du har fulgt %s (@%s)" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "Du følger ikke længere %s (@%s)" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "Du synes godt om: %s, %s" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "%s(@%s) synes godt om: %s" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "Du synes ikke længere om: %s, %s" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "%s(@%s) synes ikke længere om: %s" - -#~ msgid "You've created the list %s" -#~ msgstr "Du har oprettet listen %s" - -#~ msgid "You've deleted the list %s" -#~ msgstr "Du har slettet listen %s" - -#~ msgid "You've updated the list %s" -#~ msgstr "Du har opdateret listen %s" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "Du har tilføjet %s(@%s) til listen %s" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "%s(@%s) har tilføjet dig til listen %s" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "Du er fjernet %s(@%s) fra listen %s" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "%s(@%s) har fjernet dig fra listen %s" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "Du har abonneret på listen %s, som ejes af %s(@%s)" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "%s(@%s) har tilmeldt dig til listen %s" - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Du har afmeldt dig fra listen %s, som ejes af %s(@%s)" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Du er blevet afmeldt fra listen %s, som ejes af %s(@%s)" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "Du har retweetet et retweet fra %s(@%s): %s" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "%s(@%s) har retweetet dit retweet: %s" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "API-opkald (Et API-opkald = 200 tweets, to API-opkald = 400 tweets osv.):" - -#~ msgid "Unable to upload the audio" -#~ msgstr "Ikke i stand til at uploade lyd" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "Venter på kontogodkendelse..." - -#~ msgid "autodetect" -#~ msgstr "opdag automatisk" diff --git a/src/locales/gl/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po b/src/locales/gl/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po deleted file mode 100644 index a814fb3e..00000000 --- a/src/locales/gl/LC_MESSAGES/twblue (Jani Kinnunen's conflicted copy 2019-03-25).po +++ /dev/null @@ -1,4190 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: TW Blue 0.80\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2018-08-08 10:44+0100\n" -"Last-Translator: Manuel Cortez \n" -"Language-Team: Juan Buño \n" -"Language: gl\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.6.11\n" -"X-Poedit-KeywordsList: _;gettext;gettext_noop\n" -"X-Poedit-Basepath: .\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-SourceCharset: UTF-8\n" - -#: ../src\controller\attach.py:23 -msgid "Photo" -msgstr "Imaxe" - -#: ../src\controller\buffers\baseBuffers.py:95 -msgid "This action is not supported for this buffer" -msgstr "Esta acción non se atopa soportada para este buffer" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 -msgid "Home" -msgstr "Principal" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 -msgid "Mentions" -msgstr "Mencións" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 -msgid "Direct messages" -msgstr "Mensaxes directas" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 -msgid "Sent direct messages" -msgstr "Enviar mensaxes directas" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 -msgid "Sent tweets" -msgstr "Enviar chíos" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 -msgid "Likes" -msgstr "Marcados como Gústame" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 -msgid "Followers" -msgstr "Seguidores" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "Amigos" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 -msgid "Blocked users" -msgstr "Usuarios bloqueados" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 -msgid "Muted users" -msgstr "Usuarios silenciados" - -#: ../src\controller\buffers\twitterBuffers.py:75 -#, fuzzy -msgid "{username}'s timeline" -msgstr "Abrir líña temporal" - -#: ../src\controller\buffers\twitterBuffers.py:77 -msgid "{username}'s likes" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:79 -msgid "{username}'s followers" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:81 -msgid "{username}'s friends" -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:83 -#, fuzzy -msgid "Unknown buffer" -msgstr "Descoñecido" - -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 -msgid "Tweet" -msgstr "Chío" - -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 -msgid "Write the tweet here" -msgstr "Escribe o chío aquí" - -#: ../src\controller\buffers\twitterBuffers.py:194 -#, fuzzy -msgid "New tweet in {0}" -msgstr "Novo chío" - -#: ../src\controller\buffers\twitterBuffers.py:197 -#, fuzzy -msgid "{0} new tweets in {1}." -msgstr "@{0} citou o teu chío: {1}" - -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 -msgid "%s items retrieved" -msgstr "%s elementos recuperados" - -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "Este buffer non é unha liña temporal. Non pode ser eliminado." - -#: ../src\controller\buffers\twitterBuffers.py:402 -msgid "Reply to {arg0}" -msgstr "Respostar a {arg0}" - -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 -msgid "Reply" -msgstr "Respostar" - -#: ../src\controller\buffers\twitterBuffers.py:405 -msgid "Reply to %s" -msgstr "Respostar a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Mensaxe directa a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 -msgid "New direct message" -msgstr "Nova mensaxe directa" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Add your comment to the tweet" -msgstr "Engade o teu comentario ao chío" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Quote" -msgstr "Cita" - -#: ../src\controller\buffers\twitterBuffers.py:572 -msgid "Opening URL..." -msgstr "Abrindo URL..." - -#: ../src\controller\buffers\twitterBuffers.py:607 -msgid "User details" -msgstr "Detalles de usuario" - -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 -msgid "Opening item in web browser..." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -msgid "Mention to %s" -msgstr "Mencionar a %s" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 -msgid "Mention" -msgstr "Mención" - -#: ../src\controller\buffers\twitterBuffers.py:728 -#, fuzzy -msgid "{0} new direct messages." -msgstr "Nova mensaxe directa" - -#: ../src\controller\buffers\twitterBuffers.py:731 -#, fuzzy -msgid "This action is not supported in the buffer yet." -msgstr "Esta acción non se atopa soportada para este buffer" - -#: ../src\controller\buffers\twitterBuffers.py:741 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" - -#: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy -msgid "{0} new followers." -msgstr "Novo seguidor." - -#: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy -msgid "This action is not supported in the buffer, yet." -msgstr "Esta acción non se atopa soportada para este buffer" - -#: ../src\controller\mainController.py:273 -msgid "Ready" -msgstr "Listo" - -#: ../src\controller\mainController.py:345 -msgid "Timelines" -msgstr "Liñas temporais" - -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 -msgid "Timeline for {}" -msgstr "Liña temporal para {0}" - -#: ../src\controller\mainController.py:352 -msgid "Likes timelines" -msgstr "Liñas temporais de marcados como gústame" - -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 -msgid "Likes for {}" -msgstr "Chíos que me gustan para {}" - -#: ../src\controller\mainController.py:359 -msgid "Followers' Timelines" -msgstr "Liñas temporais de seguidores" - -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 -msgid "Followers for {}" -msgstr "Seguidores para {}" - -#: ../src\controller\mainController.py:366 -msgid "Friends' Timelines" -msgstr "Liñas temporais de amigos" - -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 -msgid "Friends for {}" -msgstr "Amigos para {}" - -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 -msgid "Lists" -msgstr "Listas" - -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 -msgid "List for {}" -msgstr "Lista para {}" - -#: ../src\controller\mainController.py:381 -msgid "Searches" -msgstr "Procuras" - -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 -msgid "Search for {}" -msgstr "Procurar {0}" - -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 -msgid "Trending topics for %s" -msgstr "Tendencias para %s" - -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "" -"Non hai unha sesión actualmente no foco. Enfoca unha sesión co atallo de " -"teclado para sesión seguinte ou anterior." - -#: ../src\controller\mainController.py:465 -msgid "Empty buffer." -msgstr "Valdeirar búffer." - -#: ../src\controller\mainController.py:472 -msgid "{0} not found." -msgstr "{0} non atopado." - -#: ../src\controller\mainController.py:482 -msgid "Filters cannot be applied on this buffer" -msgstr "Os filtros non se poden aplicar neste búfer" - -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 -msgid "Select the user" -msgstr "Seleciona un usuario" - -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy -msgid "MMM D, YYYY. H:m" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\controller\mainController.py:934 -msgid "Conversation with {0}" -msgstr "Conversa con {0}" - -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 -msgid "There are no coordinates in this tweet" -msgstr "Non hai coordinadas neste chío" - -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "Non hai resultados para as coordenadas neste chío" - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 -msgid "Error decoding coordinates. Try again later." -msgstr "Erro decodificando as coordenadas. Téntao de novo máis tarde." - -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 -msgid "%s, %s of %s" -msgstr "%s, %s de %s" - -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 -msgid "%s. Empty" -msgstr "%s. Valeiro" - -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 -msgid "{0}: This account is not logged into Twitter." -msgstr "{0}: Esta conta non está autentificada en Twitter." - -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 -msgid "%s. %s, %s of %s" -msgstr "%s. %s, %s de %s" - -#: ../src\controller\mainController.py:1170 -msgid "{0}: This account is not logged into twitter." -msgstr "{0}: Esta conta non está autentificada en twitter." - -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Eventos" - -#: ../src\controller\mainController.py:1393 -msgid "This list is already opened" -msgstr "Esta lista xa está aberta" - -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 -#, fuzzy -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "" -"Algo inesperado aconteceu cando tentabamos reportar o teu erro. Por favor, " -"volve intentalo máis tarde" - -#: ../src\controller\mainController.py:1475 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "a autolectura de novos chíos está activada neste bufer" - -#: ../src\controller\mainController.py:1478 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "a autolectura de novos chíos está desactivada neste buffer" - -#: ../src\controller\mainController.py:1485 -msgid "Session mute on" -msgstr "Sesión silenciada" - -#: ../src\controller\mainController.py:1488 -msgid "Session mute off" -msgstr "Silenciar Sesión desactivado" - -#: ../src\controller\mainController.py:1496 -msgid "Buffer mute on" -msgstr "silencio de buffer activo" - -#: ../src\controller\mainController.py:1499 -msgid "Buffer mute off" -msgstr "silencio de buffer inactivo" - -#: ../src\controller\mainController.py:1522 -msgid "Copied" -msgstr "Copiado" - -#: ../src\controller\mainController.py:1549 -msgid "Unable to update this buffer." -msgstr "Imposible actualizar este búfer." - -#: ../src\controller\mainController.py:1552 -msgid "Updating buffer..." -msgstr "Actualizando búfer..." - -#: ../src\controller\mainController.py:1555 -msgid "{0} items retrieved" -msgstr "{0} elementos recuperados" - -#: ../src\controller\mainController.py:1572 -msgid "Invalid buffer" -msgstr "Búfer inválido" - -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "Este chío non contén imaxes" - -#: ../src\controller\mainController.py:1579 -msgid "Picture {0}" -msgstr "Foto {0}" - -#: ../src\controller\mainController.py:1580 -msgid "Select the picture" -msgstr "Seleciona a foto" - -#: ../src\controller\mainController.py:1596 -msgid "Unable to extract text" -msgstr "Imposible extraer texto" - -#: ../src\controller\messages.py:54 -msgid "Translated" -msgstr "Traducido" - -#: ../src\controller\messages.py:61 -msgid "There's no URL to be shortened" -msgstr "Non hai ningunha URL para acortar" - -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 -msgid "URL shortened" -msgstr "URL Acortada" - -#: ../src\controller\messages.py:80 -msgid "There's no URL to be expanded" -msgstr "Non hai ningunha URL para expandir" - -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 -msgid "URL expanded" -msgstr "URL expandida" - -#: ../src\controller\messages.py:104 -msgid "%s - %s of %d characters" -msgstr "%s - %s de %d caracteres" - -#: ../src\controller\messages.py:108 -msgid "%s - %s characters" -msgstr "%s - %s carácteres" - -#: ../src\controller\messages.py:262 -msgid "View item" -msgstr "Ver elemento" - -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Conexión directa" - -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Ask" -msgstr "Preguntar" - -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet without comments" -msgstr "Rechiar sen comentarios" - -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet with comments" -msgstr "Rechiar con comentarios" - -#: ../src\controller\settings.py:184 -msgid "Account settings for %s" -msgstr "Opcions da conta para %s" - -#: ../src\controller\settings.py:284 -msgid "Direct Messages" -msgstr "Mensaxes directas" - -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 -msgid "Error" -msgstr "Erro" - -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 -msgid "That user does not exist" -msgstr "Ese usuario non existe" - -#: ../src\controller\user.py:30 -msgid "User has been suspended" -msgstr "O usuario foi suspendido" - -#: ../src\controller\user.py:36 -msgid "Information for %s" -msgstr "Detalles para %s" - -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 -msgid "Discarded" -msgstr "Descartado" - -#: ../src\controller\user.py:95 -msgid "Username: @%s\n" -msgstr "Nome de usuario: @%s\n" - -#: ../src\controller\user.py:96 -msgid "Name: %s\n" -msgstr "Nome: %s\n" - -#: ../src\controller\user.py:98 -msgid "Location: %s\n" -msgstr "Ubicación: %s\n" - -#: ../src\controller\user.py:100 -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: ../src\controller\user.py:102 -msgid "Bio: %s\n" -msgstr "Descrición: %s\n" - -#: ../src\controller\user.py:103 ../src\controller\user.py:118 -msgid "Yes" -msgstr "Sí" - -#: ../src\controller\user.py:104 ../src\controller\user.py:119 -msgid "No" -msgstr "Non" - -#: ../src\controller\user.py:105 -msgid "Protected: %s\n" -msgstr "Protexido: %s\n" - -#: ../src\controller\user.py:110 -msgid "You follow {0}. " -msgstr "Segues a {0}. " - -#: ../src\controller\user.py:113 -msgid "{0} is following you." -msgstr "{0} estache a seguir." - -#: ../src\controller\user.py:117 -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"Seguidores: %s\n" -" Amigos: %s\n" - -#: ../src\controller\user.py:120 -msgid "Verified: %s\n" -msgstr "Verificado: %s\n" - -#: ../src\controller\user.py:121 -msgid "Tweets: %s\n" -msgstr "Chíos: %s\n" - -#: ../src\controller\user.py:122 -msgid "Likes: %s" -msgstr "Marcados como gústame: %s" - -#: ../src\controller\userActionsController.py:75 -msgid "You can't ignore direct messages" -msgstr "Non podes ignorar as mensaxes directas" - -#: ../src\extra\AudioUploader\audioUploader.py:54 -msgid "Attaching..." -msgstr "Adxuntando..." - -#: ../src\extra\AudioUploader\audioUploader.py:71 -msgid "Pause" -msgstr "PAUSAR" - -#: ../src\extra\AudioUploader\audioUploader.py:73 -msgid "&Resume" -msgstr "&RETOMAR" - -#: ../src\extra\AudioUploader\audioUploader.py:74 -msgid "Resume" -msgstr "RETOMAR" - -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 -msgid "&Pause" -msgstr "&PAUSAR" - -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 -msgid "&Stop" -msgstr "&Deter" - -#: ../src\extra\AudioUploader\audioUploader.py:92 -msgid "Recording" -msgstr "Grabando" - -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 -msgid "Stopped" -msgstr "Detido" - -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 -msgid "&Record" -msgstr "&Grabar" - -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 -msgid "Playing..." -msgstr "Reproducindo..." - -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 -msgid "&Play" -msgstr "&Reproducir" - -#: ../src\extra\AudioUploader\audioUploader.py:156 -msgid "Recoding audio..." -msgstr "Recodificando audio..." - -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 -msgid "Error in file upload: {0}" -msgstr "Erro subindo o ficheiro: {0}" - -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 -msgid "%d day, " -msgstr "%d día, " - -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 -msgid "%d days, " -msgstr "%d días, " - -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 -msgid "%d hour, " -msgstr "%d hora, " - -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 -msgid "%d hours, " -msgstr "%d horas, " - -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 -msgid "%d minute, " -msgstr "%d minuto, " - -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 -msgid "%d minutes, " -msgstr "%d minutos, " - -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 -msgid "%s second" -msgstr "%s segundo" - -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 -msgid "%s seconds" -msgstr "%s segundos" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 -msgid "File" -msgstr "Arquivo" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 -msgid "Transferred" -msgstr "Transferido" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 -msgid "Total file size" -msgstr "Tamaño total do arquivo" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 -msgid "Transfer rate" -msgstr "Velocidade de transferencia" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 -msgid "Time left" -msgstr "Tempo restante" - -#: ../src\extra\AudioUploader\wx_ui.py:28 -msgid "Attach audio" -msgstr "Adxuntar audio" - -#: ../src\extra\AudioUploader\wx_ui.py:40 -msgid "&Add an existing file" -msgstr "&Engadir un arquivo existente" - -#: ../src\extra\AudioUploader\wx_ui.py:41 -msgid "&Discard" -msgstr "&Descartar" - -#: ../src\extra\AudioUploader\wx_ui.py:43 -msgid "Upload to" -msgstr "Subir a" - -#: ../src\extra\AudioUploader\wx_ui.py:48 -msgid "Attach" -msgstr "Adxuntar" - -#: ../src\extra\AudioUploader\wx_ui.py:50 -msgid "&Cancel" -msgstr "&Cancelar" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "Arquivos de audio (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Select the audio file to be uploaded" -msgstr "Seleciona o arquivo de audio que desexas subir" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 -msgid "Audio tweet." -msgstr "Chío de Audio." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "User timeline buffer created." -msgstr "Búfer de Liña temporal de usuario creado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "Buffer destroied." -msgstr "Búfer destruido." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Direct message received." -msgstr "Mensaxe directa recibida" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message sent." -msgstr "Mensaxe directa enviada" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Error." -msgstr "Erro" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Tweet liked." -msgstr "Chío marcado como gústame." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Likes buffer updated." -msgstr "Búfer de marcados como gústame actualizado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Geotweet." -msgstr "chío xeolocalizable" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Tweet contains one or more images" -msgstr "O chío contén una ou máis imaxes" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Boundary reached." -msgstr "Límite alcanzado" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "List updated." -msgstr "Lista actualizada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "Too many characters." -msgstr "Demasiados carácteres." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Mention received." -msgstr "Mención recibida." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "New event." -msgstr "Novo evento" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "{0} is ready." -msgstr "{0} está listo" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -msgid "Mention sent." -msgstr "Mención enviada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Tweet retweeted." -msgstr "Chío rechiado" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Search buffer updated." -msgstr "Búfer Procuras actualizado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Tweet received." -msgstr "Chío recibido." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet sent." -msgstr "Chío enviado" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Trending topics buffer updated." -msgstr "Búfer Tendencias actualizado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "New tweet in user timeline buffer." -msgstr "Novo chío no búfer liñas temporais de usuario." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New follower." -msgstr "Novo seguidor." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "Volume changed." -msgstr "Volume cambiado." - -#: ../src\extra\SoundsTutorial\wx_ui.py:8 -msgid "Sounds tutorial" -msgstr "tutorial de sons" - -#: ../src\extra\SoundsTutorial\wx_ui.py:11 -msgid "Press enter to listen to the sound for the selected event" -msgstr "" -"preme enter para escoitar o sonido correspondente ao evento selecionado" - -#: ../src\extra\SpellChecker\spellchecker.py:57 -msgid "Misspelled word: %s" -msgstr "Falta de ortografía: %s" - -#: ../src\extra\SpellChecker\wx_ui.py:27 -msgid "Misspelled word" -msgstr "Falta de ortografía" - -#: ../src\extra\SpellChecker\wx_ui.py:32 -msgid "Context" -msgstr "contexto" - -#: ../src\extra\SpellChecker\wx_ui.py:37 -msgid "Suggestions" -msgstr "suxerencias" - -#: ../src\extra\SpellChecker\wx_ui.py:42 -msgid "&Ignore" -msgstr "&Ignorar" - -#: ../src\extra\SpellChecker\wx_ui.py:43 -msgid "I&gnore all" -msgstr "I&gnorar todo" - -#: ../src\extra\SpellChecker\wx_ui.py:44 -msgid "&Replace" -msgstr "&Reemplazar" - -#: ../src\extra\SpellChecker\wx_ui.py:45 -msgid "R&eplace all" -msgstr "R&eemplazar todo" - -#: ../src\extra\SpellChecker\wx_ui.py:46 -msgid "&Add to personal dictionary" -msgstr "&Engadir ao dicionario persoal" - -#: ../src\extra\SpellChecker\wx_ui.py:79 -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "" -"ocorreu un erro. Non hai diccionarios dispoñibles para a lingua selecionada " -"no {0}" - -#: ../src\extra\SpellChecker\wx_ui.py:82 -msgid "Spell check complete." -msgstr "Corrección ortográfica completada." - -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 -msgid "You have to start writing" -msgstr "Tes que comezar a escribir" - -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 -msgid "There are no results in your users database" -msgstr "Non hai resultados na túa base de datos de usuario" - -#: ../src\extra\autocompletionUsers\completion.py:33 -msgid "Autocompletion only works for users." -msgstr "O autocompletado soamente funciona para usuarios" - -#: ../src\extra\autocompletionUsers\settings.py:27 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"Actualizando base de datos... Podes pechar esta ventá agora. Unha mensaxe " -"avisarache cando este proceso remate." - -#: ../src\extra\autocompletionUsers\wx_manage.py:8 -msgid "Manage Autocompletion database" -msgstr "Xestionar a base de datos do autocompletado de usuarios" - -#: ../src\extra\autocompletionUsers\wx_manage.py:11 -msgid "Editing {0} users database" -msgstr "Editando a base de dados de usuarios do {0} " - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Username" -msgstr "Nome de usuario" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "Nome" - -#: ../src\extra\autocompletionUsers\wx_manage.py:15 -msgid "Add user" -msgstr "Engadir usuario" - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Remove user" -msgstr "Quitar usuario" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Add user to database" -msgstr "Engadir usuario á base de datos" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Twitter username" -msgstr "Nome de usuario de twitter" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -msgid "The user does not exist" -msgstr "O usuario non existe" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "Error!" -msgstr "Erro!" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "Opcións de autocompletado de usuarios" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "Engadir usuarios dende o buffer de seguidores" - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "Engadir usuarios dende o buffer de amigos" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "Xestionar base de datos..." - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "Feito!" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "Actualizouse a base de dados de usuarios do {0}'" - -#: ../src\extra\ocr\OCRSpace.py:5 -msgid "Detect automatically" -msgstr "Detectar automáticamente" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 -msgid "Danish" -msgstr "dinamarqués" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 -msgid "Dutch" -msgstr "holandés" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 -msgid "English" -msgstr "inglés" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 -msgid "Finnish" -msgstr "finés" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 -msgid "French" -msgstr "francés" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 -msgid "German" -msgstr "alemán" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 -msgid "Hungarian" -msgstr "húngaro" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 -msgid "Italian" -msgstr "italiano" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 -msgid "Japanese" -msgstr "xaponés" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 -msgid "Korean" -msgstr "coreano" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 -msgid "Polish" -msgstr "polaco" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 -msgid "Portuguese" -msgstr "portugués" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 -msgid "Russian" -msgstr "ruso" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 -msgid "Spanish" -msgstr "castelán" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 -msgid "Turkish" -msgstr "Turco" - -#: ../src\extra\translator\translator.py:12 -msgid "Afrikaans" -msgstr "Africano" - -#: ../src\extra\translator\translator.py:13 -msgid "Albanian" -msgstr "albanés" - -#: ../src\extra\translator\translator.py:14 -msgid "Amharic" -msgstr "amárico" - -#: ../src\extra\translator\translator.py:15 -msgid "Arabic" -msgstr "árabe" - -#: ../src\extra\translator\translator.py:16 -msgid "Armenian" -msgstr "armenio" - -#: ../src\extra\translator\translator.py:17 -msgid "Azerbaijani" -msgstr "acerí" - -#: ../src\extra\translator\translator.py:18 -msgid "Basque" -msgstr "eusquera" - -#: ../src\extra\translator\translator.py:19 -msgid "Belarusian" -msgstr "bielorruso" - -#: ../src\extra\translator\translator.py:20 -msgid "Bengali" -msgstr "bengalí" - -#: ../src\extra\translator\translator.py:21 -msgid "Bihari" -msgstr "Bihari" - -#: ../src\extra\translator\translator.py:22 -msgid "Bulgarian" -msgstr "búlgaro" - -#: ../src\extra\translator\translator.py:23 -msgid "Burmese" -msgstr "virmano" - -#: ../src\extra\translator\translator.py:24 -msgid "Catalan" -msgstr "catalán" - -#: ../src\extra\translator\translator.py:25 -msgid "Cherokee" -msgstr "cheroqui" - -#: ../src\extra\translator\translator.py:26 -msgid "Chinese" -msgstr "chinés" - -#: ../src\extra\translator\translator.py:27 -msgid "Chinese_simplified" -msgstr "chinés simplificado" - -#: ../src\extra\translator\translator.py:28 -msgid "Chinese_traditional" -msgstr "chinés tradicional" - -#: ../src\extra\translator\translator.py:29 -msgid "Croatian" -msgstr "croata" - -#: ../src\extra\translator\translator.py:30 -msgid "Czech" -msgstr "checo" - -#: ../src\extra\translator\translator.py:32 -msgid "Dhivehi" -msgstr "Dhivehi" - -#: ../src\extra\translator\translator.py:35 -msgid "Esperanto" -msgstr "esperanto" - -#: ../src\extra\translator\translator.py:36 -msgid "Estonian" -msgstr "estonio" - -#: ../src\extra\translator\translator.py:37 -msgid "Filipino" -msgstr "filipino" - -#: ../src\extra\translator\translator.py:40 -msgid "Galician" -msgstr "galego" - -#: ../src\extra\translator\translator.py:41 -msgid "Georgian" -msgstr "Xeorxiano" - -#: ../src\extra\translator\translator.py:43 -msgid "Greek" -msgstr "grego" - -#: ../src\extra\translator\translator.py:44 -msgid "Guarani" -msgstr "guaraní" - -#: ../src\extra\translator\translator.py:45 -msgid "Gujarati" -msgstr "Gujarati" - -#: ../src\extra\translator\translator.py:46 -msgid "Hebrew" -msgstr "hebreo" - -#: ../src\extra\translator\translator.py:47 -msgid "Hindi" -msgstr "indi" - -#: ../src\extra\translator\translator.py:49 -msgid "Icelandic" -msgstr "islandés" - -#: ../src\extra\translator\translator.py:50 -msgid "Indonesian" -msgstr "indonesio" - -#: ../src\extra\translator\translator.py:51 -msgid "Inuktitut" -msgstr "Inuktitut" - -#: ../src\extra\translator\translator.py:52 -msgid "Irish" -msgstr "irlandés (gaélico)" - -#: ../src\extra\translator\translator.py:55 -msgid "Kannada" -msgstr "Canarés" - -#: ../src\extra\translator\translator.py:56 -msgid "Kazakh" -msgstr "cazaxo" - -#: ../src\extra\translator\translator.py:57 -msgid "Khmer" -msgstr "Cambodia" - -#: ../src\extra\translator\translator.py:59 -msgid "Kurdish" -msgstr "curdo" - -#: ../src\extra\translator\translator.py:60 -msgid "Kyrgyz" -msgstr "Quirguiz" - -#: ../src\extra\translator\translator.py:61 -msgid "Laothian" -msgstr "Lao" - -#: ../src\extra\translator\translator.py:62 -msgid "Latvian" -msgstr "letón" - -#: ../src\extra\translator\translator.py:63 -msgid "Lithuanian" -msgstr "lituano" - -#: ../src\extra\translator\translator.py:64 -msgid "Macedonian" -msgstr "macedonio" - -#: ../src\extra\translator\translator.py:65 -msgid "Malay" -msgstr "malaio" - -#: ../src\extra\translator\translator.py:66 -msgid "Malayalam" -msgstr "Malaialam" - -#: ../src\extra\translator\translator.py:67 -msgid "Maltese" -msgstr "maltés" - -#: ../src\extra\translator\translator.py:68 -msgid "Marathi" -msgstr "maratí" - -#: ../src\extra\translator\translator.py:69 -msgid "Mongolian" -msgstr "mongol" - -#: ../src\extra\translator\translator.py:70 -msgid "Nepali" -msgstr "nepalí" - -#: ../src\extra\translator\translator.py:71 -msgid "Norwegian" -msgstr "noruegués" - -#: ../src\extra\translator\translator.py:72 -msgid "Oriya" -msgstr "Oriya" - -#: ../src\extra\translator\translator.py:73 -msgid "Pashto" -msgstr "Pastú" - -#: ../src\extra\translator\translator.py:74 -msgid "Persian" -msgstr "persa" - -#: ../src\extra\translator\translator.py:77 -msgid "Punjabi" -msgstr "Punjabi" - -#: ../src\extra\translator\translator.py:78 -msgid "Romanian" -msgstr "rumano" - -#: ../src\extra\translator\translator.py:80 -msgid "Sanskrit" -msgstr "sánscrito" - -#: ../src\extra\translator\translator.py:81 -msgid "Serbian" -msgstr "serbio" - -#: ../src\extra\translator\translator.py:82 -msgid "Sindhi" -msgstr "Sindhi" - -#: ../src\extra\translator\translator.py:83 -msgid "Sinhalese" -msgstr "Cingalés" - -#: ../src\extra\translator\translator.py:84 -msgid "Slovak" -msgstr "eslovaco" - -#: ../src\extra\translator\translator.py:85 -msgid "Slovenian" -msgstr "esloveno" - -#: ../src\extra\translator\translator.py:87 -msgid "Swahili" -msgstr "swahili" - -#: ../src\extra\translator\translator.py:88 -msgid "Swedish" -msgstr "sueco" - -#: ../src\extra\translator\translator.py:89 -msgid "Tajik" -msgstr "Tajik" - -#: ../src\extra\translator\translator.py:90 -msgid "Tamil" -msgstr "tamil" - -#: ../src\extra\translator\translator.py:91 -msgid "Tagalog" -msgstr "Tagalo" - -#: ../src\extra\translator\translator.py:92 -msgid "Telugu" -msgstr "Telugú" - -#: ../src\extra\translator\translator.py:93 -msgid "Thai" -msgstr "tailandés" - -#: ../src\extra\translator\translator.py:94 -msgid "Tibetan" -msgstr "tibetano" - -#: ../src\extra\translator\translator.py:96 -msgid "Ukrainian" -msgstr "Ucraíno" - -#: ../src\extra\translator\translator.py:97 -msgid "Urdu" -msgstr "Urdu" - -#: ../src\extra\translator\translator.py:98 -msgid "Uzbek" -msgstr "uzbeco" - -#: ../src\extra\translator\translator.py:99 -msgid "Uighur" -msgstr "Uighur" - -#: ../src\extra\translator\translator.py:100 -msgid "Vietnamese" -msgstr "vietnamita" - -#: ../src\extra\translator\translator.py:101 -msgid "Welsh" -msgstr "galés" - -#: ../src\extra\translator\translator.py:102 -msgid "Yiddish" -msgstr "Yiddish" - -#: ../src\extra\translator\wx_ui.py:44 -msgid "Translate message" -msgstr "Traducir mensaxe" - -#: ../src\extra\translator\wx_ui.py:47 -msgid "Target language" -msgstr "Idioma de destino" - -#: ../src\issueReporter\issueReporter.py:30 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 -msgid "General" -msgstr "Xeral" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "always" -msgstr "Sempre" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "have not tried" -msgstr "Non se intentou" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "random" -msgstr "Aleatoriamente" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "sometimes" -msgstr "As veces" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "unable to duplicate" -msgstr "Imposible reproducir" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "block" -msgstr "Bloqueo" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "crash" -msgstr "Fallo" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "feature" -msgstr "Característica" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "major" -msgstr "Maior" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "minor" -msgstr "Menor" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "text" -msgstr "Texto" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "trivial" -msgstr "trivial" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "tweak" -msgstr "Axuste" - -#: ../src\issueReporter\wx_ui.py:25 -msgid "Report an error" -msgstr "Reportar un erro" - -#: ../src\issueReporter\wx_ui.py:28 -msgid "Select a category" -msgstr "Seleciona unha categoría" - -#: ../src\issueReporter\wx_ui.py:36 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "Describe en poucas palabras o que ocorreu, logo poderás profundizar." - -#: ../src\issueReporter\wx_ui.py:45 -msgid "Here, you can describe the bug in detail" -msgstr "Aquí podes describir o erro en detalle" - -#: ../src\issueReporter\wx_ui.py:55 -msgid "how often does this bug happen?" -msgstr "Qué tan a miúdo ocorre este erro?" - -#: ../src\issueReporter\wx_ui.py:62 -msgid "Select the importance that you think this bug has" -msgstr "Selecciona a importancia que consideras que ten este erro" - -#: ../src\issueReporter\wx_ui.py:69 -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"Coñezo que o sistema de erros de {0} obterá o meu nome de usuario de " -"Twitter para contactarme e resolver o erro rapidamente" - -#: ../src\issueReporter\wx_ui.py:72 -msgid "Send report" -msgstr "Enviar reporte" - -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 -msgid "Cancel" -msgstr "Cancelar" - -#: ../src\issueReporter\wx_ui.py:83 -msgid "You must fill out both fields" -msgstr "Debes encher ambos campos" - -#: ../src\issueReporter\wx_ui.py:86 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"Necesitas marcar a caixa para proporcionarnos o teu nome de usuario de " -"Twitter para poder contactarte se é preciso" - -#: ../src\issueReporter\wx_ui.py:89 -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"Grazas por reportar o teu erro!. Quizais poderás velo en próximas versións " -"na listaxe de trocos. Reportaches o erro número %i." - -#: ../src\issueReporter\wx_ui.py:89 -msgid "reported" -msgstr "Reportado" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "Error while reporting" -msgstr "Erro ao reportar" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"Algo inesperado aconteceu cando tentabamos reportar o teu erro. Por favor, " -"volve intentalo máis tarde" - -#: ../src\keystrokeEditor\constants.py:3 -msgid "Go up in the current buffer" -msgstr "Vai arriba no búfer actual" - -#: ../src\keystrokeEditor\constants.py:4 -msgid "Go down in the current buffer" -msgstr "vai abaixo no búfer actual" - -#: ../src\keystrokeEditor\constants.py:5 -msgid "Go to the previous buffer" -msgstr "Vai ó anterior búfer" - -#: ../src\keystrokeEditor\constants.py:6 -msgid "Go to the next buffer" -msgstr "Vai ó seguinte búfer" - -#: ../src\keystrokeEditor\constants.py:7 -msgid "Focus the next session" -msgstr "Enfocar a seguinte sesión" - -#: ../src\keystrokeEditor\constants.py:8 -msgid "Focus the previous session" -msgstr "Enfocar a anterior sesión" - -#: ../src\keystrokeEditor\constants.py:9 -msgid "Show or hide the GUI" -msgstr "Amosar ou agochar a Interface gráfica" - -#: ../src\keystrokeEditor\constants.py:10 -msgid "New tweet" -msgstr "Novo chío" - -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 -msgid "Retweet" -msgstr "Rechío" - -#: ../src\keystrokeEditor\constants.py:13 -msgid "Send direct message" -msgstr "Enviar mensaxe directa" - -#: ../src\keystrokeEditor\constants.py:14 -msgid "Like a tweet" -msgstr "Gústame un chío" - -#: ../src\keystrokeEditor\constants.py:15 -msgid "Like/unlike a tweet" -msgstr "Marcar o non marcar un chío como gússtame" - -#: ../src\keystrokeEditor\constants.py:16 -msgid "Unlike a tweet" -msgstr "Non me gusta un chío" - -#: ../src\keystrokeEditor\constants.py:17 -msgid "Open the user actions dialogue" -msgstr "Abrir o diálogo de accións do Usuario" - -#: ../src\keystrokeEditor\constants.py:18 -msgid "See user details" -msgstr "Ver detalles do usuario" - -#: ../src\keystrokeEditor\constants.py:19 -msgid "Show tweet" -msgstr "Ver chío" - -#: ../src\keystrokeEditor\constants.py:20 -msgid "Quit" -msgstr "saír" - -#: ../src\keystrokeEditor\constants.py:21 -msgid "Open user timeline" -msgstr "Abrir líña temporal" - -#: ../src\keystrokeEditor\constants.py:22 -msgid "Destroy buffer" -msgstr "Destruir o búfer" - -#: ../src\keystrokeEditor\constants.py:23 -msgid "Interact with the currently focused tweet." -msgstr "Interactuar co chío enfocado actualmente." - -#: ../src\keystrokeEditor\constants.py:24 -msgid "Open URL" -msgstr "Abrir URL" - -#: ../src\keystrokeEditor\constants.py:25 -#, fuzzy -msgid "View in Twitter" -msgstr "procurar en twitter" - -#: ../src\keystrokeEditor\constants.py:26 -msgid "Increase volume by 5%" -msgstr "Subir o volumen nun 5%" - -#: ../src\keystrokeEditor\constants.py:27 -msgid "Decrease volume by 5%" -msgstr "Baixar o volume nun 5%" - -#: ../src\keystrokeEditor\constants.py:28 -msgid "Jump to the first element of a buffer" -msgstr "Saltar ó primeiro elemento do búfer actual" - -#: ../src\keystrokeEditor\constants.py:29 -msgid "Jump to the last element of the current buffer" -msgstr "Saltar ó derradeiro elemento do búfer actual" - -#: ../src\keystrokeEditor\constants.py:30 -msgid "Jump 20 elements up in the current buffer" -msgstr "Saltar 20 elementos cara arriba no búfer actual" - -#: ../src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements down in the current buffer" -msgstr "Saltar 20 elementos cara abaixo no búfer actual" - -#: ../src\keystrokeEditor\constants.py:32 -msgid "Edit profile" -msgstr "Editar perfil" - -#: ../src\keystrokeEditor\constants.py:33 -msgid "Delete a tweet or direct message" -msgstr "Eliminar un chío ou unha mensaxe direita" - -#: ../src\keystrokeEditor\constants.py:34 -msgid "Empty the current buffer" -msgstr "Vaciar buffer actual" - -#: ../src\keystrokeEditor\constants.py:35 -msgid "Repeat last item" -msgstr "Repetir último elemento" - -#: ../src\keystrokeEditor\constants.py:36 -msgid "Copy to clipboard" -msgstr "Copiar ao portapapeis" - -#: ../src\keystrokeEditor\constants.py:37 -msgid "Add to list" -msgstr "Engadir á listaxe" - -#: ../src\keystrokeEditor\constants.py:38 -msgid "Remove from list" -msgstr "Quitar de listaxe" - -#: ../src\keystrokeEditor\constants.py:39 -msgid "Mute/unmute the active buffer" -msgstr "Silenciar ou desilenciar o buffer activo" - -#: ../src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the current session" -msgstr "Silenciar/activbar o son na sesión actual" - -#: ../src\keystrokeEditor\constants.py:41 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "" -"Conmutar entre a lectura automática de novos chíos para o buffer actual" - -#: ../src\keystrokeEditor\constants.py:42 -msgid "Search on twitter" -msgstr "procurar en twitter" - -#: ../src\keystrokeEditor\constants.py:43 -msgid "Find a string in the currently focused buffer" -msgstr "Atopar unha cadea no búfer enfocado actualmente" - -#: ../src\keystrokeEditor\constants.py:44 -msgid "Show the keystroke editor" -msgstr "Mostrar o editor de combinacións de teclado" - -#: ../src\keystrokeEditor\constants.py:45 -msgid "Show lists for a specified user" -msgstr "Mostrar listaxes para un usuario específico" - -#: ../src\keystrokeEditor\constants.py:46 -msgid "load previous items" -msgstr "cargar elementos anteriores" - -#: ../src\keystrokeEditor\constants.py:47 -msgid "Get geolocation" -msgstr "Obter a xeolocalización" - -#: ../src\keystrokeEditor\constants.py:48 -msgid "Display the tweet's geolocation in a dialog" -msgstr "Amosar a xeolocazación dos chíos nun diálogo" - -#: ../src\keystrokeEditor\constants.py:49 -msgid "Create a trending topics buffer" -msgstr "Crear un búfer de tendencias" - -#: ../src\keystrokeEditor\constants.py:50 -msgid "View conversation" -msgstr "Ver conversación" - -#: ../src\keystrokeEditor\constants.py:51 -msgid "Check and download updates" -msgstr "Comprobar e descargar actualizacións" - -#: ../src\keystrokeEditor\constants.py:52 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"Abre o xestor de listas, o que che permite crear, editar, eliminar e abrir " -"listas nos búferes." - -#: ../src\keystrokeEditor\constants.py:53 -msgid "Opens the global settings dialogue" -msgstr "Abre o diálogo de opcións blobais" - -#: ../src\keystrokeEditor\constants.py:54 -#, fuzzy -msgid "Opens the list manager" -msgstr "Xestor de listaxes" - -#: ../src\keystrokeEditor\constants.py:55 -msgid "Opens the account settings dialogue" -msgstr "Abre o diálogo de opcións da conta" - -#: ../src\keystrokeEditor\constants.py:56 -msgid "Try to play an audio file" -msgstr "Tentar reproducir un ficheiro de audio" - -#: ../src\keystrokeEditor\constants.py:57 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "Actualiza o búfer e recupera posibles elementos perdidos ahí." - -#: ../src\keystrokeEditor\constants.py:58 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "Extrae o texto dende una foto e amosa o resultado nun diálogo." - -#: ../src\keystrokeEditor\wx_ui.py:8 -msgid "Keystroke editor" -msgstr "Editor de combinacións de teclado" - -#: ../src\keystrokeEditor\wx_ui.py:12 -msgid "Select a keystroke to edit" -msgstr "Seleciona unha combinación de teclado para editala" - -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "Combinacións de teclado" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 -msgid "Action" -msgstr "Acción" - -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 -msgid "Edit" -msgstr "Editar" - -#: ../src\keystrokeEditor\wx_ui.py:20 -msgid "Execute action" -msgstr "Executar acción" - -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 -msgid "Close" -msgstr "Pechar" - -#: ../src\keystrokeEditor\wx_ui.py:48 -msgid "Editing keystroke" -msgstr "Editando combinación de teclas" - -#: ../src\keystrokeEditor\wx_ui.py:51 -msgid "Control" -msgstr "Control" - -#: ../src\keystrokeEditor\wx_ui.py:52 -msgid "Alt" -msgstr "Alt" - -#: ../src\keystrokeEditor\wx_ui.py:53 -msgid "Shift" -msgstr "Shift" - -#: ../src\keystrokeEditor\wx_ui.py:54 -msgid "Windows" -msgstr "Windows" - -#: ../src\keystrokeEditor\wx_ui.py:60 -msgid "Key" -msgstr "Tecla" - -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 -msgid "OK" -msgstr "Aceptar" - -#: ../src\keystrokeEditor\wx_ui.py:78 -msgid "You need to use the Windows key" -msgstr "Precisas empregar a tecla de Windows" - -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 -msgid "Invalid keystroke" -msgstr "Combinación de teclado inválida" - -#: ../src\keystrokeEditor\wx_ui.py:81 -msgid "You must provide a character for the keystroke" -msgstr "Debes proporcionar unha tecla para o atallo do teclado" - -#: ../src\languageHandler.py:99 -msgid "User default" -msgstr "usuario por defecto" - -#: ../src\main.py:105 -msgid "https://twblue.es/donate" -msgstr "https://twblue.es/donate" - -#: ../src\main.py:122 -msgid "" -"{0} is already running. Close the other instance before starting this one. " -"If you're sure that {0} isn't running, try deleting the file at {1}. If " -"you're unsure of how to do this, contact the {0} developers." -msgstr "" - -#: ../src\sessionmanager\wxUI.py:8 -msgid "Session manager" -msgstr "Xestor de sesión" - -#: ../src\sessionmanager\wxUI.py:11 -msgid "Accounts list" -msgstr "Lista de contas" - -#: ../src\sessionmanager\wxUI.py:13 -msgid "Account" -msgstr "Conta" - -#: ../src\sessionmanager\wxUI.py:17 -msgid "New account" -msgstr "Nova conta" - -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 -msgid "Remove account" -msgstr "Quitar conta" - -#: ../src\sessionmanager\wxUI.py:19 -msgid "Global Settings" -msgstr "Opcións Globais" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "Account Error" -msgstr "Erro na conta" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "You need to configure an account." -msgstr "Precisas configurar unha conta" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "Authorization" -msgstr "Autorización" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "" -"The request to authorize your Twitter account will be opened in your " -"browser. You only need to do this once. Would you like to continue?" -msgstr "" -"A petición para se autorizar na túa conta de Twitter abrirase no navegador. " -"Só necesitas facer isto unha vez. ¿Gostaríache continuar?" - -#: ../src\sessionmanager\wxUI.py:52 -msgid "Authorized account %d" -msgstr "Conta autorizada %d" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "Invalid user token" -msgstr "Código de acceso inválido" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "" -"Your access token is invalid or the authorization has failed. Please try " -"again." -msgstr "" -"O teu token de aceso é inválido ou fallou a autorización. Por favor téntao " -"de novo." - -#: ../src\sessionmanager\wxUI.py:64 -msgid "Do you really want to delete this account?" -msgstr "Estás seguro de que desexas eliminar esta conta?" - -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 -msgid "dddd, MMMM D, YYYY H:m:s" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 -msgid "Dm to %s " -msgstr "dm a %s" - -#: ../src\sessions\twitter\compose.py:141 -msgid "{0}. Quoted tweet from @{1}: {2}" -msgstr "{0}. chío citado dende @{1}: {2}" - -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 -msgid "Unavailable" -msgstr "Non dispoñible" - -#: ../src\sessions\twitter\compose.py:166 -msgid "" -"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " -"Twitter %s" -msgstr "" -"%s (@%s). %s seguidores, %s amigos, %s chíos. último chío %s. Unido a " -"Twitter %s" - -#: ../src\sessions\twitter\compose.py:170 -msgid "No description available" -msgstr "Non hai unha descrición dispoñible" - -#: ../src\sessions\twitter\compose.py:174 -msgid "private" -msgstr "Privado" - -#: ../src\sessions\twitter\compose.py:175 -msgid "public" -msgstr "público" - -#: ../src\sessions\twitter\session.py:169 -#, fuzzy -msgid "There are no more items to retrieve in this buffer." -msgstr "Non hai coordinadas neste chío" - -#: ../src\sessions\twitter\session.py:215 -msgid "%s failed. Reason: %s" -msgstr "%s fallou. Razón: %s" - -#: ../src\sessions\twitter\session.py:221 -msgid "%s succeeded." -msgstr "%s con éxito" - -#: ../src\sessions\twitter\utils.py:225 -msgid "Sorry, you are not authorised to see this status." -msgstr "Síntoo, non estás autorizado para ver este estado." - -#: ../src\sessions\twitter\utils.py:227 -msgid "No status found with that ID" -msgstr "Non se atopou o estado con ese ID" - -#: ../src\sessions\twitter\utils.py:229 -msgid "Error code {0}" -msgstr "Código de erro {0}" - -#: ../src\sessions\twitter\wxUI.py:6 -msgid "Authorising account..." -msgstr "Autorizando conta..." - -#: ../src\sessions\twitter\wxUI.py:9 -msgid "Enter your PIN code here" -msgstr "Introduce o código PIN aquí" - -#: ../src\sound.py:159 -msgid "Stopped." -msgstr "Detido." - -#: ../src\update\wxUpdater.py:10 -msgid "New version for %s" -msgstr "Nova versión de %s" - -#: ../src\update\wxUpdater.py:10 -msgid "" -"There's a new %s version available, released on %s. Would you like to " -"download it now?\n" -"\n" -" %s version: %s\n" -"\n" -"Changes:\n" -"%s" -msgstr "" -"Hai unha versión %s nova dispoñible, publicada en %s. ¿Gostaríache " -"descargala agora?\n" -"\n" -" %s versión: %s\n" -"\n" -"Cambios:\n" -"%s" - -#: ../src\update\wxUpdater.py:18 -msgid "Download in Progress" -msgstr "Descarga en progreso" - -#: ../src\update\wxUpdater.py:18 -msgid "Downloading the new version..." -msgstr "Descargando a nova versión..." - -#: ../src\update\wxUpdater.py:28 -msgid "Updating... %s of %s" -msgstr "Actualizando... %s de %s" - -#: ../src\update\wxUpdater.py:31 -msgid "Done!" -msgstr "¡Feito!" - -#: ../src\update\wxUpdater.py:31 -msgid "" -"The update has been downloaded and installed successfully. Press OK to " -"continue." -msgstr "" -"A nova versión de TW blue foi descargada e instalada con éxito. Preme " -"aceptar para iniciar a aplicación" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Client" -msgstr "Cliente" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Text" -msgstr "Texto" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 -msgid "Date" -msgstr "Data" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 -msgid "User" -msgstr "Usuario" - -#: ../src\wxUI\buffers\base.py:27 -msgid "Direct message" -msgstr "Mensaxe directa" - -#: ../src\wxUI\buffers\events.py:13 -msgid "Event" -msgstr "Evento" - -#: ../src\wxUI\buffers\events.py:15 -msgid "Remove event" -msgstr "Eliminar evento" - -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 -msgid "Login" -msgstr "Iniciar sesión" - -#: ../src\wxUI\buffers\panels.py:13 -msgid "Log in automatically" -msgstr "Comezar sesión automáticamente" - -#: ../src\wxUI\buffers\panels.py:21 -msgid "Logout" -msgstr "Pechar sesión" - -#: ../src\wxUI\buffers\trends.py:8 -msgid "Trending topic" -msgstr "Tendencia" - -#: ../src\wxUI\buffers\trends.py:18 -msgid "Tweet about this trend" -msgstr "Chiar sobre esta tendencia" - -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 -msgid "Search topic" -msgstr "Procurar tema" - -#: ../src\wxUI\commonMessageDialogs.py:6 -msgid "" -"This retweet is over 140 characters. Would you like to post it as a mention " -"to the poster with your comments and a link to the original tweet?" -msgstr "" -"Este rechouchío ten máis de 140 carácteres. ¿Gostaríache publicalo como unha " -"mención ó remitente cos teus comentarios e unha liga ó chío orixinal?" - -#: ../src\wxUI\commonMessageDialogs.py:9 -msgid "Would you like to add a comment to this tweet?" -msgstr "¿gustaríache engadir un comentario a este chío?" - -#: ../src\wxUI\commonMessageDialogs.py:12 -msgid "" -"Do you really want to delete this tweet? It will be deleted from Twitter as " -"well." -msgstr "¿Queres de certo eliminar esta mensaxe? Eliminarase tamén de Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 -msgid "Delete" -msgstr "Eliminar" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Do you really want to close {0}?" -msgstr "Queres pechar de certo {0}?" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Exit" -msgstr "Saír" - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid " {0} must be restarted for these changes to take effect." -msgstr " débese reiniciar {0} para que estos cambios teñan lugar." - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid "Restart {0} " -msgstr "Reiniciar {0} " - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "" -"Are you sure you want to delete this user from the database? This user will " -"not appear in autocomplete results anymore." -msgstr "" -"Estás seguro de querer eliminar este usuario da base de datos? Este xa non " -"aparecerá nos resultados do autocompletado." - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "Confirm" -msgstr "Confirmar" - -#: ../src\wxUI\commonMessageDialogs.py:25 -msgid "Enter the name of the client : " -msgstr "Introduce o nome do cliente" - -#: ../src\wxUI\commonMessageDialogs.py:25 -#: ../src\wxUI\dialogs\configuration.py:246 -msgid "Add client" -msgstr "Endadir cliente" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "" -"Do you really want to empty this buffer? It's items will be removed from " -"the list but not from Twitter" -msgstr "" -"¿realmente queres borrar o contido deste buffer? Estes chíos borraranse da " -"listaxe, mais non de twitter" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "Empty buffer" -msgstr "Vaciar buffer" - -#: ../src\wxUI\commonMessageDialogs.py:35 -msgid "Do you really want to destroy this buffer?" -msgstr "Realmente queres eliminar este buffer?" - -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Attention" -msgstr "Atención" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "A timeline for this user already exists. You can't open another" -msgstr "Xa hai unha liña temporal para este usuario. Non podes abrir outra" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "Existing timeline" -msgstr "Liña temporal existente" - -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "This user has no tweets, so you can't open a timeline for them." -msgstr "" -"Este usuario non ten chíos, así que non podes abrirlle unha liña temporal" - -#: ../src\wxUI\commonMessageDialogs.py:47 -msgid "" -"This is a protected Twitter user, which means you can't open a timeline " -"using the Streaming API. The user's tweets will not update due to a twitter " -"policy. Do you want to continue?" -msgstr "" -"Este é un usuario protexido de Twitter. Significa que non podes abrir un " -"timeline utilizando a Streaming API. Os chíos dos usuario non se " -"actualizarán debido a unha política de twitter. ¿Queres continuar?" - -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "Warning" -msgstr "Precaución" - -#: ../src\wxUI\commonMessageDialogs.py:50 -msgid "" -"This is a protected user account, you need to follow this user to view their " -"tweets or likes." -msgstr "" -"Esta é unha conta de usuario protexida, necesitas seguir a este usuario para " -"ver os seus chíos ou marcados como gústame." - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "" -"If you like {0} we need your help to keep it going. Help us by donating to " -"the project. This will help us pay for the server, the domain and some other " -"things to ensure that {0} will be actively maintained. Your donation will " -"give us the means to continue the development of {0}, and to keep {0} free. " -"Would you like to donate now?" -msgstr "" -"Se che gosta {0} necesitamos da túa axuda para mantelo en camiño. Axúdanos " -"donando ó proxecto. Esto axudaranos a pagar o servidor, o dominio e algunhas " -"outras cousas para asegurarmos de que {0} se manterá activo. A túa donación " -"daranos unha razón para continuar o desenvolvemento do {0}, e para manter a " -"{0} libre. ¿Gostaríache donar agora?" - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "We need your help" -msgstr "Necesitamos da túa axuda" - -#: ../src\wxUI\commonMessageDialogs.py:57 -msgid "This user has no tweets. {0} can't create a timeline." -msgstr "Este usuario non ten chíos. {0} non podo crear unha liña temporal." - -#: ../src\wxUI\commonMessageDialogs.py:60 -msgid "This user has no favorited tweets. {0} can't create a timeline." -msgstr "" -"Este usuario non ten chíos favoritos. {0} non podo crear unha liña temporal." - -#: ../src\wxUI\commonMessageDialogs.py:63 -msgid "This user has no followers. {0} can't create a timeline." -msgstr "" -"Este usuario non ten seguedores. {0} non podo crear unha liña temporal." - -#: ../src\wxUI\commonMessageDialogs.py:66 -msgid "This user has no friends. {0} can't create a timeline." -msgstr "Este usuario non ten amigos. {0} non podo crear unha liña temporal." - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geo data for this tweet" -msgstr "datos de xeolocalización para este chío" - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geolocation data: {0}" -msgstr "Obter a xeolocalización: {0}" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "Information" -msgstr "Información" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "" -"TWBlue has detected that you're running windows 10 and has changed the " -"default keymap to the Windows 10 keymap. It means that some keyboard " -"shorcuts could be different. Please check the keystroke editor by pressing " -"Alt+Win+K to see all available keystrokes for this keymap." -msgstr "" -"TWBlue detectou que usas o Windows 10 e cambiou o mapa dò teclado " -"predeterminado ao mapa de teclado do Windows 10. Esto significa que algunhas " -"combinacións de teclas poderían ser iferentes. Preme alt+win+k para abrir o " -"editor de combinacións de teclado e ver todas as combinacións dispoñibles " -"neste mapa de teclado." - -#: ../src\wxUI\commonMessageDialogs.py:76 -msgid "You have been blocked from viewing this content" -msgstr "Bloqueáronte e non podes ver este contido" - -#: ../src\wxUI\commonMessageDialogs.py:79 -msgid "" -"You have been blocked from viewing someone's content. In order to avoid " -"conflicts with the full session, TWBlue will remove the affected timeline." -msgstr "" -"Alguén bloqueoute e non podes ver o seu contido. Para evitar confrictos en " -"toda a sesión, TWBlue quitará o fío temporal afectado." - -#: ../src\wxUI\commonMessageDialogs.py:82 -msgid "" -"TWBlue cannot load this timeline because the user has been suspended from " -"Twitter." -msgstr "" -"O TWBlue non pode cargar este fío temporal porque o usuario foi suspendido " -"por Twitter" - -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Do you really want to delete this filter?" -msgstr "¿Realmente queres borrar este filtro?" - -#: ../src\wxUI\commonMessageDialogs.py:88 -msgid "This filter already exists. Please use a different title" -msgstr "Este filtro xa existe. Por favor usa un título diferente " - -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "" -"{0} quit unexpectedly the last time it was run. If the problem persists, " -"please report it to the {0} developers." -msgstr "" - -#: ../src\wxUI\dialogs\attach.py:9 -msgid "Add an attachment" -msgstr "Engadir un adxunto" - -#: ../src\wxUI\dialogs\attach.py:12 -msgid "Attachments" -msgstr "Adxuntos" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Title" -msgstr "Título" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Type" -msgstr "Tipo" - -#: ../src\wxUI\dialogs\attach.py:18 -msgid "Add attachments" -msgstr "Endadir adxuntos" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "&Photo" -msgstr "&Imaxe" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "Remove attachment" -msgstr "Quitar adxuntos" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "Arquivos de imaxe (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Select the picture to be uploaded" -msgstr "Seleciona unha foto para subir" - -#: ../src\wxUI\dialogs\attach.py:43 -msgid "please provide a description" -msgstr "Por favor proporciona una descrición" - -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 -msgid "Description" -msgstr "Descrición" - -#: ../src\wxUI\dialogs\configuration.py:16 -msgid "Language" -msgstr "Idioma" - -#: ../src\wxUI\dialogs\configuration.py:23 -msgid "Run {0} at Windows startup" -msgstr "Executar {0} no arranque do Windows" - -#: ../src\wxUI\dialogs\configuration.py:24 -msgid "ask before exiting {0}" -msgstr "Preguntar antes de saír do {0}" - -#: ../src\wxUI\dialogs\configuration.py:27 -msgid "Disable Streaming functions" -msgstr "Desactivar funcións de Streaming" - -#: ../src\wxUI\dialogs\configuration.py:30 -msgid "Buffer update interval, in minutes" -msgstr "Intervalo de actualización do búfer, en minutos" - -#: ../src\wxUI\dialogs\configuration.py:36 -msgid "Play a sound when {0} launches" -msgstr "Reproducir un son ó se lanzar {0}" - -#: ../src\wxUI\dialogs\configuration.py:38 -msgid "Speak a message when {0} launches" -msgstr "Falar unha mensaxe ó se lanzar {0}" - -#: ../src\wxUI\dialogs\configuration.py:40 -msgid "Use invisible interface's keyboard shortcuts while GUI is visible" -msgstr "" -"Empregar os atallos de teclado da interfaz invisible na xanela gráfica." - -#: ../src\wxUI\dialogs\configuration.py:42 -msgid "Activate Sapi5 when any other screen reader is not being run" -msgstr "activar sappy 5 cando ningún outro lector se estea a executar" - -#: ../src\wxUI\dialogs\configuration.py:44 -msgid "Hide GUI on launch" -msgstr "Agochar interfaz gráfica no lanzador" - -#: ../src\wxUI\dialogs\configuration.py:46 -msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" -msgstr "" -"Utilizar lectura completa de chíos longos (pode disminuir o rendemento do " -"cliente)" - -#: ../src\wxUI\dialogs\configuration.py:48 -msgid "Remember state for mention all and long tweet" -msgstr "Lembrar estado para mencionar a todos e chío longo" - -#: ../src\wxUI\dialogs\configuration.py:51 -msgid "Keymap" -msgstr "Mapa de teclado" - -#: ../src\wxUI\dialogs\configuration.py:56 -msgid "Check for updates when {0} launches" -msgstr "Procurar actualizacións cando se lance {0}" - -#: ../src\wxUI\dialogs\configuration.py:66 -msgid "Proxy type: " -msgstr "Typo de proxy: " - -#: ../src\wxUI\dialogs\configuration.py:73 -msgid "Proxy server: " -msgstr "Servidor Proxy: " - -#: ../src\wxUI\dialogs\configuration.py:79 -msgid "Port: " -msgstr "Porto: " - -#: ../src\wxUI\dialogs\configuration.py:85 -msgid "User: " -msgstr "Usuario" - -#: ../src\wxUI\dialogs\configuration.py:91 -msgid "Password: " -msgstr "Contrasinal" - -#: ../src\wxUI\dialogs\configuration.py:103 -msgid "Autocompletion settings..." -msgstr "Opcións de autocompletado" - -#: ../src\wxUI\dialogs\configuration.py:105 -msgid "Relative timestamps" -msgstr "Tempos relativos" - -#: ../src\wxUI\dialogs\configuration.py:108 -msgid "Items on each API call" -msgstr "Elementos por cada chamada á API" - -#: ../src\wxUI\dialogs\configuration.py:114 -msgid "" -"Inverted buffers: The newest tweets will be shown at the beginning while the " -"oldest at the end" -msgstr "" -"Buffers invertidos. Os novos chíos mostraranse ao comezo da listaxe e os " -"máis vellos ao final." - -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet mode" -msgstr "Modo de rechouchío" - -#: ../src\wxUI\dialogs\configuration.py:122 -msgid "Show screen names instead of full names" -msgstr "Amosar nomes de pantalla en lugar de nomes enteiros" - -#: ../src\wxUI\dialogs\configuration.py:124 -msgid "" -"Number of items per buffer to cache in database (0 to disable caching, blank " -"for unlimited)" -msgstr "" -"Número de elementos por búfer para gardar na caché da base de dados (0 para " -"desactivar o gardado na caché, en branco para ilimitado)" - -#: ../src\wxUI\dialogs\configuration.py:134 -msgid "Enable automatic speech feedback" -msgstr "Activar a retroalimentación automática da fala" - -#: ../src\wxUI\dialogs\configuration.py:136 -msgid "Enable automatic Braille feedback" -msgstr "Activar a retroalimentación automática do braille" - -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "Estado" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Buffer" -msgstr "Búfer" - -#: ../src\wxUI\dialogs\configuration.py:147 -msgid "Show/hide" -msgstr "Amosar/agochar" - -#: ../src\wxUI\dialogs\configuration.py:148 -msgid "Move up" -msgstr "Mover arriba" - -#: ../src\wxUI\dialogs\configuration.py:149 -msgid "Move down" -msgstr "Mover abaixo" - -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 -msgid "Show" -msgstr "Amosar" - -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 -msgid "Hide" -msgstr "Agochar" - -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 -msgid "Select a buffer first." -msgstr "Selecciona un búfer primeiro." - -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 -msgid "The buffer is hidden, show it first." -msgstr "O búffer está agochado, amósao primeiro." - -#: ../src\wxUI\dialogs\configuration.py:175 -msgid "The buffer is already at the top of the list." -msgstr "O búfer xa está enriba na lista." - -#: ../src\wxUI\dialogs\configuration.py:199 -msgid "The buffer is already at the bottom of the list." -msgstr "O búfer xa está no fondo da lista." - -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 -msgid "Ignored clients" -msgstr "Clientes rexeitados" - -#: ../src\wxUI\dialogs\configuration.py:247 -msgid "Remove client" -msgstr "Quitar cliente" - -#: ../src\wxUI\dialogs\configuration.py:271 -msgid "Volume" -msgstr "volume" - -#: ../src\wxUI\dialogs\configuration.py:282 -msgid "Session mute" -msgstr "Silenciar sesión" - -#: ../src\wxUI\dialogs\configuration.py:284 -msgid "Output device" -msgstr "dispositivo de saída" - -#: ../src\wxUI\dialogs\configuration.py:291 -msgid "Input device" -msgstr "dispositivo de entrada" - -#: ../src\wxUI\dialogs\configuration.py:299 -msgid "Sound pack" -msgstr "Paquete de sons" - -#: ../src\wxUI\dialogs\configuration.py:305 -msgid "Indicate audio tweets with sound" -msgstr "Indicar chíos de audio con son" - -#: ../src\wxUI\dialogs\configuration.py:307 -msgid "Indicate geotweets with sound" -msgstr "Indicar chíos xeolocalizados con son" - -#: ../src\wxUI\dialogs\configuration.py:309 -msgid "Indicate tweets containing images with sound" -msgstr "Indicar chíos que conteñan imaxes con son" - -#: ../src\wxUI\dialogs\configuration.py:332 -msgid "Language for OCR" -msgstr "Lingua para o OCR" - -#: ../src\wxUI\dialogs\configuration.py:338 -msgid "API Key for SndUp" -msgstr "Clave da api para SNDUp" - -#: ../src\wxUI\dialogs\configuration.py:353 -msgid "{0} preferences" -msgstr "Preferencias do {0}" - -#: ../src\wxUI\dialogs\configuration.py:364 -msgid "Proxy" -msgstr "Proxy" - -#: ../src\wxUI\dialogs\configuration.py:373 -msgid "Feedback" -msgstr "Retroalimentación" - -#: ../src\wxUI\dialogs\configuration.py:377 -msgid "Buffers" -msgstr "Búferes" - -#: ../src\wxUI\dialogs\configuration.py:385 -msgid "Sound" -msgstr "son" - -#: ../src\wxUI\dialogs\configuration.py:389 -msgid "Extras" -msgstr "Extras" - -#: ../src\wxUI\dialogs\configuration.py:394 -msgid "Save" -msgstr "Gardar" - -#: ../src\wxUI\dialogs\filterDialogs.py:15 -msgid "Create a filter for this buffer" -msgstr "Crear un filtro para este búfer" - -#: ../src\wxUI\dialogs\filterDialogs.py:16 -msgid "Filter title" -msgstr "Título do filtro" - -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by word" -msgstr "Filtrar por palabra" - -#: ../src\wxUI\dialogs\filterDialogs.py:26 -msgid "Ignore tweets wich contain the following word" -msgstr "Ignorar chíos que conteñan a seguinte palabra" - -#: ../src\wxUI\dialogs\filterDialogs.py:27 -msgid "Ignore tweets without the following word" -msgstr "Ignorar chíos sen a seguinte palabra" - -#: ../src\wxUI\dialogs\filterDialogs.py:32 -msgid "word" -msgstr "palabra" - -#: ../src\wxUI\dialogs\filterDialogs.py:37 -msgid "Allow retweets" -msgstr "Permitir rechíos" - -#: ../src\wxUI\dialogs\filterDialogs.py:38 -msgid "Allow quoted tweets" -msgstr "Permitir chíos citados" - -#: ../src\wxUI\dialogs\filterDialogs.py:39 -msgid "Allow replies" -msgstr "Permitir respostas" - -#: ../src\wxUI\dialogs\filterDialogs.py:47 -msgid "Use this term as a regular expression" -msgstr "Usa este termo coma expresión regular" - -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by language" -msgstr "Filtrar por lingua" - -#: ../src\wxUI\dialogs\filterDialogs.py:50 -msgid "Load tweets in the following languages" -msgstr "Cargar chíos nas seguintes linguas" - -#: ../src\wxUI\dialogs\filterDialogs.py:51 -msgid "Ignore tweets in the following languages" -msgstr "Ignorar chíos nas seguintes linguas" - -#: ../src\wxUI\dialogs\filterDialogs.py:52 -msgid "Don't filter by language" -msgstr "Non filtrar por lingua" - -#: ../src\wxUI\dialogs\filterDialogs.py:63 -msgid "Supported languages" -msgstr "Linguas soportadas" - -#: ../src\wxUI\dialogs\filterDialogs.py:68 -msgid "Add selected language to filter" -msgstr "Engadir lingua selecionada para filtrar" - -#: ../src\wxUI\dialogs\filterDialogs.py:72 -msgid "Selected languages" -msgstr "Linguas selecionadas" - -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 -msgid "Remove" -msgstr "Borrar" - -#: ../src\wxUI\dialogs\filterDialogs.py:122 -msgid "Manage filters" -msgstr "Xestionar filtros" - -#: ../src\wxUI\dialogs\filterDialogs.py:124 -msgid "Filters" -msgstr "Filtros" - -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter" -msgstr "Filtro" - -#: ../src\wxUI\dialogs\find.py:12 -msgid "Find in current buffer" -msgstr "Atopar no búfer actual" - -#: ../src\wxUI\dialogs\find.py:13 -msgid "String" -msgstr "Cadea" - -#: ../src\wxUI\dialogs\lists.py:10 -msgid "Lists manager" -msgstr "Xestor de listaxes" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "List" -msgstr "Listaxe" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Members" -msgstr "Membros" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Owner" -msgstr "propietario" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "mode" -msgstr "Modo" - -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 -msgid "Create a new list" -msgstr "Crear nova listaxe" - -#: ../src\wxUI\dialogs\lists.py:21 -msgid "Open in buffer" -msgstr "Abrir en buffer" - -#: ../src\wxUI\dialogs\lists.py:51 -msgid "Viewing lists for %s" -msgstr "Vendo as listaxes de %s" - -#: ../src\wxUI\dialogs\lists.py:52 -msgid "Subscribe" -msgstr "Darse de alta" - -#: ../src\wxUI\dialogs\lists.py:53 -msgid "Unsubscribe" -msgstr "Darse de baixa" - -#: ../src\wxUI\dialogs\lists.py:64 -msgid "Name (20 characters maximun)" -msgstr "Nome (máximo 20 caracteres)" - -#: ../src\wxUI\dialogs\lists.py:74 -msgid "Mode" -msgstr "Modo" - -#: ../src\wxUI\dialogs\lists.py:75 -msgid "Public" -msgstr "Público" - -#: ../src\wxUI\dialogs\lists.py:76 -msgid "Private" -msgstr "Privado" - -#: ../src\wxUI\dialogs\lists.py:96 -msgid "Editing the list %s" -msgstr "Editando a listaxe %s" - -#: ../src\wxUI\dialogs\lists.py:107 -msgid "Select a list to add the user" -msgstr "Seleciona unha listaxe para engadir o usuario" - -#: ../src\wxUI\dialogs\lists.py:108 -msgid "Add" -msgstr "Engadir" - -#: ../src\wxUI\dialogs\lists.py:130 -msgid "Select a list to remove the user" -msgstr "Seleciona unha listaxe para quitar o usuario" - -#: ../src\wxUI\dialogs\lists.py:148 -msgid "Do you really want to delete this list?" -msgstr "¿Realmente desexas eliminar esta listaxe?" - -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "Chío &longo" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "Subir &imaxen..." - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 -msgid "Check &spelling..." -msgstr "Corrección de &ortografía..." - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "&Engadir audio..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "A&curtar URL" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 -msgid "&Expand URL" -msgstr "&Expandir URL" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 -msgid "&Translate..." -msgstr "&Traducir..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "Auto&completar usuarios" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "En&viar" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 -msgid "C&lose" -msgstr "&Pechar" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "&Destinatario" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "&Mencionar a todos" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Chío - %i caracteres" - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Descrición de imaxe" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "Rechouchíos: " - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Marcados como gústame:" - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Orixe:" - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -#, fuzzy -msgid "Date: " -msgstr "Data" - -#: ../src\wxUI\dialogs\message.py:405 -msgid "View" -msgstr "Ver" - -#: ../src\wxUI\dialogs\message.py:407 -msgid "Item" -msgstr "Elemento" - -#: ../src\wxUI\dialogs\search.py:13 -msgid "Search on Twitter" -msgstr "procurar en twitter" - -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 -msgid "&Search" -msgstr "&Procurar" - -#: ../src\wxUI\dialogs\search.py:21 -msgid "Tweets" -msgstr "Chíos" - -#: ../src\wxUI\dialogs\search.py:22 -msgid "Users" -msgstr "Usuarios" - -#: ../src\wxUI\dialogs\search.py:29 -msgid "&Language for results: " -msgstr "&Lingua para os resultados: " - -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 -msgid "any" -msgstr "calquera" - -#: ../src\wxUI\dialogs\search.py:37 -msgid "Results &type: " -msgstr "&Tipo de resultados: " - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 -msgid "Mixed" -msgstr "Misturado" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 -msgid "Recent" -msgstr "Recente" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 -msgid "Popular" -msgstr "Popular" - -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 -msgid "&OK" -msgstr "&Aceptar" - -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 -msgid "&Close" -msgstr "&Pechar" - -#: ../src\wxUI\dialogs\show_user.py:11 -msgid "Details" -msgstr "Detalles" - -#: ../src\wxUI\dialogs\show_user.py:16 -msgid "&Go to URL" -msgstr "&Ir á URL" - -#: ../src\wxUI\dialogs\trends.py:12 -msgid "View trending topics" -msgstr "Ver tendencias" - -#: ../src\wxUI\dialogs\trends.py:13 -msgid "Trending topics by" -msgstr "Tendencias por..." - -#: ../src\wxUI\dialogs\trends.py:15 -msgid "Country" -msgstr "País" - -#: ../src\wxUI\dialogs\trends.py:16 -msgid "City" -msgstr "Cidade" - -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 -msgid "&Location" -msgstr "&Ubicación" - -#: ../src\wxUI\dialogs\update_profile.py:9 -msgid "Update your profile" -msgstr "Actualizar o teu perfil" - -#: ../src\wxUI\dialogs\update_profile.py:11 -msgid "&Name (50 characters maximum)" -msgstr "&Nome (máximo 50 caracteres)" - -#: ../src\wxUI\dialogs\update_profile.py:22 -msgid "&Website" -msgstr "Sitio &web" - -#: ../src\wxUI\dialogs\update_profile.py:27 -msgid "&Bio (160 characters maximum)" -msgstr "&Biografía (máximo 160 caracteres)" - -#: ../src\wxUI\dialogs\update_profile.py:33 -msgid "Upload a &picture" -msgstr "Subir unha &foto" - -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 -msgid "&Update profile" -msgstr "A&ctualizar perfil" - -#: ../src\wxUI\dialogs\update_profile.py:76 -msgid "Upload a picture" -msgstr "Subir unha foto" - -#: ../src\wxUI\dialogs\update_profile.py:78 -msgid "Discard image" -msgstr "Descartar foto" - -#: ../src\wxUI\dialogs\urlList.py:5 -msgid "Select URL" -msgstr "Seleccionar URL" - -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 -msgid "&User" -msgstr "&Usuario" - -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 -msgid "&Autocomplete users" -msgstr "&Autocompletar usuarios" - -#: ../src\wxUI\dialogs\userActions.py:19 -msgid "&Follow" -msgstr "&Seguir" - -#: ../src\wxUI\dialogs\userActions.py:20 -msgid "U&nfollow" -msgstr "Dei&xar de seguir" - -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 -msgid "&Mute" -msgstr "si&lenciar" - -#: ../src\wxUI\dialogs\userActions.py:22 -msgid "Unmu&te" -msgstr "Desactivar &silenzo" - -#: ../src\wxUI\dialogs\userActions.py:23 -msgid "&Block" -msgstr "&Bloquear" - -#: ../src\wxUI\dialogs\userActions.py:24 -msgid "Unbl&ock" -msgstr "&Desbloquear" - -#: ../src\wxUI\dialogs\userActions.py:25 -msgid "&Report as spam" -msgstr "Reportar coma s&pam" - -#: ../src\wxUI\dialogs\userActions.py:26 -msgid "&Ignore tweets from this client" -msgstr "&Ignorar chíos deste cliente" - -#: ../src\wxUI\dialogs\userSelection.py:9 -msgid "Timeline for %s" -msgstr "Liña temporal de %s" - -#: ../src\wxUI\dialogs\userSelection.py:18 -msgid "Buffer type" -msgstr "Tipo de Búfer" - -#: ../src\wxUI\dialogs\userSelection.py:19 -msgid "&Tweets" -msgstr "&Chíos" - -#: ../src\wxUI\dialogs\userSelection.py:20 -msgid "&Likes" -msgstr "&Gústame" - -#: ../src\wxUI\dialogs\userSelection.py:21 -msgid "&Followers" -msgstr "&Seguidores" - -#: ../src\wxUI\dialogs\userSelection.py:22 -msgid "F&riends" -msgstr "&Amigos" - -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 -msgid "&Retweet" -msgstr "&Rechouchío" - -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 -msgid "Re&ply" -msgstr "&Responder" - -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 -msgid "&Like" -msgstr "&´Gústame" - -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 -msgid "&Unlike" -msgstr "&Non me gusta" - -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 -msgid "&Open URL" -msgstr "&Abrir URL..." - -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -#, fuzzy -msgid "&Open in Twitter" -msgstr "procurar en twitter" - -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 -msgid "&Play audio" -msgstr "re&producir audio" - -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 -msgid "&Show tweet" -msgstr "&Ver chío" - -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 -msgid "&Copy to clipboard" -msgstr "&Copiar ao portapapeis" - -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 -msgid "&Delete" -msgstr "&Eliminar" - -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 -msgid "&User actions..." -msgstr "&Accións de usuario..." - -#: ../src\wxUI\menus.py:39 -msgid "&Show direct message" -msgstr "&ver mensaxe directa" - -#: ../src\wxUI\menus.py:67 -msgid "&Show event" -msgstr "&ver evento" - -#: ../src\wxUI\menus.py:77 -msgid "Direct &message" -msgstr "Mensaxe &directa" - -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 -msgid "&View lists" -msgstr "&Ver listaxes" - -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 -msgid "Show user &profile" -msgstr "Ver &perfil do usuario" - -#: ../src\wxUI\menus.py:84 -msgid "&Show user" -msgstr "&ver usuarios silenciados" - -#: ../src\wxUI\menus.py:98 -msgid "&Tweet about this trend" -msgstr "&twittear sobre esta tendencia" - -#: ../src\wxUI\menus.py:100 -msgid "&Show item" -msgstr "&Ver chío" - -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 -msgid "&Global settings" -msgstr "Opcións &Globais" - -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 -msgid "Account se&ttings" -msgstr "&opcións de conta" - -#: ../src\wxUI\sysTrayIcon.py:37 -msgid "Update &profile" -msgstr "Actualizar &perfil" - -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "&Show / hide" -msgstr "A&Mosar / agochar" - -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 -msgid "&Documentation" -msgstr "&Documentación" - -#: ../src\wxUI\sysTrayIcon.py:40 -msgid "Check for &updates" -msgstr "Comprobar &actualizacións" - -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "&Exit" -msgstr "&Saír" - -#: ../src\wxUI\view.py:16 -msgid "&Manage accounts" -msgstr "&Xestionar contas" - -#: ../src\wxUI\view.py:18 -msgid "&Hide window" -msgstr "Agochar &xanela" - -#: ../src\wxUI\view.py:20 -msgid "&Lists manager" -msgstr "&Xestor de listaxes" - -#: ../src\wxUI\view.py:21 -msgid "&Edit keystrokes" -msgstr "Editar combinacións de &teclas" - -#: ../src\wxUI\view.py:24 -msgid "E&xit" -msgstr "&Saír" - -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 -msgid "&Tweet" -msgstr "&Chío" - -#: ../src\wxUI\view.py:34 -msgid "View &address" -msgstr "Ver &enderezo" - -#: ../src\wxUI\view.py:35 -msgid "View conversa&tion" -msgstr "Ver conversa&ción" - -#: ../src\wxUI\view.py:36 -msgid "Read text in picture" -msgstr "Ler texto en foto" - -#: ../src\wxUI\view.py:41 -msgid "&Actions..." -msgstr "&Accións..." - -#: ../src\wxUI\view.py:42 -msgid "&View timeline..." -msgstr "&Ver principal..." - -#: ../src\wxUI\view.py:43 -msgid "Direct me&ssage" -msgstr "&Mensaxe directa" - -#: ../src\wxUI\view.py:44 -msgid "&Add to list" -msgstr "&Engadir á listaxe" - -#: ../src\wxUI\view.py:45 -msgid "R&emove from list" -msgstr "&Quitar de listaxe" - -#: ../src\wxUI\view.py:48 -msgid "V&iew likes" -msgstr "&Ver marcados como gústame" - -#: ../src\wxUI\view.py:52 -msgid "&Update buffer" -msgstr "&Actualizar buffer" - -#: ../src\wxUI\view.py:53 -msgid "New &trending topics buffer..." -msgstr "Novo búfer &tendencias..." - -#: ../src\wxUI\view.py:54 -msgid "Create a &filter" -msgstr "Crear un &filtro" - -#: ../src\wxUI\view.py:55 -msgid "&Manage filters" -msgstr "&Xestionar filtros" - -#: ../src\wxUI\view.py:56 -msgid "Find a string in the currently focused buffer..." -msgstr "Atopar unha cadea no búfer enfocado actualmente..." - -#: ../src\wxUI\view.py:57 -msgid "&Load previous items" -msgstr "&Cargar elementos anteriores" - -#: ../src\wxUI\view.py:60 -msgid "&Autoread" -msgstr "&Autoleer" - -#: ../src\wxUI\view.py:61 -msgid "&Clear buffer" -msgstr "&Limpar buffer" - -#: ../src\wxUI\view.py:62 -msgid "&Destroy" -msgstr "&Destruir" - -#: ../src\wxUI\view.py:66 -msgid "&Seek back 5 seconds" -msgstr "&buscar 5 segudnos cara atrás" - -#: ../src\wxUI\view.py:67 -msgid "&Seek forward 5 seconds" -msgstr "&Buscar 5 segundos cara adiante" - -#: ../src\wxUI\view.py:72 -msgid "Sounds &tutorial" -msgstr "tutorial de &sons" - -#: ../src\wxUI\view.py:73 -msgid "&What's new in this version?" -msgstr "Qué hai de novo nesta &versión?" - -#: ../src\wxUI\view.py:74 -msgid "&Check for updates" -msgstr "Comprobar &actualizacións" - -#: ../src\wxUI\view.py:75 -msgid "&Report an error" -msgstr "Reportar un &erro" - -#: ../src\wxUI\view.py:76 -msgid "{0}'s &website" -msgstr "Sitio &web do {0}" - -#: ../src\wxUI\view.py:77 -msgid "Get soundpacks for TWBlue" -msgstr "" - -#: ../src\wxUI\view.py:78 -msgid "About &{0}" -msgstr "Acerca do &{0}" - -#: ../src\wxUI\view.py:81 -msgid "&Application" -msgstr "&Aplicación" - -#: ../src\wxUI\view.py:84 -msgid "&Buffer" -msgstr "&Buffer" - -#: ../src\wxUI\view.py:85 -msgid "&Audio" -msgstr "&Audio" - -#: ../src\wxUI\view.py:86 -msgid "&Help" -msgstr "A&xuda" - -#: ../src\wxUI\view.py:172 -msgid "Address" -msgstr "Enderezo" - -#: ../src\wxUI\view.py:203 -msgid "Update" -msgstr "Actualización" - -#: ../src\wxUI\view.py:203 -msgid "Your {0} version is up to date" -msgstr "A túa versión {0} está ó día" - -#~ msgid "Empty" -#~ msgstr "Valeiro" - -#~ msgid "One mention from %s " -#~ msgstr "Una mención de %s" - -#~ msgid "One tweet from %s" -#~ msgstr "Un chío de %s" - -#~ msgid "You've blocked %s" -#~ msgstr "Bloqueaches a %s" - -#~ msgid "You've unblocked %s" -#~ msgstr "Desbloqueaches a %s" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "%s(@%s) comezou a seguirte" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "Agora segues a %s(@%s)" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "deixaches de seguir a %s(@%s)" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "Marcaches como gústame: %s, %s" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "%s(@%s) marcouse como gústame: %s" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "Marcaches como non me gusta: %s, %s" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "%s(@%s) marcouse como non me gusta: %s" - -#~ msgid "You've created the list %s" -#~ msgstr "Creaches a listaxe %s" - -#~ msgid "You've deleted the list %s" -#~ msgstr "Eliminaches a listaxe %s" - -#~ msgid "You've updated the list %s" -#~ msgstr "actualizaches a listaxe %s" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "Engadiches a %s(@%s) á listaxe %s" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "%s(@%s) engadiute á listaxe %s" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "Quitaches a %s(@%s) da listaxe %s" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "%s(@%s) quitouche da listaxe %s" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "décheste de alta na listaxe %s, propiedade de %s(@%s)" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "%s(@%s) subscribíute á listaxe %s" - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "décheste de baixa da listaxe %s, propiedade de %s(@%s)" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Fuches dado de baixa da listaxe %s, propiedade de %s(@%s)" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "Rechouchiaches un rechouchío de %s(@%s): %s" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "%s(@%s) rechouchiou o teu rechouchío %s" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "Chamadas á API cando o stream inicie, unha chamada é igual a 200 tuits, " -#~ "dúas a 400 etc" - -#~ msgid "Unable to upload the audio" -#~ msgstr "Imposible subir o audio" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "Agardando pola autorización da conta..." - -#~ msgid "autodetect" -#~ msgstr "Autodetectar" - -#~ msgid "" -#~ "There's a new %s version available. Would you like to download it now?\n" -#~ "\n" -#~ " %s version: %s\n" -#~ "\n" -#~ "Changes:\n" -#~ "%s" -#~ msgstr "" -#~ "Hai dispoñible unha nova versión %s. ¿Gostaríache descargala agora?\n" -#~ "\n" -#~ " %s versión: %s\n" -#~ "\n" -#~ "Cambios:\n" -#~ "%s" - -#~ msgid "Start {0} after logging in windows" -#~ msgstr "Comezar {0} despois de autentificarte no windows" - -#~ msgid "" -#~ "If you have a SndUp account, enter your API Key here. If your API Key is " -#~ "invalid, {0} will fail to upload. If there is no API Key here, {0} will " -#~ "upload annonymously." -#~ msgstr "" -#~ "Se tes unha conta en SndUp, introduce a túa clave API aquí. Se a clave " -#~ "API non é correcta, o {0} non poderá subir nada. Se non pos ningunha " -#~ "clave api aquí, os audios subiranse de forma anónima ó {0}" - -#~ msgid "Disconnect your Pocket account" -#~ msgstr "Desconectar a túa conta de Pocket" - -#~ msgid "Connect your Pocket account" -#~ msgstr "Conectar a túa conta de Pocket" - -#~ msgid "Pocket Authorization" -#~ msgstr "Autorización de Pocket" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. You only need " -#~ "to do this once. Do you want to continue?" -#~ msgstr "" -#~ "A petición para se autorizar na túa conta de Twitter abrirase no " -#~ "navegador. Só necesitas facer isto unha vez. ¿Gostaríache continuar?" - -#~ msgid "Error during authorization. Try again later." -#~ msgstr "Erro durante a autorización. Téntao de novo máis tarde" - -#~ msgid "Services" -#~ msgstr "Servizos" - -#~ msgid "Contains" -#~ msgstr "Contén" - -#~ msgid "Doesn't contain" -#~ msgstr "Non contén" - -#~ msgid "" -#~ "You have successfully logged into Twitter with {0}. You can close this " -#~ "window now." -#~ msgstr "" -#~ "Autentificácheste con éxito no Twitter con {0}. Agora podes pechar esta " -#~ "ventá." - -#~ msgid "&Send" -#~ msgstr "&Enviar" - -#~ msgid "Spelling correction" -#~ msgstr "correción hortográfica" - -#~ msgid "Shorten URL" -#~ msgstr "Acortar URL" - -#~ msgid "Expand URL" -#~ msgstr "Expandir URL" - -#~ msgid "Send" -#~ msgstr "Enviar" - -#~ msgid "unavailable" -#~ msgstr "Non dispoñible" - -#~ msgid "Search" -#~ msgstr "procurar" - -#~ msgid "Update profile" -#~ msgstr "Actualizar perfil" - -#~ msgid "Follow" -#~ msgstr "Seguir" - -#~ msgid "Mute" -#~ msgstr "silenciar" - -#~ msgid "Block" -#~ msgstr "Bloquear" - -#~ msgid "Report as spam" -#~ msgstr "Reportar coma spam" - -#~ msgid "Favourites" -#~ msgstr "Favoritos" - -#~ msgid "Favourites timeline for {}" -#~ msgstr "Liñas temporais de favoritos para {0}" - -#~ msgid "Tweet favourited." -#~ msgstr "Chío posto en favoritos." - -#~ msgid "Mark as favourite" -#~ msgstr "Marcar coma favorito" - -#~ msgid "Remove from favourites" -#~ msgstr "Quitar de favoritos" - -#~ msgid "You've added to favourites: %s, %s" -#~ msgstr "Marcaches coma favorito: %s, %s" - -#~ msgid "%s(@%s) has marked as favourite: %s" -#~ msgstr "%s(@%s) marcou coma favorito: %s" - -#~ msgid "You've removed from favourites: %s, %s" -#~ msgstr "Eliminaches dos teus favoritos: %s, %s" - -#~ msgid "%s(@%s) has removed from favourites: %s" -#~ msgstr "%s(@%s) quitou dos seus favoritos: %s" - -#~ msgid "Favourites: " -#~ msgstr "Favoritos: " - -#~ msgid "Add to &favourites" -#~ msgstr "&Marcar coma favorito" - -#~ msgid "Remove from favo&urites" -#~ msgstr "&Quitar de favoritos" - -#~ msgid "V&iew favourites" -#~ msgstr "Mostrar &favoritos" - -#~ msgid "Opening media..." -#~ msgstr "Abrindo medios..." - -#~ msgid "Add a new ignored client" -#~ msgstr "Engadir un novo cliente rexeitado" - -#~ msgid "Do you really want to delete this timeline?" -#~ msgstr "¿Realmente desexas eliminar esta liña temporal?" - -#~ msgid "Autocomplete users\\342\\200\\231 settings" -#~ msgstr "Autocompletar usuarios\\342\\200\\231 settings" - -#~ msgid "Set the autocomplete function" -#~ msgstr "Configurar a función de autocompletado" - -#~ msgid "Relative times" -#~ msgstr "Tempos relativos" - -#~ msgid "" -#~ "API calls when the stream is started (One API call equals to 200 tweetts, " -#~ "two API calls equals 400 tweets, etc):" -#~ msgstr "" -#~ "Chamadas á API cando o stream inicie, unha chamada é igual a 200 tuits, " -#~ "dúas a 400 etc" - -#~ msgid "" -#~ "Inverted buffers: The newest tweets will be shown at the beginning of the " -#~ "lists while the oldest at the end" -#~ msgstr "" -#~ "Buffers invertidos. Os novos chíos mostraranse ao comezo da listaxe e os " -#~ "máis vellos ao final." - -#~ msgid "" -#~ "The authorization request will be opened in your browser. Copy the code " -#~ "from Dropbox and paste it into the text box which will appear. You only " -#~ "need to do this once." -#~ msgstr "" -#~ "A petición de autorización abrirase no teu navegador. Copia o código " -#~ "dende Dropbox e pégao na caixa de texto que aparecerá. Só necesitas facer " -#~ "isto unha vez." - -#~ msgid "Verification code" -#~ msgstr "Código de verificación" - -#~ msgid "Error during authorisation. Try again later." -#~ msgstr "Erro durante a autorización. Téntao de novo máis tarde" - -#~ msgid "TW Blue preferences" -#~ msgstr "Preferencias do TW Blue" - -#~ msgid "Show other buffers" -#~ msgstr "Mostrar outros buffers" - -#~ msgid "JPG images" -#~ msgstr "Imaxes JPG" - -#~ msgid "GIF images" -#~ msgstr "Imaxes GIF" - -#~ msgid "PNG Images" -#~ msgstr "Imaxes PNG" - -#~ msgid "Select an URL" -#~ msgstr "Seleciona unha URL" - -#~ msgid "Not actionable." -#~ msgstr "Non accionable." - -#, fuzzy -#~ msgid "" -#~ "Perform secondary interact action (open URL in browser if Codeofdusk's " -#~ "intelegent audio tweet handlers enabled, play audio if disabled." -#~ msgstr "" -#~ "Perform secondary interact action (open URL in browser if Codeofdusk's " -#~ "intelegent audio tweet handlers enabled, play audio if disabled." - -#~ msgid "This account is not logged in twitter." -#~ msgstr "Esta conta non está autentificada en twitter." - -#~ msgid "{0}: This account is not logged in twitter." -#~ msgstr "{0}: Esta conta non está rexistrada en twitter." - -#~ msgid "Global mute off" -#~ msgstr "silencio xeral inactivo" - -#~ msgid "User-defined buffer created." -#~ msgstr "Creouse un novo búfer" - -#~ msgid "User-defined buffer destroied." -#~ msgstr "Eliminouse un novo búfer" - -#~ msgid "Someone's favourites have been updated." -#~ msgstr "os favoritos de alguén actualizáronse" - -#~ msgid "Mension received." -#~ msgstr "Mención recibida" - -#~ msgid "A trending topic buffer has been updated." -#~ msgstr "Actualizouse o búfer de tendencias." - -#~ msgid "New tweet in user-defined buffer." -#~ msgstr "hai un novo chío no buffer definido do usuario" - -#~ msgid "Mis-spelled word: %s" -#~ msgstr "palabra mal escrita: %s" - -#~ msgid "Mis-spelled word" -#~ msgstr "palabra mal escrita" - -#~ msgid "Finished" -#~ msgstr "Rematado" - -#~ msgid "The spelling review has finished." -#~ msgstr "a revisión ortográfica rematou" - -#~ msgid "" -#~ "Do you really want to delete this message? It will be eliminated from " -#~ "Twitter as well." -#~ msgstr "" -#~ "Realmente queres eliminar esta mensaxe? Eliminarase tamén de twitter" - -#~ msgid "Show followers" -#~ msgstr "Mostrar seguidores" - -#~ msgid "Show friends" -#~ msgstr "Mostrar amigos" - -#~ msgid "Show favourites" -#~ msgstr "Mostrar favoritos" - -#~ msgid "Show blocked users" -#~ msgstr "Mostrar usuarios bloqueados" - -#~ msgid "Show muted users" -#~ msgstr "Mostrar usuarios silenciados" - -#~ msgid "Show events" -#~ msgstr "Mostrar eventos" - -#~ msgid "" -#~ "The authorisation request will be shown on your browser. Copy the code " -#~ "tat Dropbox will provide and, in the text box that will appear on TW " -#~ "Blue, paste it. This code is necessary to continue. You only need to do " -#~ "it once." -#~ msgstr "" -#~ "Abrirase o teu navegador web coa solicitude que precisas a fin de iniciar " -#~ "sesión. Copia e pega no cadro de edición o código que dropbox vaiche " -#~ "proporcionar para poder iniciar sesión. Isto só terás que facelo unha vez" - -#~ msgid "Authorisation" -#~ msgstr "Autorización" - -#~ msgid "Change to the next account" -#~ msgstr "Cambiar a seguinte conta" - -#~ msgid "Change to the previous account" -#~ msgstr "Cambiar á conta anterior" - -#~ msgid "Remove buffer" -#~ msgstr "Borrar buffer" - -#~ msgid "" -#~ "Open URL on the current tweet, or further information for a friend or " -#~ "follower" -#~ msgstr "" -#~ "Abrir URL no chío anterior ou solicitar máis información en buffers de " -#~ "usuarios" - -#~ msgid "Go to the first element on the list" -#~ msgstr "Ir ao primeiro elemento da listaxe" - -#~ msgid "Go to the last element on the list" -#~ msgstr "Ir ao derradeiro elemento da listaxe" - -#~ msgid "Move 20 elements up on the current list" -#~ msgstr "Moverse 20 elementos hacia arriba na listaxe actual" - -#~ msgid "Move 20 elements down on the current list" -#~ msgstr "moverse 20 elementos hacia abaixo na listaxe actual" - -#~ msgid "Remove a tweet or direct message" -#~ msgstr "Eliminar chío ou mensaxe directa" - -#~ msgid "Globally mute/unmute the current account" -#~ msgstr "Activar ou desactivar o silencio global do tw blue" - -#~ msgid "load previous items to any buffer" -#~ msgstr "Cargar elementos anteriores para un bufer" - -#~ msgid "" -#~ "The request for the required Twitter authorisation to continue will be " -#~ "opened on your browser. You only need to do it once. Would you like to " -#~ "autorhise a new account now?" -#~ msgstr "" -#~ "Abrirase o navegador web coa solicitude de autorización de twitter que " -#~ "precisas para continuar. Só precisas facer isto unha vez. Queres " -#~ "actualizar unha nova conta agora?" - -#~ msgid "" -#~ "Your access token is invalid or the authorisation has failed. Please try " -#~ "again." -#~ msgstr "" -#~ "O código de acceso é incorrecto ou a autorización fallou. Por favor, " -#~ "inténtao de novo." - -#~ msgid "" -#~ "%s (@%s). %s followers, %s friends, %s tweets. Last tweet on %s. Joined " -#~ "Twitter on %s" -#~ msgstr "" -#~ "%s (@%s). %s seguidores, %s amigos, %s chíos. Último chío o %s. Uniuse a " -#~ "Twitter o %s" - -#~ msgid "" -#~ "The application requires to be restarted to save these changes. Press OK " -#~ "to do it now." -#~ msgstr "" -#~ "Para que estes cambios teñan efecto, a aplicación debe ser reiniciada. " -#~ "Preme aceptar para facelo agora." - -#~ msgid "" -#~ "Dropbox will open in your browser. After you log into Dropbox, an " -#~ "authorization code will be generated. Please paste it into the field " -#~ "which will appear. You only need to do this once." -#~ msgstr "" -#~ "Abriráse Dropbox no teu navegador. Despois de que te autentifiques no " -#~ "Dropbox, xenerarase un código de autorización. Por favor pégao no campo " -#~ "que aparecerá. Só necesitas facer esto unha vez." - -#~ msgid "View &trending topics" -#~ msgstr "Ver &tendencias" - -#~ msgid "&Unfollow" -#~ msgstr "&Deixar de seguir" - -#~ msgid "U&nmute" -#~ msgstr "Desactivar si&lencio" - -#~ msgid "Unb&lock" -#~ msgstr "Des&bloquear" - -#~ msgid "&Timeline" -#~ msgstr "Li&ña temporal" - -#~ msgid "&Autoread tweets for this buffer" -#~ msgstr "&Ler automáticamente chíos para este buffer" - -#~ msgid "&Remove buffer" -#~ msgstr "&Borrar buffer" - -#~ msgid "Stop recording" -#~ msgstr "Deter grabación" - -#~ msgid "The tweet may contain a playable audio" -#~ msgstr "O chío TEN QUE CONTER UN AUDIO VÁLIDO" - -#~ msgid "A timeline has been created" -#~ msgstr "creouse unha liña temporal" - -#~ msgid "A timeline has been deleted" -#~ msgstr "borrouse unha liña temporal" - -#~ msgid "You've received a direct message" -#~ msgstr "Recibiches unha mensaxe directa" - -#~ msgid "You've sent a direct message" -#~ msgstr "Enviaches unha mensaxe directa" - -#~ msgid "A bug has happened" -#~ msgstr "ocorreu un erro" - -#~ msgid "You've added a tweet to your favourites" -#~ msgstr "Engadiches un chío aos teus favoritos" - -#~ msgid "The tweet has coordinates to determine its location" -#~ msgstr "O chío contén coordenadas para determinar a súa ubicación" - -#~ msgid "There are no more tweets to read" -#~ msgstr "non hai máis chíos para ler" - -#~ msgid "A list has a new tweet" -#~ msgstr "unha listaxe ten un twit novo" - -#~ msgid "You can't add any more characters on the tweet" -#~ msgstr "non podes engadir máis caracteres ao chío" - -#~ msgid "You've been mentioned " -#~ msgstr "fuches mencionado" - -#~ msgid "A new event has happened" -#~ msgstr "ocorreu un novo evento" - -#~ msgid "You've replied" -#~ msgstr "respondiches" - -#~ msgid "You've sent a tweet" -#~ msgstr "enviaches un chío" - -#~ msgid "There's a new tweet in a timeline" -#~ msgstr "hai un novo chío nunha liña temporal" - -#~ msgid "You have a new follower" -#~ msgstr "tes un novo seguidor" - -#~ msgid "You've turned the volume up or down" -#~ msgstr "cambiaches o volume" - -#~ msgid "" -#~ "It seems as though the currently used sound pack needs an update. %i " -#~ "fails are still be required to use this function. Make sure to obtain the " -#~ "needed lacking sounds or to contact with the sound pack developer." -#~ msgstr "" -#~ "parece que o paquete de sons utilizado precisa de ser actualizado. Os " -#~ "arquivos %i son necesarios para esta función. Asegúrate de ter os sons " -#~ "necesarios ou contacta co creador do paquete" - -#~ msgid "See the users list" -#~ msgstr "Ver listaxe de usuarios" - -#~ msgid "Do you really want to delete this message?" -#~ msgstr "¿Realmente queres eliminar esta mensaxe?" - -#~ msgid "Unable to play audio." -#~ msgstr "Imposible reproducir audio" - -#~ msgid "Do you really want to delete this favourites timeline?" -#~ msgstr "Realmente desexas eliminar esta liña temporal de favoritos?" - -#~ msgid "&Mention" -#~ msgstr "M&ención" - -#~ msgid "Announce" -#~ msgstr "Anuncio" - -#~ msgid "" -#~ "Do you really want to empty this buffer? It's items will be removed from " -#~ "the list" -#~ msgstr "" -#~ "Realmente queres borrar o contido deste buffer? Os elementos eliminaranse " -#~ "da listaxe" - -#~ msgid "Do you really want to delete this search term?" -#~ msgstr "Realmente queres borrar este termo de procura?" - -#~ msgid "ask before exiting TwBlue?" -#~ msgstr "Preguntar ao saír de TWBlue" - -#~ msgid "Activate the auto-start of the invisible interface" -#~ msgstr "activar xanela invisible ao iniciar" - -#~ msgid "Global mute" -#~ msgstr "silencio xeral" - -#~ msgid "friends" -#~ msgstr "Amigos" - -#~ msgid "Favorites" -#~ msgstr "Favoritos" - -#~ msgid "You've muted to %s" -#~ msgstr "Silenciaches a %s" - -#~ msgid "You've unmuted to %s" -#~ msgstr "Desactivaches o silencio a %s" - -#~ msgid "This list is arready opened." -#~ msgstr "Esta listaxe xa está aberta." - -#~ msgid "List for %s" -#~ msgstr "Listaxe %s" - -#~ msgid "Uploading..." -#~ msgstr "Subindo..." - -#~ msgid "Men&tion all" -#~ msgstr "Mencionar &a todos" - -#~ msgid "This user does not exist on Twitter" -#~ msgstr "Ese usuario non existe en Twitter" - -#~ msgid "S&witch account" -#~ msgstr "Cambiar &conta" - -#~ msgid "&Preferences" -#~ msgstr "&Preferencias" - -#~ msgid "About &TW Blue" -#~ msgstr "Sobre &TW Blue" - -#~ msgid "" -#~ "An error occurred while looking for an update. It may be due to any " -#~ "problem either on our server or on your DNS servers. Please, try again " -#~ "later." -#~ msgstr "" -#~ "Ocorreu un erro ao buscar unha actualización. Isto pode deberse a un erro " -#~ "no noso servidor ou nos teus servidores DNS. Por favor, inténtao de novo " -#~ "máis tarde." - -#~ msgid "Sent" -#~ msgstr "Enviados" - -#~ msgid "%s favourites from %s" -#~ msgstr "%s favoritos de %s" - -#~ msgid "Streams disconnected. TW Blue will try to reconnect in a minute." -#~ msgstr "Streams desconectados. TW blue tentará conectarse nun minuto" - -#~ msgid "Reconnecting streams..." -#~ msgstr "Conectando os streams..." - -#~ msgid "search users for %s" -#~ msgstr "Procurar usuarios para %s" - -#~ msgid "Do you really want to close TW Blue?" -#~ msgstr "¿Realmente desexas saír de TW Blue?" - -#~ msgid "Exiting..." -#~ msgstr "Saíndo..." - -#~ msgid "Error while adding to favourites." -#~ msgstr "Erro ao marcar coma favorito" - -#~ msgid "Error while removing from favourites." -#~ msgstr "Erro ao quitar de favoritos" - -#~ msgid "Individual timeline" -#~ msgstr "Liña temporal individual" - -#~ msgid "List of favourites" -#~ msgstr "Listaxe de favoritos" - -#~ msgid "Existing list" -#~ msgstr "Listaxe existente " - -#~ msgid "" -#~ "There's already a list of favourites for this user. You can't create " -#~ "another." -#~ msgstr "" -#~ "Xa hai unha listaxe de favoritos aberta de este usuario. Non se pode " -#~ "abrir outra" - -#~ msgid "" -#~ "This user has no favourites. You can't create a list of favourites for " -#~ "this user." -#~ msgstr "" -#~ "Este usuario non ten favoritos. Non é posible crear unha listaxe de " -#~ "favoritos para el" - -#~ msgid "%s" -#~ msgstr "%s" - -#~ msgid "Documentation" -#~ msgstr "Documentación" - -#~ msgid "Translation" -#~ msgstr "Tradución" - -#~ msgid "Move up one tweet in the conversation" -#~ msgstr "Ir un chío hacia arriba na conversa" - -#~ msgid "Move down one tweet in the conversation" -#~ msgstr "ir un chío hacia abaixo na conversa" - -#~ msgid "Show the graphical interface" -#~ msgstr "Mostrar a interfaz gráfica" - -#~ msgid "Reply to a tweet" -#~ msgstr "Responder a un chío" - -#~ msgid "Empty the buffer removing all the elements" -#~ msgstr "Vaciar buffer quitando todos os elementos" - -#~ msgid "Listen the current message" -#~ msgstr "Escoitar a mensaxe actual" - -#~ msgid "Get location of any tweet" -#~ msgstr "Obter ubicación dun chío" - -#~ msgid "Creates a buffer for displaying trends for a desired place" -#~ msgstr "Crear un buffer para mostrar tendencias dun lugar elixido." - -#~ msgid "Select a twitter account to start TW Blue" -#~ msgstr "Seleciona unha conta de twitter para iniciar o TW Blue" - -#~ msgid "Remove session" -#~ msgstr "Eliminar sesión" - -#~ msgid "One tweet from %s in the list %s" -#~ msgstr "Un chío de %s na listaxe %s" - -#~ msgid "One direct message" -#~ msgstr "Unha mensaxe directa" - -#~ msgid "About a week ago" -#~ msgstr "Fai unha semana" - -#~ msgid "About {} weeks ago" -#~ msgstr "Fai {} semanas" - -#~ msgid "A month ago" -#~ msgstr "Fai un mes" - -#~ msgid "About {} months ago" -#~ msgstr "Fai {} meses" - -#~ msgid "About a year ago" -#~ msgstr "Fai un ano" - -#~ msgid "About {} years ago" -#~ msgstr "Fai {} anos" - -#~ msgid "About 1 day ago" -#~ msgstr "Fai un día" - -#~ msgid "About {} days ago" -#~ msgstr "Fai {} días" - -#~ msgid "just now" -#~ msgstr "Agora mesmo" - -#~ msgid "{} seconds ago" -#~ msgstr "Fai {} segundos" - -#~ msgid "1 minute ago" -#~ msgstr "Fai un minuto" - -#~ msgid "{} minutes ago" -#~ msgstr "fai {} minutos" - -#~ msgid "About 1 hour ago" -#~ msgstr "Fai unha hora" - -#~ msgid "About {} hours ago" -#~ msgstr "Fai {} horas" - -#~ msgid "January" -#~ msgstr "Xaneiro" - -#~ msgid "February" -#~ msgstr "Febreiro" - -#~ msgid "March" -#~ msgstr "Marzo" - -#~ msgid "April" -#~ msgstr "Abril" - -#~ msgid "June" -#~ msgstr "Xuño" - -#~ msgid "July" -#~ msgstr "Xullo" - -#~ msgid "August" -#~ msgstr "Agosto" - -#~ msgid "September" -#~ msgstr "Setembro" - -#~ msgid "October" -#~ msgstr "Outubro" - -#~ msgid "November" -#~ msgstr "Novembro" - -#~ msgid "December" -#~ msgstr "Decembro" - -#~ msgid "Sunday" -#~ msgstr "Domingo" - -#~ msgid "Monday" -#~ msgstr "Luns" - -#~ msgid "Tuesday" -#~ msgstr "Martes" - -#~ msgid "Wednesday" -#~ msgstr "Mércores" - -#~ msgid "Thursday" -#~ msgstr "Xoves" - -#~ msgid "Friday" -#~ msgstr "Venres" - -#~ msgid "Saturday" -#~ msgstr "Sábado" - -#~ msgid "sun" -#~ msgstr "Dom" - -#~ msgid "mon" -#~ msgstr "Lun" - -#~ msgid "tue" -#~ msgstr "Mar" - -#~ msgid "wed" -#~ msgstr "Mer" - -#~ msgid "thu" -#~ msgstr "Xov" - -#~ msgid "fri" -#~ msgstr "Ven" - -#~ msgid "sat" -#~ msgstr "Sab" - -#~ msgid "jan" -#~ msgstr "Xan" - -#~ msgid "feb" -#~ msgstr "Feb" - -#~ msgid "mar" -#~ msgstr "Mar" - -#~ msgid "apr" -#~ msgstr "Abr" - -#~ msgid "may" -#~ msgstr "Mai" - -#~ msgid "jun" -#~ msgstr "Xun" - -#~ msgid "jul" -#~ msgstr "Xul" - -#~ msgid "aug" -#~ msgstr "Ago" - -#~ msgid "sep" -#~ msgstr "Set" - -#~ msgid "oct" -#~ msgstr "Out" - -#~ msgid "nov" -#~ msgstr "Nov" - -#~ msgid "dec" -#~ msgstr "Dec" - -#~ msgid "%A, %B %d, %Y at %I:%M:%S %p" -#~ msgstr "%A, %d de %B do %Y ás %I:%M:%S %p" - -#~ msgid "Your TW Blue version is up to date" -#~ msgstr "A túa versión de TW Blue está actualizada" - -#~ msgid "Connection error. Try again later." -#~ msgstr "Erro de conexión. Téntao de novo máis tarde" - -#~ msgid "View members" -#~ msgstr "Ver membros" - -#~ msgid "View subscribers" -#~ msgstr "Ver suscritores" - -#~ msgid "Ouner" -#~ msgstr "propietario" - -#~ msgid "Successfully following %s" -#~ msgstr "Éxito seguindo a %s" - -#~ msgid "%s has been reported as spam" -#~ msgstr "%s foi reportado coma spam" - -#~ msgid "%s has been blocked" -#~ msgstr "%s foi bloqueado" - -#~ msgid "User's information" -#~ msgstr "Detalles do usuario" - -#~ msgid "You've unblock %s" -#~ msgstr "Desbloqueaches a %s" - -#~ msgid "Clear" -#~ msgstr "Limpiar" diff --git a/src/locales/it/LC_MESSAGES/twblue.po b/src/locales/it/LC_MESSAGES/twblue.po deleted file mode 100644 index bcde10fc..00000000 --- a/src/locales/it/LC_MESSAGES/twblue.po +++ /dev/null @@ -1,4157 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: TW Blue 0.80\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2019-03-23 01:38+0100\n" -"Last-Translator: Chris Leo Mameli \n" -"Language-Team: Christian Leo Mameli\n" -"Language: it\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-KeywordsList: _;gettext;gettext_noop\n" -"X-Poedit-Basepath: .\n" -"X-Poedit-SourceCharset: UTF-8\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.6.3\n" - -#: ../src\controller\attach.py:23 -msgid "Photo" -msgstr "Foto" - -#: ../src\controller\buffers\baseBuffers.py:95 -msgid "This action is not supported for this buffer" -msgstr "Questa azione non è supportata per questo buffer" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 -msgid "Home" -msgstr "Cronologia Principale" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 -msgid "Mentions" -msgstr "Menzioni" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 -msgid "Direct messages" -msgstr "Messaggi Ricevuti" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 -msgid "Sent direct messages" -msgstr "Messaggi inviati" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 -msgid "Sent tweets" -msgstr "Tweet inviati" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 -msgid "Likes" -msgstr "Mi piace" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 -msgid "Followers" -msgstr "Followers" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "Following" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 -msgid "Blocked users" -msgstr "Utenti bloccati" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 -msgid "Muted users" -msgstr "Utenti silenziati" - -#: ../src\controller\buffers\twitterBuffers.py:75 -msgid "{username}'s timeline" -msgstr "Cronologia di {username}" - -#: ../src\controller\buffers\twitterBuffers.py:77 -msgid "{username}'s likes" -msgstr "Like di {username}" - -#: ../src\controller\buffers\twitterBuffers.py:79 -msgid "{username}'s followers" -msgstr "Follower di {username}" - -#: ../src\controller\buffers\twitterBuffers.py:81 -msgid "{username}'s friends" -msgstr "Amici di {username}" - -#: ../src\controller\buffers\twitterBuffers.py:83 -msgid "Unknown buffer" -msgstr "Buffer sconosciuto" - -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 -msgid "Tweet" -msgstr "Tweet" - -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 -msgid "Write the tweet here" -msgstr "Scrivi il tweet qui" - -#: ../src\controller\buffers\twitterBuffers.py:194 -msgid "New tweet in {0}" -msgstr "Nuovo tweet in {0}" - -#: ../src\controller\buffers\twitterBuffers.py:197 -msgid "{0} new tweets in {1}." -msgstr "{0} nuovi tweet in {1}." - -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 -msgid "%s items retrieved" -msgstr "%s Elementi recuperati" - -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "Impossivile eliminare. Questo buffer non è una Cronologia;" - -#: ../src\controller\buffers\twitterBuffers.py:402 -msgid "Reply to {arg0}" -msgstr "Rispondi a {arg0}" - -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 -msgid "Reply" -msgstr "Rispondi" - -#: ../src\controller\buffers\twitterBuffers.py:405 -msgid "Reply to %s" -msgstr "Rispondi a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Messaggio diretto a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 -msgid "New direct message" -msgstr "Nuovo messaggio diretto" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Add your comment to the tweet" -msgstr "Aggiungi il tuo commento al tweet" - -#: ../src\controller\buffers\twitterBuffers.py:500 -msgid "Quote" -msgstr "Citazione..." - -#: ../src\controller\buffers\twitterBuffers.py:572 -msgid "Opening URL..." -msgstr "Collegamento alla pagina..." - -#: ../src\controller\buffers\twitterBuffers.py:607 -msgid "User details" -msgstr "Dettagli utente" - -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 -msgid "Opening item in web browser..." -msgstr "Apertura dell'articolo nel browser..." - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -msgid "Mention to %s" -msgstr "Menziona a %s" - -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 -msgid "Mention" -msgstr "Menziona" - -#: ../src\controller\buffers\twitterBuffers.py:728 -msgid "{0} new direct messages." -msgstr "{0} Nuovo messaggio diretto" - -#: ../src\controller\buffers\twitterBuffers.py:731 -msgid "This action is not supported in the buffer yet." -msgstr "Questa azione non è supportata per questo buffer" - -#: ../src\controller\buffers\twitterBuffers.py:741 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" -"Non si possono aggiungere ulteriori elementi in questo buffer. Utilizzare il " -"buffer per i messaggi diretti." - -#: ../src\controller\buffers\twitterBuffers.py:983 -msgid "{0} new followers." -msgstr "{0} Nuovo follower." - -#: ../src\controller\buffers\twitterBuffers.py:1266 -msgid "This action is not supported in the buffer, yet." -msgstr "Questa azione non è supportata per questo buffer" - -#: ../src\controller\mainController.py:273 -msgid "Ready" -msgstr "Pronto" - -#: ../src\controller\mainController.py:345 -msgid "Timelines" -msgstr "Cronologie di..." - -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 -msgid "Timeline for {}" -msgstr "Cronologia di {}" - -#: ../src\controller\mainController.py:352 -msgid "Likes timelines" -msgstr "Cronologie Favorite" - -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 -msgid "Likes for {}" -msgstr "A {} Piace" - -#: ../src\controller\mainController.py:359 -msgid "Followers' Timelines" -msgstr "Cronologie dei followers" - -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 -msgid "Followers for {}" -msgstr "Followers di {}" - -#: ../src\controller\mainController.py:366 -msgid "Friends' Timelines" -msgstr "Cronologie degli amici" - -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 -msgid "Friends for {}" -msgstr "Amici di {}" - -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 -msgid "Lists" -msgstr "Liste" - -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 -msgid "List for {}" -msgstr "Lista per {}" - -#: ../src\controller\mainController.py:381 -msgid "Searches" -msgstr "Ricerca" - -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 -msgid "Search for {}" -msgstr "Cerca per {0}" - -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 -msgid "Trending topics for %s" -msgstr "Argomenti di tendenza per %s" - -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "" -"Nessuna sessione focalizzata attualmente. Focalizzare una sessione con " -"l'apposito comando." - -#: ../src\controller\mainController.py:465 -msgid "Empty buffer." -msgstr "Svuota Elenco" - -#: ../src\controller\mainController.py:472 -msgid "{0} not found." -msgstr "{0} Non trovato." - -#: ../src\controller\mainController.py:482 -msgid "Filters cannot be applied on this buffer" -msgstr "Il filtro non è supportato in questo buffer" - -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 -msgid "Select the user" -msgstr "Seleziona l'utente" - -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -msgid "MMM D, YYYY. H:m" -msgstr "MMM D, YYYY. H:m" - -#: ../src\controller\mainController.py:934 -msgid "Conversation with {0}" -msgstr "Conversazione con {0}" - -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 -msgid "There are no coordinates in this tweet" -msgstr "Non ci sono coordinate in questo Tweet" - -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "Nessun risultato per la ricerca in questo tweet" - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 -msgid "Error decoding coordinates. Try again later." -msgstr "Errore durante l'autorizzazione. Riprovare più tardi." - -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 -msgid "%s, %s of %s" -msgstr "%s, %s di %s" - -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 -msgid "%s. Empty" -msgstr "%s. Vuoto" - -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 -msgid "{0}: This account is not logged into Twitter." -msgstr "{0}: Questo account non è connesso a Twitter." - -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 -msgid "%s. %s, %s of %s" -msgstr "%s. %s, %s di %s" - -#: ../src\controller\mainController.py:1170 -msgid "{0}: This account is not logged into twitter." -msgstr "{0}: Questo account non è connesso a Twitter." - -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Notifiche" - -#: ../src\controller\mainController.py:1393 -msgid "This list is already opened" -msgstr "Questa lista è già aperta" - -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "Errore durante la connessione al server. Per favore, riprova più tardi" - -#: ../src\controller\mainController.py:1475 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "Attivata la lettura automatica per i nuovi tweet in questo buffer;" - -#: ../src\controller\mainController.py:1478 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "Disattivata la lettura automatica per questo buffer;" - -#: ../src\controller\mainController.py:1485 -msgid "Session mute on" -msgstr "Sessione mute on" - -#: ../src\controller\mainController.py:1488 -msgid "Session mute off" -msgstr "Sessione mute off" - -#: ../src\controller\mainController.py:1496 -msgid "Buffer mute on" -msgstr "Disattivato" - -#: ../src\controller\mainController.py:1499 -msgid "Buffer mute off" -msgstr "Attivato" - -#: ../src\controller\mainController.py:1522 -msgid "Copied" -msgstr "Copiato" - -#: ../src\controller\mainController.py:1549 -msgid "Unable to update this buffer." -msgstr "Impossibile aggiornare questo buffer:" - -#: ../src\controller\mainController.py:1552 -msgid "Updating buffer..." -msgstr "Buffer aggiornato..." - -#: ../src\controller\mainController.py:1555 -msgid "{0} items retrieved" -msgstr "{0} Elementi recuperati" - -#: ../src\controller\mainController.py:1572 -msgid "Invalid buffer" -msgstr "Buffer non valido " - -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "Questo tweet non contiene immagini" - -#: ../src\controller\mainController.py:1579 -msgid "Picture {0}" -msgstr "Immagine {0}" - -#: ../src\controller\mainController.py:1580 -msgid "Select the picture" -msgstr "Seleziona immagine" - -#: ../src\controller\mainController.py:1596 -msgid "Unable to extract text" -msgstr "Impossibile estrarre il testo" - -#: ../src\controller\messages.py:54 -msgid "Translated" -msgstr "Tradotto" - -#: ../src\controller\messages.py:61 -msgid "There's no URL to be shortened" -msgstr "Nessun URL da accorciare." - -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 -msgid "URL shortened" -msgstr "URL accorciato." - -#: ../src\controller\messages.py:80 -msgid "There's no URL to be expanded" -msgstr "Nessun URL da espandere" - -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 -msgid "URL expanded" -msgstr "URL espanso" - -#: ../src\controller\messages.py:104 -msgid "%s - %s of %d characters" -msgstr "%s - %s di %d caratteri" - -#: ../src\controller\messages.py:108 -msgid "%s - %s characters" -msgstr "%s - %s Caratteri" - -#: ../src\controller\messages.py:262 -msgid "View item" -msgstr "Visualizza elemento" - -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Collegamento diretto" - -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Ask" -msgstr "Richiesta" - -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet without comments" -msgstr "Retweet senza commenti" - -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 -msgid "Retweet with comments" -msgstr "Retweet con commenti" - -#: ../src\controller\settings.py:184 -msgid "Account settings for %s" -msgstr "Impostazioni Account per %s" - -#: ../src\controller\settings.py:284 -msgid "Direct Messages" -msgstr "Messaggi diretti" - -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 -msgid "Error" -msgstr "Errore" - -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 -msgid "That user does not exist" -msgstr "Questo utente non esiste su Twitter" - -#: ../src\controller\user.py:30 -msgid "User has been suspended" -msgstr "L'utente è stato sospeso." - -#: ../src\controller\user.py:36 -msgid "Information for %s" -msgstr "Informazioni per %s" - -#: ../src\controller\user.py:66 -#: ../src\extra\AudioUploader\audioUploader.py:124 -msgid "Discarded" -msgstr "Scartato" - -#: ../src\controller\user.py:95 -msgid "Username: @%s\n" -msgstr "Nome utente: @%s\n" - -#: ../src\controller\user.py:96 -msgid "Name: %s\n" -msgstr "Nome: %s\n" - -#: ../src\controller\user.py:98 -msgid "Location: %s\n" -msgstr "Localizzazione: %s\n" - -#: ../src\controller\user.py:100 -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: ../src\controller\user.py:102 -msgid "Bio: %s\n" -msgstr "Descrizione: %s\n" - -#: ../src\controller\user.py:103 ../src\controller\user.py:118 -msgid "Yes" -msgstr "Sì" - -#: ../src\controller\user.py:104 ../src\controller\user.py:119 -msgid "No" -msgstr "No" - -#: ../src\controller\user.py:105 -msgid "Protected: %s\n" -msgstr "Protetta: %s\n" - -#: ../src\controller\user.py:110 -msgid "You follow {0}. " -msgstr "Stai seguendo {0}. " - -#: ../src\controller\user.py:113 -msgid "{0} is following you." -msgstr "{0} ti sta seguendo." - -#: ../src\controller\user.py:117 -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"Followers: %s\n" -" Following: %s\n" - -#: ../src\controller\user.py:120 -msgid "Verified: %s\n" -msgstr "Verificato: %s\n" - -#: ../src\controller\user.py:121 -msgid "Tweets: %s\n" -msgstr "Tweets: %s\n" - -#: ../src\controller\user.py:122 -msgid "Likes: %s" -msgstr "Mi Piace: %s" - -#: ../src\controller\userActionsController.py:75 -msgid "You can't ignore direct messages" -msgstr "Non è possibile ignorare i messaggi diretti" - -#: ../src\extra\AudioUploader\audioUploader.py:54 -msgid "Attaching..." -msgstr "Allegando..." - -#: ../src\extra\AudioUploader\audioUploader.py:71 -msgid "Pause" -msgstr "Pausa" - -#: ../src\extra\AudioUploader\audioUploader.py:73 -msgid "&Resume" -msgstr "&Riassumi" - -#: ../src\extra\AudioUploader\audioUploader.py:74 -msgid "Resume" -msgstr "Riassumi" - -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 -msgid "&Pause" -msgstr "&Pausa" - -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 -msgid "&Stop" -msgstr "&Stop" - -#: ../src\extra\AudioUploader\audioUploader.py:92 -msgid "Recording" -msgstr "Registrazione" - -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 -msgid "Stopped" -msgstr "Stoppato" - -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 -msgid "&Record" -msgstr "&Registra" - -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 -msgid "Playing..." -msgstr "Riproduzione" - -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 -msgid "&Play" -msgstr "Ri&produci" - -#: ../src\extra\AudioUploader\audioUploader.py:156 -msgid "Recoding audio..." -msgstr "Ricodifica audio ..." - -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 -msgid "Error in file upload: {0}" -msgstr "Errore nel file in caricamento {0}" - -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 -msgid "%d day, " -msgstr "%d giorno, " - -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 -msgid "%d days, " -msgstr "%d giorni, " - -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 -msgid "%d hour, " -msgstr "%d ora, " - -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 -msgid "%d hours, " -msgstr "%d ore, " - -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 -msgid "%d minute, " -msgstr "%d minuto, " - -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 -msgid "%d minutes, " -msgstr "%d minuti, " - -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 -msgid "%s second" -msgstr "%s secondo" - -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 -msgid "%s seconds" -msgstr "%s secondi" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 -msgid "File" -msgstr "File" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 -msgid "Transferred" -msgstr "Trasferito" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 -msgid "Total file size" -msgstr "Dimensioni totali del file" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 -msgid "Transfer rate" -msgstr "Velocità di trasferimento" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 -msgid "Time left" -msgstr "Tempo rimasto" - -#: ../src\extra\AudioUploader\wx_ui.py:28 -msgid "Attach audio" -msgstr "Allega audio" - -#: ../src\extra\AudioUploader\wx_ui.py:40 -msgid "&Add an existing file" -msgstr "&Allega un file esistente" - -#: ../src\extra\AudioUploader\wx_ui.py:41 -msgid "&Discard" -msgstr "&Scarta" - -#: ../src\extra\AudioUploader\wx_ui.py:43 -msgid "Upload to" -msgstr "Carica" - -#: ../src\extra\AudioUploader\wx_ui.py:48 -msgid "Attach" -msgstr "Allega" - -#: ../src\extra\AudioUploader\wx_ui.py:50 -msgid "&Cancel" -msgstr "&annulla" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:75 -msgid "Select the audio file to be uploaded" -msgstr "Selezionare il file audio da caricare" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 -msgid "Audio tweet." -msgstr "Audio tweet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "User timeline buffer created." -msgstr "Il Buffer per la Cronologia dell'utente specifico è stato creato." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "Buffer destroied." -msgstr "Buffer eliminato." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Direct message received." -msgstr "Messaggio diretto ricevuto" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message sent." -msgstr "Messaggi diretto inviato" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Error." -msgstr "Errore" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Tweet liked." -msgstr "Tweet marcati con Mi Piace." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Likes buffer updated." -msgstr "Un Buffer segnato come Mi Piace è stato aggiornato." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Geotweet." -msgstr "GeoTweet." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Tweet contains one or more images" -msgstr "Il Tweet contiene una o più immagini" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Boundary reached." -msgstr "Boundary reached." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "List updated." -msgstr "Lista aggiornata." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "Too many characters." -msgstr "Troppi caratteri" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Mention received." -msgstr "Menzione ricevuta." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "New event." -msgstr "Nuovo evento" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "{0} is ready." -msgstr "{0} TwBlue è pronto." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -msgid "Mention sent." -msgstr "Menzione Inviata" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Tweet retweeted." -msgstr "Tweet retweettati." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Search buffer updated." -msgstr "Buffer della Ricerca aggiornato." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Tweet received." -msgstr "Tweet ricevuto." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet sent." -msgstr "Tweet inviato" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Trending topics buffer updated." -msgstr "Il buffer degli argomenti di tendenza è stato aggiornato." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "New tweet in user timeline buffer." -msgstr "Nuovo tweet nel buffer della Cronologia utente specifico." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New follower." -msgstr "Nuovo follower." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "Volume changed." -msgstr "Volume modificato." - -#: ../src\extra\SoundsTutorial\wx_ui.py:8 -msgid "Sounds tutorial" -msgstr "Tutorial dei suoni" - -#: ../src\extra\SoundsTutorial\wx_ui.py:11 -msgid "Press enter to listen to the sound for the selected event" -msgstr "Premi Invio per ascoltare il suono dell'evento selezionato" - -#: ../src\extra\SpellChecker\spellchecker.py:57 -msgid "Misspelled word: %s" -msgstr "parola errata: %s" - -#: ../src\extra\SpellChecker\wx_ui.py:27 -msgid "Misspelled word" -msgstr "Parola errata" - -#: ../src\extra\SpellChecker\wx_ui.py:32 -msgid "Context" -msgstr "Contesto" - -#: ../src\extra\SpellChecker\wx_ui.py:37 -msgid "Suggestions" -msgstr "Suggerimenti" - -#: ../src\extra\SpellChecker\wx_ui.py:42 -msgid "&Ignore" -msgstr "&Ignora" - -#: ../src\extra\SpellChecker\wx_ui.py:43 -msgid "I&gnore all" -msgstr "I&gnora tutto" - -#: ../src\extra\SpellChecker\wx_ui.py:44 -msgid "&Replace" -msgstr "S&ostituisci" - -#: ../src\extra\SpellChecker\wx_ui.py:45 -msgid "R&eplace all" -msgstr "Sost&ituisci tutto" - -#: ../src\extra\SpellChecker\wx_ui.py:46 -msgid "&Add to personal dictionary" -msgstr "&Aggiungi al dizionario personale" - -#: ../src\extra\SpellChecker\wx_ui.py:79 -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "" -"Errore. Non ci sono i dizionari disponibili per la lingua selezionata in {0}" - -#: ../src\extra\SpellChecker\wx_ui.py:82 -msgid "Spell check complete." -msgstr "Controllo ortografico completato." - -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 -msgid "You have to start writing" -msgstr "Inizia a scrivere" - -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 -msgid "There are no results in your users database" -msgstr "Nessun risultato nel tuo Database utenti" - -#: ../src\extra\autocompletionUsers\completion.py:33 -msgid "Autocompletion only works for users." -msgstr "Il completamento automatico funziona solo per gli utenti." - -#: ../src\extra\autocompletionUsers\settings.py:27 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"Aggiornamento del database... Si può ora chiudere questa finestra. Un " -"messaggio vi informerà Quando il processo termina." - -#: ../src\extra\autocompletionUsers\wx_manage.py:8 -msgid "Manage Autocompletion database" -msgstr "Gestisci autocompletamento per gli utenti nel database" - -#: ../src\extra\autocompletionUsers\wx_manage.py:11 -msgid "Editing {0} users database" -msgstr "Modificazione del {0} database degli utenti" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Username" -msgstr "Nome utente" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "Nome" - -#: ../src\extra\autocompletionUsers\wx_manage.py:15 -msgid "Add user" -msgstr "Aggiungi utente" - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Remove user" -msgstr "Rimuovi utente" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Add user to database" -msgstr "Aggiungi utente al database" - -#: ../src\extra\autocompletionUsers\wx_manage.py:37 -msgid "Twitter username" -msgstr "Nome utente Twitter" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -msgid "The user does not exist" -msgstr "Questo utente non esiste su Twitter" - -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "Error!" -msgstr "Errore" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "Impostazioni autocompletamento utenti" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "Aggiungi utenti dall'elenco followers" - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "Aggiungi utenti dall'elenco dei following" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "Gestisci database..." - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "Fatto!" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "Il {0} database di TWBlue per gli utenti è stato aggiornato." - -#: ../src\extra\ocr\OCRSpace.py:5 -msgid "Detect automatically" -msgstr "Rileva automaticamente" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 -msgid "Danish" -msgstr "Danese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 -msgid "Dutch" -msgstr "Olandese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 -msgid "English" -msgstr "Inglese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 -msgid "Finnish" -msgstr "Finlandese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 -msgid "French" -msgstr "Francese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 -msgid "German" -msgstr "Tedesco" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 -msgid "Hungarian" -msgstr "Ungherese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 -msgid "Italian" -msgstr "Italiano" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 -msgid "Japanese" -msgstr "Giapponese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 -msgid "Korean" -msgstr "Coreano" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 -msgid "Polish" -msgstr "Polacco" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 -msgid "Portuguese" -msgstr "Portoghese" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 -msgid "Russian" -msgstr "Russo" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 -msgid "Spanish" -msgstr "Spagnolo" - -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 -msgid "Turkish" -msgstr "Turco" - -#: ../src\extra\translator\translator.py:12 -msgid "Afrikaans" -msgstr "Africano" - -#: ../src\extra\translator\translator.py:13 -msgid "Albanian" -msgstr "Albanese" - -#: ../src\extra\translator\translator.py:14 -msgid "Amharic" -msgstr "Amarico" - -#: ../src\extra\translator\translator.py:15 -msgid "Arabic" -msgstr "Arabo" - -#: ../src\extra\translator\translator.py:16 -msgid "Armenian" -msgstr "Armeno\"" - -#: ../src\extra\translator\translator.py:17 -msgid "Azerbaijani" -msgstr "Azerbaijano" - -#: ../src\extra\translator\translator.py:18 -msgid "Basque" -msgstr "Basco" - -#: ../src\extra\translator\translator.py:19 -msgid "Belarusian" -msgstr "BieloRusso" - -#: ../src\extra\translator\translator.py:20 -msgid "Bengali" -msgstr "Bengalese" - -#: ../src\extra\translator\translator.py:21 -msgid "Bihari" -msgstr "Bihari" - -#: ../src\extra\translator\translator.py:22 -msgid "Bulgarian" -msgstr "Bulgaro" - -#: ../src\extra\translator\translator.py:23 -msgid "Burmese" -msgstr "Birmano" - -#: ../src\extra\translator\translator.py:24 -msgid "Catalan" -msgstr "Catalano" - -#: ../src\extra\translator\translator.py:25 -msgid "Cherokee" -msgstr "Cherokee" - -#: ../src\extra\translator\translator.py:26 -msgid "Chinese" -msgstr "Cinese" - -#: ../src\extra\translator\translator.py:27 -msgid "Chinese_simplified" -msgstr "Cinese semplificato" - -#: ../src\extra\translator\translator.py:28 -msgid "Chinese_traditional" -msgstr "Cinese tradizionale" - -#: ../src\extra\translator\translator.py:29 -msgid "Croatian" -msgstr "Croato" - -#: ../src\extra\translator\translator.py:30 -msgid "Czech" -msgstr "Ceco" - -#: ../src\extra\translator\translator.py:32 -msgid "Dhivehi" -msgstr "Dhivehi" - -#: ../src\extra\translator\translator.py:35 -msgid "Esperanto" -msgstr "Esperanto" - -#: ../src\extra\translator\translator.py:36 -msgid "Estonian" -msgstr "Estonian" - -#: ../src\extra\translator\translator.py:37 -msgid "Filipino" -msgstr "Filippino" - -#: ../src\extra\translator\translator.py:40 -msgid "Galician" -msgstr "Galiziano" - -#: ../src\extra\translator\translator.py:41 -msgid "Georgian" -msgstr "Georgiano" - -#: ../src\extra\translator\translator.py:43 -msgid "Greek" -msgstr "Greco" - -#: ../src\extra\translator\translator.py:44 -msgid "Guarani" -msgstr "Guarani" - -#: ../src\extra\translator\translator.py:45 -msgid "Gujarati" -msgstr "Gujarati" - -#: ../src\extra\translator\translator.py:46 -msgid "Hebrew" -msgstr "Ebraico" - -#: ../src\extra\translator\translator.py:47 -msgid "Hindi" -msgstr "Hindi" - -#: ../src\extra\translator\translator.py:49 -msgid "Icelandic" -msgstr "Islandese" - -#: ../src\extra\translator\translator.py:50 -msgid "Indonesian" -msgstr "Indonesiano" - -#: ../src\extra\translator\translator.py:51 -msgid "Inuktitut" -msgstr "Inuktitut" - -#: ../src\extra\translator\translator.py:52 -msgid "Irish" -msgstr "Irlandese" - -#: ../src\extra\translator\translator.py:55 -msgid "Kannada" -msgstr "Kannada" - -#: ../src\extra\translator\translator.py:56 -msgid "Kazakh" -msgstr "Kazako" - -#: ../src\extra\translator\translator.py:57 -msgid "Khmer" -msgstr "Khmer" - -#: ../src\extra\translator\translator.py:59 -msgid "Kurdish" -msgstr "Curdo" - -#: ../src\extra\translator\translator.py:60 -msgid "Kyrgyz" -msgstr "Kirghizistan" - -#: ../src\extra\translator\translator.py:61 -msgid "Laothian" -msgstr "Laothian" - -#: ../src\extra\translator\translator.py:62 -msgid "Latvian" -msgstr "Léttone" - -#: ../src\extra\translator\translator.py:63 -msgid "Lithuanian" -msgstr "Lituano" - -#: ../src\extra\translator\translator.py:64 -msgid "Macedonian" -msgstr "Macedone" - -#: ../src\extra\translator\translator.py:65 -msgid "Malay" -msgstr "Malese" - -#: ../src\extra\translator\translator.py:66 -msgid "Malayalam" -msgstr "Malayalam" - -#: ../src\extra\translator\translator.py:67 -msgid "Maltese" -msgstr "Maltese" - -#: ../src\extra\translator\translator.py:68 -msgid "Marathi" -msgstr "Marathi" - -#: ../src\extra\translator\translator.py:69 -msgid "Mongolian" -msgstr "Mongolo" - -#: ../src\extra\translator\translator.py:70 -msgid "Nepali" -msgstr "Nepali" - -#: ../src\extra\translator\translator.py:71 -msgid "Norwegian" -msgstr "Norvegese" - -#: ../src\extra\translator\translator.py:72 -msgid "Oriya" -msgstr " Oriya" - -#: ../src\extra\translator\translator.py:73 -msgid "Pashto" -msgstr "Pashto" - -#: ../src\extra\translator\translator.py:74 -msgid "Persian" -msgstr "Persiano" - -#: ../src\extra\translator\translator.py:77 -msgid "Punjabi" -msgstr "Punjabi" - -#: ../src\extra\translator\translator.py:78 -msgid "Romanian" -msgstr "Romeno" - -#: ../src\extra\translator\translator.py:80 -msgid "Sanskrit" -msgstr "Sanskrit" - -#: ../src\extra\translator\translator.py:81 -msgid "Serbian" -msgstr "Serbo" - -#: ../src\extra\translator\translator.py:82 -msgid "Sindhi" -msgstr "Sindhi" - -#: ../src\extra\translator\translator.py:83 -msgid "Sinhalese" -msgstr "Singalese" - -#: ../src\extra\translator\translator.py:84 -msgid "Slovak" -msgstr "Slovacco" - -#: ../src\extra\translator\translator.py:85 -msgid "Slovenian" -msgstr "Sloveno" - -#: ../src\extra\translator\translator.py:87 -msgid "Swahili" -msgstr "Swahili" - -#: ../src\extra\translator\translator.py:88 -msgid "Swedish" -msgstr "Svedese" - -#: ../src\extra\translator\translator.py:89 -msgid "Tajik" -msgstr "Tagiko" - -#: ../src\extra\translator\translator.py:90 -msgid "Tamil" -msgstr "Tamil" - -#: ../src\extra\translator\translator.py:91 -msgid "Tagalog" -msgstr "Tagalog" - -#: ../src\extra\translator\translator.py:92 -msgid "Telugu" -msgstr "Telugu" - -#: ../src\extra\translator\translator.py:93 -msgid "Thai" -msgstr "Thai" - -#: ../src\extra\translator\translator.py:94 -msgid "Tibetan" -msgstr "Tibetano" - -#: ../src\extra\translator\translator.py:96 -msgid "Ukrainian" -msgstr "Ucraino" - -#: ../src\extra\translator\translator.py:97 -msgid "Urdu" -msgstr "Urdu" - -#: ../src\extra\translator\translator.py:98 -msgid "Uzbek" -msgstr "Uzbeko" - -#: ../src\extra\translator\translator.py:99 -msgid "Uighur" -msgstr "Uighur" - -#: ../src\extra\translator\translator.py:100 -msgid "Vietnamese" -msgstr "Vietnamese" - -#: ../src\extra\translator\translator.py:101 -msgid "Welsh" -msgstr "Gallese" - -#: ../src\extra\translator\translator.py:102 -msgid "Yiddish" -msgstr "Yiddish" - -#: ../src\extra\translator\wx_ui.py:44 -msgid "Translate message" -msgstr "Traduci messaggio" - -#: ../src\extra\translator\wx_ui.py:47 -msgid "Target language" -msgstr "Lingua di destinazione" - -#: ../src\issueReporter\issueReporter.py:30 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 -msgid "General" -msgstr "Generale" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "always" -msgstr "Sempre" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "have not tried" -msgstr "Nessun tentativo" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "random" -msgstr "Casualmente" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "sometimes" -msgstr "Qualche volta" - -#: ../src\issueReporter\issueReporter.py:31 -msgid "unable to duplicate" -msgstr "Impossibile duplicare" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "block" -msgstr "Blocca" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "crash" -msgstr "Crash" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "feature" -msgstr "caratteristica" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "major" -msgstr "Maggiore" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "minor" -msgstr "Minore" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "text" -msgstr "Testo" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "trivial" -msgstr "Trivial" - -#: ../src\issueReporter\issueReporter.py:32 -msgid "tweak" -msgstr "tweak" - -#: ../src\issueReporter\wx_ui.py:25 -msgid "Report an error" -msgstr "Riporta un errore" - -#: ../src\issueReporter\wx_ui.py:28 -msgid "Select a category" -msgstr "Seleziona una categoria" - -#: ../src\issueReporter\wx_ui.py:36 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "" -"Descrivi brevemente ciò che è accaduto. Sarete in grado di spiegare a fondo " -"in un secondo momento" - -#: ../src\issueReporter\wx_ui.py:45 -msgid "Here, you can describe the bug in detail" -msgstr "È possibile descrivere il bug in dettaglio quì:" - -#: ../src\issueReporter\wx_ui.py:55 -msgid "how often does this bug happen?" -msgstr "Quante volte si verifica questo bug?" - -#: ../src\issueReporter\wx_ui.py:62 -msgid "Select the importance that you think this bug has" -msgstr "Selezionare il livello di importanza del bug" - -#: ../src\issueReporter\wx_ui.py:69 -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"Sono a conoscenza che il {0} sistema di bug otterrà il mio nome utente " -"Twitter per contattarmi e fissare il bug rapidamente" - -#: ../src\issueReporter\wx_ui.py:72 -msgid "Send report" -msgstr "Invia rapporto" - -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 -msgid "Cancel" -msgstr "annulla" - -#: ../src\issueReporter\wx_ui.py:83 -msgid "You must fill out both fields" -msgstr "È necessario compilare entrambi i campi" - -#: ../src\issueReporter\wx_ui.py:86 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"Contrassegnare la casella di controllo per fornirci il tuo nome utente " -"Twitter per contattarvi se necessario." - -#: ../src\issueReporter\wx_ui.py:89 -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"Grazie per aver segnalato il bug! ;Nelle future versioni, si può essere in " -"grado di trovare nella lista delle modifiche. ;Hai segnalato il numero bug%i" - -#: ../src\issueReporter\wx_ui.py:89 -msgid "reported" -msgstr "segnalato" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "Error while reporting" -msgstr "Errore nel segnalare" - -#: ../src\issueReporter\wx_ui.py:93 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"Qualcosa di inaspettato si è verificato durante il tentativo di riportare il " -"bug. ;Per favore, riprova più tardi" - -#: ../src\keystrokeEditor\constants.py:3 -msgid "Go up in the current buffer" -msgstr "Scorri verso l'alto" - -#: ../src\keystrokeEditor\constants.py:4 -msgid "Go down in the current buffer" -msgstr "Scorri verso il basso " - -#: ../src\keystrokeEditor\constants.py:5 -msgid "Go to the previous buffer" -msgstr "Vai al buffer precedente" - -#: ../src\keystrokeEditor\constants.py:6 -msgid "Go to the next buffer" -msgstr "Vai al buffer successivo" - -#: ../src\keystrokeEditor\constants.py:7 -msgid "Focus the next session" -msgstr "Focalizza la sessione successiva" - -#: ../src\keystrokeEditor\constants.py:8 -msgid "Focus the previous session" -msgstr "Focalizza la sessione precedente" - -#: ../src\keystrokeEditor\constants.py:9 -msgid "Show or hide the GUI" -msgstr "Mostra o nascondi GUI" - -#: ../src\keystrokeEditor\constants.py:10 -msgid "New tweet" -msgstr "Nuovo tweet" - -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 -msgid "Retweet" -msgstr "Retweet" - -#: ../src\keystrokeEditor\constants.py:13 -msgid "Send direct message" -msgstr "Invia un messaggio diretto" - -#: ../src\keystrokeEditor\constants.py:14 -msgid "Like a tweet" -msgstr "Mi Piace il tweet" - -#: ../src\keystrokeEditor\constants.py:15 -msgid "Like/unlike a tweet" -msgstr "Mi piace / Non Mi piace il tweet" - -#: ../src\keystrokeEditor\constants.py:16 -msgid "Unlike a tweet" -msgstr "Non Mi piace il tweet" - -#: ../src\keystrokeEditor\constants.py:17 -msgid "Open the user actions dialogue" -msgstr "Apri una finestra per selezionare un'azione" - -#: ../src\keystrokeEditor\constants.py:18 -msgid "See user details" -msgstr "Dettagli utente" - -#: ../src\keystrokeEditor\constants.py:19 -msgid "Show tweet" -msgstr "Visualizza Tweet" - -#: ../src\keystrokeEditor\constants.py:20 -msgid "Quit" -msgstr "Esci" - -#: ../src\keystrokeEditor\constants.py:21 -msgid "Open user timeline" -msgstr "Apri una specifica Cronologia per l'utente" - -#: ../src\keystrokeEditor\constants.py:22 -msgid "Destroy buffer" -msgstr "Elimina buffer" - -#: ../src\keystrokeEditor\constants.py:23 -msgid "Interact with the currently focused tweet." -msgstr "Interagisci con il tweet attualmente focalizzato." - -#: ../src\keystrokeEditor\constants.py:24 -msgid "Open URL" -msgstr "Apri URL" - -#: ../src\keystrokeEditor\constants.py:25 -msgid "View in Twitter" -msgstr "Visualizza in Twitter" - -#: ../src\keystrokeEditor\constants.py:26 -msgid "Increase volume by 5%" -msgstr "Aumenta Volume 5%" - -#: ../src\keystrokeEditor\constants.py:27 -msgid "Decrease volume by 5%" -msgstr "Diminuisce Volume 5%" - -#: ../src\keystrokeEditor\constants.py:28 -msgid "Jump to the first element of a buffer" -msgstr "Vai alla prima voce nel buffer attuale" - -#: ../src\keystrokeEditor\constants.py:29 -msgid "Jump to the last element of the current buffer" -msgstr "Vai all'ultima voce nel buffer attuale" - -#: ../src\keystrokeEditor\constants.py:30 -msgid "Jump 20 elements up in the current buffer" -msgstr "Salta 20 voci in alto nel buffer attuale" - -#: ../src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements down in the current buffer" -msgstr "Salta 20 voci in basso nel buffer attuale" - -#: ../src\keystrokeEditor\constants.py:32 -msgid "Edit profile" -msgstr "Modifica Profilo" - -#: ../src\keystrokeEditor\constants.py:33 -msgid "Delete a tweet or direct message" -msgstr "Elimina un tweet o un messaggio diretto" - -#: ../src\keystrokeEditor\constants.py:34 -msgid "Empty the current buffer" -msgstr "Svuota Elenco" - -#: ../src\keystrokeEditor\constants.py:35 -msgid "Repeat last item" -msgstr "Ripeti l'ultima voce" - -#: ../src\keystrokeEditor\constants.py:36 -msgid "Copy to clipboard" -msgstr "Copia negli appunti" - -#: ../src\keystrokeEditor\constants.py:37 -msgid "Add to list" -msgstr "Aggiungi alla lista" - -#: ../src\keystrokeEditor\constants.py:38 -msgid "Remove from list" -msgstr "Rimuovi dalla lista" - -#: ../src\keystrokeEditor\constants.py:39 -msgid "Mute/unmute the active buffer" -msgstr "Mutes/unmutes il buffer corrente" - -#: ../src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the current session" -msgstr "Mute/unmute la sessione corrente" - -#: ../src\keystrokeEditor\constants.py:41 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "" -"Attiva o disattiva la Lettura automatica per i nuovi tweet nel buffer " -"selezionato" - -#: ../src\keystrokeEditor\constants.py:42 -msgid "Search on twitter" -msgstr "Ricerca in Twitter" - -#: ../src\keystrokeEditor\constants.py:43 -msgid "Find a string in the currently focused buffer" -msgstr "Trova del testo nel buffer attualmente focalizzato" - -#: ../src\keystrokeEditor\constants.py:44 -msgid "Show the keystroke editor" -msgstr "Visualizza il modificatore comandi" - -#: ../src\keystrokeEditor\constants.py:45 -msgid "Show lists for a specified user" -msgstr "Mostra le liste di un utente" - -#: ../src\keystrokeEditor\constants.py:46 -msgid "load previous items" -msgstr "Carica gli elementi precedenti" - -#: ../src\keystrokeEditor\constants.py:47 -msgid "Get geolocation" -msgstr "Localizzazione" - -#: ../src\keystrokeEditor\constants.py:48 -msgid "Display the tweet's geolocation in a dialog" -msgstr "Visualizza la localizzazione del Tweet in una finestra" - -#: ../src\keystrokeEditor\constants.py:49 -msgid "Create a trending topics buffer" -msgstr "Crea un buffer per gli argomenti di tendenza" - -#: ../src\keystrokeEditor\constants.py:50 -msgid "View conversation" -msgstr "Visualizza conversazione" - -#: ../src\keystrokeEditor\constants.py:51 -msgid "Check and download updates" -msgstr "Controlla e scarica aggiornamenti" - -#: ../src\keystrokeEditor\constants.py:52 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"Apre il gestore lista, che consente di creare, modificare, eliminare e " -"aprire liste nei buffer." - -#: ../src\keystrokeEditor\constants.py:53 -msgid "Opens the global settings dialogue" -msgstr "Apri le impostazioni generali" - -#: ../src\keystrokeEditor\constants.py:54 -msgid "Opens the list manager" -msgstr "Apri il gestore liste" - -#: ../src\keystrokeEditor\constants.py:55 -msgid "Opens the account settings dialogue" -msgstr "Apri le impostazioni Account" - -#: ../src\keystrokeEditor\constants.py:56 -msgid "Try to play an audio file" -msgstr "Prova ad avviare un audio." - -#: ../src\keystrokeEditor\constants.py:57 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "Aggiorna il buffer e recupera i possibili elementi persi." - -#: ../src\keystrokeEditor\constants.py:58 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "" -"Estrae il testo da un'immagine e visualizza il risultato in una finestra di " -"dialogo." - -#: ../src\keystrokeEditor\wx_ui.py:8 -msgid "Keystroke editor" -msgstr "Modifica comando" - -#: ../src\keystrokeEditor\wx_ui.py:12 -msgid "Select a keystroke to edit" -msgstr "Seleziona il comando da modificare:" - -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "Comando" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 -msgid "Action" -msgstr "Azione" - -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 -msgid "Edit" -msgstr "Modifica" - -#: ../src\keystrokeEditor\wx_ui.py:20 -msgid "Execute action" -msgstr "Esegui" - -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 -msgid "Close" -msgstr "Chiudi" - -#: ../src\keystrokeEditor\wx_ui.py:48 -msgid "Editing keystroke" -msgstr "Modifica comando" - -#: ../src\keystrokeEditor\wx_ui.py:51 -msgid "Control" -msgstr "Control" - -#: ../src\keystrokeEditor\wx_ui.py:52 -msgid "Alt" -msgstr "Alt" - -#: ../src\keystrokeEditor\wx_ui.py:53 -msgid "Shift" -msgstr "Shift" - -#: ../src\keystrokeEditor\wx_ui.py:54 -msgid "Windows" -msgstr "Windows" - -#: ../src\keystrokeEditor\wx_ui.py:60 -msgid "Key" -msgstr "Key" - -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 -msgid "OK" -msgstr "OK" - -#: ../src\keystrokeEditor\wx_ui.py:78 -msgid "You need to use the Windows key" -msgstr "È necessario utilizzare il tasto Windows" - -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 -msgid "Invalid keystroke" -msgstr "Comando non valido" - -#: ../src\keystrokeEditor\wx_ui.py:81 -msgid "You must provide a character for the keystroke" -msgstr "You must provide a character for the keystroke" - -#: ../src\languageHandler.py:99 -msgid "User default" -msgstr "Utente predefinito" - -#: ../src\main.py:105 -msgid "https://twblue.es/donate" -msgstr "https://twblue.es/donate" - -#: ../src\main.py:122 -msgid "" -"{0} is already running. Close the other instance before starting this one. " -"If you're sure that {0} isn't running, try deleting the file at {1}. If " -"you're unsure of how to do this, contact the {0} developers." -msgstr "" -"{0} è già in esecuzione. Chiudere altre istanze prima di avviare. Se sei " -"sicuro che {0} non è in esecuzione, provare a cancellare il file in {1}. Se " -"non sei sicuro di come si può fare, contattare gli sviluppatori {0}." - -#: ../src\sessionmanager\wxUI.py:8 -msgid "Session manager" -msgstr "Gestisci sessione." - -#: ../src\sessionmanager\wxUI.py:11 -msgid "Accounts list" -msgstr "Elenco Account" - -#: ../src\sessionmanager\wxUI.py:13 -msgid "Account" -msgstr "Account" - -#: ../src\sessionmanager\wxUI.py:17 -msgid "New account" -msgstr "Nuovo Account" - -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 -msgid "Remove account" -msgstr "Rimuovi account" - -#: ../src\sessionmanager\wxUI.py:19 -msgid "Global Settings" -msgstr "Impostazioni generali" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "Account Error" -msgstr "Errore!" - -#: ../src\sessionmanager\wxUI.py:42 -msgid "You need to configure an account." -msgstr "È necessario configurare un account." - -#: ../src\sessionmanager\wxUI.py:48 -msgid "Authorization" -msgstr "Autorizzazione" - -#: ../src\sessionmanager\wxUI.py:48 -msgid "" -"The request to authorize your Twitter account will be opened in your " -"browser. You only need to do this once. Would you like to continue?" -msgstr "" -"La richiesta di autorizzazione per l'account di Twitter verrà aperto nel " -"browser. Questa operazione verrà richiesta solo una volta. Vuoi continuare?" - -#: ../src\sessionmanager\wxUI.py:52 -msgid "Authorized account %d" -msgstr "Account autorizzato %d" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "Invalid user token" -msgstr "Chiave di autorizzazione utente non valido" - -#: ../src\sessionmanager\wxUI.py:58 -msgid "" -"Your access token is invalid or the authorization has failed. Please try " -"again." -msgstr "" -"Il tuo token di accesso non è valido o l'autorizzazione non è riuscita. " -"Riprova." - -#: ../src\sessionmanager\wxUI.py:64 -msgid "Do you really want to delete this account?" -msgstr "Sei sicuro di voler eliminare questo account?" - -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 -msgid "dddd, MMMM D, YYYY H:m:s" -msgstr "dddd, MMMM D, YYYY H:m:s" - -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 -msgid "Dm to %s " -msgstr "Dm a %s " - -#: ../src\sessions\twitter\compose.py:141 -msgid "{0}. Quoted tweet from @{1}: {2}" -msgstr "{0}. Tweet citato da @{1}: {2}" - -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 -msgid "Unavailable" -msgstr "Non disponibile" - -#: ../src\sessions\twitter\compose.py:166 -msgid "" -"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " -"Twitter %s" -msgstr "" -"%s (@%s). %s followers, %s following, %s tweets. Ultimo tweet %s. Iscritto " -"a Twitter %s" - -#: ../src\sessions\twitter\compose.py:170 -msgid "No description available" -msgstr "Nessuna descrizione disponibile" - -#: ../src\sessions\twitter\compose.py:174 -msgid "private" -msgstr "Privato" - -#: ../src\sessions\twitter\compose.py:175 -msgid "public" -msgstr "Pubblico" - -#: ../src\sessions\twitter\session.py:169 -msgid "There are no more items to retrieve in this buffer." -msgstr "Non ci sono più elementi da recuperare in questo buffer." - -#: ../src\sessions\twitter\session.py:215 -msgid "%s failed. Reason: %s" -msgstr "%s Errore. Motivo: %s" - -#: ../src\sessions\twitter\session.py:221 -msgid "%s succeeded." -msgstr "%s Operazione riuscita." - -#: ../src\sessions\twitter\utils.py:225 -msgid "Sorry, you are not authorised to see this status." -msgstr "Spiacente, non sei autorizzato a visualizzare questo stato." - -#: ../src\sessions\twitter\utils.py:227 -msgid "No status found with that ID" -msgstr "Nessuno stato trovato per quel ID" - -#: ../src\sessions\twitter\utils.py:229 -msgid "Error code {0}" -msgstr "codice di errore {0}" - -#: ../src\sessions\twitter\wxUI.py:6 -msgid "Authorising account..." -msgstr "Autorizzazione dell'Account..." - -#: ../src\sessions\twitter\wxUI.py:9 -msgid "Enter your PIN code here" -msgstr "Inserire il codice PIN quì" - -#: ../src\sound.py:159 -msgid "Stopped." -msgstr "Arrestato." - -#: ../src\update\wxUpdater.py:10 -msgid "New version for %s" -msgstr "Nuova versione di %s" - -#: ../src\update\wxUpdater.py:10 -msgid "" -"There's a new %s version available, released on %s. Would you like to " -"download it now?\n" -"\n" -" %s version: %s\n" -"\n" -"Changes:\n" -"%s" -msgstr "" -"È disponibile una nuova versione %s, rilasciata il %s. Scaricarla ora?\n" -"\n" -" %s versione: %s\n" -"\n" -"Change:\n" -"%s" - -#: ../src\update\wxUpdater.py:18 -msgid "Download in Progress" -msgstr "Download in corso" - -#: ../src\update\wxUpdater.py:18 -msgid "Downloading the new version..." -msgstr "Download della nuova versione..." - -#: ../src\update\wxUpdater.py:28 -msgid "Updating... %s of %s" -msgstr "Aggiornamento... %s di %s" - -#: ../src\update\wxUpdater.py:31 -msgid "Done!" -msgstr "Fatto!" - -#: ../src\update\wxUpdater.py:31 -msgid "" -"The update has been downloaded and installed successfully. Press OK to " -"continue." -msgstr "" -"La nuova versione TW blu è stata scaricata e installata. Premere OK per " -"avviare l'applicazione." - -#: ../src\wxUI\buffers\base.py:11 -msgid "Client" -msgstr "Client" - -#: ../src\wxUI\buffers\base.py:11 -msgid "Text" -msgstr "Testo" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 -msgid "Date" -msgstr "Data" - -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 -msgid "User" -msgstr "Utente" - -#: ../src\wxUI\buffers\base.py:27 -msgid "Direct message" -msgstr "Messaggio diretto" - -#: ../src\wxUI\buffers\events.py:13 -msgid "Event" -msgstr "Evento" - -#: ../src\wxUI\buffers\events.py:15 -msgid "Remove event" -msgstr "Rimuovere evento" - -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 -msgid "Login" -msgstr "Connetti" - -#: ../src\wxUI\buffers\panels.py:13 -msgid "Log in automatically" -msgstr "Login automatico" - -#: ../src\wxUI\buffers\panels.py:21 -msgid "Logout" -msgstr "Disconnetti" - -#: ../src\wxUI\buffers\trends.py:8 -msgid "Trending topic" -msgstr "Tendenze" - -#: ../src\wxUI\buffers\trends.py:18 -msgid "Tweet about this trend" -msgstr "Tweet riguardo questa tendenza" - -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 -msgid "Search topic" -msgstr "Cerca argomento" - -#: ../src\wxUI\commonMessageDialogs.py:6 -msgid "" -"This retweet is over 140 characters. Would you like to post it as a mention " -"to the poster with your comments and a link to the original tweet?" -msgstr "" -"Questo retweet ha superato i 140 caratteri. Preferisci pubblicarlo come una " -"menzione all'autore del post con i vostri commenti e un link per il tweet " -"originale?" - -#: ../src\wxUI\commonMessageDialogs.py:9 -msgid "Would you like to add a comment to this tweet?" -msgstr "Vuoi aggiungere un commento a questo tweet?" - -#: ../src\wxUI\commonMessageDialogs.py:12 -msgid "" -"Do you really want to delete this tweet? It will be deleted from Twitter as " -"well." -msgstr "Vuoi eliminare il tweet? Questo sarà cancellato anche da Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 -msgid "Delete" -msgstr "Elimina Tweet" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Do you really want to close {0}?" -msgstr "Sei sicuro di voler chiudere {0}?" - -#: ../src\wxUI\commonMessageDialogs.py:15 -msgid "Exit" -msgstr "Esci" - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid " {0} must be restarted for these changes to take effect." -msgstr " {0} Riavviare perché le modifiche abbiano effetto." - -#: ../src\wxUI\commonMessageDialogs.py:19 -msgid "Restart {0} " -msgstr "Riavvia {0}" - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "" -"Are you sure you want to delete this user from the database? This user will " -"not appear in autocomplete results anymore." -msgstr "" -"Sei sicuro di voler eliminare questo utente dal database? Questo utente non " -"apparirà nei risultati di completamento automatico." - -#: ../src\wxUI\commonMessageDialogs.py:22 -msgid "Confirm" -msgstr "Conferma" - -#: ../src\wxUI\commonMessageDialogs.py:25 -msgid "Enter the name of the client : " -msgstr "Inserire il nome del cliente" - -#: ../src\wxUI\commonMessageDialogs.py:25 -#: ../src\wxUI\dialogs\configuration.py:246 -msgid "Add client" -msgstr "Aggiungi client" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "" -"Do you really want to empty this buffer? It's items will be removed from " -"the list but not from Twitter" -msgstr "" -"Svuotare questo buffer? I tweet saranno rimossi dall'elenco, ma non da " -"Twitter" - -#: ../src\wxUI\commonMessageDialogs.py:31 -msgid "Empty buffer" -msgstr "Svuota Elenco" - -#: ../src\wxUI\commonMessageDialogs.py:35 -msgid "Do you really want to destroy this buffer?" -msgstr "Sei sicuro di voler eliminare questo buffer?" - -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Attention" -msgstr "Attenzione" - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "A timeline for this user already exists. You can't open another" -msgstr "Una Cronologia per questo utente è già presente." - -#: ../src\wxUI\commonMessageDialogs.py:41 -msgid "Existing timeline" -msgstr "Cronologia già esistente" - -#: ../src\wxUI\commonMessageDialogs.py:44 -msgid "This user has no tweets, so you can't open a timeline for them." -msgstr "" -"Questo utente non ha tweets. Non è possibile aprire una Cronologia per " -"questo utente" - -#: ../src\wxUI\commonMessageDialogs.py:47 -msgid "" -"This is a protected Twitter user, which means you can't open a timeline " -"using the Streaming API. The user's tweets will not update due to a twitter " -"policy. Do you want to continue?" -msgstr "" -"Questo è un account twitter protetto. Non è possibile aprire una Cronologia " -"utilizzando l'API Streaming. I Tweet dell'utente non verranno aggiornati a " -"causa di una politica di Twitter. Vuoi continuare?" - -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "Warning" -msgstr "Avviso" - -#: ../src\wxUI\commonMessageDialogs.py:50 -msgid "" -"This is a protected user account, you need to follow this user to view their " -"tweets or likes." -msgstr "" -"Questo è un account utente protetto, è necessario seguire l'utente per " -"visualizzare i suoi tweet o preferiti." - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "" -"If you like {0} we need your help to keep it going. Help us by donating to " -"the project. This will help us pay for the server, the domain and some other " -"things to ensure that {0} will be actively maintained. Your donation will " -"give us the means to continue the development of {0}, and to keep {0} free. " -"Would you like to donate now?" -msgstr "" -"Se ti piace {0} ricorda che abbiamo bisogno del vostro aiuto per andare " -"avanti. Aiutaci facendo una donazione per il progetto. Questo ci aiuterà a " -"pagare il server, il dominio e alcune altre cose per garantire che {0} Sarà " -"attivamente sostenuto. La vostra donazione ci darà i mezzi per continuare lo " -"sviluppo di {0}, e mantenere {0} free. Vuoi fare una donazione adesso?" - -#: ../src\wxUI\commonMessageDialogs.py:53 -msgid "We need your help" -msgstr "Abbiamo bisogno del tuo aiuto" - -#: ../src\wxUI\commonMessageDialogs.py:57 -msgid "This user has no tweets. {0} can't create a timeline." -msgstr "" -"Questo utente non ha tweets. {0} non può creare una Cronologia per questo " -"utente" - -#: ../src\wxUI\commonMessageDialogs.py:60 -msgid "This user has no favorited tweets. {0} can't create a timeline." -msgstr "" -"Questo utente non ha tweets preferiti. {0} non può creare una Cronologia per " -"questo utente" - -#: ../src\wxUI\commonMessageDialogs.py:63 -msgid "This user has no followers. {0} can't create a timeline." -msgstr "" -"Non stai seguendo questo utente . {0} non è possibile creare una Cronologia." - -#: ../src\wxUI\commonMessageDialogs.py:66 -msgid "This user has no friends. {0} can't create a timeline." -msgstr "" -"Questo utente non è tra gli amici. {0} non è possibile creare una Cronologia." - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geo data for this tweet" -msgstr "Informazioni geografiche per questo tweet." - -#: ../src\wxUI\commonMessageDialogs.py:70 -msgid "Geolocation data: {0}" -msgstr "Geolocalizzazione data: {0}" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "Information" -msgstr "Informazioni:" - -#: ../src\wxUI\commonMessageDialogs.py:73 -msgid "" -"TWBlue has detected that you're running windows 10 and has changed the " -"default keymap to the Windows 10 keymap. It means that some keyboard " -"shorcuts could be different. Please check the keystroke editor by pressing " -"Alt+Win+K to see all available keystrokes for this keymap." -msgstr "" -"TWBlue ha rilevato che si sta eseguendo windows 10 ed ha cambiato la " -"mappatura dei tasti di default per Windows 10. Ciò significa che alcuni " -"tasti di scelta rapida della tastiera potrèbbero essere diversi. Si " -"consiglia di controllare l'editor dei tasti rapidi premendo Alt+Win+K per " -"visualizzare tutti i tasti rapidi disponibili per questa mappatura di " -"tasti. " - -#: ../src\wxUI\commonMessageDialogs.py:76 -msgid "You have been blocked from viewing this content" -msgstr "Impossibile visualizzare il contenuto perché sei stato bloccato." - -#: ../src\wxUI\commonMessageDialogs.py:79 -msgid "" -"You have been blocked from viewing someone's content. In order to avoid " -"conflicts with the full session, TWBlue will remove the affected timeline." -msgstr "" -"Sei stato bloccato e non puoi visualizzare alcun contenuto. Al fine di " -"evitare conflitti con l'intera sezione, TWblue rimuoverà la relativa " -"cronologia. " - -#: ../src\wxUI\commonMessageDialogs.py:82 -msgid "" -"TWBlue cannot load this timeline because the user has been suspended from " -"Twitter." -msgstr "" -"TWBlue non può caricare la cronologia perché l'utente è stato sospeso da " -"Twitter." - -#: ../src\wxUI\commonMessageDialogs.py:85 -msgid "Do you really want to delete this filter?" -msgstr "Sei sicuro di voler eliminare questo filtro??" - -#: ../src\wxUI\commonMessageDialogs.py:88 -msgid "This filter already exists. Please use a different title" -msgstr "Questo filtro è già esistente. Utilizzare un altro titolo" - -#: ../src\wxUI\commonMessageDialogs.py:94 -msgid "" -"{0} quit unexpectedly the last time it was run. If the problem persists, " -"please report it to the {0} developers." -msgstr "" -"Si è verificato un errore nell'ultima chiusura di {0}. Se il problema " -"persiste, segnalare l'errore agli sviluppatori di {0}." - -#: ../src\wxUI\dialogs\attach.py:9 -msgid "Add an attachment" -msgstr "Aggiungi allegato" - -#: ../src\wxUI\dialogs\attach.py:12 -msgid "Attachments" -msgstr "Allegati" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Title" -msgstr "Titolo" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Type" -msgstr "Tipo" - -#: ../src\wxUI\dialogs\attach.py:18 -msgid "Add attachments" -msgstr "Aggiungi allegato" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "&Photo" -msgstr "&Foto" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "Remove attachment" -msgstr "Rimuovi allegato" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "File di immagine (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 -msgid "Select the picture to be uploaded" -msgstr "Seleziona l'immagine da caricare" - -#: ../src\wxUI\dialogs\attach.py:43 -msgid "please provide a description" -msgstr "Aggiungi una descrizione" - -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 -msgid "Description" -msgstr "Descrizione" - -#: ../src\wxUI\dialogs\configuration.py:16 -msgid "Language" -msgstr "Lingua" - -#: ../src\wxUI\dialogs\configuration.py:23 -msgid "Run {0} at Windows startup" -msgstr "Avvia {0} all'avvio di Windows." - -#: ../src\wxUI\dialogs\configuration.py:24 -msgid "ask before exiting {0}" -msgstr "Conferma prima di uscire da {0}" - -#: ../src\wxUI\dialogs\configuration.py:27 -msgid "Disable Streaming functions" -msgstr "Disattiva le funzioni di Streaming" - -#: ../src\wxUI\dialogs\configuration.py:30 -msgid "Buffer update interval, in minutes" -msgstr "Intervallo d aggiornamento del buffer, in minuti" - -#: ../src\wxUI\dialogs\configuration.py:36 -msgid "Play a sound when {0} launches" -msgstr "Riproduci un suono {0} all'avvio" - -#: ../src\wxUI\dialogs\configuration.py:38 -msgid "Speak a message when {0} launches" -msgstr "Avvisa con un messaggio {0} all'avvio" - -#: ../src\wxUI\dialogs\configuration.py:40 -msgid "Use invisible interface's keyboard shortcuts while GUI is visible" -msgstr "" -"Utilizza i comandi per l'interfaccia invisibile nell'interfaccia grafica" - -#: ../src\wxUI\dialogs\configuration.py:42 -msgid "Activate Sapi5 when any other screen reader is not being run" -msgstr "Attiva SAPI5 quando non viene eseguito un altro lettore di schermo" - -#: ../src\wxUI\dialogs\configuration.py:44 -msgid "Hide GUI on launch" -msgstr "Nascondi Interfaccia grafica all'avvio" - -#: ../src\wxUI\dialogs\configuration.py:46 -msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" -msgstr "Lettura completa dei tweet (Può ridurre le prestazioni del client)" - -#: ../src\wxUI\dialogs\configuration.py:48 -msgid "Remember state for mention all and long tweet" -msgstr "Riporta stato per i tweet lunghi e l'opzione Menziona tutti." - -#: ../src\wxUI\dialogs\configuration.py:51 -msgid "Keymap" -msgstr "Keymap" - -#: ../src\wxUI\dialogs\configuration.py:56 -msgid "Check for updates when {0} launches" -msgstr "Controlla aggiornamenti all'avvio di {0} " - -#: ../src\wxUI\dialogs\configuration.py:66 -msgid "Proxy type: " -msgstr "Servizio Proxy: " - -#: ../src\wxUI\dialogs\configuration.py:73 -msgid "Proxy server: " -msgstr "Proxy server: " - -#: ../src\wxUI\dialogs\configuration.py:79 -msgid "Port: " -msgstr "Port: " - -#: ../src\wxUI\dialogs\configuration.py:85 -msgid "User: " -msgstr "Utente" - -#: ../src\wxUI\dialogs\configuration.py:91 -msgid "Password: " -msgstr "Password: " - -#: ../src\wxUI\dialogs\configuration.py:103 -msgid "Autocompletion settings..." -msgstr "impostazioni di autocompletamento..." - -#: ../src\wxUI\dialogs\configuration.py:105 -msgid "Relative timestamps" -msgstr "Mostra tempo di ricezione trascorso" - -#: ../src\wxUI\dialogs\configuration.py:108 -msgid "Items on each API call" -msgstr "Elementi per ogni chiamata API " - -#: ../src\wxUI\dialogs\configuration.py:114 -msgid "" -"Inverted buffers: The newest tweets will be shown at the beginning while the " -"oldest at the end" -msgstr "" -"Inverti elenco: I nuovi tweets verranno mostrate in cima all'elenco, i " -"precedenti alla fine" - -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet mode" -msgstr "Retweet mode" - -#: ../src\wxUI\dialogs\configuration.py:122 -msgid "Show screen names instead of full names" -msgstr "Visualizza nome del riquadro al posto del nome completo" - -#: ../src\wxUI\dialogs\configuration.py:124 -msgid "" -"Number of items per buffer to cache in database (0 to disable caching, blank " -"for unlimited)" -msgstr "" -"Numero di voci per buffer per la cache nel database (0 per disabilitare " -"caching, vuoto per un numero illimitato)" - -#: ../src\wxUI\dialogs\configuration.py:134 -msgid "Enable automatic speech feedback" -msgstr "Attiva automaticamente il feedback vocale" - -#: ../src\wxUI\dialogs\configuration.py:136 -msgid "Enable automatic Braille feedback" -msgstr "Attiva automaticamente il feedback braille." - -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "Stato" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Buffer" -msgstr "Buffer" - -#: ../src\wxUI\dialogs\configuration.py:147 -msgid "Show/hide" -msgstr "Mostra/Nascondi" - -#: ../src\wxUI\dialogs\configuration.py:148 -msgid "Move up" -msgstr "Sposta su" - -#: ../src\wxUI\dialogs\configuration.py:149 -msgid "Move down" -msgstr "Sposta Giù" - -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 -msgid "Show" -msgstr "Mostra" - -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 -msgid "Hide" -msgstr "Nascondi" - -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 -msgid "Select a buffer first." -msgstr "Selezionare un buffer." - -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 -msgid "The buffer is hidden, show it first." -msgstr "Il buffer è nascosto." - -#: ../src\wxUI\dialogs\configuration.py:175 -msgid "The buffer is already at the top of the list." -msgstr "Il buffer è già in cima alla lista." - -#: ../src\wxUI\dialogs\configuration.py:199 -msgid "The buffer is already at the bottom of the list." -msgstr "Il buffer è già in fondo all'elenco." - -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 -msgid "Ignored clients" -msgstr "Ignora clients" - -#: ../src\wxUI\dialogs\configuration.py:247 -msgid "Remove client" -msgstr "Rimuovi client" - -#: ../src\wxUI\dialogs\configuration.py:271 -msgid "Volume" -msgstr "Volume" - -#: ../src\wxUI\dialogs\configuration.py:282 -msgid "Session mute" -msgstr "sessione mute" - -#: ../src\wxUI\dialogs\configuration.py:284 -msgid "Output device" -msgstr "Dispositivo di uscita" - -#: ../src\wxUI\dialogs\configuration.py:291 -msgid "Input device" -msgstr "Dispositivo di input" - -#: ../src\wxUI\dialogs\configuration.py:299 -msgid "Sound pack" -msgstr "Pacchetto audio" - -#: ../src\wxUI\dialogs\configuration.py:305 -msgid "Indicate audio tweets with sound" -msgstr "Avvisa con un suono per i tweet audio:" - -#: ../src\wxUI\dialogs\configuration.py:307 -msgid "Indicate geotweets with sound" -msgstr "Avvisa con un suono la geolocalizzazione dei tweet" - -#: ../src\wxUI\dialogs\configuration.py:309 -msgid "Indicate tweets containing images with sound" -msgstr "Avvisa con un suono i tweet con immagini" - -#: ../src\wxUI\dialogs\configuration.py:332 -msgid "Language for OCR" -msgstr "Lingua per l'OCR" - -#: ../src\wxUI\dialogs\configuration.py:338 -msgid "API Key for SndUp" -msgstr "API Key per SndUp" - -#: ../src\wxUI\dialogs\configuration.py:353 -msgid "{0} preferences" -msgstr "{0} Preferenze" - -#: ../src\wxUI\dialogs\configuration.py:364 -msgid "Proxy" -msgstr "Proxy" - -#: ../src\wxUI\dialogs\configuration.py:373 -msgid "Feedback" -msgstr "Feedback " - -#: ../src\wxUI\dialogs\configuration.py:377 -msgid "Buffers" -msgstr "Buffers" - -#: ../src\wxUI\dialogs\configuration.py:385 -msgid "Sound" -msgstr "Audio" - -#: ../src\wxUI\dialogs\configuration.py:389 -msgid "Extras" -msgstr "Extra" - -#: ../src\wxUI\dialogs\configuration.py:394 -msgid "Save" -msgstr "Salva" - -#: ../src\wxUI\dialogs\filterDialogs.py:15 -msgid "Create a filter for this buffer" -msgstr "Crea un filtro per questo buffer" - -#: ../src\wxUI\dialogs\filterDialogs.py:16 -msgid "Filter title" -msgstr "Titolo del filtro" - -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by word" -msgstr "Filtra per parola" - -#: ../src\wxUI\dialogs\filterDialogs.py:26 -msgid "Ignore tweets wich contain the following word" -msgstr "Ignora i tweet che contengono questa parola" - -#: ../src\wxUI\dialogs\filterDialogs.py:27 -msgid "Ignore tweets without the following word" -msgstr "Ignora i tweet che non contengono questa parola" - -#: ../src\wxUI\dialogs\filterDialogs.py:32 -msgid "word" -msgstr "Parola" - -#: ../src\wxUI\dialogs\filterDialogs.py:37 -msgid "Allow retweets" -msgstr "Consenti retweet" - -#: ../src\wxUI\dialogs\filterDialogs.py:38 -msgid "Allow quoted tweets" -msgstr "Consenti i tweet con citazione" - -#: ../src\wxUI\dialogs\filterDialogs.py:39 -msgid "Allow replies" -msgstr "Consenti risposte" - -#: ../src\wxUI\dialogs\filterDialogs.py:47 -msgid "Use this term as a regular expression" -msgstr "Usa questo elemento come espressione regolare" - -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter by language" -msgstr "Filtra per lingua" - -#: ../src\wxUI\dialogs\filterDialogs.py:50 -msgid "Load tweets in the following languages" -msgstr "Carica i tweet nelle seguenti lingue" - -#: ../src\wxUI\dialogs\filterDialogs.py:51 -msgid "Ignore tweets in the following languages" -msgstr "Ignora i tweet nelle seguenti lingue" - -#: ../src\wxUI\dialogs\filterDialogs.py:52 -msgid "Don't filter by language" -msgstr "Non filtrare per lingua" - -#: ../src\wxUI\dialogs\filterDialogs.py:63 -msgid "Supported languages" -msgstr "Lingue supportate" - -#: ../src\wxUI\dialogs\filterDialogs.py:68 -msgid "Add selected language to filter" -msgstr "Aggiungi la lingua selezionata per il filtro" - -#: ../src\wxUI\dialogs\filterDialogs.py:72 -msgid "Selected languages" -msgstr "Lingue selezionate" - -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 -msgid "Remove" -msgstr "Elimina" - -#: ../src\wxUI\dialogs\filterDialogs.py:122 -msgid "Manage filters" -msgstr "Gestione filtri" - -#: ../src\wxUI\dialogs\filterDialogs.py:124 -msgid "Filters" -msgstr "Filtri" - -#: ../src\wxUI\dialogs\filterDialogs.py:125 -msgid "Filter" -msgstr "Firltro" - -#: ../src\wxUI\dialogs\find.py:12 -msgid "Find in current buffer" -msgstr "Trova nel buffer corrente" - -#: ../src\wxUI\dialogs\find.py:13 -msgid "String" -msgstr "Stringa" - -#: ../src\wxUI\dialogs\lists.py:10 -msgid "Lists manager" -msgstr "Gestione liste" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "List" -msgstr "Lista" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Members" -msgstr "Membri" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "Owner" -msgstr "Proprietario" - -#: ../src\wxUI\dialogs\lists.py:13 -msgid "mode" -msgstr "Modalità" - -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 -msgid "Create a new list" -msgstr "Crea nuova lista" - -#: ../src\wxUI\dialogs\lists.py:21 -msgid "Open in buffer" -msgstr "Apri nel buffer" - -#: ../src\wxUI\dialogs\lists.py:51 -msgid "Viewing lists for %s" -msgstr "Visualizzazione delle liste per %s" - -#: ../src\wxUI\dialogs\lists.py:52 -msgid "Subscribe" -msgstr "Iscriviti" - -#: ../src\wxUI\dialogs\lists.py:53 -msgid "Unsubscribe" -msgstr "Disiscriviti" - -#: ../src\wxUI\dialogs\lists.py:64 -msgid "Name (20 characters maximun)" -msgstr "Nome (massimo 20 caratteri)" - -#: ../src\wxUI\dialogs\lists.py:74 -msgid "Mode" -msgstr "Modalità" - -#: ../src\wxUI\dialogs\lists.py:75 -msgid "Public" -msgstr "Pubblico" - -#: ../src\wxUI\dialogs\lists.py:76 -msgid "Private" -msgstr "Privato" - -#: ../src\wxUI\dialogs\lists.py:96 -msgid "Editing the list %s" -msgstr "Modifica elenco %s" - -#: ../src\wxUI\dialogs\lists.py:107 -msgid "Select a list to add the user" -msgstr "Seleziona una lista per aggiungere l'utente" - -#: ../src\wxUI\dialogs\lists.py:108 -msgid "Add" -msgstr "Aggiungi" - -#: ../src\wxUI\dialogs\lists.py:130 -msgid "Select a list to remove the user" -msgstr "Seleziona una lista per rimuovere l'utente" - -#: ../src\wxUI\dialogs\lists.py:148 -msgid "Do you really want to delete this list?" -msgstr "Sei sicuro di voler eliminare questa lista?" - -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "&Long tweet" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "&Carica immagine..." - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 -msgid "Check &spelling..." -msgstr "Controllo &ortografico..." - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "A&llega audio..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "Accorcia &URL" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 -msgid "&Expand URL" -msgstr "&Espandi URL" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 -msgid "&Translate..." -msgstr "&Traduci..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "&completamento automatico per gli utenti" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "In&via" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 -msgid "C&lose" -msgstr "&Chiudi" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "Destinata&rio" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "Menziona a &tutti" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Tweet -% i caratteri " - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Descrizione Immagine" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "Retweet" - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Mi piace: " - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Lingua d'origine" - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 -msgid "Date: " -msgstr "Data:" - -#: ../src\wxUI\dialogs\message.py:405 -msgid "View" -msgstr "Visualizza" - -#: ../src\wxUI\dialogs\message.py:407 -msgid "Item" -msgstr "Elemento" - -#: ../src\wxUI\dialogs\search.py:13 -msgid "Search on Twitter" -msgstr "Ricerca in Twitter" - -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 -msgid "&Search" -msgstr "&Ricerca" - -#: ../src\wxUI\dialogs\search.py:21 -msgid "Tweets" -msgstr "Tweet" - -#: ../src\wxUI\dialogs\search.py:22 -msgid "Users" -msgstr "Utente" - -#: ../src\wxUI\dialogs\search.py:29 -msgid "&Language for results: " -msgstr "&Lingua per i risultati:" - -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 -msgid "any" -msgstr "Qualsiasi" - -#: ../src\wxUI\dialogs\search.py:37 -msgid "Results &type: " -msgstr "Results &type: " - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 -msgid "Mixed" -msgstr "Misto" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 -msgid "Recent" -msgstr "Recenti" - -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 -msgid "Popular" -msgstr "Popolari" - -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 -msgid "&OK" -msgstr "&Ok" - -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 -msgid "&Close" -msgstr "&Chiudi" - -#: ../src\wxUI\dialogs\show_user.py:11 -msgid "Details" -msgstr "Dettagli" - -#: ../src\wxUI\dialogs\show_user.py:16 -msgid "&Go to URL" -msgstr "&Vai all'URL" - -#: ../src\wxUI\dialogs\trends.py:12 -msgid "View trending topics" -msgstr "Visualizza tendenze" - -#: ../src\wxUI\dialogs\trends.py:13 -msgid "Trending topics by" -msgstr "Tendenze per" - -#: ../src\wxUI\dialogs\trends.py:15 -msgid "Country" -msgstr "Paese" - -#: ../src\wxUI\dialogs\trends.py:16 -msgid "City" -msgstr "Città" - -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 -msgid "&Location" -msgstr "&Localizzazione, esterno" - -#: ../src\wxUI\dialogs\update_profile.py:9 -msgid "Update your profile" -msgstr "Aggiorna il tuo profilo" - -#: ../src\wxUI\dialogs\update_profile.py:11 -msgid "&Name (50 characters maximum)" -msgstr "&Nome (massimo 50 caratteri)" - -#: ../src\wxUI\dialogs\update_profile.py:22 -msgid "&Website" -msgstr "Sito &web" - -#: ../src\wxUI\dialogs\update_profile.py:27 -msgid "&Bio (160 characters maximum)" -msgstr "&Descrizione (massimo 160 caratteri)" - -#: ../src\wxUI\dialogs\update_profile.py:33 -msgid "Upload a &picture" -msgstr "Carica una &foto" - -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 -msgid "&Update profile" -msgstr "Aggiorna il &profilo" - -#: ../src\wxUI\dialogs\update_profile.py:76 -msgid "Upload a picture" -msgstr "Carica una foto" - -#: ../src\wxUI\dialogs\update_profile.py:78 -msgid "Discard image" -msgstr "Scartare immagine" - -#: ../src\wxUI\dialogs\urlList.py:5 -msgid "Select URL" -msgstr "Selezionare URL" - -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 -msgid "&User" -msgstr "&Utente" - -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 -msgid "&Autocomplete users" -msgstr "&completamento automatico per gli utenti" - -#: ../src\wxUI\dialogs\userActions.py:19 -msgid "&Follow" -msgstr "&Segui" - -#: ../src\wxUI\dialogs\userActions.py:20 -msgid "U&nfollow" -msgstr "&Non seguire" - -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 -msgid "&Mute" -msgstr "&Mute" - -#: ../src\wxUI\dialogs\userActions.py:22 -msgid "Unmu&te" -msgstr "U&nmute" - -#: ../src\wxUI\dialogs\userActions.py:23 -msgid "&Block" -msgstr "&Blocca" - -#: ../src\wxUI\dialogs\userActions.py:24 -msgid "Unbl&ock" -msgstr "&Sblocca" - -#: ../src\wxUI\dialogs\userActions.py:25 -msgid "&Report as spam" -msgstr "Segnala come spa&m" - -#: ../src\wxUI\dialogs\userActions.py:26 -msgid "&Ignore tweets from this client" -msgstr "&Ignora tweet da questo client" - -#: ../src\wxUI\dialogs\userSelection.py:9 -msgid "Timeline for %s" -msgstr "Cronologia di %s" - -#: ../src\wxUI\dialogs\userSelection.py:18 -msgid "Buffer type" -msgstr "Tipo di Buffer" - -#: ../src\wxUI\dialogs\userSelection.py:19 -msgid "&Tweets" -msgstr "&Tweet" - -#: ../src\wxUI\dialogs\userSelection.py:20 -msgid "&Likes" -msgstr "Mi &piace" - -#: ../src\wxUI\dialogs\userSelection.py:21 -msgid "&Followers" -msgstr "&Followers" - -#: ../src\wxUI\dialogs\userSelection.py:22 -msgid "F&riends" -msgstr "Followin&g" - -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 -msgid "&Retweet" -msgstr "&Retweet" - -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 -msgid "Re&ply" -msgstr "&Rispondi" - -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 -msgid "&Like" -msgstr "&Mi Piace" - -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 -msgid "&Unlike" -msgstr "&Non Mi Piace" - -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 -msgid "&Open URL" -msgstr "C&ollegamento alla pagina..." - -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 -msgid "&Open in Twitter" -msgstr "&Apri in Twitter" - -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 -msgid "&Play audio" -msgstr "A&vvia audio" - -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 -msgid "&Show tweet" -msgstr "&Visualizza Tweet" - -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 -msgid "&Copy to clipboard" -msgstr "&Copia negli appunti" - -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 -msgid "&Delete" -msgstr "&Elimina Tweet" - -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 -msgid "&User actions..." -msgstr "&Azioni utente..." - -#: ../src\wxUI\menus.py:39 -msgid "&Show direct message" -msgstr "Visualizza me&ssaggio diretto" - -#: ../src\wxUI\menus.py:67 -msgid "&Show event" -msgstr "&Mostra evento" - -#: ../src\wxUI\menus.py:77 -msgid "Direct &message" -msgstr "&Messaggio diretto" - -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 -msgid "&View lists" -msgstr "&Visualizza liste" - -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 -msgid "Show user &profile" -msgstr "Visualizza il profilo &utente" - -#: ../src\wxUI\menus.py:84 -msgid "&Show user" -msgstr "&Visualizza utente" - -#: ../src\wxUI\menus.py:98 -msgid "&Tweet about this trend" -msgstr "&Tweet su questa tendenza" - -#: ../src\wxUI\menus.py:100 -msgid "&Show item" -msgstr "&Visualizza voci" - -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 -msgid "&Global settings" -msgstr "Impostazioni &generali" - -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 -msgid "Account se&ttings" -msgstr "Impos&tazioni Account " - -#: ../src\wxUI\sysTrayIcon.py:37 -msgid "Update &profile" -msgstr "Aggiorna il &profilo" - -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "&Show / hide" -msgstr "&Mostra/ Nascondi" - -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 -msgid "&Documentation" -msgstr "&Documentazione" - -#: ../src\wxUI\sysTrayIcon.py:40 -msgid "Check for &updates" -msgstr "Controlla &aggiornamenti" - -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "&Exit" -msgstr "&Esci" - -#: ../src\wxUI\view.py:16 -msgid "&Manage accounts" -msgstr "Gestisci &accounts" - -#: ../src\wxUI\view.py:18 -msgid "&Hide window" -msgstr "&Nascondi la finestra" - -#: ../src\wxUI\view.py:20 -msgid "&Lists manager" -msgstr "Gestione &liste" - -#: ../src\wxUI\view.py:21 -msgid "&Edit keystrokes" -msgstr "&Modifica comandi" - -#: ../src\wxUI\view.py:24 -msgid "E&xit" -msgstr "&Esci" - -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 -msgid "&Tweet" -msgstr "&Tweet" - -#: ../src\wxUI\view.py:34 -msgid "View &address" -msgstr "Visualizza &indirizzo" - -#: ../src\wxUI\view.py:35 -msgid "View conversa&tion" -msgstr "Visualizza &conversazione" - -#: ../src\wxUI\view.py:36 -msgid "Read text in picture" -msgstr "Lettura testo da un immagine" - -#: ../src\wxUI\view.py:41 -msgid "&Actions..." -msgstr "Scegli &Azione..." - -#: ../src\wxUI\view.py:42 -msgid "&View timeline..." -msgstr "&Visualizza la Cronologia..." - -#: ../src\wxUI\view.py:43 -msgid "Direct me&ssage" -msgstr "Messaggio &diretto" - -#: ../src\wxUI\view.py:44 -msgid "&Add to list" -msgstr "Aggiungi alla &lista" - -#: ../src\wxUI\view.py:45 -msgid "R&emove from list" -msgstr "&Rimuovi dalla lista" - -#: ../src\wxUI\view.py:48 -msgid "V&iew likes" -msgstr "&Visualizza tweet marcati con Mi Piace" - -#: ../src\wxUI\view.py:52 -msgid "&Update buffer" -msgstr "&aggiorna buffer" - -#: ../src\wxUI\view.py:53 -msgid "New &trending topics buffer..." -msgstr "Nuovo buffer per argomenti di &tendenza..." - -#: ../src\wxUI\view.py:54 -msgid "Create a &filter" -msgstr "Crea &filtro" - -#: ../src\wxUI\view.py:55 -msgid "&Manage filters" -msgstr "Gestisci fi<ri" - -#: ../src\wxUI\view.py:56 -msgid "Find a string in the currently focused buffer..." -msgstr "Trova del testo nel buffer attualmente focalizzato" - -#: ../src\wxUI\view.py:57 -msgid "&Load previous items" -msgstr "&Carica le voci precedenti" - -#: ../src\wxUI\view.py:60 -msgid "&Autoread" -msgstr "Lettu&ra automatica" - -#: ../src\wxUI\view.py:61 -msgid "&Clear buffer" -msgstr "Ripulisci l'elen&co" - -#: ../src\wxUI\view.py:62 -msgid "&Destroy" -msgstr "&Elimina" - -#: ../src\wxUI\view.py:66 -msgid "&Seek back 5 seconds" -msgstr "Indietro 5 &secondi" - -#: ../src\wxUI\view.py:67 -msgid "&Seek forward 5 seconds" -msgstr "Avanti 5 &secondi" - -#: ../src\wxUI\view.py:72 -msgid "Sounds &tutorial" -msgstr "&Tutorial dei suoni" - -#: ../src\wxUI\view.py:73 -msgid "&What's new in this version?" -msgstr "Cosa c'è di &nuovo in questa versione?" - -#: ../src\wxUI\view.py:74 -msgid "&Check for updates" -msgstr "Controlla &aggiornamenti" - -#: ../src\wxUI\view.py:75 -msgid "&Report an error" -msgstr "Riporta un &errore" - -#: ../src\wxUI\view.py:76 -msgid "{0}'s &website" -msgstr "{0} Sito &Web di TW Blue" - -#: ../src\wxUI\view.py:77 -msgid "Get soundpacks for TWBlue" -msgstr "Ottieni soundpacks per TWBlue" - -#: ../src\wxUI\view.py:78 -msgid "About &{0}" -msgstr "A proposito di &{0}" - -#: ../src\wxUI\view.py:81 -msgid "&Application" -msgstr "&Applicazione" - -#: ../src\wxUI\view.py:84 -msgid "&Buffer" -msgstr "&Buffer" - -#: ../src\wxUI\view.py:85 -msgid "&Audio" -msgstr "&Audio" - -#: ../src\wxUI\view.py:86 -msgid "&Help" -msgstr "A&iuto" - -#: ../src\wxUI\view.py:172 -msgid "Address" -msgstr "Indirizzo" - -#: ../src\wxUI\view.py:203 -msgid "Update" -msgstr "Aggiorna" - -#: ../src\wxUI\view.py:203 -msgid "Your {0} version is up to date" -msgstr "La tua versione di {0} è aggiornata" - -#~ msgid "Empty" -#~ msgstr "Vuoto" - -#~ msgid "One mention from %s " -#~ msgstr "Una menzione da %s " - -#~ msgid "One tweet from %s" -#~ msgstr "Un tweet da %s" - -#~ msgid "You've blocked %s" -#~ msgstr "Hai bloccato %s" - -#~ msgid "You've unblocked %s" -#~ msgstr "Hai sbloccato %s" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "%s(@%s) ti sta seguendo" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "Stai seguendo %s(@%s)" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "Non stai più seguendo %s (@%s)" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "Ti Piace questo tweet: %s, %s" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "A %s(@%s) gli piace: %s" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "Non ti piace %s, %s" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "A %s(@%s) non gli piace: %s" - -#~ msgid "You've created the list %s" -#~ msgstr "Hai creato la lista %s" - -#~ msgid "You've deleted the list %s" -#~ msgstr "Hai eliminato la lista %s" - -#~ msgid "You've updated the list %s" -#~ msgstr "Hai aggiornato la lista %s" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "Hai aggiunto %s(@%s) alla lista %s" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "%s(@%s) ti ha aggiunto alla lista%s" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "Hai rimosso %s(@%s) dalla lista %s" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "%s(@%s) ti ha rimosso dalla lista %s" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "Ti sei iscritto alla lista %s, creata da %s(@%s)" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "%s(@%s) ti ha aggiunto alla lista %s" - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Hai annullato l'iscrizione dalla lista %s, creata da %s(@%s)" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Sei stato cancellato dalla lista %s, creata da %s(@%s)" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "Hai retweettato con un retweet da %s(@%s): %s" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "%s(@%s) Ha rituittato un tuo retweet: %s" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "Chiamate API quando viene avviato il flusso (Una chiamata API equivale a " -#~ "200 tweetts, due chiamate API equivale a 400 tweets," - -#~ msgid "Unable to upload the audio" -#~ msgstr "Impossibile caricare l'audio" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "Attendere per l'autorizzazione..." - -#~ msgid "autodetect" -#~ msgstr "Rilevamento automatico" - -#~ msgid "" -#~ "There's a new %s version available. Would you like to download it now?\n" -#~ "\n" -#~ " %s version: %s\n" -#~ "\n" -#~ "Changes:\n" -#~ "%s" -#~ msgstr "" -#~ "La nuova versione %s è disponibile. Desìderi scaricarla ora?\n" -#~ "\n" -#~ " %s versione: %s\n" -#~ "\n" -#~ "Changes:\n" -#~ "%s" - -#~ msgid "Start {0} after logging in windows" -#~ msgstr "Avvia {0} dopo l'accesso a Windows" - -#~ msgid "" -#~ "If you have a SndUp account, enter your API Key here. If your API Key is " -#~ "invalid, {0} will fail to upload. If there is no API Key here, {0} will " -#~ "upload annonymously." -#~ msgstr "" -#~ "Se avete un account SndUp, inserisci la tua API Key quì. Se l'API Key è " -#~ "sbagliata, {0} non si carica. Se non è presente una API key, {0} si " -#~ "caricherà anonimamente" - -#~ msgid "Disconnect your Pocket account" -#~ msgstr "Scollegare il tuo account Pocket" - -#~ msgid "Connect your Pocket account" -#~ msgstr "Collega il tuo account di Pocket" - -#~ msgid "Pocket Authorization" -#~ msgstr "Autorizzazione Pocket" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. You only need " -#~ "to do this once. Do you want to continue?" -#~ msgstr "" -#~ "La richiesta di autorizzazione si aprirà nel browser. Questa operazione " -#~ "verrà richiesta solo una volta. Vuoi continuare?" - -#~ msgid "Error during authorization. Try again later." -#~ msgstr "Errore durante l'autorizzazione. Riprovare più tardi." - -#~ msgid "Services" -#~ msgstr "Servizi" - -#~ msgid "Contains" -#~ msgstr "Contenuto" - -#~ msgid "Doesn't contain" -#~ msgstr "Senza contenuto" - -#~ msgid "" -#~ "You have successfully logged into Twitter with {0}. You can close this " -#~ "window now." -#~ msgstr "" -#~ "Connessione a Twitter con {0} riuscita. È possibile chiudere questa " -#~ "finestra." - -#~ msgid "&Send" -#~ msgstr "&Invia" - -#~ msgid "Spelling correction" -#~ msgstr "Correzione ortografica" - -#~ msgid "Shorten URL" -#~ msgstr "Accorcia URL" - -#~ msgid "Expand URL" -#~ msgstr "Espandi URL" - -#~ msgid "Send" -#~ msgstr "Invia" - -#~ msgid "unavailable" -#~ msgstr "Non disponibile" - -#~ msgid "Search" -#~ msgstr "Ricerca" - -#~ msgid "Update profile" -#~ msgstr "Aggiorna il profilo" - -#~ msgid "Follow" -#~ msgstr "Segui" - -#~ msgid "Mute" -#~ msgstr "Mute" - -#~ msgid "Block" -#~ msgstr "Blocca" - -#~ msgid "Report as spam" -#~ msgstr "Segnala come spam" - -#~ msgid "Favourites" -#~ msgstr "Favoriti" - -#~ msgid "Favourites timeline for {}" -#~ msgstr "Cronologia Favoriti di {0}" - -#~ msgid "Tweet favourited." -#~ msgstr "Tweet preferiti." - -#~ msgid "Mark as favourite" -#~ msgstr "Aggiungi ai preferiti" - -#~ msgid "Remove from favourites" -#~ msgstr "Rimuovi dai favoriti" - -#~ msgid "You've added to favourites: %s, %s" -#~ msgstr "Hai aggiunto ai preferiti: %s, %s" - -#~ msgid "%s(@%s) has marked as favourite: %s" -#~ msgstr "%s(@%s) ha segnato come preferito: %s" - -#~ msgid "You've removed from favourites: %s, %s" -#~ msgstr " Hai rimosso dai preferiti: %s, %s" - -#~ msgid "%s(@%s) has removed from favourites: %s" -#~ msgstr "%s(@%s) è stato rimosso dai preferiti: %s" - -#~ msgid "Favourites: " -#~ msgstr "Preferiti: " - -#~ msgid "Add to &favourites" -#~ msgstr "&Aggiungi ai preferiti" - -#~ msgid "Remove from favo&urites" -#~ msgstr "&Rimuovi dai favoriti" - -#~ msgid "V&iew favourites" -#~ msgstr "Visualizza &preferiti" - -#~ msgid "Opening media..." -#~ msgstr "Apertura contenuto multimediale..." - -#~ msgid "Add a new ignored client" -#~ msgstr "Aggiunto un nuovo client ignorato" - -#~ msgid "Do you really want to delete this timeline?" -#~ msgstr "Eliminare la Cronologia?" - -#~ msgid "Autocomplete users\\342\\200\\231 settings" -#~ msgstr "Autocomplete users\\342\\200\\231 Impostazioni" - -#~ msgid "Set the autocomplete function" -#~ msgstr "Imposta la funzione di completamento automatico" - -#~ msgid "Relative times" -#~ msgstr "Mostra tempo di ricezione trascorso" - -#~ msgid "" -#~ "API calls when the stream is started (One API call equals to 200 tweetts, " -#~ "two API calls equals 400 tweets, etc):" -#~ msgstr "" -#~ "Chiamate API quando viene avviato il flusso (Una chiamata API equivale a " -#~ "200 tweetts, due chiamate API equivale a 400 tweets," - -#~ msgid "" -#~ "Inverted buffers: The newest tweets will be shown at the beginning of the " -#~ "lists while the oldest at the end" -#~ msgstr "" -#~ "Inverti elenco: I nuovi tweets verranno mostrate in cima all'elenco, i " -#~ "precedenti alla fine" - -#~ msgid "" -#~ "The authorization request will be opened in your browser. Copy the code " -#~ "from Dropbox and paste it into the text box which will appear. You only " -#~ "need to do this once." -#~ msgstr "" -#~ "La richiesta di autorizzazione verrà aperta nel browser. Copia il codice " -#~ "da Dropbox ed incolla nel campo editazione che apparirà. Questa " -#~ "operazione verrà richiesta solo una volta." - -#~ msgid "Verification code" -#~ msgstr "Codice di verifica" - -#~ msgid "Error during authorisation. Try again later." -#~ msgstr "Errore durante l'autorizzazione. Riprovare più tardi." - -#~ msgid "TW Blue preferences" -#~ msgstr "Preferenze" - -#~ msgid "Show other buffers" -#~ msgstr "Visualizza" - -#~ msgid "JPG images" -#~ msgstr "Immagini JPG" - -#~ msgid "GIF images" -#~ msgstr "Immagini GIF" - -#~ msgid "PNG Images" -#~ msgstr "Immagini PNG" - -#~ msgid "Select an URL" -#~ msgstr "Seleziona un indirizzo" - -#~ msgid "This account is not logged in twitter." -#~ msgstr "Questo account non è registrato in twitter." - -#~ msgid "{0}: This account is not logged in twitter." -#~ msgstr "{0}: Questo account non è connesso a twitter." - -#~ msgid "Global mute off" -#~ msgstr "Silenzia tutto off" - -#~ msgid "User-defined buffer created." -#~ msgstr "Buffer per l'utente definito creato." - -#~ msgid "User-defined buffer destroied." -#~ msgstr "Buffer per l'utente definito è stato eliminato" - -#~ msgid "Someone's favourites have been updated." -#~ msgstr "I preferiti di qualcuno son stati aggiornati" - -#~ msgid "Mension received." -#~ msgstr "Menzione ricevuta." - -#~ msgid "A trending topic buffer has been updated." -#~ msgstr "Aggiornamento nel buffer argomenti di tendenza" - -#~ msgid "New tweet in user-defined buffer." -#~ msgstr "Nuovo tweet nella linea temporale di un utente definito" - -#~ msgid "Mis-spelled word: %s" -#~ msgstr "Mis-spelled word: %s" - -#~ msgid "Mis-spelled word" -#~ msgstr "Mis-spelled word" - -#~ msgid "Finished" -#~ msgstr "Finito" - -#~ msgid "The spelling review has finished." -#~ msgstr "Correzione di ortografia terminata" - -#~ msgid "" -#~ "Do you really want to delete this message? It will be eliminated from " -#~ "Twitter as well." -#~ msgstr "" -#~ "Sei sicuro di voler eliminare questo messaggio? Verrà eliminato anche da " -#~ "Twitter." - -#~ msgid "Show followers" -#~ msgstr "Visualizza followers" - -#~ msgid "Show friends" -#~ msgstr "Visualizza following" - -#~ msgid "Show favourites" -#~ msgstr "Visualizza preferiti" - -#~ msgid "Show blocked users" -#~ msgstr "Mostra gli utenti bloccati" - -#~ msgid "Show muted users" -#~ msgstr "Mostra utenti silenziati" - -#~ msgid "Show events" -#~ msgstr "Visualizza notifiche" - -#~ msgid "" -#~ "The authorisation request will be shown on your browser. Copy the code " -#~ "tat Dropbox will provide and, in the text box that will appear on TW " -#~ "Blue, paste it. This code is necessary to continue. You only need to do " -#~ "it once." -#~ msgstr "" -#~ "Una richiesta di autorizzazione verrà visualizzata nel tuo browser. " -#~ "Copiare il codice fornito da Dropbox nella casella di testo che " -#~ "apparirà ed incolla su TW Blue. Questo codice è necessario per continuare." - -#~ msgid "Authorisation" -#~ msgstr "Autorizzazione" - -#~ msgid "Change to the next account" -#~ msgstr "Passa al successivo account" - -#~ msgid "Change to the previous account" -#~ msgstr "Passa al precedente account" - -#~ msgid "Remove buffer" -#~ msgstr "Elimina Elenco" - -#~ msgid "" -#~ "Open URL on the current tweet, or further information for a friend or " -#~ "follower" -#~ msgstr "Apri il link nel tweet corrente, o ulteriori informazioni" - -#~ msgid "Go to the first element on the list" -#~ msgstr "Vai al primo elemento dell'elenco" - -#~ msgid "Go to the last element on the list" -#~ msgstr "Vai all'ultimo elemento dell'elenco" - -#~ msgid "Move 20 elements up on the current list" -#~ msgstr "Salta 20 elementi in alto nell'elenco corrente" - -#~ msgid "Move 20 elements down on the current list" -#~ msgstr "Salta 20 elementi in basso nell'elenco corrente" - -#~ msgid "Remove a tweet or direct message" -#~ msgstr "Rimuovi un tweet o un messaggio diretto" - -#~ msgid "Globally mute/unmute the current account" -#~ msgstr "mute/unmute l'account corrente" - -#~ msgid "load previous items to any buffer" -#~ msgstr "Carica voci precedenti per tutti i buffer" - -#~ msgid "" -#~ "The request for the required Twitter authorisation to continue will be " -#~ "opened on your browser. You only need to do it once. Would you like to " -#~ "autorhise a new account now?" -#~ msgstr "" -#~ "La richiesta per l'autorizzazione a Twitter necessaria per continuare " -#~ "sarà aperto sul tuo browser. Desìderi autorizzare un nuovo account?" - -#~ msgid "" -#~ "Your access token is invalid or the authorisation has failed. Please try " -#~ "again." -#~ msgstr "" -#~ "La tua chiave di accesso non è valido o l'autorizzazione non è riuscita. " -#~ "Riprova." - -#~ msgid "" -#~ "%s (@%s). %s followers, %s friends, %s tweets. Last tweet on %s. Joined " -#~ "Twitter on %s" -#~ msgstr "" -#~ "%s (@%s). %s followers, %s Amici, %s tweets. Ultimo tweet %s. Iscritto a " -#~ "Twitter da %s" - -#~ msgid "" -#~ "The application requires to be restarted to save these changes. Press OK " -#~ "to do it now." -#~ msgstr "" -#~ "L'applicazione richiede di essere riavviata per salvare le modifiche. " -#~ "Premi OK per farlo ora." - -#~ msgid "" -#~ "Dropbox will open in your browser. After you log into Dropbox, an " -#~ "authorization code will be generated. Please paste it into the field " -#~ "which will appear. You only need to do this once." -#~ msgstr "" -#~ "Dropbox si aprirà nel tuo browser. Dopo la connessione a Dropbox viene " -#~ "generato un codice di autorizzazione. Incollare nell'apposito campo " -#~ "editazione. Questa operazione verrà eseguita una volta sola." - -#~ msgid "View &trending topics" -#~ msgstr "Visualizza &tendenze" - -#~ msgid "&Unfollow" -#~ msgstr "Non seg&uire" - -#~ msgid "U&nmute" -#~ msgstr "&Unmute" - -#~ msgid "Unb&lock" -#~ msgstr "Sb&locca" - -#~ msgid "&Timeline" -#~ msgstr "Linea &temporale" - -#~ msgid "&Autoread tweets for this buffer" -#~ msgstr "Leggi &automaticamente tweets per questo buffer" - -#~ msgid "&Remove buffer" -#~ msgstr "&Elimina Elenco" - -#~ msgid "Stop recording" -#~ msgstr "Ferma la registrazione" - -#~ msgid "The tweet may contain a playable audio" -#~ msgstr "Il tweet contiene un audio riproducibile" - -#~ msgid "A timeline has been created" -#~ msgstr "Creata nuova Linea temporale" - -#~ msgid "A timeline has been deleted" -#~ msgstr "Linea temporale cancellata" - -#~ msgid "You've received a direct message" -#~ msgstr "Hai ricevuto un messaggio diretto" - -#~ msgid "You've sent a direct message" -#~ msgstr "Hai inviato un messaggio diretto" - -#~ msgid "A bug has happened" -#~ msgstr "Segnalazione errore" - -#~ msgid "You've added a tweet to your favourites" -#~ msgstr "Hai aggiunto un tweet ai tuoi preferiti" - -#~ msgid "The tweet has coordinates to determine its location" -#~ msgstr "Il tweet contiene coordinate per determinare la localizzazione" - -#~ msgid "There are no more tweets to read" -#~ msgstr "Non ci sono altri tweet da leggere" - -#~ msgid "A list has a new tweet" -#~ msgstr "Una lista ha un nuovo tweet" - -#~ msgid "You can't add any more characters on the tweet" -#~ msgstr "Non è possibile aggiungere altri caratteri al tweet" - -#~ msgid "You've been mentioned " -#~ msgstr "Sei stato menzionato" - -#~ msgid "A new event has happened" -#~ msgstr "Nuovo evento " - -#~ msgid "You've replied" -#~ msgstr "Hai risposto" - -#~ msgid "You've sent a tweet" -#~ msgstr "Hai inviato un tweet" - -#~ msgid "There's a new tweet in a timeline" -#~ msgstr "Nuovo tweet nella linea temporale" - -#~ msgid "You have a new follower" -#~ msgstr "Hai un nuovo seguitore" - -#~ msgid "You've turned the volume up or down" -#~ msgstr "Volume regolato" - -#~ msgid "" -#~ "It seems as though the currently used sound pack needs an update. %i " -#~ "fails are still be required to use this function. Make sure to obtain the " -#~ "needed lacking sounds or to contact with the sound pack developer." -#~ msgstr "" -#~ "Sembra che attualmente il pacchetto dei suoni usato richiede un " -#~ "aggiornamento. %i I fail sono ancora necessari per utilizzare questa " -#~ "funzione. Assicurati di ottenere i suoni mancanti necessari o contatta lo " -#~ "sviluppatore per il pacchetto." - -#~ msgid "See the users list" -#~ msgstr "Visualizza la lista degli utenti" - -#~ msgid "Do you really want to delete this message?" -#~ msgstr "Sei sicuro di voler eliminare questo messaggio?" - -#~ msgid "Unable to play audio." -#~ msgstr "Impossibile riprodurre audio." - -#~ msgid "Do you really want to delete this favourites timeline?" -#~ msgstr "Sei sicuro di voler eliminare questa Linea temporale?" - -#~ msgid "&Mention" -#~ msgstr "&Menziona" - -#~ msgid "Announce" -#~ msgstr "Notifica" - -#~ msgid "" -#~ "Do you really want to empty this buffer? It's items will be removed from " -#~ "the list" -#~ msgstr "" -#~ "Sei sicuro di voler svuotare questo buffer? It's items will be removed " -#~ "from the list" - -#~ msgid "Do you really want to delete this search term?" -#~ msgstr "Eliminare la ricerca? " - -#~ msgid "ask before exiting TwBlue?" -#~ msgstr "Richiedere conferma prima di uscire da TwBlue?" - -#~ msgid "Activate the auto-start of the invisible interface" -#~ msgstr "Attiva automaticamente all'avvio l'interfaccia invisibile" - -#~ msgid "Global mute" -#~ msgstr "Silenzia tutto" - -#~ msgid "friends" -#~ msgstr "Following" - -#~ msgid "Favorites" -#~ msgstr "Favoriti" - -#~ msgid "You've muted to %s" -#~ msgstr "Silenziato a %s" - -#~ msgid "You've unmuted to %s" -#~ msgstr "Hai de-silenziato %s" - -#~ msgid "This list is arready opened." -#~ msgstr "Questa lista è già aperta." - -#~ msgid "List for %s" -#~ msgstr "Modifica elenco %s" - -#~ msgid "Uploading..." -#~ msgstr "Caricando..." - -#~ msgid "Men&tion all" -#~ msgstr "Menziona &Tutti" - -#~ msgid "This user does not exist on Twitter" -#~ msgstr "Questo utente non esiste su Twitter" - -#~ msgid "S&witch account" -#~ msgstr "&Passa a un altro account" - -#~ msgid "&Preferences" -#~ msgstr "Preferen&ze" - -#~ msgid "About &TW Blue" -#~ msgstr "&Informazioni su TW Blue" - -#~ msgid "" -#~ "An error occurred while looking for an update. It may be due to any " -#~ "problem either on our server or on your DNS servers. Please, try again " -#~ "later." -#~ msgstr "" -#~ "Si è verificato un errore durante il tentativo di aggiornare. Probabili " -#~ "problemi Sia sul nostro server o sui server DNS. Provare più tardi." - -#~ msgid "Sent" -#~ msgstr "Inviati" - -#~ msgid "%s favourites from %s" -#~ msgstr "%s preferiti da %s" - -#~ msgid "Streams disconnected. TW Blue will try to reconnect in a minute." -#~ msgstr "Streams scollegati. TW Blu tenterà di riconnettersi immediatamente." - -#~ msgid "Reconnecting streams..." -#~ msgstr "Riconnessione streams..." - -#~ msgid "search users for %s" -#~ msgstr "Cerca utente per %s" - -#~ msgid "Do you really want to close TW Blue?" -#~ msgstr "Sei sicuro di voler uscire daTW Blue?" - -#~ msgid "Exiting..." -#~ msgstr "Chiusura in corso..." - -#~ msgid "Error while adding to favourites." -#~ msgstr "Errore durante l'aggiunta ai preferiti." - -#~ msgid "Error while removing from favourites." -#~ msgstr "Errore durante la rimozione dai preferiti." - -#~ msgid "Individual timeline" -#~ msgstr "Linea Temporale individuale" - -#~ msgid "List of favourites" -#~ msgstr "Lista dei favoriti" - -#~ msgid "Existing list" -#~ msgstr "Elenco esistente" - -#~ msgid "" -#~ "There's already a list of favourites for this user. You can't create " -#~ "another." -#~ msgstr "C'è già una lista di preferiti per questo utente." - -#~ msgid "" -#~ "This user has no favourites. You can't create a list of favourites for " -#~ "this user." -#~ msgstr "" -#~ "Questo utente non ha preferenze. Non è possibile creare una lista di " -#~ "preferiti per questo utente." - -#~ msgid "%s" -#~ msgstr "%s" - -#~ msgid "Documentation" -#~ msgstr "Documentazione" - -#~ msgid "Translation" -#~ msgstr "Traduzione" - -#~ msgid "Move up one tweet in the conversation" -#~ msgstr "Vai al tweet precedente" - -#~ msgid "Move down one tweet in the conversation" -#~ msgstr "Vai al tweet successivo" - -#~ msgid "Show the graphical interface" -#~ msgstr "Mostra l'interfaccia grafica" - -#~ msgid "Reply to a tweet" -#~ msgstr "Rispondi" - -#~ msgid "Empty the buffer removing all the elements" -#~ msgstr "Svuota il buffer rimuovendo tutti gli elementi" - -#~ msgid "Listen the current message" -#~ msgstr "Ascolta il messaggio corrente" - -#~ msgid "Get location of any tweet" -#~ msgstr "Localizza tutti i tweet" - -#~ msgid "Creates a buffer for displaying trends for a desired place" -#~ msgstr "" -#~ "Crea un buffer per la visualizzazione di tendenze per un luogo desiderato" - -#~ msgid "Select a twitter account to start TW Blue" -#~ msgstr "Selezionare un account twitter per avviare TW Blue" - -#~ msgid "Remove session" -#~ msgstr "Rimuovi sessione" - -#~ msgid "One tweet from %s in the list %s" -#~ msgstr " Un tweet da %s nella lista %s" - -#~ msgid "One direct message" -#~ msgstr "Un messaggio diretto" - -#~ msgid "About a week ago" -#~ msgstr "Circa una settimana fa" - -#~ msgid "About {} weeks ago" -#~ msgstr "Circa {} settimane fa" - -#~ msgid "A month ago" -#~ msgstr "Un mese fa" - -#~ msgid "About {} months ago" -#~ msgstr "Circa {} mesi fa" - -#~ msgid "About a year ago" -#~ msgstr "Circa un anno fa" - -#~ msgid "About {} years ago" -#~ msgstr "Circa {} anni fa" - -#~ msgid "About 1 day ago" -#~ msgstr "Un giorno fa" - -#~ msgid "About {} days ago" -#~ msgstr "Circa {} giorni fa" - -#~ msgid "just now" -#~ msgstr "Adesso" - -#~ msgid "{} seconds ago" -#~ msgstr "{} secondi fa" - -#~ msgid "1 minute ago" -#~ msgstr "Un minuto fa" - -#~ msgid "{} minutes ago" -#~ msgstr "{} minuti fa" - -#~ msgid "About 1 hour ago" -#~ msgstr "Un'ora fa" - -#~ msgid "About {} hours ago" -#~ msgstr "Circa {} ore fa" - -#~ msgid "January" -#~ msgstr "Gennaio" - -#~ msgid "February" -#~ msgstr "Febbraio" - -#~ msgid "March" -#~ msgstr "Marzo" - -#~ msgid "April" -#~ msgstr "Aprile" - -#~ msgid "June" -#~ msgstr "Giugno" - -#~ msgid "July" -#~ msgstr "Luglio" - -#~ msgid "August" -#~ msgstr "Agosto" - -#~ msgid "September" -#~ msgstr "Settembre" - -#~ msgid "October" -#~ msgstr "Ottobre" - -#~ msgid "November" -#~ msgstr "Novembre" - -#~ msgid "December" -#~ msgstr "Dicembre" - -#~ msgid "Sunday" -#~ msgstr "Domenica" - -#~ msgid "Monday" -#~ msgstr "Lunedì" - -#~ msgid "Tuesday" -#~ msgstr "Martedì" - -#~ msgid "Wednesday" -#~ msgstr "Mercoledì" - -#~ msgid "Thursday" -#~ msgstr "Giovedì" - -#~ msgid "Friday" -#~ msgstr "Venerdì" - -#~ msgid "Saturday" -#~ msgstr "Sabato" - -#~ msgid "sun" -#~ msgstr "Dom" - -#~ msgid "mon" -#~ msgstr "Lu" - -#~ msgid "tue" -#~ msgstr "Ma" - -#~ msgid "wed" -#~ msgstr "Me" - -#~ msgid "thu" -#~ msgstr "Gio" - -#~ msgid "fri" -#~ msgstr "Ve" - -#~ msgid "sat" -#~ msgstr "Sab" - -#~ msgid "jan" -#~ msgstr "Gen" - -#~ msgid "feb" -#~ msgstr "feb" - -#~ msgid "mar" -#~ msgstr "Mar" - -#~ msgid "apr" -#~ msgstr "Apr" - -#~ msgid "may" -#~ msgstr "Mag" - -#~ msgid "jun" -#~ msgstr "Giu" - -#~ msgid "jul" -#~ msgstr "Lug" - -#~ msgid "aug" -#~ msgstr "Ago" - -#~ msgid "sep" -#~ msgstr "Set" - -#~ msgid "oct" -#~ msgstr "Ott" - -#~ msgid "nov" -#~ msgstr "Nov" - -#~ msgid "dec" -#~ msgstr "dic" - -#~ msgid "%A, %B %d, %Y at %I:%M:%S %p" -#~ msgstr "%A, %B %d, %Y at %I:%M:%S %p" - -#~ msgid "Your TW Blue version is up to date" -#~ msgstr "La tua versione di TW Blue è aggiornata" - -#~ msgid "Connection error. Try again later." -#~ msgstr "Errore durante la connessione. Riprovare più tardi." - -#~ msgid "Ouner" -#~ msgstr "Ouner" - -#~ msgid "View members" -#~ msgstr "Visualizza membri" - -#~ msgid "View subscribers" -#~ msgstr "Visualizza gli Iscritti" From 97afc379e870d6dc1ba22c1321da8363ca117d4d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 00:47:23 -0500 Subject: [PATCH 064/245] Pushed a new snapshot --- doc/changelog.md | 1 + src/application.py | 2 +- src/sessions/twitter/reduce.py | 2 +- updates/snapshots.json | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 66ef6a13..51149f76 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384)) * We just implemented some changes in the way TWBlue handles tweets in order to reduce its RAM memory usage [#380](https://github.com/manuelcortez/TWBlue/pull/380): * We reduced the tweets size by storing only the tweet fields we currently use. This should reduce tweet's size in memory for every object up to 75%. * When using the cache database to store your tweets, there is a new setting present in the account settings dialog, in the general tab. This setting allows you to control whether TWBlue will load the whole database into memory (which is the current behaviour) or not. diff --git a/src/application.py b/src/application.py index 41869e88..de258a64 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "5" + version = "6" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] diff --git a/src/sessions/twitter/reduce.py b/src/sessions/twitter/reduce.py index eae64a70..73d8c45e 100644 --- a/src/sessions/twitter/reduce.py +++ b/src/sessions/twitter/reduce.py @@ -4,7 +4,7 @@ from tweepy.models import Status def reduce_tweet(tweet): """ generates a new Tweet model with the fields we currently need, excluding everything else including null values and empty collections. """ - allowed_values = ["created_at", "id", "full_text", "text", "message", "in_reply_to_status_id", "in_reply_to_user_id", "is_quote_status", "lang", "source", "coordinates", "quoted_status_id", ] + allowed_values = ["created_at", "id", "full_text", "text", "message", "in_reply_to_status_id", "in_reply_to_user_id", "is_quote_status", "lang", "source", "coordinates", "quoted_status_id", "extended_entities"] allowed_entities = ["hashtags", "media", "urls", "user_mentions", "polls"] status_dict = {} for key in allowed_values: diff --git a/updates/snapshots.json b/updates/snapshots.json index f12f4a45..1505065f 100644 --- a/updates/snapshots.json +++ b/updates/snapshots.json @@ -1,4 +1,4 @@ -{"current_version": "5", +{"current_version": "6", "description": "Snapshot version.", "date": "unknown", "downloads": From 2b719858c22edf3ba88aaebf8c6f7b38e7cf087e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 03:28:43 -0500 Subject: [PATCH 065/245] Initial implementation of gitlab's CI file --- .gitlab-ci.yml | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..c2a212ef --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,72 @@ +variables: + PYTHON: "C:\\python38\\python.exe" + NSIS: "C:\\program files (x86)\\nsis\\makensis.exe" + +stages: + - build + - upload + +snapshot32: + tags: + - shared-windows + - windows + - windows-1809 + before_script: + - Set-Variable -Name "time" -Value (date -Format "%H:%m") + - echo ${time} + - echo "started by ${GITLAB_USER_NAME}" + - choco install python --version 3.8.7 -y -ForceX86 + - '&$env:PYTHON -V' + - '&$env:PYTHON -m pip install --upgrade pip' + - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' + - '&$env:PYTHON -m pip uninstall enum34 -y' + stage: build + interruptible: true + script: + # Create html documentation firstly. + - cd doc + - '&$env:PYTHON documentation_importer.py' + - cd ..\src + - '&$env:PYTHON ..\doc\generator.py' + - '&$env:PYTHON setup.py build' + - cd .. + - mkdir artifacts + - mv src/dist artifacts/TWBlue + only: + - master + artifacts: + paths: + - artifacts + expire_in: 1 day + +snapshot64: + tags: + - shared-windows + - windows + - windows-1809 + before_script: + - Set-Variable -Name "time" -Value (date -Format "%H:%m") + - echo ${time} + - echo "started by ${GITLAB_USER_NAME}" + - choco install python --version 3.8.7 -y + - '&$env:PYTHON -V' + - '&$env:PYTHON -m pip install --upgrade pip' + - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' + stage: build + interruptible: true + script: + # Create html documentation firstly. + - cd doc + - '&$env:PYTHON documentation_importer.py' + - cd ..\src + - '&$env:PYTHON ..\doc\generator.py' + - '&$env:PYTHON setup.py build' + - cd .. + - mkdir artifacts + - mv src/dist artifacts/TWBlue64 + only: + - master + artifacts: + paths: + - artifacts + expire_in: 1 day From b839dc077cd83c72f7cddc3f1fd563c7f83d4869 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 03:29:27 -0500 Subject: [PATCH 066/245] Updated a small typo --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c2a212ef..c08ab114 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,7 +33,7 @@ snapshot32: - mkdir artifacts - mv src/dist artifacts/TWBlue only: - - master + - next-gen artifacts: paths: - artifacts @@ -65,7 +65,7 @@ snapshot64: - mkdir artifacts - mv src/dist artifacts/TWBlue64 only: - - master + - next-gen artifacts: paths: - artifacts From a27eee1fa2bd4b0dfaeca19455a78c04d777a4ee Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 03:40:00 -0500 Subject: [PATCH 067/245] Add submodules --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c08ab114..aa0e89c6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,5 @@ variables: + GIT_SUBMODULE_STRATEGY: recursive PYTHON: "C:\\python38\\python.exe" NSIS: "C:\\program files (x86)\\nsis\\makensis.exe" From ef443346d1db24eadc7dc2f9ecae6d1baea836f9 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 04:16:59 -0500 Subject: [PATCH 068/245] Try to generate zip versions and installers --- .gitlab-ci.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aa0e89c6..2f011efe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,7 @@ variables: stages: - build + - make_installer - upload snapshot32: @@ -32,7 +33,11 @@ snapshot32: - '&$env:PYTHON setup.py build' - cd .. - mkdir artifacts + - cd scripts + - '&$env:PYTHON make_archive.py' + - cd .. - mv src/dist artifacts/TWBlue + - move src/twblue.zip artifacts/twblue_snapshot_x86.zip only: - next-gen artifacts: @@ -64,10 +69,34 @@ snapshot64: - '&$env:PYTHON setup.py build' - cd .. - mkdir artifacts + - cd scripts + - '&$env:PYTHON make_archive.py' + - cd .. - mv src/dist artifacts/TWBlue64 + - move src/twblue.zip artifacts/twblue_snapshot_x64.zip only: - next-gen artifacts: paths: - artifacts expire_in: 1 day + +generate_versions: + tags: + - shared-windows + - windows + - windows-1809 + before_script: + - Set-Variable -Name "time" -Value (date -Format "%H:%m") + - echo ${time} + - echo "started by ${GITLAB_USER_NAME}" + - choco install nsis -y -ForceX86 + script: + - move artifacts/TWBlue scripts/ + - move artifacts/TWBlue64 scripts/ + - '&$env:NSIS twblue.nsi' + - move twblue_setup.exe ../artifacts + artifacts: + paths: + - artifacts + expire_in: 1 day \ No newline at end of file From 7935f79d7713e8bcd2cdac1dba016326abe7f850 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 04:20:54 -0500 Subject: [PATCH 069/245] fixed a syntax error --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2f011efe..d9395d8f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -82,6 +82,7 @@ snapshot64: expire_in: 1 day generate_versions: + stage: make_installer tags: - shared-windows - windows From a6032cae465e84d31313d3e32aaad36e2b96f931 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 04:30:42 -0500 Subject: [PATCH 070/245] Added make_archive as a script --- scripts/make_archive.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 scripts/make_archive.py diff --git a/scripts/make_archive.py b/scripts/make_archive.py new file mode 100644 index 00000000..4f967183 --- /dev/null +++ b/scripts/make_archive.py @@ -0,0 +1,12 @@ +import shutil +import os +import sys + +def create_archive(): + os.chdir("..\\src") + print("Creating zip archive...") + folder = "dist" + shutil.make_archive("twblue", "zip", folder) + os.chdir("..\\scripts") + +create_archive() \ No newline at end of file From f998fa62a692f8291bae4e0c3880b47e1bab4f4a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 04:50:36 -0500 Subject: [PATCH 071/245] Added missed move command --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d9395d8f..c8f23c64 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -95,6 +95,7 @@ generate_versions: script: - move artifacts/TWBlue scripts/ - move artifacts/TWBlue64 scripts/ + - cd scripts - '&$env:NSIS twblue.nsi' - move twblue_setup.exe ../artifacts artifacts: From 3515df9b153e7cdafb3e82ae32e227cd2e745f54 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 05:26:42 -0500 Subject: [PATCH 072/245] Upload files to FTP server after generating snapshots --- .gitlab-ci.yml | 16 +++++++++++++++- scripts/upload.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 scripts/upload.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c8f23c64..4a34ebc3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -101,4 +101,18 @@ generate_versions: artifacts: paths: - artifacts - expire_in: 1 day \ No newline at end of file + expire_in: 1 day + +upload: + stage: upload + tags: + - linux + image: python + interruptible: true + script: + - cd artifacts + - python ../scripts/upload.py + only: + - master + - tags + - schedules \ No newline at end of file diff --git a/scripts/upload.py b/scripts/upload.py new file mode 100644 index 00000000..b170412a --- /dev/null +++ b/scripts/upload.py @@ -0,0 +1,33 @@ +#! /usr/bin/env python +import sys +import os +import glob +import ftplib + +transferred=0 + +def callback(progress): + global transferred + transferred = transferred+len(progress) + print("Uploaded {}".format(convert_bytes(transferred),)) + +ftp_server = os.environ.get("FTP_SERVER") or sys.argv[1] +ftp_username = os.environ.get("FTP_USERNAME") or sys.argv[2] +ftp_password = os.environ.get("FTP_PASSWORD") or sys.argv[3] + +print("Uploading files to the TWBlue server...") +print("Connecting to %s" % (ftp_server,)) +connection = ftplib.FTP(ftp_server) +print("Connected to FTP server {}".format(ftp_server,)) +connection.login(user=ftp_username, passwd=ftp_password) +print("Logged in successfully") +connection.cwd("web/pubs") +files = glob.glob("*.zip")+glob.glob("*.exe") +print("These files will be uploaded into the version folder: {}".format(files,)) +for file in files: + transferred = 0 + print("Uploading {}".format(file,)) + with open(file, "rb") as f: + connection.storbinary('STOR %s' % file, f, callback=callback, blocksize=1024*1024) +print("Upload completed. exiting...") +connection.quit() \ No newline at end of file From 13c47f7b9fccea7da2ebc1afcc0b341c3893521b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 05:28:15 -0500 Subject: [PATCH 073/245] Fixed branch name --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4a34ebc3..97544e94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -113,6 +113,6 @@ upload: - cd artifacts - python ../scripts/upload.py only: - - master + - next-gen - tags - schedules \ No newline at end of file From a9f52b3a94be8ec55306ee9679b33946e3b122cd Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 06:01:05 -0500 Subject: [PATCH 074/245] Added convert_bytes function to show correctly FTP upload progress --- scripts/upload.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/upload.py b/scripts/upload.py index b170412a..b3460158 100644 --- a/scripts/upload.py +++ b/scripts/upload.py @@ -6,6 +6,21 @@ import ftplib transferred=0 +def convert_bytes(n): + K, M, G, T, P = 1 << 10, 1 << 20, 1 << 30, 1 << 40, 1 << 50 + if n >= P: + return '%.2fPb' % (float(n) / T) + elif n >= T: + return '%.2fTb' % (float(n) / T) + elif n >= G: + return '%.2fGb' % (float(n) / G) + elif n >= M: + return '%.2fMb' % (float(n) / M) + elif n >= K: + return '%.2fKb' % (float(n) / K) + else: + return '%d' % n + def callback(progress): global transferred transferred = transferred+len(progress) From fe8b58a7b9f88f9d15ae2e95e4cd1894f79eaab1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 10:20:39 -0500 Subject: [PATCH 075/245] Include quoted tweets and retweets in audio detection and playback --- src/sessions/twitter/utils.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index ce0ae47b..fc080bdf 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -41,9 +41,9 @@ def find_urls (tweet, twitter_media=False): if i["expanded_url"] not in urls: urls.append(i["expanded_url"]) if hasattr(tweet, "quoted_status"): - urls.extend(find_urls(tweet.quoted_status)) + urls.extend(find_urls(tweet.quoted_status, twitter_media)) if hasattr(tweet, "retweeted_status"): - urls.extend(find_urls(tweet.retweeted_status)) + urls.extend(find_urls(tweet.retweeted_status, twitter_media)) if hasattr(tweet, "message"): i = "message" elif hasattr(tweet, "full_text"): @@ -70,6 +70,14 @@ def find_list(name, lists): if lists[i].name == name: return lists[i].id def is_audio(tweet): + if hasattr(tweet, "quoted_status") and hasattr(tweet.quoted_status, "extended_entities"): + result = is_audio(tweet.quoted_status) + if result != None: + return result + if hasattr(tweet, "retweeted_status") and hasattr(tweet.retweeted_status, "extended_entities"): + result = is_audio(tweet.retweeted_status) + if result == True: + return result # Checks firstly for Twitter videos and audios. if hasattr(tweet, "extended_entities"): for mediaItem in tweet.extended_entities["media"]: From a7838bbf7d1c52b5ee5613d4a68be6f6747aded3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 10:23:39 -0500 Subject: [PATCH 076/245] Next snapshots will have installer and 64 bits version. Switched to Gitlab CI to generate snapshots. --- .gitlab-ci.yml | 8 ++-- appveyor.yml | 84 -------------------------------- scripts/twblue.nsi | 4 +- scripts/twblue_snapshot.nsi | 95 +++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 90 deletions(-) delete mode 100644 appveyor.yml create mode 100644 scripts/twblue_snapshot.nsi diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 97544e94..b56b63f5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,7 +39,7 @@ snapshot32: - mv src/dist artifacts/TWBlue - move src/twblue.zip artifacts/twblue_snapshot_x86.zip only: - - next-gen + - tags artifacts: paths: - artifacts @@ -75,7 +75,7 @@ snapshot64: - mv src/dist artifacts/TWBlue64 - move src/twblue.zip artifacts/twblue_snapshot_x64.zip only: - - next-gen + - tags artifacts: paths: - artifacts @@ -96,8 +96,8 @@ generate_versions: - move artifacts/TWBlue scripts/ - move artifacts/TWBlue64 scripts/ - cd scripts - - '&$env:NSIS twblue.nsi' - - move twblue_setup.exe ../artifacts + - '&$env:NSIS twblue_snapshot.nsi' + - move twblue_snapshot_setup.exe ../artifacts artifacts: paths: - artifacts diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 6fc07d83..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,84 +0,0 @@ -pull_requests: - # Avoid building after pull requests. Shall we disable this option? - do_not_increment_build_number: true - -# Only build whenever we add tags to the repo. -skip_non_tags: true - -environment: - - matrix: - - # List of python versions we want to work with. - - PYTHON: "C:\\Python38" - PYTHON_VERSION: "3.8.x" # currently 2.7.9 - PYTHON_ARCH: "32" - - # perhaps we may enable this one in future? -# - PYTHON: "C:\\Python37-x64" -# PYTHON_VERSION: "3.7.x" # currently 2.7.9 -# PYTHON_ARCH: "64" - -# This is important so we will retrieve everything in submodules as opposed to default method. -clone_script: - - cmd: >- - git clone -q --branch=%APPVEYOR_REPO_BRANCH% https://github.com/%APPVEYOR_REPO_NAME%.git %APPVEYOR_BUILD_FOLDER% - && cd %APPVEYOR_BUILD_FOLDER% - && git checkout -qf %APPVEYOR_REPO_COMMIT% - && git submodule update --init --recursive - -install: - # If there is a newer build queued for the same PR, cancel this one. - # The AppVeyor 'rollout builds' option is supposed to serve the same - # purpose but it is problematic because it tends to cancel builds pushed - # directly to master instead of just PR builds (or the converse). - # credits: JuliaLang developers. - - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` - https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` - Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` - throw "There are newer queued builds for this pull request, failing early." } -# - ECHO "Filesystem root:" -# - ps: "ls \"C:/\"" - - # Check that we have the expected version and architecture for Python - - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - - "python --version" - - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - # Upgrade to the latest version of pip to avoid it displaying warnings - # about it being out of date. - - "python -m pip install --upgrade pip setuptools" - - # Install the build dependencies of the project. If some dependencies contain - # compiled extensions and are not provided as pre-built wheel packages, - # pip will build them from source using the MSVC compiler matching the - # target Python version and architecture - - "%CMD_IN_ENV% pip install -r requirements.txt" - - "%CMD_IN_ENV% pip install pyenchant" - -build_script: - # Build documentation at first, so setup.py won't fail when copying everything. - - "cd doc" - # Import documentation before building, so strings.py will be created. - - "%CMD_IN_ENV% python documentation_importer.py" - # build doc from src folder so it will generate result files right there. - - "cd ..\\src" - - "%CMD_IN_ENV% python ..\\doc\\generator.py" - # Build distributable files. - - "%CMD_IN_ENV% python setup.py build" - - "cd dist" - # Zip it all. - - cmd: 7z a ..\..\snapshot.zip * - -artifacts: - - path: snapshot.zip - -deploy: -- provider: FTP - host: twblue.es - protocol: ftp - beta: true - username: twblue.es - password: - secure: lQZqpYRnHf4LLVOg0C42NQ== - folder: 'web/pubs' \ No newline at end of file diff --git a/scripts/twblue.nsi b/scripts/twblue.nsi index eca410c0..f83fe05b 100644 --- a/scripts/twblue.nsi +++ b/scripts/twblue.nsi @@ -14,7 +14,7 @@ SetCompress auto SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue" -VIAddVersionKey LegalCopyright "Copyright 2018 Manuel Cortéz." +VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." VIAddVersionKey ProductVersion "0.95" VIAddVersionKey FileVersion "0.95" VIProductVersion "0.95.0.0" @@ -27,7 +27,7 @@ var StartMenuFolder !insertmacro MUI_PAGE_STARTMENU startmenu $StartMenuFolder !insertmacro MUI_PAGE_INSTFILES !define MUI_FINISHPAGE_LINK "Visit TWBlue website" -!define MUI_FINISHPAGE_LINK_LOCATION "http://twblue.es" +!define MUI_FINISHPAGE_LINK_LOCATION "https://twblue.es" !define MUI_FINISHPAGE_RUN "$INSTDIR\TWBlue.exe" !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi new file mode 100644 index 00000000..73f5c7ed --- /dev/null +++ b/scripts/twblue_snapshot.nsi @@ -0,0 +1,95 @@ +!include "MUI2.nsh" +!include "LogicLib.nsh" +!include "x64.nsh" +Unicode true +CRCCheck on +ManifestSupportedOS all +XPStyle on +Name "TWBlue" +OutFile "TWBlue_snapshot_setup.exe" +InstallDir "$PROGRAMFILES\twblue" +InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "InstallLocation" +RequestExecutionLevel admin +SetCompress auto +SetCompressor /solid lzma +SetDatablockOptimize on +VIAddVersionKey ProductName "TWBlue Snapshot version" +VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." +VIAddVersionKey ProductVersion "6" +VIAddVersionKey FileVersion "6" +VIProductVersion "6.0.0" +VIFileVersion "6.0.0" +!insertmacro MUI_PAGE_WELCOME +!define MUI_LICENSEPAGE_RADIOBUTTONS +!insertmacro MUI_PAGE_LICENSE "license.txt" +!insertmacro MUI_PAGE_DIRECTORY +var StartMenuFolder +!insertmacro MUI_PAGE_STARTMENU startmenu $StartMenuFolder +!insertmacro MUI_PAGE_INSTFILES +!define MUI_FINISHPAGE_LINK "Visit TWBlue website" +!define MUI_FINISHPAGE_LINK_LOCATION "https://twblue.es" +!define MUI_FINISHPAGE_RUN "$INSTDIR\TWBlue.exe" +!insertmacro MUI_PAGE_FINISH +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "Spanish" +!insertmacro MUI_LANGUAGE "Italian" +!insertmacro MUI_LANGUAGE "Finnish" +!insertmacro MUI_LANGUAGE "Russian" +!insertmacro MUI_LANGUAGE "PortugueseBR" +!insertmacro MUI_LANGUAGE "Polish" +!insertmacro MUI_LANGUAGE "German" +!insertmacro MUI_LANGUAGE "Hungarian" +!insertmacro MUI_LANGUAGE "Turkish" +!insertmacro MUI_LANGUAGE "Arabic" +!insertmacro MUI_LANGUAGE "Galician" +!insertmacro MUI_LANGUAGE "Catalan" +!insertmacro MUI_LANGUAGE "Basque" +!insertmacro MUI_LANGUAGE "Croatian" +!insertmacro MUI_LANGUAGE "Japanese" +!insertmacro MUI_LANGUAGE "SerbianLatin" +!insertmacro MUI_LANGUAGE "Romanian" +!insertmacro MUI_RESERVEFILE_LANGDLL +Section +SetShellVarContext All +SetOutPath "$INSTDIR" +${If} ${RunningX64} +File /r TWBlue64\* +${Else} +File /r TWBlue\* +${EndIf} +CreateShortCut "$DESKTOP\TWBlue.lnk" "$INSTDIR\TWBlue.exe" +!insertmacro MUI_STARTMENU_WRITE_BEGIN startmenu +CreateDirectory "$SMPROGRAMS\$StartMenuFolder" +CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TWBlue.lnk" "$INSTDIR\TWBlue.exe" +CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TWBlue on the web.lnk" "http://twblue.es" +CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe" +!insertmacro MUI_STARTMENU_WRITE_END +WriteUninstaller "$INSTDIR\Uninstall.exe" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayName" "TWBlue" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.95" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.es" +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 95 +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1 +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1 +SectionEnd +Section "Uninstall" +SetShellVarContext All +DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" +RMDir /r /REBOOTOK $INSTDIR +Delete "$DESKTOP\TWBlue.lnk" +!insertmacro MUI_STARTMENU_GETFOLDER startmenu $StartMenuFolder +RMDir /r "$SMPROGRAMS\$StartMenuFolder" +SectionEnd +Function .onInit +${If} ${RunningX64} +StrCpy $instdir "$programfiles64\twblue" +${EndIf} +!insertmacro MUI_LANGDLL_DISPLAY +FunctionEnd From 168c7e7a5d6ee02506da1564c76b62cb7cb3cf11 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 28 Jun 2021 17:03:26 -0500 Subject: [PATCH 077/245] Initial test for supporting a subset of the Streaming API --- src/controller/mainController.py | 11 +++++++++-- src/sessions/twitter/session.py | 22 +++++++++++++++++++++- src/sessions/twitter/streaming.py | 18 ++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 src/sessions/twitter/streaming.py diff --git a/src/controller/mainController.py b/src/controller/mainController.py index b405b3b2..2c3d5836 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -126,6 +126,7 @@ class Controller(object): pub.subscribe(self.update_sent_dms, "sent-dms-updated") pub.subscribe(self.more_dms, "more-sent-dms") pub.subscribe(self.manage_sent_tweets, "sent-tweet") + pub.subscribe(self.manage_tweet_in_home, "tweet-in-home") pub.subscribe(self.manage_friend, "friend") pub.subscribe(self.manage_unfollowing, "unfollowing") pub.subscribe(self.manage_favourite, "favourite") @@ -266,6 +267,7 @@ class Controller(object): if sessions.sessions[i].is_logged == False: continue self.start_buffers(sessions.sessions[i]) self.set_buffer_positions(sessions.sessions[i]) + sessions.sessions[i].start_streaming() if config.app["app-settings"]["play_ready_sound"] == True: sessions.sessions[list(sessions.sessions.keys())[0]].sound.play("ready.ogg") if config.app["app-settings"]["speak_ready_msg"] == True: @@ -1269,8 +1271,6 @@ class Controller(object): def manage_sent_tweets(self, data, user): buffer = self.search_buffer("sent_tweets", user) if buffer == None: return -# if "sent_tweets" not in buffer.session.settings["other_buffers"]["muted_buffers"]: -# self.notify(buffer.session, play_sound=play_sound) data = buffer.session.check_quoted_status(data) data = buffer.session.check_long_tweet(data) if data == False: # Long tweet deleted from twishort. @@ -1627,3 +1627,10 @@ class Controller(object): def save_data_in_db(self): for i in sessions.sessions: sessions.sessions[i].save_persistent_data() + + def manage_tweet_in_home(self, data, user): + buffer = self.search_buffer("home_timeline", user) + if buffer == None or buffer.session.db["user_name"] != user: return + buffer.add_new_item(data) + if "home_timeline" not in buffer.session.settings["other_buffers"]["muted_buffers"]: + self.notify(buffer.session, "tweet_received.ogg") \ No newline at end of file diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index e33d1019..ce02c888 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -17,7 +17,7 @@ from keys import keyring from sessions import base from sessions.twitter import utils, compose from sessions.twitter.long_tweets import tweets, twishort -from . import reduce +from . import reduce, streaming from .wxUI import authorisationDialog log = logging.getLogger("sessions.twitterSession") @@ -125,6 +125,7 @@ class Session(base.baseSession): # This will be especially useful because if the user reactivates their account later, TWblue will try to retrieve such user again at startup. # If we wouldn't implement this approach, TWBlue would save permanently the "deleted user" object. self.deleted_users = {} + pub.subscribe(self.handle_new_status, "newStatus") # @_require_configuration def login(self, verify_credentials=True): @@ -501,3 +502,22 @@ class Session(base.baseSession): if hasattr(i, "retweeted_status") and (i.retweeted_status.user.id_str in self.db["users"]) == False: users[i.retweeted_status.user.id_str] = i.retweeted_status.user self.db["users"] = users + + def start_streaming(self): + self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"]) + self.stream = tweepy.Stream(auth = self.auth, listener=self.stream_listener) + call_threaded(self.stream.filter, follow=self.stream_listener.users) + + def handle_new_status(self, status, user): + if self.db["user_name"] != user: + return + if hasattr(status, "retweeted_status") and status.retweeted_status.truncated: + status.retweeted_status._json["full_text"] = status.retweeted_status.extended_tweet["full_text"] + if hasattr(status, "quoted_status") and status.quoted_status.truncated: + status.quoted_status._json["full_text"] = status.quoted_status.extended_tweet["full_text"] + if status.truncated: + status._json["full_text"] = status.extended_tweet["full_text"] + num = self.order_buffer("home_timeline", [status]) + if num == 1: + status = reduce.reduce_tweet(status) + pub.sendMessage("tweet-in-home", data=status, user=self.db["user_name"]) \ No newline at end of file diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py new file mode 100644 index 00000000..b40ccc61 --- /dev/null +++ b/src/sessions/twitter/streaming.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +import tweepy +from pubsub import pub + +class StreamListener(tweepy.StreamListener): + + def __init__(self, twitter_api, user, *args, **kwargs): + super(StreamListener, self).__init__(*args, **kwargs) + self.api = twitter_api + self.user = user + self.users = [str(id) for id in self.api.friends_ids()] + + def on_status(self, status): + """ Checks data arriving as a tweet. """ + if status.user.id_str in self.users: + pub.sendMessage("newStatus", status=status, user=self.user) +# print(status.text) + From bb5ead80dea5ab3af0871955a073a401a0aaf35d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 29 Jun 2021 05:05:20 -0500 Subject: [PATCH 078/245] Parse correctly incoming tweets from Streaming API --- src/sessions/twitter/session.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index ce02c888..f74b8837 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -509,15 +509,27 @@ class Session(base.baseSession): call_threaded(self.stream.filter, follow=self.stream_listener.users) def handle_new_status(self, status, user): + """ Handles a new status present in the Streaming API. """ + # Discard processing the status if the streaming sends a tweet for another account. if self.db["user_name"] != user: return - if hasattr(status, "retweeted_status") and status.retweeted_status.truncated: - status.retweeted_status._json["full_text"] = status.retweeted_status.extended_tweet["full_text"] - if hasattr(status, "quoted_status") and status.quoted_status.truncated: - status.quoted_status._json["full_text"] = status.quoted_status.extended_tweet["full_text"] + # the Streaming API sends non-extended tweets with an optional parameter "extended_tweets" which contains full_text and other data. + # so we have to make sure we check it before processing the normal status. + # As usual, we handle also quotes and retweets at first. + if hasattr(status, "retweeted_status") and hasattr(status.retweeted_status, "extended_tweet"): + status.retweeted_status._json = {**status.retweeted_status._json, **status.retweeted_status._json["extended_tweet"]} + # compose.compose_tweet requires the parent tweet to have a full_text field, so we have to add it to retweets here. + status._json["full_text"] = status._json["text"] + if hasattr(status, "quoted_status") and hasattr(status.quoted_status, "extended_tweet"): + status.quoted_status._json = {**status.quoted_status._json, **status.quoted_status._json["extended_tweet"]} if status.truncated: - status._json["full_text"] = status.extended_tweet["full_text"] + status._json = {**status._json, **status._json["extended_tweet"]} + # Sends status to database, where it will be reduced and changed according to our needs. num = self.order_buffer("home_timeline", [status]) if num == 1: + # However, we have to do the "reduce and change" process here because the status we sent to the db is going to be a different object that the one sent to database. status = reduce.reduce_tweet(status) + status = self.check_quoted_status(status) + status = self.check_long_tweet(status) + # Send it to the main controller object. pub.sendMessage("tweet-in-home", data=status, user=self.db["user_name"]) \ No newline at end of file From 8fd3041efd2baa5ccac582c85832c7244b3befc3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 29 Jun 2021 17:16:53 -0500 Subject: [PATCH 079/245] Added some reconnection code and logging --- src/controller/mainController.py | 15 ++++++++++++++- src/sessions/twitter/session.py | 16 +++++++++++++--- src/sessions/twitter/streaming.py | 14 +++++++++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 2c3d5836..c56a9f7c 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -273,6 +273,9 @@ class Controller(object): if config.app["app-settings"]["speak_ready_msg"] == True: output.speak(_(u"Ready")) self.started = True + self.streams_checker_function = RepeatingTimer(60, self.check_streams) + self.streams_checker_function.start() + def create_ignored_session_buffer(self, session): self.accounts.append(session.settings["twitter"]["user_name"]) @@ -1633,4 +1636,14 @@ class Controller(object): if buffer == None or buffer.session.db["user_name"] != user: return buffer.add_new_item(data) if "home_timeline" not in buffer.session.settings["other_buffers"]["muted_buffers"]: - self.notify(buffer.session, "tweet_received.ogg") \ No newline at end of file + self.notify(buffer.session, "tweet_received.ogg") + + def check_streams(self): + if self.started == False: + return + for i in sessions.sessions: + try: + if sessions.sessions[i].is_logged == False: continue + sessions.sessions[i].check_streams() + except TweepError: # We shouldn't allow this function to die. + pass diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index f74b8837..8dbb6333 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -126,6 +126,7 @@ class Session(base.baseSession): # If we wouldn't implement this approach, TWBlue would save permanently the "deleted user" object. self.deleted_users = {} pub.subscribe(self.handle_new_status, "newStatus") + pub.subscribe(self.handle_connected, "streamConnected") # @_require_configuration def login(self, verify_credentials=True): @@ -504,9 +505,9 @@ class Session(base.baseSession): self.db["users"] = users def start_streaming(self): - self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"]) + self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"]) self.stream = tweepy.Stream(auth = self.auth, listener=self.stream_listener) - call_threaded(self.stream.filter, follow=self.stream_listener.users) + self.stream_thread = self.stream.filter(follow=self.stream_listener.users, is_async=True) def handle_new_status(self, status, user): """ Handles a new status present in the Streaming API. """ @@ -532,4 +533,13 @@ class Session(base.baseSession): status = self.check_quoted_status(status) status = self.check_long_tweet(status) # Send it to the main controller object. - pub.sendMessage("tweet-in-home", data=status, user=self.db["user_name"]) \ No newline at end of file + pub.sendMessage("tweet-in-home", data=status, user=self.db["user_name"]) + + def check_streams(self): + log.debug("Status of running stream for user {}: {}".format(self.db["user_name"], self.stream.running)) + if self.stream.running == False: + self.start_streaming() + + def handle_connected(self, user): + if user != self.db["user_name"]: + log.debug("Connected streaming endpoint on account {}".format(user)) \ No newline at end of file diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py index b40ccc61..1dabf7f6 100644 --- a/src/sessions/twitter/streaming.py +++ b/src/sessions/twitter/streaming.py @@ -1,14 +1,26 @@ # -*- coding: utf-8 -*- import tweepy +import logging from pubsub import pub +log = logging.getLogger("sessions.twitter.streaming") + class StreamListener(tweepy.StreamListener): - def __init__(self, twitter_api, user, *args, **kwargs): + def __init__(self, twitter_api, user, user_id, *args, **kwargs): super(StreamListener, self).__init__(*args, **kwargs) self.api = twitter_api self.user = user + self.user_id = user_id self.users = [str(id) for id in self.api.friends_ids()] + self.users.append(str(self.user_id)) + log.debug("Started streaming object for user {}".format(self.user)) + + def on_connect(self): + pub.sendMessage("streamConnected", user=self.user) + + def on_exception(self, ex): + log.exception("Exception received on streaming endpoint for user {}".format(self.user)) def on_status(self, status): """ Checks data arriving as a tweet. """ From ba908421859707034884900045d444a93b43a75f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 29 Jun 2021 17:55:36 -0500 Subject: [PATCH 080/245] Initial work to put tweets in mentions, sent and timelines --- src/controller/mainController.py | 21 ++++++++++++++------- src/sessions/twitter/session.py | 30 ++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index c56a9f7c..9e75b459 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -126,7 +126,7 @@ class Controller(object): pub.subscribe(self.update_sent_dms, "sent-dms-updated") pub.subscribe(self.more_dms, "more-sent-dms") pub.subscribe(self.manage_sent_tweets, "sent-tweet") - pub.subscribe(self.manage_tweet_in_home, "tweet-in-home") + pub.subscribe(self.manage_new_tweet, "newTweet") pub.subscribe(self.manage_friend, "friend") pub.subscribe(self.manage_unfollowing, "unfollowing") pub.subscribe(self.manage_favourite, "favourite") @@ -1631,12 +1631,19 @@ class Controller(object): for i in sessions.sessions: sessions.sessions[i].save_persistent_data() - def manage_tweet_in_home(self, data, user): - buffer = self.search_buffer("home_timeline", user) - if buffer == None or buffer.session.db["user_name"] != user: return - buffer.add_new_item(data) - if "home_timeline" not in buffer.session.settings["other_buffers"]["muted_buffers"]: - self.notify(buffer.session, "tweet_received.ogg") + def manage_new_tweet(self, data, user, _buffers): + sound_to_play = None + for buff in _buffers: + buffer = self.search_buffer(buff, user) + if buffer == None or buffer.session.db["user_name"] != user: return + buffer.add_new_item(data) + if buff == "home_timeline": sound_to_play = "tweet_received.ogg" + elif buff == "mentions_timeline": sound_to_play = "mention_received.ogg" + elif buff == "sent_tweets": sound_to_play = "tweet_send.ogg" + elif "timeline" in buff: sound_to_play = "tweet_timeline.ogg" + else: sound_to_play = None + if sound_to_play != None and buff not in buffer.session.settings["other_buffers"]["muted_buffers"]: + self.notify(buffer.session, sound_to_play) def check_streams(self): if self.started == False: diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 8dbb6333..0bee2fd7 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -526,14 +526,28 @@ class Session(base.baseSession): if status.truncated: status._json = {**status._json, **status._json["extended_tweet"]} # Sends status to database, where it will be reduced and changed according to our needs. - num = self.order_buffer("home_timeline", [status]) - if num == 1: - # However, we have to do the "reduce and change" process here because the status we sent to the db is going to be a different object that the one sent to database. - status = reduce.reduce_tweet(status) - status = self.check_quoted_status(status) - status = self.check_long_tweet(status) - # Send it to the main controller object. - pub.sendMessage("tweet-in-home", data=status, user=self.db["user_name"]) + buffers_to_send = [] + if status.user.id_str in self.stream_listener.users: + buffers_to_send.append("home_timeline") + if status.user.id == self.db["user_id"]: + buffers_to_send.append("sent_tweets") + for user in status.entities["user_mentions"]: + if user["id"] == self.db["user_id"]: + buffers_to_send.append("mentions_timeline") + users_with_timeline = [user.split("-")[0] for user in self.db.keys() if user.endswith("-timeline")] + for user in users_with_timeline: + if status.user.id_str == user: + buffers_to_send.append("{}-timeline".format(user)) + for buffer in buffers_to_send[::]: + num = self.order_buffer(buffer, [status]) + if num == 0: + buffers_to_send.remove(buffer) + # However, we have to do the "reduce and change" process here because the status we sent to the db is going to be a different object that the one sent to database. + reduced_status = reduce.reduce_tweet(status) + status = self.check_quoted_status(status) + status = self.check_long_tweet(status) + # Send it to the main controller object. + pub.sendMessage("newTweet", data=status, user=self.db["user_name"], _buffers=buffers_to_send) def check_streams(self): log.debug("Status of running stream for user {}: {}".format(self.db["user_name"], self.stream.running)) From 55b1c7bdaeb20a177cbb3fbd218c7263c7fe3dd7 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 09:50:22 -0500 Subject: [PATCH 081/245] Integrates Tweepy's 68e19cc for preventing Urllib3 ProtocolError --- src/sessions/twitter/streaming.py | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py index 1dabf7f6..613edc01 100644 --- a/src/sessions/twitter/streaming.py +++ b/src/sessions/twitter/streaming.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" Streaming support for TWBlue. """ +import time +import six +import requests +import urllib3 +import ssl import tweepy import logging from pubsub import pub @@ -28,3 +34,76 @@ class StreamListener(tweepy.StreamListener): pub.sendMessage("newStatus", status=status, user=self.user) # print(status.text) + +class Stream(tweepy.Stream): + + def _run(self): + # Authenticate + url = "https://%s%s" % (self.host, self.url) + + # Connect and process the stream + error_counter = 0 + resp = None + exc_info = None + while self.running: + if self.retry_count is not None: + if error_counter > self.retry_count: + # quit if error count greater than retry count + break + try: + auth = self.auth.apply_auth() + resp = self.session.request('POST', + url, + data=self.body, + timeout=self.timeout, + stream=True, + auth=auth, + verify=self.verify, + proxies = self.proxies) + if resp.status_code != 200: + if self.listener.on_error(resp.status_code) is False: + break + error_counter += 1 + if resp.status_code == 420: + self.retry_time = max(self.retry_420_start, + self.retry_time) + time.sleep(self.retry_time) + self.retry_time = min(self.retry_time * 2, + self.retry_time_cap) + else: + error_counter = 0 + self.retry_time = self.retry_time_start + self.snooze_time = self.snooze_time_step + self.listener.on_connect() + self._read_loop(resp) + except (requests.ConnectionError, requests.Timeout, ssl.SSLError, urllib3.exceptions.ReadTimeoutError, urllib3.exceptions.ProtocolError) as exc: + # This is still necessary, as a SSLError can actually be + # thrown when using Requests + # If it's not time out treat it like any other exception + if isinstance(exc, ssl.SSLError): + if not (exc.args and 'timed out' in str(exc.args[0])): + exc_info = sys.exc_info() + break + if self.listener.on_timeout() is False: + break + if self.running is False: + break + time.sleep(self.snooze_time) + self.snooze_time = min(self.snooze_time + self.snooze_time_step, + self.snooze_time_cap) + except Exception as exc: + exc_info = sys.exc_info() + # any other exception is fatal, so kill loop + break + + # cleanup + self.running = False + if resp: + resp.close() + + self.new_session() + + if exc_info: + # call a handler first so that the exception can be logged. + self.listener.on_exception(exc_info[1]) + six.reraise(*exc_info) From 5f11467f2749fead5de6700401674812a62b05f3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 09:52:21 -0500 Subject: [PATCH 082/245] Switched threads to our own facilities and attempts to improve thread management for streaming endpoints --- src/controller/mainController.py | 2 ++ src/sessions/twitter/session.py | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 9e75b459..d6021a78 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -659,6 +659,8 @@ class Controller(object): sessions.sessions[item].sound.cleaner.cancel() log.debug("Saving database for " + sessions.sessions[item].session_id) sessions.sessions[item].save_persistent_data() + log.debug("Disconnecting streaming endpoint for session" + sessions.sessions[item].session_id) + sessions.sessions[item].stop_streaming() if system == "Windows": self.systrayIcon.RemoveIcon() pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 0bee2fd7..e14916f1 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -506,8 +506,13 @@ class Session(base.baseSession): def start_streaming(self): self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"]) - self.stream = tweepy.Stream(auth = self.auth, listener=self.stream_listener) - self.stream_thread = self.stream.filter(follow=self.stream_listener.users, is_async=True) + self.stream = streaming.Stream(auth = self.auth, listener=self.stream_listener, chunk_size=1025) + self.stream_thread = call_threaded(self.stream.filter, follow=self.stream_listener.users, stall_warnings=True) + + def stop_streaming(self): + if hasattr(self, "stream_thread"): + self.stream_thread.join() + log.debug("Stopping Streaming Endpoint...") def handle_new_status(self, status, user): """ Handles a new status present in the Streaming API. """ From 9053fcd5dec14e808acdef1ca133d48abf918408 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 10:11:50 -0500 Subject: [PATCH 083/245] Send Tweets to mentions properly --- src/controller/mainController.py | 2 +- src/sessions/twitter/session.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index d6021a78..0dc5e29d 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1640,7 +1640,7 @@ class Controller(object): if buffer == None or buffer.session.db["user_name"] != user: return buffer.add_new_item(data) if buff == "home_timeline": sound_to_play = "tweet_received.ogg" - elif buff == "mentions_timeline": sound_to_play = "mention_received.ogg" + elif buff == "mentions": sound_to_play = "mention_received.ogg" elif buff == "sent_tweets": sound_to_play = "tweet_send.ogg" elif "timeline" in buff: sound_to_play = "tweet_timeline.ogg" else: sound_to_play = None diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index e14916f1..6e01a9e8 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -538,7 +538,7 @@ class Session(base.baseSession): buffers_to_send.append("sent_tweets") for user in status.entities["user_mentions"]: if user["id"] == self.db["user_id"]: - buffers_to_send.append("mentions_timeline") + buffers_to_send.append("mentions") users_with_timeline = [user.split("-")[0] for user in self.db.keys() if user.endswith("-timeline")] for user in users_with_timeline: if status.user.id_str == user: From 77eadb42bbf1d2f99b3c8f825d564b2f363351e3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 10:35:20 -0500 Subject: [PATCH 084/245] Make sure to disconnect the streams as tweepy implements it --- src/controller/mainController.py | 7 +++++-- src/sessions/twitter/session.py | 5 ++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 0dc5e29d..340f6071 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -655,17 +655,20 @@ class Controller(object): log.debug("Saving global configuration...") for item in sessions.sessions: if sessions.sessions[item].logged == False: continue + log.debug("Disconnecting streaming endpoint for session" + sessions.sessions[item].session_id) + sessions.sessions[item].stop_streaming() log.debug("Disconnecting streams for %s session" % (sessions.sessions[item].session_id,)) sessions.sessions[item].sound.cleaner.cancel() log.debug("Saving database for " + sessions.sessions[item].session_id) sessions.sessions[item].save_persistent_data() - log.debug("Disconnecting streaming endpoint for session" + sessions.sessions[item].session_id) - sessions.sessions[item].stop_streaming() if system == "Windows": self.systrayIcon.RemoveIcon() pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name)) if os.path.exists(pidpath): os.remove(pidpath) + if hasattr(self, "streams_checker_function"): + log.debug("Stopping stream checker...") + self.streams_checker_function.cancel() widgetUtils.exit_application() def follow(self, *args, **kwargs): diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 6e01a9e8..cdfd9684 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -510,9 +510,8 @@ class Session(base.baseSession): self.stream_thread = call_threaded(self.stream.filter, follow=self.stream_listener.users, stall_warnings=True) def stop_streaming(self): - if hasattr(self, "stream_thread"): - self.stream_thread.join() - log.debug("Stopping Streaming Endpoint...") + self.stream.running = False + log.debug("Stream stopped for accounr {}".format(self.db["user_name"])) def handle_new_status(self, status, user): """ Handles a new status present in the Streaming API. """ From 3c7063792c60cea8dcea1aba1756b09adc19a970 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 17:22:24 -0500 Subject: [PATCH 085/245] Separate all buffers in modules for an easier work with code --- src/controller/buffers/__init__.py | 9 +- src/controller/buffers/base/__init__.py | 4 + src/controller/buffers/base/account.py | 56 ++ .../buffers/{baseBuffers.py => base/base.py} | 81 +-- src/controller/buffers/base/empty.py | 19 + src/controller/buffers/twitter/__init__.py | 7 + .../{twitterBuffers.py => twitter/base.py} | 638 +----------------- .../buffers/twitter/directMessages.py | 158 +++++ src/controller/buffers/twitter/list.py | 44 ++ src/controller/buffers/twitter/people.py | 259 +++++++ src/controller/buffers/twitter/search.py | 113 ++++ src/controller/buffers/twitter/trends.py | 145 ++++ src/controller/mainController.py | 85 ++- 13 files changed, 856 insertions(+), 762 deletions(-) create mode 100644 src/controller/buffers/base/__init__.py create mode 100644 src/controller/buffers/base/account.py rename src/controller/buffers/{baseBuffers.py => base/base.py} (62%) create mode 100644 src/controller/buffers/base/empty.py create mode 100644 src/controller/buffers/twitter/__init__.py rename src/controller/buffers/{twitterBuffers.py => twitter/base.py} (50%) create mode 100644 src/controller/buffers/twitter/directMessages.py create mode 100644 src/controller/buffers/twitter/list.py create mode 100644 src/controller/buffers/twitter/people.py create mode 100644 src/controller/buffers/twitter/search.py create mode 100644 src/controller/buffers/twitter/trends.py diff --git a/src/controller/buffers/__init__.py b/src/controller/buffers/__init__.py index 4e7aa78c..10e8971c 100644 --- a/src/controller/buffers/__init__.py +++ b/src/controller/buffers/__init__.py @@ -1,8 +1,3 @@ # -*- coding: utf-8 -*- -""" this package contains logic related to buffers. A buffer is a virtual representation of a group of items retrieved through the Social network API'S. - Ideally, new social networks added to TWBlue will have its own "buffers", and these buffers should be defined within this package, following the Twitter example. - Currently, the package contains the following modules: - * baseBuffers: Define a set of functions and structure to be expected in all buffers. New buffers should inherit its classes from one of the classes present here. - * twitterBuffers: All other code, specific to Twitter. -""" -from __future__ import unicode_literals +from . import base as base +from . import twitter as twitter \ No newline at end of file diff --git a/src/controller/buffers/base/__init__.py b/src/controller/buffers/base/__init__.py new file mode 100644 index 00000000..293bbdd8 --- /dev/null +++ b/src/controller/buffers/base/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +from .account import AccountBuffer +from .base import Buffer +from .empty import EmptyBuffer \ No newline at end of file diff --git a/src/controller/buffers/base/account.py b/src/controller/buffers/base/account.py new file mode 100644 index 00000000..46ecbb6d --- /dev/null +++ b/src/controller/buffers/base/account.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +""" Common logic to all buffers in TWBlue.""" +import logging +import config +import widgetUtils +from pubsub import pub +from wxUI import buffers +from . import base + +log = logging.getLogger("controller.buffers.base.account") + +class AccountBuffer(base.Buffer): + def __init__(self, parent, name, account, account_id): + super(AccountBuffer, self).__init__(parent, None, name) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + self.buffer = buffers.accountPanel(parent, name) + self.type = self.buffer.type + self.compose_function = None + self.session = None + self.needs_init = False + self.account = account + self.buffer.account = account + self.name = name + self.account_id = account_id + + def setup_account(self): + widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account) + if self.account_id in config.app["sessions"]["ignored_sessions"]: + self.buffer.change_autostart(False) + else: + self.buffer.change_autostart(True) + if not hasattr(self, "logged"): + self.buffer.change_login(login=False) + widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout) + else: + self.buffer.change_login(login=True) + widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login) + + def login(self, *args, **kwargs): + del self.logged + self.setup_account() + pub.sendMessage("login", session_id=self.account_id) + + def logout(self, *args, **kwargs): + self.logged = False + self.setup_account() + pub.sendMessage("logout", session_id=self.account_id) + + def autostart(self, *args, **kwargs): + if self.account_id in config.app["sessions"]["ignored_sessions"]: + self.buffer.change_autostart(True) + config.app["sessions"]["ignored_sessions"].remove(self.account_id) + else: + self.buffer.change_autostart(False) + config.app["sessions"]["ignored_sessions"].append(self.account_id) + config.app.write() \ No newline at end of file diff --git a/src/controller/buffers/baseBuffers.py b/src/controller/buffers/base/base.py similarity index 62% rename from src/controller/buffers/baseBuffers.py rename to src/controller/buffers/base/base.py index 7437aa48..41b31219 100644 --- a/src/controller/buffers/baseBuffers.py +++ b/src/controller/buffers/base/base.py @@ -1,26 +1,14 @@ # -*- coding: utf-8 -*- """ Common logic to all buffers in TWBlue.""" -from __future__ import unicode_literals -from builtins import object import logging import wx import output -import config import sound import widgetUtils -from pubsub import pub -from wxUI import buffers -log = logging.getLogger("controller.buffers.baseBuffers") +log = logging.getLogger("controller.buffers.base.base") -def _items_exist(function): - """ A decorator to execute a function only if the selected buffer contains at least one item.""" - def function_(self, *args, **kwargs): - if self.buffer.list.get_count() > 0: - function(self, *args, **kwargs) - return function_ - -class buffer(object): +class Buffer(object): """ A basic buffer object. This should be the base class for all other derived buffers.""" def __init__(self, parent=None, function=None, session=None, *args, **kwargs): @@ -29,11 +17,11 @@ class buffer(object): @ function str or None: function to be called periodically and update items on this buffer. @ session sessionmanager.session object or None: Session handler for settings, database and data access. """ - super(buffer, self).__init__() + super(Buffer, self).__init__() self.function = function # Compose_function will be used to render an object on this buffer. Normally, signature is as follows: # compose_function(item, db, relative_times, show_screen_names=False, session=None) - # Read more about compose functions in twitter/compose.py. + # Read more about compose functions in sessions/twitter/compose.py. self.compose_function = None self.args = args self.kwargs = kwargs @@ -147,63 +135,4 @@ class buffer(object): try: self.session.db[self.name+"_pos"]=self.buffer.list.get_selected() except AttributeError: - pass - -class accountPanel(buffer): - def __init__(self, parent, name, account, account_id): - super(accountPanel, self).__init__(parent, None, name) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - self.buffer = buffers.accountPanel(parent, name) - self.type = self.buffer.type - self.compose_function = None - self.session = None - self.needs_init = False - self.account = account - self.buffer.account = account - self.name = name - self.account_id = account_id - - def setup_account(self): - widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account) - if self.account_id in config.app["sessions"]["ignored_sessions"]: - self.buffer.change_autostart(False) - else: - self.buffer.change_autostart(True) - if not hasattr(self, "logged"): - self.buffer.change_login(login=False) - widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout) - else: - self.buffer.change_login(login=True) - widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login) - - def login(self, *args, **kwargs): - del self.logged - self.setup_account() - pub.sendMessage("login", session_id=self.account_id) - - def logout(self, *args, **kwargs): - self.logged = False - self.setup_account() - pub.sendMessage("logout", session_id=self.account_id) - - def autostart(self, *args, **kwargs): - if self.account_id in config.app["sessions"]["ignored_sessions"]: - self.buffer.change_autostart(True) - config.app["sessions"]["ignored_sessions"].remove(self.account_id) - else: - self.buffer.change_autostart(False) - config.app["sessions"]["ignored_sessions"].append(self.account_id) - config.app.write() - -class emptyPanel(buffer): - def __init__(self, parent, name, account): - super(emptyPanel, self).__init__(parent=parent) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - self.buffer = buffers.emptyPanel(parent, name) - self.type = self.buffer.type - self.compose_function = None - self.account = account - self.buffer.account = account - self.name = name - self.session = None - self.needs_init = True + pass \ No newline at end of file diff --git a/src/controller/buffers/base/empty.py b/src/controller/buffers/base/empty.py new file mode 100644 index 00000000..66373d7c --- /dev/null +++ b/src/controller/buffers/base/empty.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +import logging +from wxUI import buffers +from . import base + +log = logging.getLogger("controller.buffers.base.empty") + +class EmptyBuffer(base.Buffer): + def __init__(self, parent, name, account): + super(EmptyBuffer, self).__init__(parent=parent) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + self.buffer = buffers.emptyPanel(parent, name) + self.type = self.buffer.type + self.compose_function = None + self.account = account + self.buffer.account = account + self.name = name + self.session = None + self.needs_init = True diff --git a/src/controller/buffers/twitter/__init__.py b/src/controller/buffers/twitter/__init__.py new file mode 100644 index 00000000..c893f6ba --- /dev/null +++ b/src/controller/buffers/twitter/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from .base import BaseBuffer +from .directMessages import DirectMessagesBuffer, SentDirectMessagesBuffer +from .list import ListBuffer +from .people import PeopleBuffer +from .trends import TrendsBuffer +from .search import SearchBuffer, SearchPeopleBuffer, ConversationBuffer diff --git a/src/controller/buffers/twitterBuffers.py b/src/controller/buffers/twitter/base.py similarity index 50% rename from src/controller/buffers/twitterBuffers.py rename to src/controller/buffers/twitter/base.py index 3e09243f..5ccc0ae6 100644 --- a/src/controller/buffers/twitterBuffers.py +++ b/src/controller/buffers/twitter/base.py @@ -18,7 +18,7 @@ import sound import languageHandler import logging from audio_services import youtube_utils -from controller.buffers import baseBuffers +from controller.buffers.base import base from sessions.twitter import compose, utils, reduce from mysc.thread_utils import call_threaded from tweepy.error import TweepError @@ -35,9 +35,9 @@ def _tweets_exist(function): function(self, *args, **kwargs) return function_ -class baseBufferController(baseBuffers.buffer): +class BaseBuffer(base.Buffer): def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, compose_func="compose_tweet", *args, **kwargs): - super(baseBufferController, self).__init__(parent, function, *args, **kwargs) + super(BaseBuffer, self).__init__(parent, function, *args, **kwargs) log.debug("Initializing buffer %s, account %s" % (name, account,)) if bufferType != None: self.buffer = getattr(buffers, bufferType)(parent, name) @@ -638,634 +638,4 @@ class baseBufferController(baseBuffers.buffer): tweet = self.get_tweet() output.speak(_(u"Opening item in web browser...")) url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=self.session.get_user(tweet.user).screen_name, tweet_id=tweet.id) - webbrowser.open(url) - -class directMessagesController(baseBufferController): - - def get_more_items(self): - # 50 results are allowed per API call, so let's assume max value can be 50. - # reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events - if self.session.settings["general"]["max_tweets_per_call"] > 50: - count = 50 - else: - count = self.session.settings["general"]["max_tweets_per_call"] - total = 0 - # try to retrieve the cursor for the current buffer. - cursor = self.session.db["cursors"].get(self.name) - try: - items = getattr(self.session.twitter, self.function)(return_cursors=True, cursor=cursor, count=count, *self.args, **self.kwargs) - if type(items) == tuple: - items, cursor = items - if type(cursor) == tuple: - cursor = cursor[1] - cursors = self.session.db["cursors"] - cursors[self.name] = cursor - self.session.db["cursors"] = cursors - results = [i for i in items] - items = results - log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - if items == None: - return - sent = [] - received = [] - sent_dms = self.session.db["sent_direct_messages"] - received_dms = self.session.db["direct_messages"] - for i in items: - if int(i.message_create["sender_id"]) == self.session.db["user_id"]: - if self.session.settings["general"]["reverse_timelines"] == False: - sent_dms.insert(0, i) - sent.append(i) - else: - sent_dms.append(i) - sent.insert(0, i) - else: - if self.session.settings["general"]["reverse_timelines"] == False: - received_dms.insert(0, i) - received.append(i) - else: - received_dms.append(i) - received.insert(0, i) - total = total+1 - self.session.db["direct_messages"] = received_dms - self.session.db["sent_direct_messages"] = sent_dms - user_ids = [item.message_create["sender_id"] for item in items] - self.session.save_users(user_ids) - pub.sendMessage("more-sent-dms", data=sent, account=self.session.db["user_name"]) - selected = self.buffer.list.get_selected() - if self.session.settings["general"]["reverse_timelines"] == True: - for i in received: - if int(i.message_create["sender_id"]) == self.session.db["user_id"]: - continue - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(True, *tweet) - self.buffer.list.select_item(selected) - else: - for i in received: - if int(i.message_create["sender_id"]) == self.session.db["user_id"]: - continue - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(True, *tweet) - output.speak(_(u"%s items retrieved") % (total), True) - - @_tweets_exist - def reply(self, *args, **kwargs): - tweet = self.get_right_tweet() - screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name - message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - config.app.write() - if message.image == None: - item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) - if hasattr(message.message, "destroy"): message.message.destroy() - - def onFocus(self, *args, **kwargs): - tweet = self.get_tweet() - if platform.system() == "Windows" and self.session.settings["general"]["relative_times"] == True: - # fix this: - original_date = arrow.get(int(tweet.created_timestamp)) - ts = original_date.humanize(locale=languageHandler.getLanguage()) - self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts) - if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet): - self.session.sound.play("audio.ogg") - if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet): - self.session.sound.play("image.ogg") - - def clear_list(self): - dlg = commonMessageDialogs.clear_list() - if dlg == widgetUtils.YES: - self.session.db[self.name] = [] - self.buffer.list.clear() - - def auto_read(self, number_of_items): - if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - if self.session.settings["general"]["reverse_timelines"] == False: - tweet = self.session.db[self.name][-1] - else: - tweet = self.session.db[self.name][0] - output.speak(_(u"New direct message")) - output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) - elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(_(u"{0} new direct messages.").format(number_of_items,)) - - def open_in_browser(self, *args, **kwargs): - output.speak(_(u"This action is not supported in the buffer yet.")) - -class sentDirectMessagesController(directMessagesController): - - def __init__(self, *args, **kwargs): - super(sentDirectMessagesController, self).__init__(*args, **kwargs) - if ("sent_direct_messages" in self.session.db) == False: - self.session.db["sent_direct_messages"] = [] - - def get_more_items(self): - output.speak(_(u"Getting more items cannot be done in this buffer. Use the direct messages buffer instead.")) - - def start_stream(self, *args, **kwargs): - pass - - def put_more_items(self, items): - if self.session.settings["general"]["reverse_timelines"] == True: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) - else: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) - self.buffer.list.insert_item(False, *tweet) - -class listBufferController(baseBufferController): - def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, list_id=None, *args, **kwargs): - super(listBufferController, self).__init__(parent, function, name, sessionObject, account, sound=None, bufferType=None, *args, **kwargs) - self.users = [] - self.list_id = list_id - self.kwargs["list_id"] = list_id - - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - self.get_user_ids() - super(listBufferController, self).start_stream(mandatory, play_sound, avoid_autoreading) - - def get_user_ids(self): - for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): - if i.id not in self.users: - self.users.append(i.id) - - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-5] in self.session.settings["other_buffers"]["lists"]: - self.session.settings["other_buffers"]["lists"].remove(self.name[:-5]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False - -class peopleBufferController(baseBufferController): - def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs): - super(peopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) - log.debug("Initializing buffer %s, account %s" % (name, account,)) - self.compose_function = compose.compose_followers_list - log.debug("Compose_function: %s" % (self.compose_function,)) - self.get_tweet = self.get_right_tweet - self.url = self.interact - if "-followers" in self.name or "-friends" in self.name: - self.finished_timeline = False - # Add a compatibility layer for username based timelines from config. - # ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory. - try: - int(self.kwargs["user_id"]) - except ValueError: - self.is_screen_name = True - self.kwargs["screen_name"] = self.kwargs["user_id"] - self.kwargs.pop("user_id") - - def remove_buffer(self, force=True): - if "-followers" in self.name: - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]: - self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False - elif "-friends" in self.name: - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]: - self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8]) - if self.name in self.session.db: - self.session.db.pop(self.name) - self.session.settings.write() - return True - elif dlg == widgetUtils.NO: - return False - else: - output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True) - return False - - def onFocus(self, ev): - pass - - def get_message(self): - return " ".join(self.compose_function(self.get_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)) - - def delete_item(self): pass - - @_tweets_exist - def reply(self, *args, **kwargs): - tweet = self.get_right_tweet() - screen_name = tweet.screen_name - message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - config.app.write() - if message.image == None: - item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) - if hasattr(message.message, "destroy"): message.message.destroy() - - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: - self.execution_time = current_time - log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,)) - log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) - try: - val = getattr(self.session.twitter, self.function)(return_cursors=True, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - if type(val) == tuple: - val, cursor = val - if type(cursor) == tuple: - cursor = cursor[1] - cursors = self.session.db["cursors"] - cursors[self.name] = cursor - self.session.db["cursors"] = cursors - results = [i for i in val] - val = results - val.reverse() - log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - number_of_items = self.session.order_people(self.name, val) - log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) - if hasattr(self, "finished_timeline") and self.finished_timeline == False: - self.username = self.session.api_call("get_user", **self.kwargs).screen_name - self.finished_timeline = True - if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(number_of_items) - return number_of_items - - def get_more_items(self): - try: - cursor = self.session.db["cursors"].get(self.name) - items = getattr(self.session.twitter, self.function)(return_cursors=True, users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - if type(items) == tuple: - items, cursor = items - if type(cursor) == tuple: - cursor = cursor[1] - cursors = self.session.db["cursors"] - cursors[self.name] = cursor - self.session.db["cursors"] = cursors - results = [i for i in items] - items = results - log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) - except TweepError as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) - return - if items == None: - return - items_db = self.session.db[self.name] - for i in items: - if self.session.settings["general"]["reverse_timelines"] == False: - items_db.insert(0, i) - else: - items_db.append(i) - self.session.db[self.name] = items_db - selected = self.buffer.list.get_selected() - if self.session.settings["general"]["reverse_timelines"] == True: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(True, *tweet) - self.buffer.list.select_item(selected) - else: - for i in items: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(True, *tweet) - output.speak(_(u"%s items retrieved") % (len(items)), True) - - def put_items_on_list(self, number_of_items): - log.debug("The list contains %d items" % (self.buffer.list.get_count(),)) -# log.debug("Putting %d items on the list..." % (number_of_items,)) - if self.buffer.list.get_count() == 0: - for i in self.session.db[self.name]: - tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) - self.buffer.list.insert_item(False, *tweet) - self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) -# self.buffer.set_list_position() - elif self.buffer.list.get_count() > 0: - if self.session.settings["general"]["reverse_timelines"] == False: - for i in self.session.db[self.name][len(self.session.db[self.name])-number_of_items:]: - tweet = self.compose_function(i, self.session.db) - self.buffer.list.insert_item(False, *tweet) - else: - items = self.session.db[self.name][0:number_of_items] - items.reverse() - for i in items: - tweet = self.compose_function(i, self.session.db) - self.buffer.list.insert_item(True, *tweet) - log.debug("now the list contains %d items" % (self.buffer.list.get_count(),)) - - def get_right_tweet(self): - tweet = self.session.db[self.name][self.buffer.list.get_selected()] - return tweet - - def add_new_item(self, item): - tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session) - if self.session.settings["general"]["reverse_timelines"] == False: - self.buffer.list.insert_item(False, *tweet) - else: - self.buffer.list.insert_item(True, *tweet) - if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(" ".join(tweet)) - - def clear_list(self): - dlg = commonMessageDialogs.clear_list() - if dlg == widgetUtils.YES: - self.session.db[self.name] = [] - self.session.db["cursors"][self.name] = -1 - self.buffer.list.clear() - - def interact(self): - user.profileController(self.session, user=self.get_right_tweet().screen_name) - - def show_menu(self, ev, pos=0, *args, **kwargs): - menu = menus.peoplePanelMenu() - widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details) -# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) - if hasattr(menu, "openInBrowser"): - widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser) - if pos != 0: - self.buffer.PopupMenu(menu, pos) - else: - self.buffer.PopupMenu(menu, ev.GetPosition()) - - def details(self, *args, **kwargs): - pub.sendMessage("execute-action", action="user_details") - - def auto_read(self, number_of_items): - if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - if self.session.settings["general"]["reverse_timelines"] == False: - tweet = self.session.db[self.name][-1] - else: - tweet = self.session.db[self.name][0] - output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) - elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: - output.speak(_(u"{0} new followers.").format(number_of_items)) - - def open_in_browser(self, *args, **kwargs): - tweet = self.get_tweet() - output.speak(_(u"Opening item in web browser...")) - url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name) - webbrowser.open(url) - -class searchBufferController(baseBufferController): - - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: - self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False - -class searchPeopleBufferController(peopleBufferController): - """ This is identical to a normal peopleBufferController, except that uses the page parameter instead of a cursor.""" - def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs): - super(searchPeopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) - if ("page" in self.kwargs) == False: - self.page = 1 - else: - self.page = self.kwargs.pop("page") - - def get_more_items(self, *args, **kwargs): - # Add 1 to the page parameter, put it in kwargs and calls to get_more_items in the parent buffer. - self.page = self.page +1 - self.kwargs["page"] = self.page - super(searchPeopleBufferController, self).get_more_items(*args, **kwargs) - # remove the parameter again to make sure start_stream won't fetch items for this page indefinitely. - self.kwargs.pop("page") - - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: - self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False - -class trendsBufferController(baseBuffers.buffer): - def __init__(self, parent, name, session, account, trendsFor, *args, **kwargs): - super(trendsBufferController, self).__init__(parent=parent, session=session) - self.trendsFor = trendsFor - self.session = session - self.account = account - self.invisible = True - self.buffer = buffers.trendsPanel(parent, name) - self.buffer.account = account - self.type = self.buffer.type - self.bind_events() - self.sound = "trends_updated.ogg" - self.trends = [] - self.name = name - self.buffer.name = name - self.compose_function = self.compose_function_ - self.get_formatted_message = self.get_message - self.reply = self.search_topic - - def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: - self.execution_time = current_time - try: - data = self.session.twitter.trends_place(id=self.trendsFor) - except TweepError as err: - log.error("Error %s: %s" % (err.api_code, err.reason)) - if not hasattr(self, "name_"): - self.name_ = data[0]["locations"][0]["name"] - self.trends = data[0]["trends"] - self.put_items_on_the_list() - if self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - - def put_items_on_the_list(self): - selected_item = self.buffer.list.get_selected() - self.buffer.list.clear() - for i in self.trends: - tweet = self.compose_function(i) - self.buffer.list.insert_item(False, *tweet) - self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) - - def compose_function_(self, trend): - return [trend["name"]] - - def bind_events(self): - log.debug("Binding events...") - self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.tweet_about_this_trend, self.buffer.tweetTrendBtn) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet) - widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu) - widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key) - widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.search_topic, self.buffer.search_topic) - - def get_message(self): - return self.compose_function(self.trends[self.buffer.list.get_selected()])[0] - - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]: - self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3]) - self.session.settings.write() - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False - - def url(self, *args, **kwargs): - self.tweet_about_this_trend() - - def search_topic(self, *args, **kwargs): - topic = self.trends[self.buffer.list.get_selected()]["name"] - pub.sendMessage("search", term=topic) - - def show_menu(self, ev, pos=0, *args, **kwargs): - menu = menus.trendsPanelMenu() - widgetUtils.connect_event(menu, widgetUtils.MENU, self.search_topic, menuitem=menu.search_topic) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.tweet_about_this_trend, menuitem=menu.tweetThisTrend) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) - widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) - if pos != 0: - self.buffer.PopupMenu(menu, pos) - else: - self.buffer.PopupMenu(menu, ev.GetPosition()) - - def view(self, *args, **kwargs): - pub.sendMessage("execute-action", action="view_item") - - def copy(self, *args, **kwargs): - pub.sendMessage("execute-action", action="copy_to_clipboard") - - def tweet_about_this_trend(self, *args, **kwargs): - if self.buffer.list.get_count() == 0: return - title = _(u"Tweet") - caption = _(u"Write the tweet here") - tweet = messages.tweet(self.session, title, caption, self.get_message()+ " ") - tweet.message.set_cursor_at_end() - if tweet.message.get_response() == widgetUtils.OK: - text = tweet.message.get_text() - if len(text) > 280 and tweet.message.get("long_tweet") == True: - if tweet.image == None: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - if tweet.image == None: - call_threaded(self.session.api_call, call_name="update_status", status=text) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image) - if hasattr(tweet.message, "destroy"): tweet.message.destroy() - - def show_menu_by_key(self, ev): - if self.buffer.list.get_count() == 0: - return - if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: - self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) - - def open_in_browser(self, *args, **kwargs): - output.speak(_(u"This action is not supported in the buffer, yet.")) - -class conversationBufferController(searchBufferController): - - def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. - current_time = time.time() - if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: - self.execution_time = current_time - if start == True: - self.statuses = [] - self.ids = [] - self.statuses.append(self.tweet) - self.ids.append(self.tweet.id) - tweet = self.tweet - if not hasattr(tweet, "in_reply_to_status_id"): - tweet.in_reply_to_status_id = None - while tweet.in_reply_to_status_id != None: - try: - tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") - except TweepError as err: - break - self.statuses.insert(0, tweet) - self.ids.append(tweet.id) - if tweet.in_reply_to_status_id == None: - self.kwargs["since_id"] = tweet.id - self.ids.append(tweet.id) - val2 = self.session.search(self.name, tweet_mode="extended", *self.args, **self.kwargs) - for i in val2: - if i.in_reply_to_status_id in self.ids: - self.statuses.append(i) - self.ids.append(i.id) - tweet = i - number_of_items = self.session.order_buffer(self.name, self.statuses) - log.debug("Number of items retrieved: %d" % (number_of_items,)) - self.put_items_on_list(number_of_items) - if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: - self.session.sound.play(self.sound) - # Autoread settings - if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: - self.auto_read(number_of_items) - return number_of_items - - def remove_buffer(self, force=False): - if force == False: - dlg = commonMessageDialogs.remove_buffer() - else: - dlg = widgetUtils.YES - if dlg == widgetUtils.YES: - if self.name in self.session.db: - self.session.db.pop(self.name) - return True - elif dlg == widgetUtils.NO: - return False + webbrowser.open(url) \ No newline at end of file diff --git a/src/controller/buffers/twitter/directMessages.py b/src/controller/buffers/twitter/directMessages.py new file mode 100644 index 00000000..d5e556b6 --- /dev/null +++ b/src/controller/buffers/twitter/directMessages.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +import platform +import widgetUtils +import arrow +import webbrowser +import output +import config +import languageHandler +import logging +from controller import messages +from sessions.twitter import compose, utils +from mysc.thread_utils import call_threaded +from tweepy.error import TweepError +from pubsub import pub +from . import base + +log = logging.getLogger("controller.buffers.twitter.dmBuffer") + +class DirectMessagesBuffer(base.BaseBuffer): + + def get_more_items(self): + # 50 results are allowed per API call, so let's assume max value can be 50. + # reference: https://developer.twitter.com/en/docs/twitter-api/v1/direct-messages/sending-and-receiving/api-reference/list-events + if self.session.settings["general"]["max_tweets_per_call"] > 50: + count = 50 + else: + count = self.session.settings["general"]["max_tweets_per_call"] + total = 0 + # try to retrieve the cursor for the current buffer. + cursor = self.session.db["cursors"].get(self.name) + try: + items = getattr(self.session.twitter, self.function)(return_cursors=True, cursor=cursor, count=count, *self.args, **self.kwargs) + if type(items) == tuple: + items, cursor = items + if type(cursor) == tuple: + cursor = cursor[1] + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors + results = [i for i in items] + items = results + log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + if items == None: + return + sent = [] + received = [] + sent_dms = self.session.db["sent_direct_messages"] + received_dms = self.session.db["direct_messages"] + for i in items: + if int(i.message_create["sender_id"]) == self.session.db["user_id"]: + if self.session.settings["general"]["reverse_timelines"] == False: + sent_dms.insert(0, i) + sent.append(i) + else: + sent_dms.append(i) + sent.insert(0, i) + else: + if self.session.settings["general"]["reverse_timelines"] == False: + received_dms.insert(0, i) + received.append(i) + else: + received_dms.append(i) + received.insert(0, i) + total = total+1 + self.session.db["direct_messages"] = received_dms + self.session.db["sent_direct_messages"] = sent_dms + user_ids = [item.message_create["sender_id"] for item in items] + self.session.save_users(user_ids) + pub.sendMessage("more-sent-dms", data=sent, account=self.session.db["user_name"]) + selected = self.buffer.list.get_selected() + if self.session.settings["general"]["reverse_timelines"] == True: + for i in received: + if int(i.message_create["sender_id"]) == self.session.db["user_id"]: + continue + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(True, *tweet) + self.buffer.list.select_item(selected) + else: + for i in received: + if int(i.message_create["sender_id"]) == self.session.db["user_id"]: + continue + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(True, *tweet) + output.speak(_(u"%s items retrieved") % (total), True) + + def reply(self, *args, **kwargs): + tweet = self.get_right_tweet() + screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name + message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) + if message.message.get_response() == widgetUtils.OK: + if config.app["app-settings"]["remember_mention_and_longtweet"]: + config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() + config.app.write() + if message.image == None: + item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + else: + call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) + if hasattr(message.message, "destroy"): message.message.destroy() + + def onFocus(self, *args, **kwargs): + tweet = self.get_tweet() + if platform.system() == "Windows" and self.session.settings["general"]["relative_times"] == True: + # fix this: + original_date = arrow.get(int(tweet.created_timestamp)) + ts = original_date.humanize(locale=languageHandler.getLanguage()) + self.buffer.list.list.SetItem(self.buffer.list.get_selected(), 2, ts) + if self.session.settings['sound']['indicate_audio'] and utils.is_audio(tweet): + self.session.sound.play("audio.ogg") + if self.session.settings['sound']['indicate_img'] and utils.is_media(tweet): + self.session.sound.play("image.ogg") + + def clear_list(self): + dlg = commonMessageDialogs.clear_list() + if dlg == widgetUtils.YES: + self.session.db[self.name] = [] + self.buffer.list.clear() + + def auto_read(self, number_of_items): + if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + if self.session.settings["general"]["reverse_timelines"] == False: + tweet = self.session.db[self.name][-1] + else: + tweet = self.session.db[self.name][0] + output.speak(_(u"New direct message")) + output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) + elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(_(u"{0} new direct messages.").format(number_of_items,)) + + def open_in_browser(self, *args, **kwargs): + output.speak(_(u"This action is not supported in the buffer yet.")) + +class SentDirectMessagesBuffer(DirectMessagesBuffer): + + def __init__(self, *args, **kwargs): + super(SentDirectMessagesBuffer, self).__init__(*args, **kwargs) + if ("sent_direct_messages" in self.session.db) == False: + self.session.db["sent_direct_messages"] = [] + + def get_more_items(self): + output.speak(_(u"Getting more items cannot be done in this buffer. Use the direct messages buffer instead.")) + + def start_stream(self, *args, **kwargs): + pass + + def put_more_items(self, items): + if self.session.settings["general"]["reverse_timelines"] == True: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) + else: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session) + self.buffer.list.insert_item(False, *tweet) \ No newline at end of file diff --git a/src/controller/buffers/twitter/list.py b/src/controller/buffers/twitter/list.py new file mode 100644 index 00000000..766c34fb --- /dev/null +++ b/src/controller/buffers/twitter/list.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +import platform +if platform.system() == "Windows": + from wxUI import dialogs, commonMessageDialogs +elif platform.system() == "Linux": + from gi.repository import Gtk + from gtkUI import dialogs, commonMessageDialogs +import widgetUtils +import logging +from tweepy.cursor import Cursor +from . import base + +log = logging.getLogger("controller.buffers.twitter.listBuffer") + +class ListBuffer(base.BaseBuffer): + def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, list_id=None, *args, **kwargs): + super(ListBuffer, self).__init__(parent, function, name, sessionObject, account, sound=None, bufferType=None, *args, **kwargs) + self.users = [] + self.list_id = list_id + self.kwargs["list_id"] = list_id + + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + self.get_user_ids() + super(ListBuffer, self).start_stream(mandatory, play_sound, avoid_autoreading) + + def get_user_ids(self): + for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): + if i.id not in self.users: + self.users.append(i.id) + + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-5] in self.session.settings["other_buffers"]["lists"]: + self.session.settings["other_buffers"]["lists"].remove(self.name[:-5]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False diff --git a/src/controller/buffers/twitter/people.py b/src/controller/buffers/twitter/people.py new file mode 100644 index 00000000..09d89c5d --- /dev/null +++ b/src/controller/buffers/twitter/people.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +import time +import platform +if platform.system() == "Windows": + from wxUI import commonMessageDialogs, menus + from controller import user +elif platform.system() == "Linux": + from gi.repository import Gtk + from gtkUI import dialogs, commonMessageDialogs +from controller import messages +import widgetUtils +import webbrowser +import output +import config +import logging +from mysc.thread_utils import call_threaded +from tweepy.error import TweepError +from pubsub import pub +from sessions.twitter import compose +from . import base + +log = logging.getLogger("controller.buffers.twitter.peopleBuffer") + +def _tweets_exist(function): + """ A decorator to execute a function only if the selected buffer contains at least one item.""" + def function_(self, *args, **kwargs): + if self.buffer.list.get_count() > 0: + function(self, *args, **kwargs) + return function_ + +class PeopleBuffer(base.BaseBuffer): + def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs): + super(PeopleBuffer, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) + log.debug("Initializing buffer %s, account %s" % (name, account,)) + self.compose_function = compose.compose_followers_list + log.debug("Compose_function: %s" % (self.compose_function,)) + self.get_tweet = self.get_right_tweet + self.url = self.interact + if "-followers" in self.name or "-friends" in self.name: + self.finished_timeline = False + # Add a compatibility layer for username based timelines from config. + # ToDo: Remove this in some new versions of the client, when user ID timelines become mandatory. + try: + int(self.kwargs["user_id"]) + except ValueError: + self.is_screen_name = True + self.kwargs["screen_name"] = self.kwargs["user_id"] + self.kwargs.pop("user_id") + + def remove_buffer(self, force=True): + if "-followers" in self.name: + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]: + self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False + elif "-friends" in self.name: + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]: + self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8]) + if self.name in self.session.db: + self.session.db.pop(self.name) + self.session.settings.write() + return True + elif dlg == widgetUtils.NO: + return False + else: + output.speak(_(u"This buffer is not a timeline; it can't be deleted."), True) + return False + + def onFocus(self, ev): + pass + + def get_message(self): + return " ".join(self.compose_function(self.get_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)) + + def delete_item(self): pass + + @_tweets_exist + def reply(self, *args, **kwargs): + tweet = self.get_right_tweet() + screen_name = tweet.screen_name + message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) + if message.message.get_response() == widgetUtils.OK: + if config.app["app-settings"]["remember_mention_and_longtweet"]: + config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() + config.app.write() + if message.image == None: + item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") + if item != None: + pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + else: + call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) + if hasattr(message.message, "destroy"): message.message.destroy() + + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True: + self.execution_time = current_time + log.debug("Starting stream for %s buffer, %s account" % (self.name, self.account,)) + log.debug("args: %s, kwargs: %s" % (self.args, self.kwargs)) + try: + val = getattr(self.session.twitter, self.function)(return_cursors=True, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + if type(val) == tuple: + val, cursor = val + if type(cursor) == tuple: + cursor = cursor[1] + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors + results = [i for i in val] + val = results + val.reverse() + log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + number_of_items = self.session.order_people(self.name, val) + log.debug("Number of items retrieved: %d" % (number_of_items,)) + self.put_items_on_list(number_of_items) + if hasattr(self, "finished_timeline") and self.finished_timeline == False: + self.username = self.session.api_call("get_user", **self.kwargs).screen_name + self.finished_timeline = True + if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) + # Autoread settings + if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: + self.auto_read(number_of_items) + return number_of_items + + def get_more_items(self): + try: + cursor = self.session.db["cursors"].get(self.name) + items = getattr(self.session.twitter, self.function)(return_cursors=True, users=True, cursor=cursor, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) + if type(items) == tuple: + items, cursor = items + if type(cursor) == tuple: + cursor = cursor[1] + cursors = self.session.db["cursors"] + cursors[self.name] = cursor + self.session.db["cursors"] = cursors + results = [i for i in items] + items = results + log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) + except TweepError as e: + log.error("Error %s: %s" % (e.api_code, e.reason)) + return + if items == None: + return + items_db = self.session.db[self.name] + for i in items: + if self.session.settings["general"]["reverse_timelines"] == False: + items_db.insert(0, i) + else: + items_db.append(i) + self.session.db[self.name] = items_db + selected = self.buffer.list.get_selected() + if self.session.settings["general"]["reverse_timelines"] == True: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) + self.buffer.list.insert_item(True, *tweet) + self.buffer.list.select_item(selected) + else: + for i in items: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) + self.buffer.list.insert_item(True, *tweet) + output.speak(_(u"%s items retrieved") % (len(items)), True) + + def put_items_on_list(self, number_of_items): + log.debug("The list contains %d items" % (self.buffer.list.get_count(),)) +# log.debug("Putting %d items on the list..." % (number_of_items,)) + if self.buffer.list.get_count() == 0: + for i in self.session.db[self.name]: + tweet = self.compose_function(i, self.session.db, self.session.settings["general"]["relative_times"], self.session) + self.buffer.list.insert_item(False, *tweet) + self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) +# self.buffer.set_list_position() + elif self.buffer.list.get_count() > 0: + if self.session.settings["general"]["reverse_timelines"] == False: + for i in self.session.db[self.name][len(self.session.db[self.name])-number_of_items:]: + tweet = self.compose_function(i, self.session.db) + self.buffer.list.insert_item(False, *tweet) + else: + items = self.session.db[self.name][0:number_of_items] + items.reverse() + for i in items: + tweet = self.compose_function(i, self.session.db) + self.buffer.list.insert_item(True, *tweet) + log.debug("now the list contains %d items" % (self.buffer.list.get_count(),)) + + def get_right_tweet(self): + tweet = self.session.db[self.name][self.buffer.list.get_selected()] + return tweet + + def add_new_item(self, item): + tweet = self.compose_function(item, self.session.db, self.session.settings["general"]["relative_times"], self.session) + if self.session.settings["general"]["reverse_timelines"] == False: + self.buffer.list.insert_item(False, *tweet) + else: + self.buffer.list.insert_item(True, *tweet) + if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(" ".join(tweet)) + + def clear_list(self): + dlg = commonMessageDialogs.clear_list() + if dlg == widgetUtils.YES: + self.session.db[self.name] = [] + self.session.db["cursors"][self.name] = -1 + self.buffer.list.clear() + + def interact(self): + user.profileController(self.session, user=self.get_right_tweet().screen_name) + + def show_menu(self, ev, pos=0, *args, **kwargs): + menu = menus.peoplePanelMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details) +# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) + if hasattr(menu, "openInBrowser"): + widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser) + if pos != 0: + self.buffer.PopupMenu(menu, pos) + else: + self.buffer.PopupMenu(menu, ev.GetPosition()) + + def details(self, *args, **kwargs): + pub.sendMessage("execute-action", action="user_details") + + def auto_read(self, number_of_items): + if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + if self.session.settings["general"]["reverse_timelines"] == False: + tweet = self.session.db[self.name][-1] + else: + tweet = self.session.db[self.name][0] + output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session))) + elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: + output.speak(_(u"{0} new followers.").format(number_of_items)) + + def open_in_browser(self, *args, **kwargs): + tweet = self.get_tweet() + output.speak(_(u"Opening item in web browser...")) + url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name) + webbrowser.open(url) \ No newline at end of file diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py new file mode 100644 index 00000000..0b34a4a1 --- /dev/null +++ b/src/controller/buffers/twitter/search.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +import platform +if platform.system() == "Windows": + from wxUI import commonMessageDialogs +elif platform.system() == "Linux": + from gi.repository import Gtk + from gtkUI import commonMessageDialogs +import logging +from . import base, people + +log = logging.getLogger("controller.buffers.twitter.searchBuffer") + +class SearchBuffer(base.BaseBuffer): + + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: + self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False + +class SearchPeopleBuffer(people.PeopleBuffer): + """ This is identical to a normal peopleBufferController, except that uses the page parameter instead of a cursor.""" + def __init__(self, parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs): + super(SearchPeopleBuffer, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs) + if ("page" in self.kwargs) == False: + self.page = 1 + else: + self.page = self.kwargs.pop("page") + + def get_more_items(self, *args, **kwargs): + # Add 1 to the page parameter, put it in kwargs and calls to get_more_items in the parent buffer. + self.page = self.page +1 + self.kwargs["page"] = self.page + super(SearchPeopleBuffer, self).get_more_items(*args, **kwargs) + # remove the parameter again to make sure start_stream won't fetch items for this page indefinitely. + self.kwargs.pop("page") + + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]: + self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False + +class ConversationBuffer(SearchBuffer): + + def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: + self.execution_time = current_time + if start == True: + self.statuses = [] + self.ids = [] + self.statuses.append(self.tweet) + self.ids.append(self.tweet.id) + tweet = self.tweet + if not hasattr(tweet, "in_reply_to_status_id"): + tweet.in_reply_to_status_id = None + while tweet.in_reply_to_status_id != None: + try: + tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") + except TweepError as err: + break + self.statuses.insert(0, tweet) + self.ids.append(tweet.id) + if tweet.in_reply_to_status_id == None: + self.kwargs["since_id"] = tweet.id + self.ids.append(tweet.id) + val2 = self.session.search(self.name, tweet_mode="extended", *self.args, **self.kwargs) + for i in val2: + if i.in_reply_to_status_id in self.ids: + self.statuses.append(i) + self.ids.append(i.id) + tweet = i + number_of_items = self.session.order_buffer(self.name, self.statuses) + log.debug("Number of items retrieved: %d" % (number_of_items,)) + self.put_items_on_list(number_of_items) + if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) + # Autoread settings + if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]: + self.auto_read(number_of_items) + return number_of_items + + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False diff --git a/src/controller/buffers/twitter/trends.py b/src/controller/buffers/twitter/trends.py new file mode 100644 index 00000000..23049818 --- /dev/null +++ b/src/controller/buffers/twitter/trends.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +import time +import platform +if platform.system() == "Windows": + import wx + from wxUI import buffers, commonMessageDialogs, menus + from controller import user +elif platform.system() == "Linux": + from gi.repository import Gtk + from gtkUI import buffers, commonMessageDialogs +from controller import messages +import widgetUtils +import output +import logging +from mysc.thread_utils import call_threaded +from tweepy.error import TweepError +from pubsub import pub +from controller.buffers import base + +log = logging.getLogger("controller.buffers.twitter.trends") + +class TrendsBuffer(base.Buffer): + def __init__(self, parent, name, session, account, trendsFor, *args, **kwargs): + super(TrendsBuffer, self).__init__(parent=parent, session=session) + self.trendsFor = trendsFor + self.session = session + self.account = account + self.invisible = True + self.buffer = buffers.trendsPanel(parent, name) + self.buffer.account = account + self.type = self.buffer.type + self.bind_events() + self.sound = "trends_updated.ogg" + self.trends = [] + self.name = name + self.buffer.name = name + self.compose_function = self.compose_function_ + self.get_formatted_message = self.get_message + self.reply = self.search_topic + + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): + # starts stream every 3 minutes. + current_time = time.time() + if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: + self.execution_time = current_time + try: + data = self.session.twitter.trends_place(id=self.trendsFor) + except TweepError as err: + log.error("Error %s: %s" % (err.api_code, err.reason)) + if not hasattr(self, "name_"): + self.name_ = data[0]["locations"][0]["name"] + self.trends = data[0]["trends"] + self.put_items_on_the_list() + if self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: + self.session.sound.play(self.sound) + + def put_items_on_the_list(self): + selected_item = self.buffer.list.get_selected() + self.buffer.list.clear() + for i in self.trends: + tweet = self.compose_function(i) + self.buffer.list.insert_item(False, *tweet) + self.buffer.set_position(self.session.settings["general"]["reverse_timelines"]) + + def compose_function_(self, trend): + return [trend["name"]] + + def bind_events(self): + log.debug("Binding events...") + self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.tweet_about_this_trend, self.buffer.tweetTrendBtn) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet) + widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu) + widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key) + widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.search_topic, self.buffer.search_topic) + + def get_message(self): + return self.compose_function(self.trends[self.buffer.list.get_selected()])[0] + + def remove_buffer(self, force=False): + if force == False: + dlg = commonMessageDialogs.remove_buffer() + else: + dlg = widgetUtils.YES + if dlg == widgetUtils.YES: + if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]: + self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3]) + self.session.settings.write() + if self.name in self.session.db: + self.session.db.pop(self.name) + return True + elif dlg == widgetUtils.NO: + return False + + def url(self, *args, **kwargs): + self.tweet_about_this_trend() + + def search_topic(self, *args, **kwargs): + topic = self.trends[self.buffer.list.get_selected()]["name"] + pub.sendMessage("search", term=topic) + + def show_menu(self, ev, pos=0, *args, **kwargs): + menu = menus.trendsPanelMenu() + widgetUtils.connect_event(menu, widgetUtils.MENU, self.search_topic, menuitem=menu.search_topic) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.tweet_about_this_trend, menuitem=menu.tweetThisTrend) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view) + widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy) + if pos != 0: + self.buffer.PopupMenu(menu, pos) + else: + self.buffer.PopupMenu(menu, ev.GetPosition()) + + def view(self, *args, **kwargs): + pub.sendMessage("execute-action", action="view_item") + + def copy(self, *args, **kwargs): + pub.sendMessage("execute-action", action="copy_to_clipboard") + + def tweet_about_this_trend(self, *args, **kwargs): + if self.buffer.list.get_count() == 0: return + title = _(u"Tweet") + caption = _(u"Write the tweet here") + tweet = messages.tweet(self.session, title, caption, self.get_message()+ " ") + tweet.message.set_cursor_at_end() + if tweet.message.get_response() == widgetUtils.OK: + text = tweet.message.get_text() + if len(text) > 280 and tweet.message.get("long_tweet") == True: + if tweet.image == None: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) + else: + text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) + if tweet.image == None: + call_threaded(self.session.api_call, call_name="update_status", status=text) + else: + call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image) + if hasattr(tweet.message, "destroy"): tweet.message.destroy() + + def show_menu_by_key(self, ev): + if self.buffer.list.get_count() == 0: + return + if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: + self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition()) + + def open_in_browser(self, *args, **kwargs): + output.speak(_(u"This action is not supported in the buffer, yet.")) \ No newline at end of file diff --git a/src/controller/mainController.py b/src/controller/mainController.py index b405b3b2..6f6e21ea 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -22,8 +22,7 @@ elif system == "Linux": from gtkUI import (view, commonMessageDialogs) from sessions.twitter import utils, compose from sessionmanager import manager, sessionManager - -from controller.buffers import baseBuffers, twitterBuffers +from controller import buffers from . import messages import sessions from sessions.twitter import session as session_ @@ -274,7 +273,7 @@ class Controller(object): def create_ignored_session_buffer(self, session): self.accounts.append(session.settings["twitter"]["user_name"]) - account = baseBuffers.accountPanel(self.view.nb, session.settings["twitter"]["user_name"], session.settings["twitter"]["user_name"], session.session_id) + account = buffers.base.AccountBuffer(self.view.nb, session.settings["twitter"]["user_name"], session.settings["twitter"]["user_name"], session.session_id) account.logged = False account.setup_account() self.buffers.append(account) @@ -294,96 +293,96 @@ class Controller(object): session.get_user_info() if createAccounts == True: self.accounts.append(session.db["user_name"]) - account = baseBuffers.accountPanel(self.view.nb, session.db["user_name"], session.db["user_name"], session.session_id) + account = buffers.base.AccountBuffer(self.view.nb, session.db["user_name"], session.db["user_name"], session.session_id) account.setup_account() self.buffers.append(account) self.view.add_buffer(account.buffer , name=session.db["user_name"]) for i in session.settings['general']['buffer_order']: if i == 'home': - home = twitterBuffers.baseBufferController(self.view.nb, "home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended") + home = buffers.twitter.BaseBuffer(self.view.nb, "home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended") self.buffers.append(home) self.view.insert_buffer(home.buffer, name=_(u"Home"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'mentions': - mentions = twitterBuffers.baseBufferController(self.view.nb, "mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended") + mentions = buffers.twitter.BaseBuffer(self.view.nb, "mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended") self.buffers.append(mentions) self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'dm': - dm = twitterBuffers.directMessagesController(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg") + dm = buffers.twitter.DirectMessagesBuffer(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg") self.buffers.append(dm) self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'sent_dm': - sent_dm = twitterBuffers.sentDirectMessagesController(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message") + sent_dm = buffers.twitter.SentDirectMessagesBuffer(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message") self.buffers.append(sent_dm) self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'sent_tweets': - sent_tweets = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended") + sent_tweets = buffers.twitter.BaseBuffer(self.view.nb, "user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended") self.buffers.append(sent_tweets) self.view.insert_buffer(sent_tweets.buffer, name=_(u"Sent tweets"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'favorites': - favourites = twitterBuffers.baseBufferController(self.view.nb, "favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended") + favourites = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended") self.buffers.append(favourites) self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'followers': - followers = twitterBuffers.peopleBufferController(self.view.nb, "followers", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"]) + followers = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"]) self.buffers.append(followers) self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'friends': - friends = twitterBuffers.peopleBufferController(self.view.nb, "friends", "friends", session, session.db["user_name"], screen_name=session.db["user_name"]) + friends = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "friends", session, session.db["user_name"], screen_name=session.db["user_name"]) self.buffers.append(friends) self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'blocks': - blocks = twitterBuffers.peopleBufferController(self.view.nb, "blocks", "blocked", session, session.db["user_name"]) + blocks = buffers.twitter.PeopleBuffer(self.view.nb, "blocks", "blocked", session, session.db["user_name"]) self.buffers.append(blocks) self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) elif i == 'muted': - muted = twitterBuffers.peopleBufferController(self.view.nb, "mutes", "muted", session, session.db["user_name"]) + muted = buffers.twitter.PeopleBuffer(self.view.nb, "mutes", "muted", session, session.db["user_name"]) self.buffers.append(muted) self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - timelines = baseBuffers.emptyPanel(self.view.nb, "timelines", session.db["user_name"]) + timelines = buffers.base.EmptyBuffer(self.view.nb, "timelines", session.db["user_name"]) self.buffers.append(timelines) self.view.insert_buffer(timelines.buffer , name=_(u"Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) for i in session.settings["other_buffers"]["timelines"]: - tl = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended") + tl = buffers.twitter.BaseBuffer(self.view.nb, "user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended") self.buffers.append(tl) self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(i,), pos=self.view.search("timelines", session.db["user_name"])) - favs_timelines = baseBuffers.emptyPanel(self.view.nb, "favs_timelines", session.db["user_name"]) + favs_timelines = buffers.base.EmptyBuffer(self.view.nb, "favs_timelines", session.db["user_name"]) self.buffers.append(favs_timelines) self.view.insert_buffer(favs_timelines.buffer , name=_(u"Likes timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) for i in session.settings["other_buffers"]["favourites_timelines"]: - tl = twitterBuffers.baseBufferController(self.view.nb, "favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended") + tl = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended") self.buffers.append(tl) self.view.insert_buffer(tl.buffer, name=_(u"Likes for {}").format(i,), pos=self.view.search("favs_timelines", session.db["user_name"])) - followers_timelines = baseBuffers.emptyPanel(self.view.nb, "followers_timelines", session.db["user_name"]) + followers_timelines = buffers.base.EmptyBuffer(self.view.nb, "followers_timelines", session.db["user_name"]) self.buffers.append(followers_timelines) self.view.insert_buffer(followers_timelines.buffer , name=_(u"Followers' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) for i in session.settings["other_buffers"]["followers_timelines"]: - tl = twitterBuffers.peopleBufferController(self.view.nb, "followers", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) + tl = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) self.buffers.append(tl) self.view.insert_buffer(tl.buffer, name=_(u"Followers for {}").format(i,), pos=self.view.search("followers_timelines", session.db["user_name"])) - friends_timelines = baseBuffers.emptyPanel(self.view.nb, "friends_timelines", session.db["user_name"]) + friends_timelines = buffers.base.EmptyBuffer(self.view.nb, "friends_timelines", session.db["user_name"]) self.buffers.append(friends_timelines) self.view.insert_buffer(friends_timelines.buffer , name=_(u"Friends' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) for i in session.settings["other_buffers"]["friends_timelines"]: - tl = twitterBuffers.peopleBufferController(self.view.nb, "friends", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) + tl = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) self.buffers.append(tl) self.view.insert_buffer(tl.buffer, name=_(u"Friends for {}").format(i,), pos=self.view.search("friends_timelines", session.db["user_name"])) - lists = baseBuffers.emptyPanel(self.view.nb, "lists", session.db["user_name"]) + lists = buffers.base.EmptyBuffer(self.view.nb, "lists", session.db["user_name"]) self.buffers.append(lists) self.view.insert_buffer(lists.buffer , name=_(u"Lists"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) for i in session.settings["other_buffers"]["lists"]: - tl = twitterBuffers.listBufferController(self.view.nb, "list_timeline", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended") + tl = buffers.twitter.ListBuffer(self.view.nb, "list_timeline", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended") session.lists.append(tl) self.buffers.append(tl) self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(i), pos=self.view.search("lists", session.db["user_name"])) - searches = baseBuffers.emptyPanel(self.view.nb, "searches", session.db["user_name"]) + searches = buffers.base.EmptyBuffer(self.view.nb, "searches", session.db["user_name"]) self.buffers.append(searches) self.view.insert_buffer(searches.buffer , name=_(u"Searches"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) for i in session.settings["other_buffers"]["tweet_searches"]: - tl = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended") + tl = buffers.twitter.SearchBuffer(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended") self.buffers.append(tl) self.view.insert_buffer(tl.buffer, name=_(u"Search for {}").format(i), pos=self.view.search("searches", session.db["user_name"])) for i in session.settings["other_buffers"]["trending_topic_buffers"]: - buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg") + buffer = buffers.twitter.TrendsBuffer(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg") buffer.start_stream(play_sound=False) buffer.searchfunction = self.search self.buffers.append(buffer) @@ -431,12 +430,12 @@ class Controller(object): buffer.session.settings["other_buffers"]["tweet_searches"].append(term) buffer.session.settings.write() args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()} - search = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args) + search = buffers.twitter.SearchBuffer(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args) else: log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) return elif dlg.get("users") == True: - search = twitterBuffers.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) + search = buffers.twitter.SearchBuffer(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) search.start_stream(mandatory=True) pos=self.view.search("searches", buffer.session.db["user_name"]) self.insert_buffer(search, pos) @@ -849,7 +848,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["timelines"]: commonMessageDialogs.timeline_exist() return - tl = twitterBuffers.baseBufferController(self.view.nb, "user_timeline", "%s-timeline" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="tweet_timeline.ogg", user_id=usr.id_str, tweet_mode="extended") + tl = buffers.twitter.BaseBuffer(self.view.nb, "user_timeline", "%s-timeline" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="tweet_timeline.ogg", user_id=usr.id_str, tweet_mode="extended") try: tl.start_stream(play_sound=False) except ValueError: @@ -868,7 +867,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["favourites_timelines"]: commonMessageDialogs.timeline_exist() return - tl = twitterBuffers.baseBufferController(self.view.nb, "favorites", "%s-favorite" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, tweet_mode="extended") + tl = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "%s-favorite" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, tweet_mode="extended") try: tl.start_stream(play_sound=False) except ValueError: @@ -887,7 +886,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["followers_timelines"]: commonMessageDialogs.timeline_exist() return - tl = twitterBuffers.peopleBufferController(self.view.nb, "followers", "%s-followers" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) + tl = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "%s-followers" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) try: tl.start_stream(play_sound=False) except ValueError: @@ -906,7 +905,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["friends_timelines"]: commonMessageDialogs.timeline_exist() return - tl = twitterBuffers.peopleBufferController(self.view.nb, "friends", "%s-friends" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) + tl = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "%s-friends" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) try: tl.start_stream(play_sound=False) except ValueError: @@ -926,7 +925,7 @@ class Controller(object): buffer = self.get_current_buffer() id = buffer.get_right_tweet().id user = buffer.session.get_user(buffer.get_right_tweet().user).screen_name - search = twitterBuffers.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) + search = buffers.twitter.ConversationBuffer(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) search.tweet = buffer.get_right_tweet() search.start_stream(start=True) pos=self.view.search("searches", buffer.session.db["user_name"]) @@ -953,7 +952,7 @@ class Controller(object): if trends.dialog.get_response() == widgetUtils.OK: woeid = trends.get_woeid() if woeid in buff.session.settings["other_buffers"]["trending_topic_buffers"]: return - buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (woeid,), buff.session, buff.account, woeid, sound="trends_updated.ogg") + buffer = buffers.twitter.TrendsBuffer(self.view.nb, "%s_tt" % (woeid,), buff.session, buff.account, woeid, sound="trends_updated.ogg") buffer.searchfunction = self.search pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]) self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (trends.get_string()), pos=pos) @@ -1364,41 +1363,37 @@ class Controller(object): buff = self.search_buffer("home_timeline", account) if create == True: if buffer == "favourites": - favourites = twitterBuffers.baseBufferController(self.view.nb, "favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended") + favourites = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended") self.buffers.append(favourites) self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) favourites.start_stream(play_sound=False) if buffer == "followers": - followers = twitterBuffers.peopleBufferController(self.view.nb, "followers", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) + followers = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) self.buffers.append(followers) self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) followers.start_stream(play_sound=False) elif buffer == "friends": - friends = twitterBuffers.peopleBufferController(self.view.nb, "friends", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) + friends = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) self.buffers.append(friends) self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) friends.start_stream(play_sound=False) elif buffer == "blocked": - blocks = twitterBuffers.peopleBufferController(self.view.nb, "blocks", "blocked", buff.session, buff.session.db["user_name"]) + blocks = buffers.twitter.PeopleBuffer(self.view.nb, "blocks", "blocked", buff.session, buff.session.db["user_name"]) self.buffers.append(blocks) self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) blocks.start_stream(play_sound=False) elif buffer == "muted": - muted = twitterBuffers.peopleBufferController(self.view.nb, "mutes", "muted", buff.session, buff.session.db["user_name"]) + muted = buffers.twitter.PeopleBuffer(self.view.nb, "mutes", "muted", buff.session, buff.session.db["user_name"]) self.buffers.append(muted) self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) muted.start_stream(play_sound=False) - elif buffer == "events": - events = twitterBuffers.eventsBufferController(self.view.nb, "events", buff.session, buff.session.db["user_name"], bufferType="dmPanel", screen_name=buff.session.db["user_name"]) - self.buffers.append(events) - self.view.insert_buffer(events.buffer, name=_(u"Events"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) elif create == False: self.destroy_buffer(buffer, buff.session.db["user_name"]) elif buffer == "list": if create in buff.session.settings["other_buffers"]["lists"]: output.speak(_(u"This list is already opened"), True) return - tl = twitterBuffers.listBufferController(self.view.nb, "list_timeline", create+"-list", buff.session, buff.session.db["user_name"], bufferType=None, list_id=utils.find_list(create, buff.session.db["lists"]), tweet_mode="extended") + tl = buffers.twitter.ListBuffer(self.view.nb, "list_timeline", create+"-list", buff.session, buff.session.db["user_name"], bufferType=None, list_id=utils.find_list(create, buff.session.db["lists"]), tweet_mode="extended") buff.session.lists.append(tl) pos=self.view.search("lists", buff.session.db["user_name"]) self.insert_buffer(tl, pos) From 818bc243e4bf5f4257dce887f3e1c7503a49613a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 17:34:40 -0500 Subject: [PATCH 086/245] Handle Twyshort's detection for reduced tweets --- src/sessions/twitter/long_tweets/twishort.py | 24 ++++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/sessions/twitter/long_tweets/twishort.py b/src/sessions/twitter/long_tweets/twishort.py index 2f465cd3..e016b174 100644 --- a/src/sessions/twitter/long_tweets/twishort.py +++ b/src/sessions/twitter/long_tweets/twishort.py @@ -39,26 +39,20 @@ def get_twishort_uri(url): def is_long(tweet): """ Check if the passed tweet is made with Twishort. returns True if is a long tweet, False otherwise.""" - long = False - for url in range(0, len(tweet.entities["urls"])): - try: - if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]: - long = get_twishort_uri(tweet.entities["urls"][url]["expanded_url"]) - except IndexError: - pass - # sometimes Twitter returns URL's with None objects, so let's take it. - # see https://github.com/manuelcortez/TWBlue/issues/103 - except TypeError: - pass - if long == False and hasattr(tweet, "retweeted_status"): - for url in range(0, len(tweet.retweeted_status.entities["urls"])): + if hasattr(tweet, "entities") and tweet.entities.get("urls"): + long = False + for url in range(0, len(tweet.entities["urls"])): try: - if tweet.retweeted_status.entities["urls"][url] != None and "twishort.com" in tweet.retweeted_status.entities["urls"][url]["expanded_url"]: - long = get_twishort_uri(tweet.retweeted_status.entities["urls"][url]["expanded_url"]) + if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]: + long = get_twishort_uri(tweet.entities["urls"][url]["expanded_url"]) except IndexError: pass + # sometimes Twitter returns URL's with None objects, so let's take it. + # see https://github.com/manuelcortez/TWBlue/issues/103 except TypeError: pass + if long == False and hasattr(tweet, "retweeted_status"): + return is_long(tweet.retweeted_status) return long def get_full_text(uri): From ee9a92bcb4222ae8f703890baa9795aa702a2884 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 17:53:05 -0500 Subject: [PATCH 087/245] Makes time available on conversation buffers --- src/controller/buffers/twitter/search.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index 0b34a4a1..cea68a0b 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import time import platform if platform.system() == "Windows": from wxUI import commonMessageDialogs From 864ebdf96d6e89535f6778c5140b48e1a0d7b5c3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 2 Jul 2021 17:57:39 -0500 Subject: [PATCH 088/245] Made widgetUtils available to searchBuffers --- src/controller/buffers/twitter/search.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index cea68a0b..bbf324b6 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -6,6 +6,7 @@ if platform.system() == "Windows": elif platform.system() == "Linux": from gi.repository import Gtk from gtkUI import commonMessageDialogs +import widgetUtils import logging from . import base, people From 7eb2d8930f59ff0fb069326bee78188bd85f612b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 3 Jul 2021 11:51:11 -0500 Subject: [PATCH 089/245] Fixed traceback happened when attempting to send streaming data to not logged sessions --- src/sessions/twitter/session.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index cdfd9684..9ecf1d3f 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -108,7 +108,6 @@ class Session(base.baseSession): self.db["sent_direct_messages"] = sent_objects pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"]) - return incoming def __init__(self, *args, **kwargs): @@ -515,6 +514,8 @@ class Session(base.baseSession): def handle_new_status(self, status, user): """ Handles a new status present in the Streaming API. """ + if self.logged == False: + return # Discard processing the status if the streaming sends a tweet for another account. if self.db["user_name"] != user: return @@ -559,5 +560,7 @@ class Session(base.baseSession): self.start_streaming() def handle_connected(self, user): + if self.logged == False: + return if user != self.db["user_name"]: log.debug("Connected streaming endpoint on account {}".format(user)) \ No newline at end of file From 84cbf5c4971bec2e91af48df74d86d35837e4edd Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 3 Jul 2021 11:51:43 -0500 Subject: [PATCH 090/245] Fix yet another error due to reduced tweets --- src/sessions/twitter/long_tweets/twishort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessions/twitter/long_tweets/twishort.py b/src/sessions/twitter/long_tweets/twishort.py index e016b174..4e42fbf8 100644 --- a/src/sessions/twitter/long_tweets/twishort.py +++ b/src/sessions/twitter/long_tweets/twishort.py @@ -39,8 +39,8 @@ def get_twishort_uri(url): def is_long(tweet): """ Check if the passed tweet is made with Twishort. returns True if is a long tweet, False otherwise.""" + long = False if hasattr(tweet, "entities") and tweet.entities.get("urls"): - long = False for url in range(0, len(tweet.entities["urls"])): try: if tweet.entities["urls"][url] != None and "twishort.com" in tweet.entities["urls"][url]["expanded_url"]: From c926355048ffcd059cb15addcb0011370e7c2fe8 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 3 Jul 2021 11:52:21 -0500 Subject: [PATCH 091/245] Hide replies to users the current account doesn't follow in streaming API --- src/sessions/twitter/streaming.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py index 613edc01..3c63b3f0 100644 --- a/src/sessions/twitter/streaming.py +++ b/src/sessions/twitter/streaming.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """ Streaming support for TWBlue. """ import time +import sys import six import requests import urllib3 @@ -30,9 +31,12 @@ class StreamListener(tweepy.StreamListener): def on_status(self, status): """ Checks data arriving as a tweet. """ + # Hide replies to users not followed by current account. + if status.in_reply_to_user_id_str != None and status.in_reply_to_user_id_str not in self.users: + return if status.user.id_str in self.users: pub.sendMessage("newStatus", status=status, user=self.user) -# print(status.text) + class Stream(tweepy.Stream): From 788811bf6c5ca8e9d3378bbab9fa6ec14b4adf29 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 3 Jul 2021 14:04:14 -0500 Subject: [PATCH 092/245] Ensure a tweet is reduced when sent by streaming API --- src/sessions/twitter/session.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 9ecf1d3f..98448c02 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -405,9 +405,9 @@ class Session(base.baseSession): """ Returns an user object associated with an ID. id str: User identifier, provided by Twitter. returns a tweepy user object.""" - if hasattr(id, "id_str"): - log.error("Called get_user function by passing a full user id as a parameter.") - id = id.id_str +# if hasattr(id, "id_str"): +# log.error("Called get_user function by passing a full user id as a parameter.") +# id = id.id_str # Check if the user has been added to the list of deleted users previously. if id in self.deleted_users: log.debug("Returning user {} from the list of deleted users.".format(id)) @@ -548,7 +548,7 @@ class Session(base.baseSession): if num == 0: buffers_to_send.remove(buffer) # However, we have to do the "reduce and change" process here because the status we sent to the db is going to be a different object that the one sent to database. - reduced_status = reduce.reduce_tweet(status) + status = reduce.reduce_tweet(status) status = self.check_quoted_status(status) status = self.check_long_tweet(status) # Send it to the main controller object. From 465b550c30a3825112ed5de569a5cc52e2fc8750 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 3 Jul 2021 14:05:02 -0500 Subject: [PATCH 093/245] Removed old code to deal with invalid users --- src/sessions/twitter/session.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 98448c02..c23d411c 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -405,9 +405,9 @@ class Session(base.baseSession): """ Returns an user object associated with an ID. id str: User identifier, provided by Twitter. returns a tweepy user object.""" -# if hasattr(id, "id_str"): -# log.error("Called get_user function by passing a full user id as a parameter.") -# id = id.id_str + if hasattr(id, "id_str"): + log.error("Called get_user function by passing a full user id as a parameter.") + id = id.id_str # Check if the user has been added to the list of deleted users previously. if id in self.deleted_users: log.debug("Returning user {} from the list of deleted users.".format(id)) From ccba22cfd229242b3a4b6b6ca062e45f3b3dcc38 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 3 Jul 2021 14:09:52 -0500 Subject: [PATCH 094/245] Show dialog on suspended users again. closes #387 --- src/controller/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/user.py b/src/controller/user.py index 755b21ba..f48346e6 100644 --- a/src/controller/user.py +++ b/src/controller/user.py @@ -27,7 +27,7 @@ class profileController(object): except TweepError as err: if err.api_code == 50: wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() - if err.api_code == 403: + if err.api_code == 63: wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal() log.error("error %d: %s" % (err.api_code, err.reason)) return From 81d18d4656a1de6cdc7bcc2d89e8939474594f31 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 04:47:13 -0500 Subject: [PATCH 095/245] Updated changelog --- doc/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog.md b/doc/changelog.md index 51149f76..c268b795 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,8 @@ ## changes in this version +* Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385)) +* Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387)) * Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384)) * We just implemented some changes in the way TWBlue handles tweets in order to reduce its RAM memory usage [#380](https://github.com/manuelcortez/TWBlue/pull/380): * We reduced the tweets size by storing only the tweet fields we currently use. This should reduce tweet's size in memory for every object up to 75%. From d301f841e380be62162acae74257effc7da36595 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 05:02:02 -0500 Subject: [PATCH 096/245] TWBlue should stop showing sent retweets as original tweets in Streaming API --- src/controller/buffers/twitter/base.py | 34 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 5ccc0ae6..5d3aca86 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -102,8 +102,10 @@ class BaseBuffer(base.Buffer): item = self.session.api_call(call_name="update_status", status=text, _sound="tweet_send.ogg", tweet_mode="extended") else: call_threaded(self.post_with_media, text=text, attachments=tweet.attachments) - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. + # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. +# if item != None: +# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) if hasattr(tweet.message, "destroy"): tweet.message.destroy() self.session.settings.write() @@ -114,8 +116,10 @@ class BaseBuffer(base.Buffer): self.session.twitter.create_media_metadata(media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) item = self.session.twitter.update_status(status=text, media_ids=media_ids) - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. + # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. +# if item != None: +# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) def get_formatted_message(self): if self.type == "dm" or self.name == "direct_messages": @@ -454,8 +458,10 @@ class BaseBuffer(base.Buffer): params["call_name"] = "update_status_with_media" params["media"] = message.file item = self.session.api_call(**params) - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. + # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. +# if item != None: +# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) if hasattr(message.message, "destroy"): message.message.destroy() self.session.settings.write() @@ -518,21 +524,25 @@ class BaseBuffer(base.Buffer): text = retweet.message.get_text() text = text+" https://twitter.com/{0}/status/{1}".format(self.session.get_user(tweet.user).screen_name, id) if retweet.image == None: + # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. + # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. item = self.session.api_call(call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id, tweet_mode="extended") - if item != None: - new_item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") - pub.sendMessage("sent-tweet", data=new_item, user=self.session.db["user_name"]) +# if item != None: +# new_item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") +# pub.sendMessage("sent-tweet", data=new_item, user=self.session.db["user_name"]) else: call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=text, media=retweet.image) if hasattr(retweet.message, "destroy"): retweet.message.destroy() def _direct_retweet(self, id): item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id) - if item != None: + # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. + # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. +# if item != None: # Retweets are returned as non-extended tweets, so let's get the object as extended # just before sending the event message. See https://github.com/manuelcortez/TWBlue/issues/253 - item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) +# item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") +# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) def onFocus(self, *args, **kwargs): tweet = self.get_tweet() From 01dd93e076e6c2a0b3ba8702c2389479f26ea9ae Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 05:30:52 -0500 Subject: [PATCH 097/245] Show all current account replies in streaming API --- src/sessions/twitter/streaming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py index 3c63b3f0..29cfe052 100644 --- a/src/sessions/twitter/streaming.py +++ b/src/sessions/twitter/streaming.py @@ -32,7 +32,7 @@ class StreamListener(tweepy.StreamListener): def on_status(self, status): """ Checks data arriving as a tweet. """ # Hide replies to users not followed by current account. - if status.in_reply_to_user_id_str != None and status.in_reply_to_user_id_str not in self.users: + if status.in_reply_to_user_id_str != None and status.in_reply_to_user_id_str not in self.users and status.user.screen_name != self.user: return if status.user.id_str in self.users: pub.sendMessage("newStatus", status=status, user=self.user) From 5cad4ab2a7e86ba6baa65e06eb5e22ea85e0b8b5 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 05:31:27 -0500 Subject: [PATCH 098/245] Restore get_all_users and get_all_mentionned in nested tweets --- src/sessions/twitter/utils.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index fc080bdf..75b37768 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -120,6 +120,10 @@ def is_media(tweet): def get_all_mentioned(tweet, conf, field="screen_name"): """ Gets all users that have been mentioned.""" results = [] + if hasattr(tweet, "retweeted_status"): + results.extend(get_all_mentionned(tweet.retweeted_status, conf, field)) + if hasattr(tweet, "quoted_status"): + results.extend(tweet.quoted_status, conf, field) if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): for i in tweet.entities["user_mentions"]: if i["screen_name"] != conf["user_name"] and i["id_str"] != tweet.user: @@ -130,17 +134,19 @@ def get_all_mentioned(tweet, conf, field="screen_name"): def get_all_users(tweet, session): string = [] user = session.get_user(tweet.user) - if hasattr(tweet, "retweeted_status"): + if user.screen_name != session.db["user_name"]: string.append(user.screen_name) - tweet = tweet.retweeted_status - else: - if user.screen_name != session.db["user_name"]: - string.append(user.screen_name) - if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): - for i in tweet.entities["user_mentions"]: - if i["screen_name"] != session.db["user_name"] and i["screen_name"] != user.screen_name: - if i["screen_name"] not in string: - string.append(i["screen_name"]) + if hasattr(tweet, "retweeted_status"): + string.extend(get_all_users(tweet.retweeted_status, session)) + if hasattr(tweet, "quoted_status"): + string.extend(get_all_users(tweet.quoted_status, session)) + if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): + for i in tweet.entities["user_mentions"]: + if i["screen_name"] != session.db["user_name"] and i["screen_name"] != user.screen_name: + if i["screen_name"] not in string: + string.append(i["screen_name"]) + # Attempt to remove duplicates, tipically caused by nested tweets. + string = list(dict.fromkeys(string)) if len(string) == 0: string.append(user.screen_name) return string From e9e8a8fba923d253465ed1f392db134d8d8d0051 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 05:43:06 -0500 Subject: [PATCH 099/245] Pushed a new snapshot --- scripts/twblue_snapshot.nsi | 12 ++++++------ src/application.py | 2 +- updates/snapshots.json | 6 ++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi index 73f5c7ed..ceec3938 100644 --- a/scripts/twblue_snapshot.nsi +++ b/scripts/twblue_snapshot.nsi @@ -15,10 +15,10 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue Snapshot version" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "6" -VIAddVersionKey FileVersion "6" -VIProductVersion "6.0.0" -VIFileVersion "6.0.0" +VIAddVersionKey ProductVersion "7" +VIAddVersionKey FileVersion "7" +VIProductVersion "7.0.0" +VIFileVersion "7.0.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -72,10 +72,10 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.95" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "7" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.es" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 -WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 95 +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1 SectionEnd diff --git a/src/application.py b/src/application.py index de258a64..2d89c093 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "6" + version = "7" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] diff --git a/updates/snapshots.json b/updates/snapshots.json index 1505065f..d8698087 100644 --- a/updates/snapshots.json +++ b/updates/snapshots.json @@ -1,5 +1,7 @@ -{"current_version": "6", +{"current_version": "7", "description": "Snapshot version.", "date": "unknown", "downloads": -{"Windows32": "https://twblue.es/pubs/snapshot.zip"}} \ No newline at end of file +{"Windows32": "https://twblue.es/pubs/twblue_snapshot_x86.zip"}, +{"Windows64": "https://twblue.es/pubs/twblue_snapshot_x64.zip"} +} \ No newline at end of file From 4312ad82e7bf8930ad61f667d59849431e3238b7 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 05:51:59 -0500 Subject: [PATCH 100/245] Fixed runner config --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b56b63f5..5b055530 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -98,6 +98,8 @@ generate_versions: - cd scripts - '&$env:NSIS twblue_snapshot.nsi' - move twblue_snapshot_setup.exe ../artifacts + only: + - tags artifacts: paths: - artifacts @@ -113,6 +115,5 @@ upload: - cd artifacts - python ../scripts/upload.py only: - - next-gen - tags - schedules \ No newline at end of file From 37af7225569bc2b611b21fff2593342e8012587e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 06:15:40 -0500 Subject: [PATCH 101/245] Fixed alpha version for snapshots --- scripts/twblue_snapshot.nsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi index ceec3938..bd5c2f82 100644 --- a/scripts/twblue_snapshot.nsi +++ b/scripts/twblue_snapshot.nsi @@ -17,8 +17,8 @@ VIAddVersionKey ProductName "TWBlue Snapshot version" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." VIAddVersionKey ProductVersion "7" VIAddVersionKey FileVersion "7" -VIProductVersion "7.0.0" -VIFileVersion "7.0.0" +VIProductVersion "7.0.0.0" +VIFileVersion "7.0.0.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" From 8fe2f4c64df2f1098af6893fe0608f8e3d7412f0 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 09:15:04 -0500 Subject: [PATCH 102/245] Exclude muted users from Streaming API --- src/sessions/twitter/session.py | 2 +- src/sessions/twitter/streaming.py | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index c23d411c..35d7a495 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -504,7 +504,7 @@ class Session(base.baseSession): self.db["users"] = users def start_streaming(self): - self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"]) + self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"], muted_users=self.db["muted_users"]) self.stream = streaming.Stream(auth = self.auth, listener=self.stream_listener, chunk_size=1025) self.stream_thread = call_threaded(self.stream.filter, follow=self.stream_listener.users, stall_warnings=True) diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py index 29cfe052..dcd5711d 100644 --- a/src/sessions/twitter/streaming.py +++ b/src/sessions/twitter/streaming.py @@ -14,14 +14,23 @@ log = logging.getLogger("sessions.twitter.streaming") class StreamListener(tweepy.StreamListener): - def __init__(self, twitter_api, user, user_id, *args, **kwargs): + def __init__(self, twitter_api, user, user_id, muted_users=[], *args, **kwargs): super(StreamListener, self).__init__(*args, **kwargs) + log.debug("Starting streaming listener for account {}".format(user)) + self.started = False + self.users = [] self.api = twitter_api self.user = user self.user_id = user_id - self.users = [str(id) for id in self.api.friends_ids()] + friends = self.api.friends_ids() + log.debug("Retrieved {} friends to add to the streaming listener.".format(len(friends))) self.users.append(str(self.user_id)) - log.debug("Started streaming object for user {}".format(self.user)) + log.debug("Got {} muted users.".format(len(muted_users))) + for user in friends: + if user not in muted_users: + self.users.append(str(user)) + self.started = True + log.debug("Streaming listener started with {} users to follow.".format(len(self.users))) def on_connect(self): pub.sendMessage("streamConnected", user=self.user) From 03b61946f84a4cf0e42ef7e478c4f58acff61ffd Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 09:43:53 -0500 Subject: [PATCH 103/245] Fixed user searches --- src/controller/mainController.py | 2 +- src/sessions/twitter/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 4f415f8c..4cc72170 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -440,7 +440,7 @@ class Controller(object): log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) return elif dlg.get("users") == True: - search = buffers.twitter.SearchBuffer(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) + search = buffers.twitter.SearchPeopleBuffer(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) search.start_stream(mandatory=True) pos=self.view.search("searches", buffer.session.db["user_name"]) self.insert_buffer(search, pos) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 75b37768..d7bce3e5 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -168,7 +168,7 @@ def is_allowed(tweet, settings, buffer_name): tweet_data = {} if hasattr(tweet, "retweeted_status"): tweet_data["retweet"] = True - if tweet.in_reply_to_status_id != None: + if hasattr(tweet, "in_reply_to_status_id"): tweet_data["reply"] = True if hasattr(tweet, "quoted_status"): tweet_data["quote"] = True From e6543bcf776cf1d15fb257c1387972ccb28c6010 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 09:44:48 -0500 Subject: [PATCH 104/245] Allow streaming API support to be disabled from global settings dialog --- src/sessions/twitter/session.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 35d7a495..5b0f46e8 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -504,13 +504,18 @@ class Session(base.baseSession): self.db["users"] = users def start_streaming(self): + if config.app["app-settings"]["no_streaming"]: + return self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"], muted_users=self.db["muted_users"]) self.stream = streaming.Stream(auth = self.auth, listener=self.stream_listener, chunk_size=1025) self.stream_thread = call_threaded(self.stream.filter, follow=self.stream_listener.users, stall_warnings=True) def stop_streaming(self): - self.stream.running = False - log.debug("Stream stopped for accounr {}".format(self.db["user_name"])) + if config.app["app-settings"]["no_streaming"]: + return + if hasattr(self, "stream"): + self.stream.running = False + log.debug("Stream stopped for accounr {}".format(self.db["user_name"])) def handle_new_status(self, status, user): """ Handles a new status present in the Streaming API. """ @@ -555,6 +560,10 @@ class Session(base.baseSession): pub.sendMessage("newTweet", data=status, user=self.db["user_name"], _buffers=buffers_to_send) def check_streams(self): + if config.app["app-settings"]["no_streaming"]: + return + if not hasattr(self, "stream"): + return log.debug("Status of running stream for user {}: {}".format(self.db["user_name"], self.stream.running)) if self.stream.running == False: self.start_streaming() From b9a9bd03c22753214c2f40383fdc79003e08a8e7 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 09:47:33 -0500 Subject: [PATCH 105/245] Pushed a new snapshot --- scripts/twblue_snapshot.nsi | 12 ++++++------ src/application.py | 2 +- updates/snapshots.json | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi index bd5c2f82..00d10e27 100644 --- a/scripts/twblue_snapshot.nsi +++ b/scripts/twblue_snapshot.nsi @@ -15,10 +15,10 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue Snapshot version" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "7" -VIAddVersionKey FileVersion "7" -VIProductVersion "7.0.0.0" -VIFileVersion "7.0.0.0" +VIAddVersionKey ProductVersion "8" +VIAddVersionKey FileVersion "8" +VIProductVersion "8.0.0.0" +VIFileVersion "8.0.0.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -72,8 +72,8 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "7" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.es" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "8" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "https://twblue.es" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1 diff --git a/src/application.py b/src/application.py index 2d89c093..d463c956 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "7" + version = "8" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] diff --git a/updates/snapshots.json b/updates/snapshots.json index d8698087..b3a3ff75 100644 --- a/updates/snapshots.json +++ b/updates/snapshots.json @@ -1,7 +1,7 @@ -{"current_version": "7", +{"current_version": "8", "description": "Snapshot version.", "date": "unknown", "downloads": -{"Windows32": "https://twblue.es/pubs/twblue_snapshot_x86.zip"}, -{"Windows64": "https://twblue.es/pubs/twblue_snapshot_x64.zip"} +{"Windows32": "https://twblue.es/pubs/twblue_snapshot_x86.zip", +{"Windows64": "https://twblue.es/pubs/twblue_snapshot_x64.zip" } \ No newline at end of file From bcc72c932d35e67793f82a9d6623c15393daa792 Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Sun, 4 Jul 2021 18:26:49 +0200 Subject: [PATCH 106/245] Updated Windows dependencies. Python 3.8.10 --- windows-dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows-dependencies b/windows-dependencies index 27d86088..3244b9e3 160000 --- a/windows-dependencies +++ b/windows-dependencies @@ -1 +1 @@ -Subproject commit 27d860885f8f3bf9246364f69fc66d79b7412680 +Subproject commit 3244b9e3fb7cb5adcac516e455fc00fabf3151c3 From 37ad6b5fbfe0b3e56276f0c8e51c54baf8fefc1c Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Sun, 4 Jul 2021 18:32:17 +0200 Subject: [PATCH 107/245] paths.py: replace socializer by TW Blue in data_path function definition --- src/paths.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/paths.py b/src/paths.py index 1eeb67d5..72435db0 100644 --- a/src/paths.py +++ b/src/paths.py @@ -39,7 +39,7 @@ def logs_path(): os.mkdir(path) return path -def data_path(app_name='socializer'): +def data_path(app_name='TW Blue'): if platform.system() == "Windows": data_path = os.path.join(os.getenv("AppData"), app_name) else: From 5268f166f884d0162394eda113f54ac1e282acac Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Sun, 4 Jul 2021 18:43:33 +0200 Subject: [PATCH 108/245] Use Python 3.8.10 for automated builds --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5b055530..8f377e5a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,7 +17,7 @@ snapshot32: - Set-Variable -Name "time" -Value (date -Format "%H:%m") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - choco install python --version 3.8.7 -y -ForceX86 + - choco install python --version 3.8.10 -y -ForceX86 - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' @@ -54,7 +54,7 @@ snapshot64: - Set-Variable -Name "time" -Value (date -Format "%H:%m") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - choco install python --version 3.8.7 -y + - choco install python --version 3.8.10 -y - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' From 44b6e821832d2b5cafc15edaddf517ad8a3ec7d6 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 11:50:03 -0500 Subject: [PATCH 109/245] Fix reply dialog issue --- src/sessions/twitter/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index d7bce3e5..24d498b4 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -121,9 +121,9 @@ def get_all_mentioned(tweet, conf, field="screen_name"): """ Gets all users that have been mentioned.""" results = [] if hasattr(tweet, "retweeted_status"): - results.extend(get_all_mentionned(tweet.retweeted_status, conf, field)) + results.extend(get_all_mentioned(tweet.retweeted_status, conf, field)) if hasattr(tweet, "quoted_status"): - results.extend(tweet.quoted_status, conf, field) + results.extend(get_all_mentioned(tweet.quoted_status, conf, field)) if hasattr(tweet, "entities") and tweet.entities.get("user_mentions"): for i in tweet.entities["user_mentions"]: if i["screen_name"] != conf["user_name"] and i["id_str"] != tweet.user: From bb4869b7be526f447e5cd59b19210662b3fccd18 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 4 Jul 2021 17:05:06 -0500 Subject: [PATCH 110/245] Pushed a new snapshot --- scripts/twblue_snapshot.nsi | 10 +++++----- src/application.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi index 00d10e27..62f88198 100644 --- a/scripts/twblue_snapshot.nsi +++ b/scripts/twblue_snapshot.nsi @@ -15,10 +15,10 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue Snapshot version" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "8" -VIAddVersionKey FileVersion "8" -VIProductVersion "8.0.0.0" -VIFileVersion "8.0.0.0" +VIAddVersionKey ProductVersion "9" +VIAddVersionKey FileVersion "9" +VIProductVersion "9.0.0.0" +VIFileVersion "9.0.0.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -72,7 +72,7 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "8" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "9" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "https://twblue.es" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 diff --git a/src/application.py b/src/application.py index d463c956..a7baf074 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "8" + version = "9" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] From d5ac0db67b6df624459f78ed5ceaef24aeb68217 Mon Sep 17 00:00:00 2001 From: zstanecic Date: Mon, 5 Jul 2021 16:04:19 +0200 Subject: [PATCH 111/245] updated the russian localization. --- src/locales/ru/LC_MESSAGES/twblue.mo | Bin 64532 -> 64832 bytes src/locales/ru/LC_MESSAGES/twblue.po | 16 ++++++---------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/locales/ru/LC_MESSAGES/twblue.mo b/src/locales/ru/LC_MESSAGES/twblue.mo index fea14909653734e74743bff51784cb10098faec1..ab4e62681a302c26df510a503233c0e837e6f3a6 100644 GIT binary patch delta 15536 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 delta 15405 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 Dro3=i diff --git a/src/locales/ru/LC_MESSAGES/twblue.po b/src/locales/ru/LC_MESSAGES/twblue.po index ee83c122..4b041800 100644 --- a/src/locales/ru/LC_MESSAGES/twblue.po +++ b/src/locales/ru/LC_MESSAGES/twblue.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.85\n" "POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2020-10-23 14:30+0300\n" +"PO-Revision-Date: 2021-07-05 16:03+0200\n" "Last-Translator: Artem Plaksin \n" "Language-Team: Alexander Jaszyn \n" "Language: ru\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 1.8.8\n" +"X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -208,14 +208,12 @@ msgstr "" "личных сообщений вместо этого." #: ../src\controller\buffers\twitterBuffers.py:983 -#, fuzzy msgid "{0} new followers." -msgstr "Новый читатель." +msgstr "{0} новых читателей." #: ../src\controller\buffers\twitterBuffers.py:1266 -#, fuzzy msgid "This action is not supported in the buffer, yet." -msgstr "Это действие не поддерживается в данном буфере" +msgstr "Это действие пока не поддерживается в буфере." #: ../src\controller\mainController.py:273 msgid "Ready" @@ -314,9 +312,8 @@ msgid "Select the user" msgstr "Выберите пользователя" #: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 -#, fuzzy msgid "MMM D, YYYY. H:m" -msgstr "dddd, MMMM D, YYYY H:m:s" +msgstr "MMM D, YYYY. H:m" #: ../src\controller\mainController.py:934 msgid "Conversation with {0}" @@ -1702,9 +1699,8 @@ msgid "Opens the global settings dialogue" msgstr "Открыть основные настройки" #: ../src\keystrokeEditor\constants.py:54 -#, fuzzy msgid "Opens the list manager" -msgstr "Менеджер Списков" +msgstr "Открывает менеджер списков" #: ../src\keystrokeEditor\constants.py:55 msgid "Opens the account settings dialogue" From 23a56c637dd6925374dd16213380e90f82fdea19 Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Mon, 5 Jul 2021 23:03:40 +0200 Subject: [PATCH 112/245] Add some indirect dependencies to requirements.txt in order to easily keep them updated --- requirements.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/requirements.txt b/requirements.txt index 9943eb0f..94ca651f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,6 +25,7 @@ urllib3 youtube-dl python-vlc pypiwin32 +pywin32 certifi backports.functools_lru_cache cx_freeze @@ -32,6 +33,16 @@ tweepy twitter-text-parser pyenchant sqlitedict +cx-Logging +h11 +h2 +hpack +hstspreload +httpcore +httpx +hyperframe +rfc3986 +sniffio git+https://github.com/accessibleapps/libloader git+https://github.com/accessibleapps/platform_utils git+https://github.com/accessibleapps/accessible_output2 From 86130954d7cfed7ee4467c3e069292d342f4e693 Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Tue, 6 Jul 2021 12:39:47 +0200 Subject: [PATCH 113/245] Updated Windows dependencies. Latest versions of NSIS and VLC, among others --- windows-dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows-dependencies b/windows-dependencies index 3244b9e3..27a7c419 160000 --- a/windows-dependencies +++ b/windows-dependencies @@ -1 +1 @@ -Subproject commit 3244b9e3fb7cb5adcac516e455fc00fabf3151c3 +Subproject commit 27a7c419835c5fed4ba77bc31d0e1aff50a78f2a From 1206aba83b614c0ea5a7bdf918c64fefb970c480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Tue, 6 Jul 2021 20:42:03 +0200 Subject: [PATCH 114/245] Added a few more dependencies to requirements.txt --- requirements.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/requirements.txt b/requirements.txt index 94ca651f..a3282f7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,6 +43,10 @@ httpx hyperframe rfc3986 sniffio +attrs +importlib-metadata +numpy +pillow git+https://github.com/accessibleapps/libloader git+https://github.com/accessibleapps/platform_utils git+https://github.com/accessibleapps/accessible_output2 From 877c90948278ecaac57014bf77c285a2f36a08e5 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 6 Jul 2021 13:56:56 -0500 Subject: [PATCH 115/245] Added user-aliases section on session configs --- src/Conf.defaults | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Conf.defaults b/src/Conf.defaults index 80b28db6..a723b767 100644 --- a/src/Conf.defaults +++ b/src/Conf.defaults @@ -49,3 +49,5 @@ braille_reporting = boolean(default=True) speech_reporting = boolean(default=True) [filters] + +[user-aliases] \ No newline at end of file From de12dadac2035e3298425d2281b85e02d8f636d2 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 6 Jul 2021 13:58:13 -0500 Subject: [PATCH 116/245] Added GUI for user alias addition --- src/controller/mainController.py | 21 ++++++++++++++++++++ src/wxUI/dialogs/utils.py | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 4cc72170..fa689661 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -185,6 +185,7 @@ class Controller(object): widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report_error, self.view.reportError) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_documentation, self.view.doc) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_changelog, self.view.changelog) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_alias, self.view.addAlias) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_list, self.view.addToList) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_list, self.view.removeFromList) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_buffer, self.view.update_buffer) @@ -754,6 +755,26 @@ class Controller(object): users = utils.get_all_users(tweet, buff.session) u = userActionsController.userActionsController(buff, users, "report") + def add_alias(self, *args, **kwargs): + buff = self.get_best_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type == "people": + users = [tweet.screen_name] + elif buff.type == "dm": + users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] + else: + users = utils.get_all_users(tweet, buff.session) + dlg = dialogs.utils.addAliasDialog(_("Add an user alias"), users) + if dlg.get_response() == widgetUtils.OK: + user, alias = dlg.get_user() + if user == "" or alias == "": + return + user_id = buff.session.get_user_by_screen_name(user) + buff.session.settings["user-aliases"][str(user_id)] = alias + buff.session.settings.write() + output.speak(_("Alias has been set correctly for {}.").format(user)) + def post_tweet(self, event=None): buffer = self.get_best_buffer() buffer.post_status() diff --git a/src/wxUI/dialogs/utils.py b/src/wxUI/dialogs/utils.py index 8335d61d..6f308685 100644 --- a/src/wxUI/dialogs/utils.py +++ b/src/wxUI/dialogs/utils.py @@ -48,3 +48,36 @@ class selectUserDialog(baseDialog.BaseWXDialog): def get_user(self): return self.cb.GetValue() +class addAliasDialog(baseDialog.BaseWXDialog): + def __init__(self, title, users): + super(addAliasDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize) + self.cb.SetFocus() + self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) + userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + userSizer.Add(self.autocompletion, 0, wx.ALL, 5) + aliasSizer = wx.BoxSizer(wx.HORIZONTAL) + aliasLabel = wx.StaticText(panel, wx.ID_ANY, _("Alias")) + self.alias = wx.TextCtrl(panel, wx.ID_ANY) + aliasSizer.Add(aliasLabel, 0, wx.ALL, 5) + aliasSizer.Add(self.alias, 0, wx.ALL, 5) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() +# ok.Bind(wx.EVT_BUTTON, self.onok) + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(userSizer, 0, wx.ALL, 5) + sizer.Add(aliasSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def get_user(self): + return (self.cb.GetValue(), self.alias.GetValue()) + From 07f9afb14e932d2d9e00638d577acd6ec44ecc59 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 6 Jul 2021 13:58:34 -0500 Subject: [PATCH 117/245] Added option to user menu in the menu bar --- src/wxUI/view.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wxUI/view.py b/src/wxUI/view.py index cef105be..5e5f034b 100644 --- a/src/wxUI/view.py +++ b/src/wxUI/view.py @@ -43,6 +43,7 @@ class mainFrame(wx.Frame): self.follow = user.Append(wx.ID_ANY, _(u"&Actions...")) self.timeline = user.Append(wx.ID_ANY, _(u"&View timeline...")) self.dm = user.Append(wx.ID_ANY, _(u"Direct me&ssage")) + self.addAlias = user.Append(wx.ID_ANY, _("Add a&lias")) self.addToList = user.Append(wx.ID_ANY, _(u"&Add to list")) self.removeFromList = user.Append(wx.ID_ANY, _(u"R&emove from list")) self.viewLists = user.Append(wx.ID_ANY, _(u"&View lists")) From 3688d7548c4dc14c51c63a2031cece3fa449ba3c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 6 Jul 2021 13:59:34 -0500 Subject: [PATCH 118/245] Check alias before returning any user object --- src/sessions/twitter/session.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 5b0f46e8..ea0561e2 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -430,9 +430,25 @@ class Session(base.baseSession): users = self.db["users"] users[user.id_str] = user self.db["users"] = users + user.name = self.get_user_alias(user) return user else: - return self.db["users"][str(id)] + user = self.db["users"][str(id)] + user.name = self.get_user_alias(user) + return user + + def get_user_alias(self, user): + """ Retrieves an alias for the passed user model, if exists. + @ user Tweepy.models.user: An user object. + """ + aliases = self.settings.get("user-aliases") + if aliases == None: + log.error("Aliases are not defined for this config spec.") + return user.name + user_alias = aliases.get(user.id_str) + if user_alias != None: + return user_alias + return user.name def get_user_by_screen_name(self, screen_name): """ Returns an user identifier associated with a screen_name. From 8ff6809f08442ac6b4e57616c02365b27dca0345 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 6 Jul 2021 16:22:52 -0500 Subject: [PATCH 119/245] Updated changelog --- doc/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.md b/doc/changelog.md index c268b795..905e29af 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) * Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385)) * Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387)) * Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384)) From b74cd9a73d68e29f143e74eec935f4071c2b3d8b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 6 Jul 2021 17:01:42 -0500 Subject: [PATCH 120/245] Ignore undefined actions in keymaps --- src/controller/mainController.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index fa689661..99f77e28 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1265,7 +1265,8 @@ class Controller(object): keymap = {} for i in config.keymap["keymap"]: if hasattr(self, i): - keymap[config.keymap["keymap"][i]] = getattr(self, i) + if config.keymap["keymap"][i] != "": + keymap[config.keymap["keymap"][i]] = getattr(self, i) return keymap def register_invisible_keyboard_shorcuts(self, keymap): From 70c095febe885552affb6d317782a37239b4f0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Wed, 7 Jul 2021 08:41:08 +0200 Subject: [PATCH 121/245] setup.py: patch cx_freeze to include our Microsoft Visual C++ runtime files --- src/setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/setup.py b/src/setup.py index c6043db8..c965c06c 100644 --- a/src/setup.py +++ b/src/setup.py @@ -3,7 +3,7 @@ import sys import application import platform import os -from cx_Freeze import setup, Executable +from cx_Freeze import setup, Executable, winmsvcr from requests import certs def get_architecture_files(): @@ -40,7 +40,7 @@ build_exe_options = dict( build_exe="dist", optimize=1, includes=["enchant.tokenize.en"], # This is not handled automatically by cx_freeze. - include_msvcr=True, + include_msvcr=False, replace_paths = [("*", "")], include_files=["icon.ico", "conf.defaults", "app-configuration.defaults", "keymaps", "locales", "sounds", "documentation", ("keys/lib", "keys/lib"), find_sound_lib_datafiles(), find_accessible_output2_datafiles()]+get_architecture_files(), packages=["wxUI"], @@ -50,6 +50,8 @@ executables = [ Executable('main.py', base=base, targetName="twblue") ] +winmsvcr.FILES = () +winmsvcr.FILES_TO_DUPLICATE = () setup(name=application.name, version=application.version, description=application.description, From e314cf0599c0ca32229a1483a00b7062c1715c3b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 10 Jul 2021 05:24:56 -0500 Subject: [PATCH 122/245] Allow search users by names in autocomplete users --- doc/changelog.md | 2 ++ src/extra/autocompletionUsers/storage.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/changelog.md b/doc/changelog.md index 905e29af..639d32b2 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -3,6 +3,8 @@ ## changes in this version * Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) +* There are some changes to the autocomplete users feature: + * Now users can search for twitter screen names or display names in the database. * Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385)) * Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387)) * Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384)) diff --git a/src/extra/autocompletionUsers/storage.py b/src/extra/autocompletionUsers/storage.py index 0b56781e..4ac80ebf 100644 --- a/src/extra/autocompletionUsers/storage.py +++ b/src/extra/autocompletionUsers/storage.py @@ -21,7 +21,7 @@ class storage(object): return self.cursor.fetchall() def get_users(self, term): - self.cursor.execute("""SELECT * FROM users WHERE user LIKE ?""", ('{}%'.format(term),)) + self.cursor.execute("""SELECT * FROM users WHERE UPPER(user) LIKE :term OR UPPER(name) LIKE :term""", {"term": "%{}%".format(term.upper())}) return self.cursor.fetchall() def set_user(self, screen_name, user_name, from_a_buffer): From ff0fbeafa3fb3b651541f149ca257129e675a8ae Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 13 Jul 2021 17:22:20 -0500 Subject: [PATCH 123/245] Modified keystrokeEditor to allow undefined keystrokes --- doc/changelog.md | 3 ++- src/keystrokeEditor/constants.py | 3 ++- src/keystrokeEditor/keystrokeEditor.py | 15 ++++++++++++--- src/keystrokeEditor/wx_ui.py | 9 +++++++-- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 905e29af..e0b555bd 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,7 +2,8 @@ ## changes in this version -* Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) +* Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. Users are displayed with their display name in people buffers only. This action is supported in all keymaps, although it is undefined by default. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) +* It is possible to undefine keystrokes in the current keymap in TWBlue. This allows you, for example, to redefine keystrokes completely. * Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385)) * Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387)) * Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384)) diff --git a/src/keystrokeEditor/constants.py b/src/keystrokeEditor/constants.py index b14616bc..2d176ac1 100644 --- a/src/keystrokeEditor/constants.py +++ b/src/keystrokeEditor/constants.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals actions = { "up": _(u"Go up in the current buffer"), "down": _(u"Go down in the current buffer"), @@ -57,4 +56,6 @@ actions = { "audio": _(u"Try to play an audio file"), "update_buffer": _(u"Updates the buffer and retrieves possible lost items there."), "ocr_image": _(u"Extracts the text from a picture and displays the result in a dialog."), + "add_alias": _("Adds an alias to an user"), } + \ No newline at end of file diff --git a/src/keystrokeEditor/keystrokeEditor.py b/src/keystrokeEditor/keystrokeEditor.py index 720e1b1b..1af14b23 100644 --- a/src/keystrokeEditor/keystrokeEditor.py +++ b/src/keystrokeEditor/keystrokeEditor.py @@ -1,7 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -from builtins import object import widgetUtils import config from . import wx_ui @@ -18,6 +15,7 @@ class KeystrokeEditor(object): self.hold_map = self.map.copy() self.dialog.put_keystrokes(constants.actions, self.map) widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.edit_keystroke) + widgetUtils.connect_event(self.dialog.undefine, widgetUtils.BUTTON_PRESSED, self.undefine_keystroke) widgetUtils.connect_event(self.dialog.execute, widgetUtils.BUTTON_PRESSED, self.execute_action) self.dialog.get_response() @@ -33,6 +31,17 @@ class KeystrokeEditor(object): self.map[action] = new_keystroke self.dialog.put_keystrokes(constants.actions, self.map) + def undefine_keystroke(self, *args, **kwargs): + action = self.dialog.actions[self.dialog.get_action()] + keystroke = self.map.get(action) + if keystroke == None: + return + answer = self.dialog.undefine_keystroke_confirmation() + if answer == widgetUtils.YES: + self.map[action] = "" + self.changed = True + self.dialog.put_keystrokes(constants.actions, self.map) + def set_keystroke(self, keystroke, dialog): for i in keystroke.split("+"): if hasattr(dialog, i): diff --git a/src/keystrokeEditor/wx_ui.py b/src/keystrokeEditor/wx_ui.py index 51c03e69..ddb2e6a5 100644 --- a/src/keystrokeEditor/wx_ui.py +++ b/src/keystrokeEditor/wx_ui.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals import wx from multiplatform_widgets import widgets from wxUI.dialogs import baseDialog @@ -18,6 +17,7 @@ class keystrokeEditorDialog(baseDialog.BaseWXDialog): firstSizer.Add(self.keys.list, 0, wx.ALL, 5) self.edit = wx.Button(panel, -1, _(u"Edit")) self.edit.SetDefault() + self.undefine = wx.Button(panel, -1, _("Undefine keystroke")) self.execute = wx.Button(panel, -1, _(u"Execute action")) close = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) secondSizer = wx.BoxSizer(wx.HORIZONTAL) @@ -37,13 +37,18 @@ class keystrokeEditorDialog(baseDialog.BaseWXDialog): continue action = actions[i] self.actions.append(i) - keystroke = keystrokes[i] + keystroke = keystrokes.get(i) + if keystroke == "": + keystroke = _("Undefined") self.keys.insert_item(False, *[action, keystroke]) self.keys.select_item(selection) def get_action(self): return self.keys.get_selected() + def undefine_keystroke_confirmation(self): + return wx.MessageDialog(self, _("Are you sure you want to undefine this keystroke?"), _("Undefine keystroke"), wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION).ShowModal() + class editKeystrokeDialog(baseDialog.BaseWXDialog): def __init__(self): super(editKeystrokeDialog, self).__init__(parent=None, id=-1, title=_(u"Editing keystroke")) From 582be54deaa8aa5f393e7a193fec23b669779c37 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 13 Jul 2021 17:25:48 -0500 Subject: [PATCH 124/245] Added add_alias action to keymaps as undefined --- src/keymaps/Chicken Nugget.keymap | 3 ++- src/keymaps/Qwitter.keymap | 3 ++- src/keymaps/Windows 10.keymap | 3 ++- src/keymaps/base.template | 3 ++- src/keymaps/default.keymap | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/keymaps/Chicken Nugget.keymap b/src/keymaps/Chicken Nugget.keymap index c741ba5a..2f1888b0 100644 --- a/src/keymaps/Chicken Nugget.keymap +++ b/src/keymaps/Chicken Nugget.keymap @@ -34,4 +34,5 @@ configuration = string(default="control+win+o") accountConfiguration = string(default="control+win+shift+o") update_buffer = string(default="control+win+shift+u") ocr_image = string(default="win+alt+o") -open_in_browser = string(default="alt+control+win+return") \ No newline at end of file +open_in_browser = string(default="alt+control+win+return") +add_alias=string(default="") \ No newline at end of file diff --git a/src/keymaps/Qwitter.keymap b/src/keymaps/Qwitter.keymap index 21ae6160..e9736a5b 100644 --- a/src/keymaps/Qwitter.keymap +++ b/src/keymaps/Qwitter.keymap @@ -53,4 +53,5 @@ configuration = string(default="control+win+o") accountConfiguration = string(default="control+win+shift+o") update_buffer = string(default="control+win+shift+u") ocr_image = string(default="win+alt+o") -open_in_browser = string(default="alt+control+win+return") \ No newline at end of file +open_in_browser = string(default="alt+control+win+return") +add_alias=string(default="") \ No newline at end of file diff --git a/src/keymaps/Windows 10.keymap b/src/keymaps/Windows 10.keymap index e02e6278..70e79664 100644 --- a/src/keymaps/Windows 10.keymap +++ b/src/keymaps/Windows 10.keymap @@ -54,4 +54,5 @@ configuration = string(default="control+win+alt+o") accountConfiguration = string(default="control+win+shift+o") update_buffer = string(default="control+alt+shift+u") ocr_image = string(default="win+alt+o") -open_in_browser = string(default="alt+control+win+return") \ No newline at end of file +open_in_browser = string(default="alt+control+win+return") +add_alias=string(default="") \ No newline at end of file diff --git a/src/keymaps/base.template b/src/keymaps/base.template index 31784e42..f95ffcc1 100644 --- a/src/keymaps/base.template +++ b/src/keymaps/base.template @@ -55,4 +55,5 @@ list_manager = string(default="control+win+shift+l") configuration = string(default="control+win+o") accountConfiguration = string(default="control+win+shift+o") update_buffer = string(default="control+win+shift+u") -open_in_browser = string(default="alt+control+win+return") \ No newline at end of file +open_in_browser = string(default="alt+control+win+return") +add_alias=string(default="") \ No newline at end of file diff --git a/src/keymaps/default.keymap b/src/keymaps/default.keymap index f4dbb190..fa5157e0 100644 --- a/src/keymaps/default.keymap +++ b/src/keymaps/default.keymap @@ -56,4 +56,5 @@ configuration = string(default="control+win+o") accountConfiguration = string(default="control+win+shift+o") update_buffer = string(default="control+win+shift+u") ocr_image = string(default="win+alt+o") -open_in_browser = string(default="alt+control+win+return") \ No newline at end of file +open_in_browser = string(default="alt+control+win+return") +add_alias=string(default="") \ No newline at end of file From b2b9cd810fa5fd280b881dd85b4315d1dfb0cca3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 13 Jul 2021 17:53:01 -0500 Subject: [PATCH 125/245] Fixed an issue when indefined keystrokes --- src/controller/mainController.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 99f77e28..0db1a6ca 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1272,8 +1272,10 @@ class Controller(object): def register_invisible_keyboard_shorcuts(self, keymap): if config.changed_keymap: commonMessageDialogs.changed_keymap() + # Make sure we pass a keymap without undefined keystrokes. + new_keymap = {key: keymap[key] for key in keymap.keys() if keymap[key] != ""} self.keyboard_handler = WXKeyboardHandler(self.view) - self.keyboard_handler.register_keys(keymap) + self.keyboard_handler.register_keys(new_keymap) def unregister_invisible_keyboard_shorcuts(self, keymap): try: From 24d1ad093d94335d8d18c80838e2ceb90b4b264f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 16 Jul 2021 10:22:51 -0500 Subject: [PATCH 126/245] Streaming API: Ignore retweets if original tweet is present in a buffer --- src/controller/buffers/twitter/base.py | 2 +- src/sessions/twitter/session.py | 8 ++++---- src/sessions/twitter/utils.py | 10 +++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 5d3aca86..b7b535e1 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -237,7 +237,7 @@ class BaseBuffer(base.Buffer): items_db = self.session.db[self.name] self.session.add_users_from_results(items) for i in items: - if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i.id, self.session.db[self.name]) == None: + if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i, self.session.db[self.name]) == None: i = reduce.reduce_tweet(i) i = self.session.check_quoted_status(i) i = self.session.check_long_tweet(i) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index ea0561e2..45089a23 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -51,7 +51,7 @@ class Session(base.baseSession): if i.id < last_id: log.error("Ignoring an older tweet... Last id: {0}, tweet id: {1}".format(last_id, i.id)) continue - if utils.find_item(i.id, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True: + if utils.find_item(i, self.db[name]) == None and utils.is_allowed(i, self.settings, name) == True: if i == False: continue reduced_object = reduce.reduce_tweet(i) reduced_object = self.check_quoted_status(reduced_object) @@ -72,7 +72,7 @@ class Session(base.baseSession): self.db[name] = [] objects = self.db[name] for i in data: - if utils.find_item(i.id, self.db[name]) == None: + if utils.find_item(i, self.db[name]) == None: if self.settings["general"]["reverse_timelines"] == False: objects.append(i) else: objects.insert(0, i) num = num+1 @@ -94,12 +94,12 @@ class Session(base.baseSession): for i in data: # Twitter returns sender_id as str, which must be converted to int in order to match to our user_id object. if int(i.message_create["sender_id"]) == self.db["user_id"]: - if "sent_direct_messages" in self.db and utils.find_item(i.id, self.db["sent_direct_messages"]) == None: + if "sent_direct_messages" in self.db and utils.find_item(i, self.db["sent_direct_messages"]) == None: if self.settings["general"]["reverse_timelines"] == False: sent_objects.append(i) else: sent_objects.insert(0, i) sent = sent+1 else: - if utils.find_item(i.id, self.db["direct_messages"]) == None: + if utils.find_item(i, self.db["direct_messages"]) == None: if self.settings["general"]["reverse_timelines"] == False: objects.append(i) else: objects.insert(0, i) incoming = incoming+1 diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 24d498b4..70ebfb1e 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -60,9 +60,13 @@ def find_urls (tweet, twitter_media=False): urls.append(i) return urls -def find_item(id, listItem): - for i in range(0, len(listItem)): - if listItem[i].id == id: return i +def find_item(item, listItems): + for i in range(0, len(listItems)): + if listItems[i].id == item.id: + return i + # Check also retweets. + if hasattr(item, "retweeted_status") and item.retweeted_status.id == listItems[i].id: + return i return None def find_list(name, lists): From 9c680130f72084552e5a99b6aa7706fc410e5392 Mon Sep 17 00:00:00 2001 From: Jesus Date: Sat, 24 Jul 2021 06:24:08 +0200 Subject: [PATCH 127/245] Keypad para windows 11 --- src/keymaps/Windows11.keymap | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/keymaps/Windows11.keymap diff --git a/src/keymaps/Windows11.keymap b/src/keymaps/Windows11.keymap new file mode 100644 index 00000000..727cb365 --- /dev/null +++ b/src/keymaps/Windows11.keymap @@ -0,0 +1,58 @@ +[info] +name = string(default="Windows 11") +desc = string(default="A keymap with remapped modifiers for Windows 11 compatibility.") +author = string(default="Bill Jesús ") + +[keymap] +up = string(default="control+alt+win+up") +down = string(default="control+alt+win+down") +left = string(default="control+alt+win+left") +right = string(default="control+alt+win+right") +next_account = string(default="control+alt+win+shift+right") +previous_account = string(default="control+alt+win+shift+left") +open_conversation = string(default="control+alt+win+c") +show_hide = string(default="control+win+w") +post_tweet = string(default="alt+win+n") +post_reply = string(default="control+win+r") +post_retweet = string(default="alt+win+shift+r") +send_dm = string(default="alt+win+shift+d") +toggle_like = string(default="control+alt+win+f") +follow = string(default="alt+win+shift+s") +user_details = string(default="alt+win+shift+n") +view_item = string(default="alt+win+v") +exit = string(default="alt+win+f4") +open_timeline = string(default="alt+win+i") +remove_buffer = string(default="alt+win+shift+i") +url = string(default="alt+win+return") +audio = string(default="alt+shift+win+return") +volume_up = string(default="control+alt+win+shift+up") +go_home = string(default="alt+win+home") +volume_down = string(default="control+alt+win+shift+down") +go_end = string(default="alt+win+end") +go_page_up = string(default="control+win+pageup") +go_page_down = string(default="control+win+pagedown") +update_profile = string(default="alt+win+p") +delete = string(default="alt+win+delete") +clear_buffer = string(default="alt+win+shift+delete") +repeat_item = string(default="alt+win+space") +copy_to_clipboard = string(default="alt+win+shift+c") +add_to_list = string(default="alt+win+a") +remove_from_list = string(default="alt+win+shift+a") +toggle_buffer_mute = string(default="alt+win+shift+m") +toggle_session_mute = string(default="control+alt+win+m") +toggle_autoread = string(default="alt+win+e") +search = string(default="alt+win+-") +edit_keystrokes = string(default="alt+win+k") +view_user_lists = string(default="alt+win+l") +get_more_items = string(default="alt+win+pageup") +reverse_geocode = string(default="control+win+g") +view_reverse_geocode = string(default="alt+win+shift+g") +get_trending_topics = string(default="control+win+t") +check_for_updates = string(default="alt+win+u") +list_manager = string(default="alt+win+shift+l") +configuration = string(default="control+win+alt+o") +accountConfiguration = string(default="control+win+shift+o") +update_buffer = string(default="control+alt+shift+u") +ocr_image = string(default="win+alt+o") +open_in_browser = string(default="alt+control+win+return") +add_alias=string(default="") \ No newline at end of file From 54938ecb6c51517e782099c2b9c4b044828d0164 Mon Sep 17 00:00:00 2001 From: Jesus Date: Mon, 26 Jul 2021 12:47:51 +0200 Subject: [PATCH 128/245] Fixed shortkuts --- src/keymaps/Windows11.keymap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keymaps/Windows11.keymap b/src/keymaps/Windows11.keymap index 727cb365..22f7ab0c 100644 --- a/src/keymaps/Windows11.keymap +++ b/src/keymaps/Windows11.keymap @@ -26,9 +26,9 @@ remove_buffer = string(default="alt+win+shift+i") url = string(default="alt+win+return") audio = string(default="alt+shift+win+return") volume_up = string(default="control+alt+win+shift+up") -go_home = string(default="alt+win+home") +go_home = string(default="control+alt+win+home") volume_down = string(default="control+alt+win+shift+down") -go_end = string(default="alt+win+end") +go_end = string(default="control+alt+win+end") go_page_up = string(default="control+win+pageup") go_page_down = string(default="control+win+pagedown") update_profile = string(default="alt+win+p") From 576b5064c01bca1eddd499439d3cb294ba0c0857 Mon Sep 17 00:00:00 2001 From: Jesus Date: Wed, 28 Jul 2021 07:23:57 +0200 Subject: [PATCH 129/245] Added a fix. --- src/keymaps/Windows11.keymap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keymaps/Windows11.keymap b/src/keymaps/Windows11.keymap index 22f7ab0c..57ca311e 100644 --- a/src/keymaps/Windows11.keymap +++ b/src/keymaps/Windows11.keymap @@ -34,7 +34,7 @@ go_page_down = string(default="control+win+pagedown") update_profile = string(default="alt+win+p") delete = string(default="alt+win+delete") clear_buffer = string(default="alt+win+shift+delete") -repeat_item = string(default="alt+win+space") +repeat_item = string(default="control+alt+win+space") copy_to_clipboard = string(default="alt+win+shift+c") add_to_list = string(default="alt+win+a") remove_from_list = string(default="alt+win+shift+a") From 9ea36a26d2601c21bad100e55234fcc96381b037 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 31 Jul 2021 22:33:32 -0500 Subject: [PATCH 130/245] Updated changelog with windows 11 keymap --- doc/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.md b/doc/changelog.md index 6ba375ad..f02f8e66 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Added a keymap capable to work under Windows 11. ([#391](https://github.com/manuelcortez/TWBlue/pull/391)) * Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. Users are displayed with their display name in people buffers only. This action is supported in all keymaps, although it is undefined by default. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) * There are some changes to the autocomplete users feature: * Now users can search for twitter screen names or display names in the database. From ddc80a29fdf90dd84d4590b8137ec070c86bd2e2 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Mon, 2 Aug 2021 19:30:24 +0200 Subject: [PATCH 131/245] Update french interface translation --- src/locales/fr/LC_MESSAGES/twblue.po | 1660 ++++++++++++++------------ 1 file changed, 882 insertions(+), 778 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index aaa1ea81..6b900577 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -1,201 +1,200 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" -"PO-Revision-Date: 2020-06-04 21:19+0200\n" +"POT-Creation-Date: 2021-08-02 19:18+Paris, Madrid (heure d’été)\n" +"PO-Revision-Date: 2021-08-02 19:29+0200\n" "Last-Translator: Corentin BACQUÉ-CAZENAVE \n" "Language-Team: Oreonan \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.3.1\n" +"X-Generator: Poedit 3.0\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop\n" "X-Poedit-Basepath: .\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Bookmarks: -1,-1,-1,-1,-1,384,-1,-1,-1,-1\n" -#: ../src\controller\attach.py:23 +#: ../src\controller\attach.py:25 msgid "Photo" msgstr "Photo" -#: ../src\controller\buffers\baseBuffers.py:95 +#: ../src\controller\buffers\base\base.py:91 msgid "This action is not supported for this buffer" msgstr "Cette action n'est pas supportée pour ce tampon" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:310 ../src\controller\settings.py:286 msgid "Home" msgstr "Accueil" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:314 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Mentions" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:318 msgid "Direct messages" msgstr "Messages privés" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:322 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Messages privés envoyés" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:326 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Tweets envoyés" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:330 +#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:291 msgid "Likes" msgstr "Favoris" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:334 +#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:292 msgid "Followers" msgstr "Abonnés" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:338 +#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:293 msgid "Friends" msgstr "Abonnements" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:342 +#: ../src\controller\mainController.py:1415 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Utilisateurs bloqués" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:346 +#: ../src\controller\mainController.py:1420 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Utilisateurs masqués" -#: ../src\controller\buffers\twitterBuffers.py:75 +#: ../src\controller\buffers\twitter\base.py:76 msgid "{username}'s timeline" msgstr "Chronologie de {username}" -#: ../src\controller\buffers\twitterBuffers.py:77 +#: ../src\controller\buffers\twitter\base.py:78 msgid "{username}'s likes" msgstr "Favoris de {username}" -#: ../src\controller\buffers\twitterBuffers.py:79 +#: ../src\controller\buffers\twitter\base.py:80 msgid "{username}'s followers" msgstr "Abonnés de {username}" -#: ../src\controller\buffers\twitterBuffers.py:81 +#: ../src\controller\buffers\twitter\base.py:82 msgid "{username}'s friends" msgstr "Abonnements de {username}" -#: ../src\controller\buffers\twitterBuffers.py:83 +#: ../src\controller\buffers\twitter\base.py:84 msgid "Unknown buffer" msgstr "Tampon inconnu" -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:121 +#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\dialogs\message.py:306 ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "Tweet" -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 +#: ../src\controller\buffers\twitter\base.py:89 +#: ../src\controller\buffers\twitter\trends.py:122 msgid "Write the tweet here" msgstr "Écrivez le tweet ici" -#: ../src\controller\buffers\twitterBuffers.py:194 +#: ../src\controller\buffers\twitter\base.py:219 msgid "New tweet in {0}" msgstr "Nouveau tweet dans {0}" -#: ../src\controller\buffers\twitterBuffers.py:197 +#: ../src\controller\buffers\twitter\base.py:222 msgid "{0} new tweets in {1}." msgstr "{0} nouveau tweet dans {1}" -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 +#: ../src\controller\buffers\twitter\base.py:261 +#: ../src\controller\buffers\twitter\directMessages.py:87 +#: ../src\controller\buffers\twitter\people.py:180 msgid "%s items retrieved" msgstr "%s éléments récupérés" -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 +#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\people.py:80 msgid "This buffer is not a timeline; it can't be deleted." msgstr "Ce tampon n'est pas une chronologie ; Impossible de le supprimé." -#: ../src\controller\buffers\twitterBuffers.py:402 +#: ../src\controller\buffers\twitter\base.py:430 msgid "Reply to {arg0}" msgstr "Répondre à {arg0}" -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 +#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 msgid "Reply" msgstr "Répondre" -#: ../src\controller\buffers\twitterBuffers.py:405 +#: ../src\controller\buffers\twitter\base.py:433 msgid "Reply to %s" msgstr "Répondre à %s" -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Message privé à %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\buffers\twitter\directMessages.py:129 msgid "New direct message" msgstr "Nouveau message privé" -#: ../src\controller\buffers\twitterBuffers.py:500 +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\messages.py:200 +msgid "Direct message to %s" +msgstr "Message privé à %s" + +#: ../src\controller\buffers\twitter\base.py:520 msgid "Add your comment to the tweet" msgstr "Ajoutez votre commentaire pour le tweet" -#: ../src\controller\buffers\twitterBuffers.py:500 +#: ../src\controller\buffers\twitter\base.py:520 msgid "Quote" msgstr "Citer" -#: ../src\controller\buffers\twitterBuffers.py:572 +#: ../src\controller\buffers\twitter\base.py:596 msgid "Opening URL..." msgstr "Ouverture de l'URL..." -#: ../src\controller\buffers\twitterBuffers.py:607 +#: ../src\controller\buffers\twitter\base.py:633 msgid "User details" msgstr "Détails de l'utilisateur" -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 +#: ../src\controller\buffers\twitter\base.py:649 +#: ../src\controller\buffers\twitter\people.py:257 msgid "Opening item in web browser..." msgstr "Ouverture de l'élément dans le navigateur Web..." -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 +#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\people.py:95 msgid "Mention to %s" msgstr "Mention pour %s" -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 +#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\people.py:95 +#: ../src\wxUI\buffers\people.py:17 msgid "Mention" msgstr "Mention" -#: ../src\controller\buffers\twitterBuffers.py:728 +#: ../src\controller\buffers\twitter\directMessages.py:132 msgid "{0} new direct messages." msgstr "{0} nouveau message privé" -#: ../src\controller\buffers\twitterBuffers.py:731 +#: ../src\controller\buffers\twitter\directMessages.py:135 msgid "This action is not supported in the buffer yet." msgstr "Cette action n'est pas supportée dans le tampon actuel" -#: ../src\controller\buffers\twitterBuffers.py:741 +#: ../src\controller\buffers\twitter\directMessages.py:145 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -203,87 +202,87 @@ msgstr "" "Récupérer plus d'élément est impossible dans ce tampon, utilisez le tampon " "des messages privés à la place." -#: ../src\controller\buffers\twitterBuffers.py:983 +#: ../src\controller\buffers\twitter\people.py:253 msgid "{0} new followers." msgstr "{0} nouvel abonné" -#: ../src\controller\buffers\twitterBuffers.py:1266 +#: ../src\controller\buffers\twitter\trends.py:145 msgid "This action is not supported in the buffer, yet." msgstr "Cette action n'est pas supportée pour le tampon actuel" -#: ../src\controller\mainController.py:273 +#: ../src\controller\mainController.py:274 msgid "Ready" msgstr "Prêt" -#: ../src\controller\mainController.py:345 +#: ../src\controller\mainController.py:349 msgid "Timelines" msgstr "Chronologies" -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 +#: ../src\controller\mainController.py:353 +#: ../src\controller\mainController.py:890 +#: ../src\controller\mainController.py:1596 msgid "Timeline for {}" msgstr "Chronologie de {}" -#: ../src\controller\mainController.py:352 +#: ../src\controller\mainController.py:356 msgid "Likes timelines" msgstr "Chronologies des favoris" -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 +#: ../src\controller\mainController.py:360 +#: ../src\controller\mainController.py:909 +#: ../src\controller\mainController.py:1598 msgid "Likes for {}" msgstr "Favoris de {}" -#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:363 msgid "Followers' Timelines" msgstr "Chronologies des abonnés" -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 +#: ../src\controller\mainController.py:367 +#: ../src\controller\mainController.py:928 +#: ../src\controller\mainController.py:1600 msgid "Followers for {}" msgstr "Abonnés de {}" -#: ../src\controller\mainController.py:366 +#: ../src\controller\mainController.py:370 msgid "Friends' Timelines" msgstr "Chronologies des abonnements" -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 +#: ../src\controller\mainController.py:374 +#: ../src\controller\mainController.py:947 +#: ../src\controller\mainController.py:1602 msgid "Friends for {}" msgstr "Abonnements de {}" -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 +#: ../src\controller\mainController.py:377 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Listes" -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 +#: ../src\controller\mainController.py:382 +#: ../src\controller\mainController.py:1432 msgid "List for {}" msgstr "Liste {}" -#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:385 msgid "Searches" msgstr "Recherches" -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 +#: ../src\controller\mainController.py:389 +#: ../src\controller\mainController.py:448 msgid "Search for {}" msgstr "Recherche de {}" -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 +#: ../src\controller\mainController.py:395 +#: ../src\controller\mainController.py:989 msgid "Trending topics for %s" msgstr "Tendances pour %s" -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 +#: ../src\controller\mainController.py:465 +#: ../src\controller\mainController.py:481 +#: ../src\controller\mainController.py:1089 +#: ../src\controller\mainController.py:1108 +#: ../src\controller\mainController.py:1127 +#: ../src\controller\mainController.py:1146 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." @@ -291,238 +290,259 @@ msgstr "" "Aucune session n'a actuellement le focus. Sélectionnez-en une avec le " "raccourci pour la session précédente ou suivante." -#: ../src\controller\mainController.py:465 +#: ../src\controller\mainController.py:469 msgid "Empty buffer." msgstr "Tampon vide." -#: ../src\controller\mainController.py:472 +#: ../src\controller\mainController.py:476 msgid "{0} not found." msgstr "{0} introuvable." -#: ../src\controller\mainController.py:482 +#: ../src\controller\mainController.py:486 msgid "Filters cannot be applied on this buffer" msgstr "Les filtres ne peuvent pas s'appliquer à ce tampon" -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 +#: ../src\controller\mainController.py:539 +#: ../src\controller\mainController.py:556 +#: ../src\controller\mainController.py:584 msgid "Select the user" msgstr "Sélectionnez l'utilisateur" -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 +#: ../src\controller\mainController.py:768 +msgid "Add an user alias" +msgstr "Ajoute un alis pour l'utilisateur" + +#: ../src\controller\mainController.py:776 +msgid "Alias has been set correctly for {}." +msgstr "L'alias pour {} a correctement été définie" + +#: ../src\controller\mainController.py:839 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "D MMM YYYY à H:m" -#: ../src\controller\mainController.py:934 +#: ../src\controller\mainController.py:964 msgid "Conversation with {0}" msgstr "Conversation avec {0}" -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 +#: ../src\controller\mainController.py:1005 +#: ../src\controller\mainController.py:1024 msgid "There are no coordinates in this tweet" msgstr "Il n'y a aucune coordonnée dans ce tweet" -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 +#: ../src\controller\mainController.py:1007 +#: ../src\controller\mainController.py:1026 msgid "There are no results for the coordinates in this tweet" msgstr "Il n'y a aucun résultat pour les coordonnées dans ce tweet" -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1009 +#: ../src\controller\mainController.py:1028 msgid "Error decoding coordinates. Try again later." msgstr "Erreur pendant le décodage des coordonnées. Réessayez plus tard." -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 +#: ../src\controller\mainController.py:1137 +#: ../src\controller\mainController.py:1156 msgid "%s, %s of %s" msgstr "%s, %s de %s" -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 +#: ../src\controller\mainController.py:1139 +#: ../src\controller\mainController.py:1158 +#: ../src\controller\mainController.py:1183 +#: ../src\controller\mainController.py:1208 msgid "%s. Empty" msgstr "%s. Vide" -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1171 +#: ../src\controller\mainController.py:1175 +#: ../src\controller\mainController.py:1196 msgid "{0}: This account is not logged into Twitter." msgstr "{0}: Ce compte n'est pas connecté à twitter." -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 +#: ../src\controller\mainController.py:1181 +#: ../src\controller\mainController.py:1206 msgid "%s. %s, %s of %s" msgstr "%s. %s, %s de %s" -#: ../src\controller\mainController.py:1170 +#: ../src\controller\mainController.py:1200 msgid "{0}: This account is not logged into twitter." msgstr "{0}: Ce compte n'est pas connecté à twitter." -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Événements" - -#: ../src\controller\mainController.py:1393 +#: ../src\controller\mainController.py:1426 msgid "This list is already opened" msgstr "Cette liste est déjà ouverte" -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 +#: ../src\controller\mainController.py:1456 +#: ../src\controller\mainController.py:1472 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" "Une erreur s'est produite en essayant de se connecter au serveur. Veuillez " "réessayer plus tard." -#: ../src\controller\mainController.py:1475 +#: ../src\controller\mainController.py:1508 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "La lecture automatique des nouveaux tweets est activée pour ce tampon" -#: ../src\controller\mainController.py:1478 +#: ../src\controller\mainController.py:1511 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "" "La lecture automatique des nouveaux tweets est désactivée pour ce tampon" -#: ../src\controller\mainController.py:1485 +#: ../src\controller\mainController.py:1518 msgid "Session mute on" msgstr "Session muet" -#: ../src\controller\mainController.py:1488 +#: ../src\controller\mainController.py:1521 msgid "Session mute off" msgstr "Session non muet" -#: ../src\controller\mainController.py:1496 +#: ../src\controller\mainController.py:1529 msgid "Buffer mute on" msgstr "Tampon muet" -#: ../src\controller\mainController.py:1499 +#: ../src\controller\mainController.py:1532 msgid "Buffer mute off" msgstr "Tampon non muet" -#: ../src\controller\mainController.py:1522 +#: ../src\controller\mainController.py:1555 msgid "Copied" msgstr "Copié" -#: ../src\controller\mainController.py:1549 +#: ../src\controller\mainController.py:1586 msgid "Unable to update this buffer." msgstr "Impossible de mettre à jour ce tampon." -#: ../src\controller\mainController.py:1552 +#: ../src\controller\mainController.py:1589 msgid "Updating buffer..." msgstr "Actualisation..." -#: ../src\controller\mainController.py:1555 +#: ../src\controller\mainController.py:1592 msgid "{0} items retrieved" msgstr "{0} éléments récupérés" -#: ../src\controller\mainController.py:1572 +#: ../src\controller\mainController.py:1609 +#: ../src\controller\mainController.py:1629 msgid "Invalid buffer" msgstr "Tampon invalide" -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "Ce tweet ne contient pas d'images" - -#: ../src\controller\mainController.py:1579 +#: ../src\controller\mainController.py:1620 msgid "Picture {0}" msgstr "Photo {0}" -#: ../src\controller\mainController.py:1580 +#: ../src\controller\mainController.py:1621 msgid "Select the picture" msgstr "Sélectionner la photo" -#: ../src\controller\mainController.py:1596 +#: ../src\controller\mainController.py:1640 msgid "Unable to extract text" msgstr "Impossible d'extraire le texte" -#: ../src\controller\messages.py:54 +#: ../src\controller\messages.py:56 msgid "Translated" msgstr "Traduit" -#: ../src\controller\messages.py:61 +#: ../src\controller\messages.py:63 msgid "There's no URL to be shortened" msgstr "Aucune URL à réduire" -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 +#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 msgid "URL shortened" msgstr "URL réduite" -#: ../src\controller\messages.py:80 +#: ../src\controller\messages.py:82 msgid "There's no URL to be expanded" msgstr "Aucune URL à élargir" -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 +#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 msgid "URL expanded" msgstr "URL élargi" -#: ../src\controller\messages.py:104 +#: ../src\controller\messages.py:108 msgid "%s - %s of %d characters" msgstr "%s - %s/%d caractères" -#: ../src\controller\messages.py:108 +#: ../src\controller\messages.py:112 msgid "%s - %s characters" msgstr "%s - %s caractères" -#: ../src\controller\messages.py:262 +#: ../src\controller\messages.py:272 msgid "View item" msgstr "Voir l'élément" -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Connexion directe" +#: ../src\controller\settings.py:74 +msgid "HTTP" +msgstr "HTTP" -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:74 +msgid "SOCKS v4" +msgstr "SOCKS v4" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4 with DNS support" +msgstr "SOCKS v4 avec support DNS" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5" +msgstr "SOCKS v5" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5 with DNS support" +msgstr "SOCKS v5 avec support DNS" + +#: ../src\controller\settings.py:74 +msgid "System default" +msgstr "Système par défaut" + +#: ../src\controller\settings.py:145 ../src\controller\settings.py:211 +#: ../src\wxUI\dialogs\configuration.py:116 msgid "Ask" msgstr "Demander" -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:147 ../src\controller\settings.py:213 +#: ../src\wxUI\dialogs\configuration.py:116 msgid "Retweet without comments" msgstr "Retweet sans commentaires" -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:116 msgid "Retweet with comments" msgstr "Retweet avec commentaires" -#: ../src\controller\settings.py:184 +#: ../src\controller\settings.py:185 msgid "Account settings for %s" msgstr "Paramètres du compte de %s" -#: ../src\controller\settings.py:284 +#: ../src\controller\settings.py:288 msgid "Direct Messages" msgstr "Messages privés" -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 +#: ../src\controller\user.py:29 ../src\controller\user.py:31 +#: ../src\extra\SpellChecker\wx_ui.py:80 ../src\issueReporter\wx_ui.py:84 +#: ../src\issueReporter\wx_ui.py:87 ../src\wxUI\commonMessageDialogs.py:39 +#: ../src\wxUI\commonMessageDialogs.py:51 +#: ../src\wxUI\commonMessageDialogs.py:58 +#: ../src\wxUI\commonMessageDialogs.py:61 +#: ../src\wxUI\commonMessageDialogs.py:64 +#: ../src\wxUI\commonMessageDialogs.py:67 +#: ../src\wxUI\commonMessageDialogs.py:77 +#: ../src\wxUI\commonMessageDialogs.py:80 +#: ../src\wxUI\commonMessageDialogs.py:83 +#: ../src\wxUI\commonMessageDialogs.py:89 +#: ../src\wxUI\commonMessageDialogs.py:92 msgid "Error" msgstr "Erreur" -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 +#: ../src\controller\user.py:29 ../src\wxUI\commonMessageDialogs.py:39 msgid "That user does not exist" msgstr "Cet utilisateur n'existe pas" -#: ../src\controller\user.py:30 +#: ../src\controller\user.py:31 msgid "User has been suspended" msgstr "L'utilisateur a été suspendu" -#: ../src\controller\user.py:36 +#: ../src\controller\user.py:37 msgid "Information for %s" msgstr "Détails de %s" -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 +#: ../src\controller\user.py:67 ../src\extra\AudioUploader\audioUploader.py:127 msgid "Discarded" msgstr "Ignoré" @@ -542,31 +562,31 @@ msgstr "Localisation: %s\n" msgid "URL: %s\n" msgstr "Site Web: %s\n" -#: ../src\controller\user.py:102 +#: ../src\controller\user.py:104 msgid "Bio: %s\n" msgstr "Biographie: %s\n" -#: ../src\controller\user.py:103 ../src\controller\user.py:118 +#: ../src\controller\user.py:105 ../src\controller\user.py:120 msgid "Yes" msgstr "Oui" -#: ../src\controller\user.py:104 ../src\controller\user.py:119 +#: ../src\controller\user.py:106 ../src\controller\user.py:121 msgid "No" msgstr "Non" -#: ../src\controller\user.py:105 +#: ../src\controller\user.py:107 msgid "Protected: %s\n" msgstr "Protégé: %s\n" -#: ../src\controller\user.py:110 +#: ../src\controller\user.py:112 msgid "You follow {0}. " msgstr "Vous suivez {0}. " -#: ../src\controller\user.py:113 +#: ../src\controller\user.py:115 msgid "{0} is following you." msgstr "{0} vous suit." -#: ../src\controller\user.py:117 +#: ../src\controller\user.py:119 msgid "" "Followers: %s\n" " Friends: %s\n" @@ -574,311 +594,311 @@ msgstr "" "Abonnés: %s\n" " Abonnements: %s\n" -#: ../src\controller\user.py:120 +#: ../src\controller\user.py:122 msgid "Verified: %s\n" msgstr "Vérifié : %s\n" -#: ../src\controller\user.py:121 +#: ../src\controller\user.py:123 msgid "Tweets: %s\n" msgstr "Tweets: %s\n" -#: ../src\controller\user.py:122 +#: ../src\controller\user.py:124 msgid "Likes: %s" msgstr "Favoris: %s" -#: ../src\controller\userActionsController.py:75 +#: ../src\controller\userActionsController.py:74 msgid "You can't ignore direct messages" msgstr "Vous ne pouvez pas ignorer les messages privés" -#: ../src\extra\AudioUploader\audioUploader.py:54 +#: ../src\extra\AudioUploader\audioUploader.py:57 msgid "Attaching..." msgstr "Ajout en cours..." -#: ../src\extra\AudioUploader\audioUploader.py:71 +#: ../src\extra\AudioUploader\audioUploader.py:74 msgid "Pause" msgstr "Pause" -#: ../src\extra\AudioUploader\audioUploader.py:73 +#: ../src\extra\AudioUploader\audioUploader.py:76 msgid "&Resume" msgstr "&Reprendre" -#: ../src\extra\AudioUploader\audioUploader.py:74 +#: ../src\extra\AudioUploader\audioUploader.py:77 msgid "Resume" msgstr "Reprendre" -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 +#: ../src\extra\AudioUploader\audioUploader.py:79 +#: ../src\extra\AudioUploader\audioUploader.py:106 +#: ../src\extra\AudioUploader\wx_ui.py:37 msgid "&Pause" msgstr "&Pause" -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 +#: ../src\extra\AudioUploader\audioUploader.py:94 +#: ../src\extra\AudioUploader\audioUploader.py:140 msgid "&Stop" msgstr "&Arrêter" -#: ../src\extra\AudioUploader\audioUploader.py:92 +#: ../src\extra\AudioUploader\audioUploader.py:95 msgid "Recording" msgstr "Enregistrement en cours" -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 +#: ../src\extra\AudioUploader\audioUploader.py:100 +#: ../src\extra\AudioUploader\audioUploader.py:151 msgid "Stopped" msgstr "Arrêté" -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 +#: ../src\extra\AudioUploader\audioUploader.py:102 +#: ../src\extra\AudioUploader\wx_ui.py:39 msgid "&Record" msgstr "&Enregistrer" -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:146 msgid "Playing..." msgstr "Lecture..." -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 +#: ../src\extra\AudioUploader\audioUploader.py:144 +#: ../src\extra\AudioUploader\audioUploader.py:154 +#: ../src\extra\AudioUploader\wx_ui.py:35 msgid "&Play" msgstr "&Lire" -#: ../src\extra\AudioUploader\audioUploader.py:156 +#: ../src\extra\AudioUploader\audioUploader.py:159 msgid "Recoding audio..." msgstr "Recodage audio..." -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 +#: ../src\extra\AudioUploader\transfer.py:82 +#: ../src\extra\AudioUploader\transfer.py:88 msgid "Error in file upload: {0}" msgstr "Erreur lors du chargement du fichier: {0}" -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 +#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 msgid "%d day, " msgstr "%d jour, " -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 +#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 msgid "%d days, " msgstr "%d jours, " -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 +#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 msgid "%d hour, " msgstr "%d heure, " -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 +#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 msgid "%d hours, " msgstr "%d heures, " -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 +#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 msgid "%d minute, " msgstr "%d minute, " -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 +#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 msgid "%d minutes, " msgstr "%d minutes, " -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 +#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 msgid "%s second" msgstr "%s seconde" -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 +#: ../src\extra\AudioUploader\utils.py:43 ../src\update\utils.py:43 msgid "%s seconds" msgstr "%s secondes" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 msgid "File" msgstr "Fichier" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:21 msgid "Transferred" msgstr "Transféré" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:26 msgid "Total file size" msgstr "Taille totale du fichier" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:31 msgid "Transfer rate" msgstr "Vitesse du transfert" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:36 msgid "Time left" msgstr "Temps restant" -#: ../src\extra\AudioUploader\wx_ui.py:28 +#: ../src\extra\AudioUploader\wx_ui.py:29 msgid "Attach audio" msgstr "Joindre un audio" -#: ../src\extra\AudioUploader\wx_ui.py:40 +#: ../src\extra\AudioUploader\wx_ui.py:41 msgid "&Add an existing file" msgstr "&Ajouter un fichier existant" -#: ../src\extra\AudioUploader\wx_ui.py:41 +#: ../src\extra\AudioUploader\wx_ui.py:42 msgid "&Discard" msgstr "&Ignorer" -#: ../src\extra\AudioUploader\wx_ui.py:43 +#: ../src\extra\AudioUploader\wx_ui.py:44 msgid "Upload to" msgstr "Charger" -#: ../src\extra\AudioUploader\wx_ui.py:48 +#: ../src\extra\AudioUploader\wx_ui.py:49 msgid "Attach" msgstr "Joindre " -#: ../src\extra\AudioUploader\wx_ui.py:50 +#: ../src\extra\AudioUploader\wx_ui.py:51 msgid "&Cancel" msgstr "&Annuler" -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: ../src\extra\AudioUploader\wx_ui.py:76 msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" msgstr "Fichiers audio (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: ../src\extra\AudioUploader\wx_ui.py:76 msgid "Select the audio file to be uploaded" msgstr "Sélectionnez le fichier audio que vous souhaitez charger" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 msgid "Audio tweet." msgstr "Tweet audio." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 msgid "User timeline buffer created." msgstr "Tampon de chronologie utilisateur créé." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 msgid "Buffer destroied." msgstr "Tampon détruit." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 msgid "Direct message received." msgstr "Message privé reçu." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 msgid "Direct message sent." msgstr "Message privé envoyé." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 msgid "Error." msgstr "Erreur." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 msgid "Tweet liked." msgstr "Tweet aimé." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 msgid "Likes buffer updated." msgstr "Tampon des favoris mis à jour." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 msgid "Geotweet." msgstr "Tweet avec localisation géographique." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 msgid "Tweet contains one or more images" msgstr "Ce tweet contient une ou plusieurs images" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 msgid "Boundary reached." msgstr "Limite atteinte." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 msgid "List updated." msgstr "Liste mise à jour." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 msgid "Too many characters." msgstr "Trop de caractères." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 msgid "Mention received." msgstr "Mention reçue." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 msgid "New event." msgstr "Nouvel événement." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 msgid "{0} is ready." msgstr "{0} est prêt." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 msgid "Mention sent." msgstr "Mention envoyée." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 msgid "Tweet retweeted." msgstr "Tweet retweeté." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 msgid "Search buffer updated." msgstr "Tampon de recherche mis à jour." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 msgid "Tweet received." msgstr "Tweet reçu." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 msgid "Tweet sent." msgstr "Tweet envoyé." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 msgid "Trending topics buffer updated." msgstr "Tampon de tendances mis à jour." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 msgid "New tweet in user timeline buffer." msgstr "Nouveau tweet dans un tampon de chronologie utilisateur." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 msgid "New follower." msgstr "Nouvel abonné." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:31 msgid "Volume changed." msgstr "Volume changé." -#: ../src\extra\SoundsTutorial\wx_ui.py:8 +#: ../src\extra\SoundsTutorial\wx_ui.py:9 msgid "Sounds tutorial" msgstr "Apprentissage des sons" -#: ../src\extra\SoundsTutorial\wx_ui.py:11 +#: ../src\extra\SoundsTutorial\wx_ui.py:12 msgid "Press enter to listen to the sound for the selected event" msgstr "Pressez sur entrée pour entendre le son lié à l'événement sélectionné" -#: ../src\extra\SpellChecker\spellchecker.py:57 +#: ../src\extra\SpellChecker\spellchecker.py:60 msgid "Misspelled word: %s" msgstr "Mot mal orthographié: %s" -#: ../src\extra\SpellChecker\wx_ui.py:27 +#: ../src\extra\SpellChecker\wx_ui.py:28 msgid "Misspelled word" msgstr "Mot mal orthographié" -#: ../src\extra\SpellChecker\wx_ui.py:32 +#: ../src\extra\SpellChecker\wx_ui.py:33 msgid "Context" msgstr "Contexte" -#: ../src\extra\SpellChecker\wx_ui.py:37 +#: ../src\extra\SpellChecker\wx_ui.py:38 msgid "Suggestions" msgstr "Suggestions" -#: ../src\extra\SpellChecker\wx_ui.py:42 +#: ../src\extra\SpellChecker\wx_ui.py:43 msgid "&Ignore" msgstr "&Ignorer" -#: ../src\extra\SpellChecker\wx_ui.py:43 +#: ../src\extra\SpellChecker\wx_ui.py:44 msgid "I&gnore all" msgstr "I&gnorer tout" -#: ../src\extra\SpellChecker\wx_ui.py:44 +#: ../src\extra\SpellChecker\wx_ui.py:45 msgid "&Replace" msgstr "&Remplacer" -#: ../src\extra\SpellChecker\wx_ui.py:45 +#: ../src\extra\SpellChecker\wx_ui.py:46 msgid "R&eplace all" msgstr "R&emplacer tout" -#: ../src\extra\SpellChecker\wx_ui.py:46 +#: ../src\extra\SpellChecker\wx_ui.py:47 msgid "&Add to personal dictionary" msgstr "&Ajouter au dictionnaire personnel" -#: ../src\extra\SpellChecker\wx_ui.py:79 +#: ../src\extra\SpellChecker\wx_ui.py:80 msgid "" "An error has occurred. There are no dictionaries available for the selected " "language in {0}" @@ -886,25 +906,25 @@ msgstr "" "Une erreur s'est produite. Il n'existe aucun dictionnaires disponibles pour " "la langue sélectionnée dans {0}" -#: ../src\extra\SpellChecker\wx_ui.py:82 +#: ../src\extra\SpellChecker\wx_ui.py:83 msgid "Spell check complete." msgstr "Vérification orthographique terminée." -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 +#: ../src\extra\autocompletionUsers\completion.py:20 +#: ../src\extra\autocompletionUsers\completion.py:38 msgid "You have to start writing" msgstr "Vous devez commencer à écrire" -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 +#: ../src\extra\autocompletionUsers\completion.py:30 +#: ../src\extra\autocompletionUsers\completion.py:47 msgid "There are no results in your users database" msgstr "Il n'y a aucun résultat dans votre base de données des utilisateurs" -#: ../src\extra\autocompletionUsers\completion.py:33 +#: ../src\extra\autocompletionUsers\completion.py:32 msgid "Autocompletion only works for users." msgstr "La saisie automatique fonctionne uniquement pour les utilisateurs." -#: ../src\extra\autocompletionUsers\settings.py:27 +#: ../src\extra\autocompletionUsers\settings.py:25 msgid "" "Updating database... You can close this window now. A message will tell you " "when the process finishes." @@ -913,45 +933,45 @@ msgstr "" "fenêtre maintenant. Un message vous avertira lorsque le processus est " "terminé." -#: ../src\extra\autocompletionUsers\wx_manage.py:8 +#: ../src\extra\autocompletionUsers\wx_manage.py:9 msgid "Manage Autocompletion database" msgstr "Gérer la base de données pour la saisie automatique" -#: ../src\extra\autocompletionUsers\wx_manage.py:11 +#: ../src\extra\autocompletionUsers\wx_manage.py:12 msgid "Editing {0} users database" msgstr "Modification de la base de données des utilisateurs de {0}" -#: ../src\extra\autocompletionUsers\wx_manage.py:12 +#: ../src\extra\autocompletionUsers\wx_manage.py:13 msgid "Username" msgstr "Nom d'utilisateur" -#: ../src\extra\autocompletionUsers\wx_manage.py:12 +#: ../src\extra\autocompletionUsers\wx_manage.py:13 #: ../src\wxUI\dialogs\configuration.py:144 msgid "Name" msgstr "Nom" -#: ../src\extra\autocompletionUsers\wx_manage.py:15 +#: ../src\extra\autocompletionUsers\wx_manage.py:16 msgid "Add user" msgstr "Ajouter l'utilisateur" -#: ../src\extra\autocompletionUsers\wx_manage.py:16 +#: ../src\extra\autocompletionUsers\wx_manage.py:17 msgid "Remove user" msgstr "Supprimer l'utilisateur" -#: ../src\extra\autocompletionUsers\wx_manage.py:37 +#: ../src\extra\autocompletionUsers\wx_manage.py:38 msgid "Add user to database" msgstr "Ajouter l'utilisateur à la base de données" -#: ../src\extra\autocompletionUsers\wx_manage.py:37 +#: ../src\extra\autocompletionUsers\wx_manage.py:38 msgid "Twitter username" msgstr "Nom d'utilisateur de Twitter" -#: ../src\extra\autocompletionUsers\wx_manage.py:43 +#: ../src\extra\autocompletionUsers\wx_manage.py:44 msgid "The user does not exist" msgstr "Cet utilisateur n'existe pas sur Twitter" -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 +#: ../src\extra\autocompletionUsers\wx_manage.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "Error!" msgstr "Erreur !" @@ -979,449 +999,449 @@ msgstr "Terminé" msgid "{0}'s database of users has been updated." msgstr "La base de données des utilisateurs de {0} a été mis à jour." -#: ../src\extra\ocr\OCRSpace.py:5 +#: ../src\extra\ocr\OCRSpace.py:7 msgid "Detect automatically" msgstr "Détecter automatiquement" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:41 msgid "Danish" msgstr "Danois" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:43 msgid "Dutch" msgstr "Néerlandais" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:44 msgid "English" msgstr "Anglais" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:48 msgid "Finnish" msgstr "Finnois" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:49 msgid "French" msgstr "Français" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:52 msgid "German" msgstr "Allemand" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:58 msgid "Hungarian" msgstr "Hongrois" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:63 msgid "Italian" msgstr "Italien" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:64 msgid "Japanese" msgstr "Japonais" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:68 msgid "Korean" msgstr "Coréen" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:85 msgid "Polish" msgstr "Polonais" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:86 msgid "Portuguese" msgstr "Portugais" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:89 msgid "Russian" msgstr "Russe" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:96 msgid "Spanish" msgstr "Espagnol" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:105 msgid "Turkish" msgstr "Turc" -#: ../src\extra\translator\translator.py:12 +#: ../src\extra\translator\translator.py:22 msgid "Afrikaans" msgstr "Africain" -#: ../src\extra\translator\translator.py:13 +#: ../src\extra\translator\translator.py:23 msgid "Albanian" msgstr "Albanais" -#: ../src\extra\translator\translator.py:14 +#: ../src\extra\translator\translator.py:24 msgid "Amharic" msgstr "Amharique" -#: ../src\extra\translator\translator.py:15 +#: ../src\extra\translator\translator.py:25 msgid "Arabic" msgstr "Arabe" -#: ../src\extra\translator\translator.py:16 +#: ../src\extra\translator\translator.py:26 msgid "Armenian" msgstr "Arménien" -#: ../src\extra\translator\translator.py:17 +#: ../src\extra\translator\translator.py:27 msgid "Azerbaijani" msgstr "Azerbaïdjanais" -#: ../src\extra\translator\translator.py:18 +#: ../src\extra\translator\translator.py:28 msgid "Basque" msgstr "Basque" -#: ../src\extra\translator\translator.py:19 +#: ../src\extra\translator\translator.py:29 msgid "Belarusian" msgstr "Biélorusse" -#: ../src\extra\translator\translator.py:20 +#: ../src\extra\translator\translator.py:30 msgid "Bengali" msgstr "Bengali" -#: ../src\extra\translator\translator.py:21 +#: ../src\extra\translator\translator.py:31 msgid "Bihari" msgstr "Bihari" -#: ../src\extra\translator\translator.py:22 +#: ../src\extra\translator\translator.py:32 msgid "Bulgarian" msgstr "Bulgare" -#: ../src\extra\translator\translator.py:23 +#: ../src\extra\translator\translator.py:33 msgid "Burmese" msgstr "Birman" -#: ../src\extra\translator\translator.py:24 +#: ../src\extra\translator\translator.py:34 msgid "Catalan" msgstr "Catalan" -#: ../src\extra\translator\translator.py:25 +#: ../src\extra\translator\translator.py:35 msgid "Cherokee" msgstr "Cherokee" -#: ../src\extra\translator\translator.py:26 +#: ../src\extra\translator\translator.py:36 msgid "Chinese" msgstr "Chinois" -#: ../src\extra\translator\translator.py:27 +#: ../src\extra\translator\translator.py:37 msgid "Chinese_simplified" msgstr "Chinois simplifié" -#: ../src\extra\translator\translator.py:28 +#: ../src\extra\translator\translator.py:38 msgid "Chinese_traditional" msgstr "Chinois traditionnel" -#: ../src\extra\translator\translator.py:29 +#: ../src\extra\translator\translator.py:39 msgid "Croatian" msgstr "Croate" -#: ../src\extra\translator\translator.py:30 +#: ../src\extra\translator\translator.py:40 msgid "Czech" msgstr "Tchèque" -#: ../src\extra\translator\translator.py:32 +#: ../src\extra\translator\translator.py:42 msgid "Dhivehi" msgstr "Dhivehi" -#: ../src\extra\translator\translator.py:35 +#: ../src\extra\translator\translator.py:45 msgid "Esperanto" msgstr "Esperanto" -#: ../src\extra\translator\translator.py:36 +#: ../src\extra\translator\translator.py:46 msgid "Estonian" msgstr "Estonien" -#: ../src\extra\translator\translator.py:37 +#: ../src\extra\translator\translator.py:47 msgid "Filipino" msgstr "Filipino" -#: ../src\extra\translator\translator.py:40 +#: ../src\extra\translator\translator.py:50 msgid "Galician" msgstr "Galicien" -#: ../src\extra\translator\translator.py:41 +#: ../src\extra\translator\translator.py:51 msgid "Georgian" msgstr "Géorgien" -#: ../src\extra\translator\translator.py:43 +#: ../src\extra\translator\translator.py:53 msgid "Greek" msgstr "Grec" -#: ../src\extra\translator\translator.py:44 +#: ../src\extra\translator\translator.py:54 msgid "Guarani" msgstr "Guarani" -#: ../src\extra\translator\translator.py:45 +#: ../src\extra\translator\translator.py:55 msgid "Gujarati" msgstr "Gujarâtî" -#: ../src\extra\translator\translator.py:46 +#: ../src\extra\translator\translator.py:56 msgid "Hebrew" msgstr "Hébreu" -#: ../src\extra\translator\translator.py:47 +#: ../src\extra\translator\translator.py:57 msgid "Hindi" msgstr "Hindi" -#: ../src\extra\translator\translator.py:49 +#: ../src\extra\translator\translator.py:59 msgid "Icelandic" msgstr "Islandais" -#: ../src\extra\translator\translator.py:50 +#: ../src\extra\translator\translator.py:60 msgid "Indonesian" msgstr "Indonésien" -#: ../src\extra\translator\translator.py:51 +#: ../src\extra\translator\translator.py:61 msgid "Inuktitut" msgstr "Inuktitut" -#: ../src\extra\translator\translator.py:52 +#: ../src\extra\translator\translator.py:62 msgid "Irish" msgstr "Irlandais" -#: ../src\extra\translator\translator.py:55 +#: ../src\extra\translator\translator.py:65 msgid "Kannada" msgstr "Canara" -#: ../src\extra\translator\translator.py:56 +#: ../src\extra\translator\translator.py:66 msgid "Kazakh" msgstr "Kazakh" -#: ../src\extra\translator\translator.py:57 +#: ../src\extra\translator\translator.py:67 msgid "Khmer" msgstr "Cambodgien" -#: ../src\extra\translator\translator.py:59 +#: ../src\extra\translator\translator.py:69 msgid "Kurdish" msgstr "Kurde" -#: ../src\extra\translator\translator.py:60 +#: ../src\extra\translator\translator.py:70 msgid "Kyrgyz" msgstr "Kirghiz" -#: ../src\extra\translator\translator.py:61 +#: ../src\extra\translator\translator.py:71 msgid "Laothian" msgstr "Laotien" -#: ../src\extra\translator\translator.py:62 +#: ../src\extra\translator\translator.py:72 msgid "Latvian" msgstr "Letton" -#: ../src\extra\translator\translator.py:63 +#: ../src\extra\translator\translator.py:73 msgid "Lithuanian" msgstr "Lituanien" -#: ../src\extra\translator\translator.py:64 +#: ../src\extra\translator\translator.py:74 msgid "Macedonian" msgstr "Macédonien" -#: ../src\extra\translator\translator.py:65 +#: ../src\extra\translator\translator.py:75 msgid "Malay" msgstr "Malaisien" -#: ../src\extra\translator\translator.py:66 +#: ../src\extra\translator\translator.py:76 msgid "Malayalam" msgstr "Malayalam" -#: ../src\extra\translator\translator.py:67 +#: ../src\extra\translator\translator.py:77 msgid "Maltese" msgstr "Maltais" -#: ../src\extra\translator\translator.py:68 +#: ../src\extra\translator\translator.py:78 msgid "Marathi" msgstr "Marathi" -#: ../src\extra\translator\translator.py:69 +#: ../src\extra\translator\translator.py:79 msgid "Mongolian" msgstr "Mongol" -#: ../src\extra\translator\translator.py:70 +#: ../src\extra\translator\translator.py:80 msgid "Nepali" msgstr "Népali" -#: ../src\extra\translator\translator.py:71 +#: ../src\extra\translator\translator.py:81 msgid "Norwegian" msgstr "Norvégien" -#: ../src\extra\translator\translator.py:72 +#: ../src\extra\translator\translator.py:82 msgid "Oriya" msgstr "Oriya" -#: ../src\extra\translator\translator.py:73 +#: ../src\extra\translator\translator.py:83 msgid "Pashto" msgstr "Pashto" -#: ../src\extra\translator\translator.py:74 +#: ../src\extra\translator\translator.py:84 msgid "Persian" msgstr "Perse" -#: ../src\extra\translator\translator.py:77 +#: ../src\extra\translator\translator.py:87 msgid "Punjabi" msgstr "Punjabi" -#: ../src\extra\translator\translator.py:78 +#: ../src\extra\translator\translator.py:88 msgid "Romanian" msgstr "Roumain" -#: ../src\extra\translator\translator.py:80 +#: ../src\extra\translator\translator.py:90 msgid "Sanskrit" msgstr "Sanscrit" -#: ../src\extra\translator\translator.py:81 +#: ../src\extra\translator\translator.py:91 msgid "Serbian" msgstr "Serbe" -#: ../src\extra\translator\translator.py:82 +#: ../src\extra\translator\translator.py:92 msgid "Sindhi" msgstr "Sindhi" -#: ../src\extra\translator\translator.py:83 +#: ../src\extra\translator\translator.py:93 msgid "Sinhalese" msgstr "Cinghalais" -#: ../src\extra\translator\translator.py:84 +#: ../src\extra\translator\translator.py:94 msgid "Slovak" msgstr "Slovaque" -#: ../src\extra\translator\translator.py:85 +#: ../src\extra\translator\translator.py:95 msgid "Slovenian" msgstr "Slovène" -#: ../src\extra\translator\translator.py:87 +#: ../src\extra\translator\translator.py:97 msgid "Swahili" msgstr "Swahili" -#: ../src\extra\translator\translator.py:88 +#: ../src\extra\translator\translator.py:98 msgid "Swedish" msgstr "Suédois" -#: ../src\extra\translator\translator.py:89 +#: ../src\extra\translator\translator.py:99 msgid "Tajik" msgstr "Tadjik" -#: ../src\extra\translator\translator.py:90 +#: ../src\extra\translator\translator.py:100 msgid "Tamil" msgstr "Tamil" -#: ../src\extra\translator\translator.py:91 +#: ../src\extra\translator\translator.py:101 msgid "Tagalog" msgstr "Tagalog" -#: ../src\extra\translator\translator.py:92 +#: ../src\extra\translator\translator.py:102 msgid "Telugu" msgstr "Telugu" -#: ../src\extra\translator\translator.py:93 +#: ../src\extra\translator\translator.py:103 msgid "Thai" msgstr "Thaï" -#: ../src\extra\translator\translator.py:94 +#: ../src\extra\translator\translator.py:104 msgid "Tibetan" msgstr "Tibétain" -#: ../src\extra\translator\translator.py:96 +#: ../src\extra\translator\translator.py:106 msgid "Ukrainian" msgstr "Ukrainien" -#: ../src\extra\translator\translator.py:97 +#: ../src\extra\translator\translator.py:107 msgid "Urdu" msgstr "Urdu" -#: ../src\extra\translator\translator.py:98 +#: ../src\extra\translator\translator.py:108 msgid "Uzbek" msgstr "Ouzbek" -#: ../src\extra\translator\translator.py:99 +#: ../src\extra\translator\translator.py:109 msgid "Uighur" msgstr "Uighur" -#: ../src\extra\translator\translator.py:100 +#: ../src\extra\translator\translator.py:110 msgid "Vietnamese" msgstr "Vietnamien" -#: ../src\extra\translator\translator.py:101 +#: ../src\extra\translator\translator.py:111 msgid "Welsh" msgstr "Gallois" -#: ../src\extra\translator\translator.py:102 +#: ../src\extra\translator\translator.py:112 msgid "Yiddish" msgstr "Yiddish" -#: ../src\extra\translator\wx_ui.py:44 +#: ../src\extra\translator\wx_ui.py:29 msgid "Translate message" msgstr "Traduire le message" -#: ../src\extra\translator\wx_ui.py:47 +#: ../src\extra\translator\wx_ui.py:32 msgid "Target language" msgstr "Langue cible" -#: ../src\issueReporter\issueReporter.py:30 +#: ../src\issueReporter\issueReporter.py:32 #: ../src\wxUI\dialogs\configuration.py:359 #: ../src\wxUI\dialogs\configuration.py:368 msgid "General" msgstr "Général" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "always" msgstr "Toujours" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "have not tried" msgstr "Vous n'avez pas essayé" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "random" msgstr "Aléatoire" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "sometimes" msgstr "Parfois" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "unable to duplicate" msgstr "Impossible de reproduire" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "block" msgstr "Bloquer" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "crash" msgstr "Problème" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "feature" msgstr "Fonctionnalité" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "major" msgstr "Majeur" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "minor" msgstr "Mineur" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "text" msgstr "Texte" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "trivial" msgstr "Trivial" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "tweak" msgstr "Réglage" -#: ../src\issueReporter\wx_ui.py:25 +#: ../src\issueReporter\wx_ui.py:26 msgid "Report an error" msgstr "Signaler une erreur" -#: ../src\issueReporter\wx_ui.py:28 +#: ../src\issueReporter\wx_ui.py:29 msgid "Select a category" msgstr "Sélectionnez une catégorie" -#: ../src\issueReporter\wx_ui.py:36 +#: ../src\issueReporter\wx_ui.py:37 msgid "" "Briefly describe what happened. You will be able to thoroughly explain it " "later" @@ -1429,19 +1449,19 @@ msgstr "" "Décrivez brièvement ce qui s'est passé. Vous serez en mesure d'expliquer en " "profondeur par la suite." -#: ../src\issueReporter\wx_ui.py:45 +#: ../src\issueReporter\wx_ui.py:46 msgid "Here, you can describe the bug in detail" msgstr "Ici, vous pouvez décrire le problème en détail" -#: ../src\issueReporter\wx_ui.py:55 +#: ../src\issueReporter\wx_ui.py:56 msgid "how often does this bug happen?" msgstr "Combien de fois s'est produit ce problème ?" -#: ../src\issueReporter\wx_ui.py:62 +#: ../src\issueReporter\wx_ui.py:63 msgid "Select the importance that you think this bug has" msgstr "Sélectionnez l'importance que vous pensez que ce problème a" -#: ../src\issueReporter\wx_ui.py:69 +#: ../src\issueReporter\wx_ui.py:70 msgid "" "I know that the {0} bug system will get my Twitter username to contact me " "and fix the bug quickly" @@ -1449,20 +1469,20 @@ msgstr "" "Je sais que le système d'erreurs de {0} obtiendra mon nom d'utilisateur de " "Twitter afin de me contacter et corriger l'erreur rapidement" -#: ../src\issueReporter\wx_ui.py:72 +#: ../src\issueReporter\wx_ui.py:73 msgid "Send report" msgstr "Envoyer le rapport" -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "Annuler" -#: ../src\issueReporter\wx_ui.py:83 +#: ../src\issueReporter\wx_ui.py:84 msgid "You must fill out both fields" msgstr "Vous devez remplir les deux champs" -#: ../src\issueReporter\wx_ui.py:86 +#: ../src\issueReporter\wx_ui.py:87 msgid "" "You need to mark the checkbox to provide us your twitter username to contact " "you if it is necessary." @@ -1470,7 +1490,7 @@ msgstr "" "Vous devez cocher la case à cocher afin de nous fournir votre nom " "d'utilisateur de Twitter pour communiquer avec vous si c'est nécessaire." -#: ../src\issueReporter\wx_ui.py:89 +#: ../src\issueReporter\wx_ui.py:90 msgid "" "Thanks for reporting this bug! In future versions, you may be able to find " "it in the changes list. You've reported the bug number %i" @@ -1479,15 +1499,15 @@ msgstr "" "pourrez le trouver dans la liste des changements. Vous avez signalé le " "numéro d'erreur %i" -#: ../src\issueReporter\wx_ui.py:89 +#: ../src\issueReporter\wx_ui.py:90 msgid "reported" msgstr "signalé" -#: ../src\issueReporter\wx_ui.py:93 +#: ../src\issueReporter\wx_ui.py:94 msgid "Error while reporting" msgstr "Erreur lors du signalement du rapport" -#: ../src\issueReporter\wx_ui.py:93 +#: ../src\issueReporter\wx_ui.py:94 msgid "" "Something unexpected occurred while trying to report the bug. Please, try " "again later" @@ -1527,8 +1547,8 @@ msgstr "Afficher ou masquer l'interface graphique" msgid "New tweet" msgstr "Nouveau tweet" -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 +#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 +#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:128 msgid "Retweet" msgstr "Retweet" @@ -1725,6 +1745,10 @@ msgstr "" "Extraire le texte d'une photo et afficher le résultat dans une boîte de " "dialogue." +#: ../src\keystrokeEditor\constants.py:59 +msgid "Adds an alias to an user" +msgstr "Ajouter un alias à un utilisateur" + #: ../src\keystrokeEditor\wx_ui.py:8 msgid "Keystroke editor" msgstr "Modificateur de raccourci" @@ -1737,63 +1761,76 @@ msgstr "Sélectionnez un raccourci à modifier" msgid "Keystroke" msgstr "Raccourci" -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 +#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:10 +#: ../src\wxUI\dialogs\userActions.py:19 ../src\wxUI\dialogs\userActions.py:20 msgid "Action" msgstr "Action" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\wxUI\dialogs\lists.py:20 msgid "Edit" msgstr "Modifier" -#: ../src\keystrokeEditor\wx_ui.py:20 +#: ../src\keystrokeEditor\wx_ui.py:20 ../src\keystrokeEditor\wx_ui.py:50 +msgid "Undefine keystroke" +msgstr "Indéfinir le raccourcis clavier" + +#: ../src\keystrokeEditor\wx_ui.py:21 msgid "Execute action" msgstr "Exécuter une action" -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 +#: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 +#: ../src\wxUI\dialogs\utils.py:39 ../src\wxUI\dialogs\utils.py:71 msgid "Close" msgstr "Fermer" -#: ../src\keystrokeEditor\wx_ui.py:48 +#: ../src\keystrokeEditor\wx_ui.py:42 +msgid "Undefined" +msgstr "Non défini" + +#: ../src\keystrokeEditor\wx_ui.py:50 +msgid "Are you sure you want to undefine this keystroke?" +msgstr "Êtes-vous sûr de vouloir indéfinir ce raccourcis ?" + +#: ../src\keystrokeEditor\wx_ui.py:54 msgid "Editing keystroke" msgstr "Modification en cours d'un raccourci" -#: ../src\keystrokeEditor\wx_ui.py:51 +#: ../src\keystrokeEditor\wx_ui.py:57 msgid "Control" msgstr "Contrôle" -#: ../src\keystrokeEditor\wx_ui.py:52 +#: ../src\keystrokeEditor\wx_ui.py:58 msgid "Alt" msgstr "Alt" -#: ../src\keystrokeEditor\wx_ui.py:53 +#: ../src\keystrokeEditor\wx_ui.py:59 msgid "Shift" msgstr "Maj" -#: ../src\keystrokeEditor\wx_ui.py:54 +#: ../src\keystrokeEditor\wx_ui.py:60 msgid "Windows" msgstr "Windows" -#: ../src\keystrokeEditor\wx_ui.py:60 +#: ../src\keystrokeEditor\wx_ui.py:66 msgid "Key" msgstr "Touche" -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\utils.py:36 +#: ../src\wxUI\dialogs\utils.py:68 msgid "OK" msgstr "OK" -#: ../src\keystrokeEditor\wx_ui.py:78 +#: ../src\keystrokeEditor\wx_ui.py:84 msgid "You need to use the Windows key" msgstr "Vous devez utiliser la touche Windows" -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 +#: ../src\keystrokeEditor\wx_ui.py:84 ../src\keystrokeEditor\wx_ui.py:87 msgid "Invalid keystroke" msgstr "Raccourci invalide" -#: ../src\keystrokeEditor\wx_ui.py:81 +#: ../src\keystrokeEditor\wx_ui.py:87 msgid "You must provide a character for the keystroke" msgstr "Vous devez fournir une lettre pour le raccourci" @@ -1801,11 +1838,11 @@ msgstr "Vous devez fournir une lettre pour le raccourci" msgid "User default" msgstr "Utilisateur par défaut" -#: ../src\main.py:105 +#: ../src\main.py:120 msgid "https://twblue.es/donate" msgstr "https://twblue.es/donate" -#: ../src\main.py:122 +#: ../src\main.py:137 msgid "" "{0} is already running. Close the other instance before starting this one. " "If you're sure that {0} isn't running, try deleting the file at {1}. If " @@ -1816,43 +1853,43 @@ msgstr "" "de supprimer le fichier {1}. Si vous ne savez pas comment faire cela, " "contactez les développeurs de {0}." -#: ../src\sessionmanager\wxUI.py:8 +#: ../src\sessionmanager\wxUI.py:9 msgid "Session manager" msgstr "Gestion des comptes" -#: ../src\sessionmanager\wxUI.py:11 +#: ../src\sessionmanager\wxUI.py:12 msgid "Accounts list" msgstr "Liste des comptes" -#: ../src\sessionmanager\wxUI.py:13 +#: ../src\sessionmanager\wxUI.py:14 msgid "Account" msgstr "Compte" -#: ../src\sessionmanager\wxUI.py:17 +#: ../src\sessionmanager\wxUI.py:18 msgid "New account" msgstr "Nouveau compte" -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 +#: ../src\sessionmanager\wxUI.py:19 ../src\sessionmanager\wxUI.py:65 msgid "Remove account" msgstr "Supprimer le compte" -#: ../src\sessionmanager\wxUI.py:19 +#: ../src\sessionmanager\wxUI.py:20 msgid "Global Settings" msgstr "Paramètres Globaux" -#: ../src\sessionmanager\wxUI.py:42 +#: ../src\sessionmanager\wxUI.py:43 msgid "Account Error" msgstr "Erreur dans le Compte" -#: ../src\sessionmanager\wxUI.py:42 +#: ../src\sessionmanager\wxUI.py:43 msgid "You need to configure an account." msgstr "Vous devez configurer un compte." -#: ../src\sessionmanager\wxUI.py:48 +#: ../src\sessionmanager\wxUI.py:49 msgid "Authorization" msgstr "Autorisation" -#: ../src\sessionmanager\wxUI.py:48 +#: ../src\sessionmanager\wxUI.py:49 msgid "" "The request to authorize your Twitter account will be opened in your " "browser. You only need to do this once. Would you like to continue?" @@ -1861,15 +1898,15 @@ msgstr "" "navigateur. Vous devrez seulement réaliser ceci une fois. Souhaitez-vous " "continuer ?" -#: ../src\sessionmanager\wxUI.py:52 +#: ../src\sessionmanager\wxUI.py:53 msgid "Authorized account %d" msgstr "Compte autorisé %d" -#: ../src\sessionmanager\wxUI.py:58 +#: ../src\sessionmanager\wxUI.py:59 msgid "Invalid user token" msgstr "Code d'accès invalide" -#: ../src\sessionmanager\wxUI.py:58 +#: ../src\sessionmanager\wxUI.py:59 msgid "" "Your access token is invalid or the authorization has failed. Please try " "again." @@ -1877,30 +1914,66 @@ msgstr "" "Votre code d'accès est incorrect ou l'autorisation a échoué. S'il vous plaît " "essayer de nouveau." -#: ../src\sessionmanager\wxUI.py:64 +#: ../src\sessionmanager\wxUI.py:65 msgid "Do you really want to delete this account?" msgstr "Voulez-vous vraiment supprimer ce compte ?" -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 +#: ../src\sessionmanager\wxUI.py:81 +msgid "Authentication error for session {}" +msgstr "Erreur d'authentification pour la session {}" + +#: ../src\sessionmanager\wxUI.py:81 +msgid "" +"TWBlue is unable to authenticate the account for {} in Twitter. It might be " +"due to an invalid or expired token, revoqued access to the application, or " +"after an account reactivation. Please remove the account manually from your " +"Twitter sessions in order to stop seeing this message." +msgstr "" +"TWBlue ne parvient pas à authentifier le compte pour {} sur Twitter. Cela " +"peut être dû à un jeton d'accès incorrect, un accès d'application révoqué, " +"ou après la réactivation d'un compte. Veuillez supprimer manuellement ce " +"compte depuis votre session Twitter pour ne plus voir ce message." + +#: ../src\sessions\base.py:109 +msgid "" +"An exception occurred while saving the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"Une erreur est survenue lors de l'enregistrement de la base de données de " +"{app}, elle va être détruite et recréée automatiquement. Si ce problème " +"perciste, veuillez envoyer le journal d'erreur aux développeurs de {app}." + +#: ../src\sessions\base.py:149 +msgid "" +"An exception occurred while loading the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"Une erreur est survenue lors du chargement de la base de données de {app}, " +"elle va être détruite et recréée automatiquement. Si ce problème perciste, " +"veuillez envoyer le journal d'erreur aux développeurs de {app}." + +#: ../src\sessions\twitter\compose.py:38 ../src\sessions\twitter\compose.py:81 +#: ../src\sessions\twitter\compose.py:146 +#: ../src\sessions\twitter\compose.py:155 msgid "dddd, MMMM D, YYYY H:m:s" msgstr "dddd D MMMM YYYY à H:m:s" -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 +#: ../src\sessions\twitter\compose.py:89 ../src\sessions\twitter\compose.py:91 msgid "Dm to %s " msgstr "Mp à %s" -#: ../src\sessions\twitter\compose.py:141 +#: ../src\sessions\twitter\compose.py:130 msgid "{0}. Quoted tweet from @{1}: {2}" msgstr "{0}. Tweet de @{1} cité : {2}" -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 +#: ../src\sessions\twitter\compose.py:157 +#: ../src\sessions\twitter\compose.py:159 msgid "Unavailable" msgstr "Indisponible" -#: ../src\sessions\twitter\compose.py:166 +#: ../src\sessions\twitter\compose.py:160 msgid "" "%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " "Twitter %s" @@ -1908,47 +1981,48 @@ msgstr "" "%s (@%s). %s abonnés, %s abonnements, %s tweets. Dernier tweet envoyé %s. À " "rejoint Twitter %s" -#: ../src\sessions\twitter\compose.py:170 +#: ../src\sessions\twitter\compose.py:164 msgid "No description available" msgstr "Aucune description disponible" -#: ../src\sessions\twitter\compose.py:174 +#: ../src\sessions\twitter\compose.py:168 msgid "private" msgstr "privé" -#: ../src\sessions\twitter\compose.py:175 +#: ../src\sessions\twitter\compose.py:169 msgid "public" msgstr "public" -#: ../src\sessions\twitter\session.py:169 -msgid "There are no more items to retrieve in this buffer." -msgstr "Il n'y a aucun nouvel élément a récupéré dans ce tampon" - -#: ../src\sessions\twitter\session.py:215 +#: ../src\sessions\twitter\session.py:208 msgid "%s failed. Reason: %s" msgstr "%s erreur. Raison: %s" -#: ../src\sessions\twitter\session.py:221 +#: ../src\sessions\twitter\session.py:214 msgid "%s succeeded." msgstr "%s réussi." -#: ../src\sessions\twitter\utils.py:225 +#: ../src\sessions\twitter\session.py:423 +#: ../src\sessions\twitter\session.py:501 +msgid "Deleted account" +msgstr "Compte supprimé" + +#: ../src\sessions\twitter\utils.py:231 msgid "Sorry, you are not authorised to see this status." msgstr "Désolé, vous n'êtes pas autorisé à voir ce Tweet." -#: ../src\sessions\twitter\utils.py:227 +#: ../src\sessions\twitter\utils.py:233 msgid "No status found with that ID" msgstr "Aucun Tweet trouvée avec cet ID" -#: ../src\sessions\twitter\utils.py:229 +#: ../src\sessions\twitter\utils.py:235 msgid "Error code {0}" msgstr "Code d'erreur {0}" -#: ../src\sessions\twitter\wxUI.py:6 +#: ../src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." msgstr "Compte en cours d'autorisation..." -#: ../src\sessions\twitter\wxUI.py:9 +#: ../src\sessions\twitter\wxUI.py:10 msgid "Enter your PIN code here" msgstr "Entrer votre code PIN ici" @@ -1956,11 +2030,11 @@ msgstr "Entrer votre code PIN ici" msgid "Stopped." msgstr "Arrêté." -#: ../src\update\wxUpdater.py:10 +#: ../src\update\wxUpdater.py:14 msgid "New version for %s" msgstr "Nouvelle version de %s" -#: ../src\update\wxUpdater.py:10 +#: ../src\update\wxUpdater.py:14 msgid "" "There's a new %s version available, released on %s. Would you like to " "download it now?\n" @@ -1978,23 +2052,23 @@ msgstr "" "Modifications:\n" "%s" -#: ../src\update\wxUpdater.py:18 +#: ../src\update\wxUpdater.py:22 msgid "Download in Progress" msgstr "Téléchargement en cours" -#: ../src\update\wxUpdater.py:18 +#: ../src\update\wxUpdater.py:22 msgid "Downloading the new version..." msgstr "Téléchargement de la nouvelle version en cours..." -#: ../src\update\wxUpdater.py:28 +#: ../src\update\wxUpdater.py:32 msgid "Updating... %s of %s" msgstr "Mise à jour en cours... %s sur %s" -#: ../src\update\wxUpdater.py:31 +#: ../src\update\wxUpdater.py:35 msgid "Done!" msgstr "Terminé !" -#: ../src\update\wxUpdater.py:31 +#: ../src\update\wxUpdater.py:35 msgid "" "The update has been downloaded and installed successfully. Press OK to " "continue." @@ -2002,61 +2076,62 @@ msgstr "" "La mise à jour a été téléchargé et installé avec succès. Appuyez sur OK pour " "continuer." -#: ../src\wxUI\buffers\base.py:11 +#: ../src\wxUI\buffers\base.py:12 msgid "Client" msgstr "Client" -#: ../src\wxUI\buffers\base.py:11 +#: ../src\wxUI\buffers\base.py:12 msgid "Text" msgstr "Texte" -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 msgid "Date" msgstr "Date" -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 +#: ../src\wxUI\buffers\user_searches.py:11 +#: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 +#: ../src\wxUI\dialogs\utils.py:59 msgid "User" msgstr "Utilisateur" -#: ../src\wxUI\buffers\base.py:27 +#: ../src\wxUI\buffers\base.py:28 msgid "Direct message" msgstr "Message privé" -#: ../src\wxUI\buffers\events.py:13 +#: ../src\wxUI\buffers\events.py:14 msgid "Event" msgstr "Événement" -#: ../src\wxUI\buffers\events.py:15 +#: ../src\wxUI\buffers\events.py:16 msgid "Remove event" msgstr "Supprimer l'événement" -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 +#: ../src\wxUI\buffers\panels.py:12 ../src\wxUI\buffers\panels.py:20 msgid "Login" msgstr "Connexion" -#: ../src\wxUI\buffers\panels.py:13 +#: ../src\wxUI\buffers\panels.py:14 msgid "Log in automatically" msgstr "Connexion automatique" -#: ../src\wxUI\buffers\panels.py:21 +#: ../src\wxUI\buffers\panels.py:22 msgid "Logout" msgstr "Déconnexion" -#: ../src\wxUI\buffers\trends.py:8 +#: ../src\wxUI\buffers\trends.py:9 msgid "Trending topic" msgstr "Tendance" -#: ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\buffers\trends.py:19 msgid "Tweet about this trend" msgstr "Tweet sur cette tendance" -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 +#: ../src\wxUI\buffers\trends.py:20 ../src\wxUI\menus.py:97 msgid "Search topic" msgstr "Recherche tendance" -#: ../src\wxUI\commonMessageDialogs.py:6 +#: ../src\wxUI\commonMessageDialogs.py:7 msgid "" "This retweet is over 140 characters. Would you like to post it as a mention " "to the poster with your comments and a link to the original tweet?" @@ -2065,11 +2140,11 @@ msgstr "" "commentaires avec en mentionnant l'utilisateur qui a publié le tweet " "original et un lien vers celui-ci ?" -#: ../src\wxUI\commonMessageDialogs.py:9 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Would you like to add a comment to this tweet?" msgstr "Souhaitez-vous ajouter un commentaire à ce tweet ?" -#: ../src\wxUI\commonMessageDialogs.py:12 +#: ../src\wxUI\commonMessageDialogs.py:13 msgid "" "Do you really want to delete this tweet? It will be deleted from Twitter as " "well." @@ -2077,27 +2152,27 @@ msgstr "" "Voulez-vous vraiment supprimer ce tweet ? Il sera également supprimé de " "Twitter." -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 +#: ../src\wxUI\commonMessageDialogs.py:13 ../src\wxUI\dialogs\lists.py:149 msgid "Delete" msgstr "Supprimer Tweet" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Do you really want to close {0}?" msgstr "Voulez-vous vraiment quitter {0} ?" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Exit" msgstr "Quitter" -#: ../src\wxUI\commonMessageDialogs.py:19 +#: ../src\wxUI\commonMessageDialogs.py:20 msgid " {0} must be restarted for these changes to take effect." msgstr " {0} doit être redémarré pour que ces modifications prennent effet." -#: ../src\wxUI\commonMessageDialogs.py:19 +#: ../src\wxUI\commonMessageDialogs.py:20 msgid "Restart {0} " msgstr "Redémarrez {0} " -#: ../src\wxUI\commonMessageDialogs.py:22 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "" "Are you sure you want to delete this user from the database? This user will " "not appear in autocomplete results anymore." @@ -2106,20 +2181,20 @@ msgstr "" "Cet utilisateur n'apparaîtra plus dans les résultats lors de La saisie " "automatique." -#: ../src\wxUI\commonMessageDialogs.py:22 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "Confirm" msgstr "Confirmer" -#: ../src\wxUI\commonMessageDialogs.py:25 +#: ../src\wxUI\commonMessageDialogs.py:26 msgid "Enter the name of the client : " msgstr "Entrez le nom du client: " -#: ../src\wxUI\commonMessageDialogs.py:25 +#: ../src\wxUI\commonMessageDialogs.py:26 #: ../src\wxUI\dialogs\configuration.py:246 msgid "Add client" msgstr "Ajouter un client" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "" "Do you really want to empty this buffer? It's items will be removed from " "the list but not from Twitter" @@ -2127,36 +2202,36 @@ msgstr "" "Voulez-vous vraiment vider ce tampon ? Ces éléments seront supprimés de la " "liste, mais pas de Twitter" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "Empty buffer" msgstr "Tampon Vide" -#: ../src\wxUI\commonMessageDialogs.py:35 +#: ../src\wxUI\commonMessageDialogs.py:36 msgid "Do you really want to destroy this buffer?" msgstr "Voulez-vous vraiment détruire ce tampon ?" -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 +#: ../src\wxUI\commonMessageDialogs.py:36 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Attention" msgstr "Attention" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "A timeline for this user already exists. You can't open another" msgstr "" "Une chronologie pour cet utilisateur existe déjà. Vous ne pouvez pas ouvrir " "une autre" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "Existing timeline" msgstr "Chronologie existante" -#: ../src\wxUI\commonMessageDialogs.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "This user has no tweets, so you can't open a timeline for them." msgstr "" "Cet utilisateur n'a aucun tweets, donc vous ne pouvez pas ouvrir une " "chronologie pour lui." -#: ../src\wxUI\commonMessageDialogs.py:47 +#: ../src\wxUI\commonMessageDialogs.py:48 msgid "" "This is a protected Twitter user, which means you can't open a timeline " "using the Streaming API. The user's tweets will not update due to a twitter " @@ -2167,12 +2242,12 @@ msgstr "" "tweets ne mettra pas à jour en raison d'une politique de twitter. Voulez-" "vous continuer ?" -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 +#: ../src\wxUI\commonMessageDialogs.py:48 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "Warning" msgstr "Attention" -#: ../src\wxUI\commonMessageDialogs.py:50 +#: ../src\wxUI\commonMessageDialogs.py:51 msgid "" "This is a protected user account, you need to follow this user to view their " "tweets or likes." @@ -2180,7 +2255,7 @@ msgstr "" "Ce compte utilisateur est protégé, vous devez suivre cet utilisateur pour " "afficher ces tweets ou favoris." -#: ../src\wxUI\commonMessageDialogs.py:53 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "" "If you like {0} we need your help to keep it going. Help us by donating to " "the project. This will help us pay for the server, the domain and some other " @@ -2195,44 +2270,44 @@ msgstr "" "poursuivre le développement de {0}, et de garder {0} gratuit. Vous souhaitez " "faire un don maintenant ?" -#: ../src\wxUI\commonMessageDialogs.py:53 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "We need your help" msgstr "Nous avons besoin de votre aide" -#: ../src\wxUI\commonMessageDialogs.py:57 +#: ../src\wxUI\commonMessageDialogs.py:58 msgid "This user has no tweets. {0} can't create a timeline." msgstr "" "Cet utilisateur n'a aucun tweets. {0} ne peut pas créer une chronologie." -#: ../src\wxUI\commonMessageDialogs.py:60 +#: ../src\wxUI\commonMessageDialogs.py:61 msgid "This user has no favorited tweets. {0} can't create a timeline." msgstr "" "Cet utilisateur n'a aucun tweets marqué comme favori. {0} ne peut pas créer " "une chronologie." -#: ../src\wxUI\commonMessageDialogs.py:63 +#: ../src\wxUI\commonMessageDialogs.py:64 msgid "This user has no followers. {0} can't create a timeline." msgstr "" "Cet utilisateur n'a aucun abonnés. {0} ne peut pas créer une chronologie." -#: ../src\wxUI\commonMessageDialogs.py:66 +#: ../src\wxUI\commonMessageDialogs.py:67 msgid "This user has no friends. {0} can't create a timeline." msgstr "" "Cet utilisateur n'a aucun abonnements. {0} ne peut pas créer une chronologie." -#: ../src\wxUI\commonMessageDialogs.py:70 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geo data for this tweet" msgstr "Données de localisation géographique pour ce tweet" -#: ../src\wxUI\commonMessageDialogs.py:70 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geolocation data: {0}" msgstr "Données de localisation géographique: {0}" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "Information" msgstr "Information" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "" "TWBlue has detected that you're running windows 10 and has changed the " "default keymap to the Windows 10 keymap. It means that some keyboard " @@ -2245,11 +2320,11 @@ msgstr "" "vérifier le Modificateur de raccourci en appuyant sur Alt+Win+K pour voir " "tous les raccourcis disponibles pour cette configuration clavier." -#: ../src\wxUI\commonMessageDialogs.py:76 +#: ../src\wxUI\commonMessageDialogs.py:77 msgid "You have been blocked from viewing this content" msgstr "Vous avez été bloqué de voir ce contenu" -#: ../src\wxUI\commonMessageDialogs.py:79 +#: ../src\wxUI\commonMessageDialogs.py:80 msgid "" "You have been blocked from viewing someone's content. In order to avoid " "conflicts with the full session, TWBlue will remove the affected timeline." @@ -2257,7 +2332,7 @@ msgstr "" "Vous avez été bloqué de voir le contenu de quelqu'un. Afin d'éviter les " "conflits avec la session complète, TWBlue supprime la chronologie affecté." -#: ../src\wxUI\commonMessageDialogs.py:82 +#: ../src\wxUI\commonMessageDialogs.py:83 msgid "" "TWBlue cannot load this timeline because the user has been suspended from " "Twitter." @@ -2265,15 +2340,15 @@ msgstr "" "TWBlue ne peut pas charger cette chronologie car l'utilisateur a été " "suspendu de Twitter." -#: ../src\wxUI\commonMessageDialogs.py:85 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Do you really want to delete this filter?" msgstr "Voulez-vous vraiment supprimer ce filtre ?" -#: ../src\wxUI\commonMessageDialogs.py:88 +#: ../src\wxUI\commonMessageDialogs.py:89 msgid "This filter already exists. Please use a different title" msgstr "Ce filtre existe déjà. Veuillez utiliser un titre différent" -#: ../src\wxUI\commonMessageDialogs.py:94 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." @@ -2281,149 +2356,149 @@ msgstr "" "{0} a été quitté inopinément lors de sa dernière exécution. Si ce problème " "perciste, veuillez le signaler aux développeurs de {0}." -#: ../src\wxUI\dialogs\attach.py:9 +#: ../src\wxUI\dialogs\attach.py:10 msgid "Add an attachment" msgstr "Ajouter un fichier" -#: ../src\wxUI\dialogs\attach.py:12 +#: ../src\wxUI\dialogs\attach.py:13 msgid "Attachments" msgstr "Fichiers joints" -#: ../src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Title" msgstr "Titre" -#: ../src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Type" msgstr "Type" -#: ../src\wxUI\dialogs\attach.py:18 +#: ../src\wxUI\dialogs\attach.py:19 msgid "Add attachments" msgstr "Joindre des fichiers" -#: ../src\wxUI\dialogs\attach.py:19 +#: ../src\wxUI\dialogs\attach.py:20 msgid "&Photo" msgstr "&Image" -#: ../src\wxUI\dialogs\attach.py:20 +#: ../src\wxUI\dialogs\attach.py:21 msgid "Remove attachment" msgstr "Supprimer le fichier joint" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:118 +#: ../src\wxUI\dialogs\message.py:177 ../src\wxUI\dialogs\message.py:237 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" msgstr "Fichiers image (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:118 +#: ../src\wxUI\dialogs\message.py:177 ../src\wxUI\dialogs\message.py:237 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Select the picture to be uploaded" msgstr "Sélectionnez la photo à charger" -#: ../src\wxUI\dialogs\attach.py:43 +#: ../src\wxUI\dialogs\attach.py:44 msgid "please provide a description" msgstr "Veuillez fournir une description" -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 +#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:70 msgid "Description" msgstr "Description" -#: ../src\wxUI\dialogs\configuration.py:16 +#: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "Langue" -#: ../src\wxUI\dialogs\configuration.py:23 +#: ../src\wxUI\dialogs\configuration.py:22 msgid "Run {0} at Windows startup" msgstr "Démarrer {0} en même temps que Windows" -#: ../src\wxUI\dialogs\configuration.py:24 +#: ../src\wxUI\dialogs\configuration.py:23 msgid "ask before exiting {0}" msgstr "Demander avant de quitter {0}" -#: ../src\wxUI\dialogs\configuration.py:27 +#: ../src\wxUI\dialogs\configuration.py:26 msgid "Disable Streaming functions" msgstr "Désactiver les fonctions de streaming" -#: ../src\wxUI\dialogs\configuration.py:30 +#: ../src\wxUI\dialogs\configuration.py:29 msgid "Buffer update interval, in minutes" msgstr "Intervalle de mise à jour des tampons, en minutes" -#: ../src\wxUI\dialogs\configuration.py:36 +#: ../src\wxUI\dialogs\configuration.py:35 msgid "Play a sound when {0} launches" msgstr "Jouer un son lorsque {0} démarre" -#: ../src\wxUI\dialogs\configuration.py:38 +#: ../src\wxUI\dialogs\configuration.py:37 msgid "Speak a message when {0} launches" msgstr "Dire un message lorsque {0} démarre" -#: ../src\wxUI\dialogs\configuration.py:40 +#: ../src\wxUI\dialogs\configuration.py:39 msgid "Use invisible interface's keyboard shortcuts while GUI is visible" msgstr "" "Utilisez les raccourcis clavier de l'interface invisible alors que " "l'interface graphique est affichée" -#: ../src\wxUI\dialogs\configuration.py:42 +#: ../src\wxUI\dialogs\configuration.py:41 msgid "Activate Sapi5 when any other screen reader is not being run" msgstr "" "Activer Sapi5 lorsqu'il n'y a aucun autre lecteur d'écran en cours " "d'exécution" -#: ../src\wxUI\dialogs\configuration.py:44 +#: ../src\wxUI\dialogs\configuration.py:43 msgid "Hide GUI on launch" msgstr "Masquer l'interface graphique au démarrage" -#: ../src\wxUI\dialogs\configuration.py:46 +#: ../src\wxUI\dialogs\configuration.py:45 msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" msgstr "" "Lecture complète de tweets longs (peut diminuer les performances du client)" -#: ../src\wxUI\dialogs\configuration.py:48 +#: ../src\wxUI\dialogs\configuration.py:47 msgid "Remember state for mention all and long tweet" msgstr "Se souvenir de l'état pour \"Répondre à tous\" et \"Tweet long\"" -#: ../src\wxUI\dialogs\configuration.py:51 +#: ../src\wxUI\dialogs\configuration.py:50 msgid "Keymap" msgstr "Configuration clavier" -#: ../src\wxUI\dialogs\configuration.py:56 +#: ../src\wxUI\dialogs\configuration.py:55 msgid "Check for updates when {0} launches" msgstr "Vérifier les mises à jour lorsque {0} démarre" -#: ../src\wxUI\dialogs\configuration.py:66 +#: ../src\wxUI\dialogs\configuration.py:65 msgid "Proxy type: " msgstr "Type de proxy: " -#: ../src\wxUI\dialogs\configuration.py:73 +#: ../src\wxUI\dialogs\configuration.py:72 msgid "Proxy server: " msgstr "Serveur proxy: " -#: ../src\wxUI\dialogs\configuration.py:79 +#: ../src\wxUI\dialogs\configuration.py:78 msgid "Port: " msgstr "Port: " -#: ../src\wxUI\dialogs\configuration.py:85 +#: ../src\wxUI\dialogs\configuration.py:84 msgid "User: " msgstr "Utilisateur: " -#: ../src\wxUI\dialogs\configuration.py:91 +#: ../src\wxUI\dialogs\configuration.py:90 msgid "Password: " msgstr "Mot de passe: " -#: ../src\wxUI\dialogs\configuration.py:103 +#: ../src\wxUI\dialogs\configuration.py:102 msgid "Autocompletion settings..." msgstr "Paramètres pour la saisie automatique..." -#: ../src\wxUI\dialogs\configuration.py:105 +#: ../src\wxUI\dialogs\configuration.py:104 msgid "Relative timestamps" msgstr "Temps relatifs" -#: ../src\wxUI\dialogs\configuration.py:108 +#: ../src\wxUI\dialogs\configuration.py:107 msgid "Items on each API call" msgstr "Éléments pour chaque appel à l'API" -#: ../src\wxUI\dialogs\configuration.py:114 +#: ../src\wxUI\dialogs\configuration.py:113 msgid "" "Inverted buffers: The newest tweets will be shown at the beginning while the " "oldest at the end" @@ -2431,15 +2506,15 @@ msgstr "" "Tampons inversés: les tweets plus récents seront affichées en haut alors que " "les plus ancien à la fin" -#: ../src\wxUI\dialogs\configuration.py:116 +#: ../src\wxUI\dialogs\configuration.py:115 msgid "Retweet mode" msgstr "Mode retweet" -#: ../src\wxUI\dialogs\configuration.py:122 +#: ../src\wxUI\dialogs\configuration.py:121 msgid "Show screen names instead of full names" msgstr "Afficher les noms d'écran au lieu des noms complets" -#: ../src\wxUI\dialogs\configuration.py:124 +#: ../src\wxUI\dialogs\configuration.py:123 msgid "" "Number of items per buffer to cache in database (0 to disable caching, blank " "for unlimited)" @@ -2447,6 +2522,14 @@ msgstr "" "Nombre d'éléments par tampon en cache dans la base de données (0 pour " "désactiver la mise en cache, laissez en blanc pour illimité)" +#: ../src\wxUI\dialogs\configuration.py:127 +msgid "" +"Load cache for tweets in memory (much faster in big datasets but requires " +"more RAM)" +msgstr "" +"Charger le cache des tweets en mémoire (plus rapide pour les gros ensembles " +"de données mais nécessite plus de RAM)" + #: ../src\wxUI\dialogs\configuration.py:134 msgid "Enable automatic speech feedback" msgstr "Activer le retour automatique de la parole" @@ -2460,7 +2543,7 @@ msgid "Status" msgstr "Statut" #: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Buffer" msgstr "Tampon" @@ -2585,276 +2668,276 @@ msgstr "Supplémentaires" msgid "Save" msgstr "Enregistrer" -#: ../src\wxUI\dialogs\filterDialogs.py:15 +#: ../src\wxUI\dialogs\filterDialogs.py:16 msgid "Create a filter for this buffer" msgstr "Créer un filtre pour ce tampon" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:17 msgid "Filter title" msgstr "Titre du filtre" -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by word" msgstr "Filtrer par mot" -#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:27 msgid "Ignore tweets wich contain the following word" msgstr "Ignorer les tweets contenant le mot suivant" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:28 msgid "Ignore tweets without the following word" msgstr "Ignorer les tweets ne contenant pas le mot suivant" -#: ../src\wxUI\dialogs\filterDialogs.py:32 +#: ../src\wxUI\dialogs\filterDialogs.py:33 msgid "word" msgstr "Mot" -#: ../src\wxUI\dialogs\filterDialogs.py:37 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow retweets" msgstr "Permettre les retweets" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:39 msgid "Allow quoted tweets" msgstr "Permettre les tweets cités" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:40 msgid "Allow replies" msgstr "Permettre les réponses" -#: ../src\wxUI\dialogs\filterDialogs.py:47 +#: ../src\wxUI\dialogs\filterDialogs.py:48 msgid "Use this term as a regular expression" msgstr "Utiliser ce terme comme une expression régulière" -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by language" msgstr "Filtrer par langue" -#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Load tweets in the following languages" msgstr "Charger tweets dans les suivantes langues" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:52 msgid "Ignore tweets in the following languages" msgstr "Ignorer tweets dans les suivantes langues" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:53 msgid "Don't filter by language" msgstr "Ne pas filtrer par langue" -#: ../src\wxUI\dialogs\filterDialogs.py:63 +#: ../src\wxUI\dialogs\filterDialogs.py:64 msgid "Supported languages" msgstr "Langues supportées" -#: ../src\wxUI\dialogs\filterDialogs.py:68 +#: ../src\wxUI\dialogs\filterDialogs.py:69 msgid "Add selected language to filter" msgstr "Ajouter la langue sélectionnée au filtre" -#: ../src\wxUI\dialogs\filterDialogs.py:72 +#: ../src\wxUI\dialogs\filterDialogs.py:73 msgid "Selected languages" msgstr "Langue sélectionnée" -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 +#: ../src\wxUI\dialogs\filterDialogs.py:75 +#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:132 msgid "Remove" msgstr "Effacer" -#: ../src\wxUI\dialogs\filterDialogs.py:122 +#: ../src\wxUI\dialogs\filterDialogs.py:123 msgid "Manage filters" msgstr "Gérer les filtres" -#: ../src\wxUI\dialogs\filterDialogs.py:124 +#: ../src\wxUI\dialogs\filterDialogs.py:125 msgid "Filters" msgstr "Filtres" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter" msgstr "Filtre" -#: ../src\wxUI\dialogs\find.py:12 +#: ../src\wxUI\dialogs\find.py:13 msgid "Find in current buffer" msgstr "Trouver dans le tampon actuel" -#: ../src\wxUI\dialogs\find.py:13 +#: ../src\wxUI\dialogs\find.py:14 msgid "String" msgstr "Chaîne" -#: ../src\wxUI\dialogs\lists.py:10 +#: ../src\wxUI\dialogs\lists.py:11 msgid "Lists manager" msgstr "Gestionnaire de listes" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "List" msgstr "Liste" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Members" msgstr "Membres" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Owner" msgstr "Propriétaire" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "mode" msgstr "mode" -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 +#: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "Créer une nouvelle liste" -#: ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:22 msgid "Open in buffer" msgstr "Ouvrir dans un tampon" -#: ../src\wxUI\dialogs\lists.py:51 +#: ../src\wxUI\dialogs\lists.py:52 msgid "Viewing lists for %s" msgstr "Affichage des listes pour %s" -#: ../src\wxUI\dialogs\lists.py:52 +#: ../src\wxUI\dialogs\lists.py:53 msgid "Subscribe" msgstr "S'abonner" -#: ../src\wxUI\dialogs\lists.py:53 +#: ../src\wxUI\dialogs\lists.py:54 msgid "Unsubscribe" msgstr "Se désabonner" -#: ../src\wxUI\dialogs\lists.py:64 +#: ../src\wxUI\dialogs\lists.py:65 msgid "Name (20 characters maximun)" msgstr "Nom (maximum 20 caractères)" -#: ../src\wxUI\dialogs\lists.py:74 +#: ../src\wxUI\dialogs\lists.py:75 msgid "Mode" msgstr "Mode" -#: ../src\wxUI\dialogs\lists.py:75 +#: ../src\wxUI\dialogs\lists.py:76 msgid "Public" msgstr "Public" -#: ../src\wxUI\dialogs\lists.py:76 +#: ../src\wxUI\dialogs\lists.py:77 msgid "Private" msgstr "Privé" -#: ../src\wxUI\dialogs\lists.py:96 +#: ../src\wxUI\dialogs\lists.py:97 msgid "Editing the list %s" msgstr "Modification de la liste %s" -#: ../src\wxUI\dialogs\lists.py:107 +#: ../src\wxUI\dialogs\lists.py:108 msgid "Select a list to add the user" msgstr "Sélectionnez une liste pour ajouter l'utilisateur" -#: ../src\wxUI\dialogs\lists.py:108 +#: ../src\wxUI\dialogs\lists.py:109 msgid "Add" msgstr "Ajouter" -#: ../src\wxUI\dialogs\lists.py:130 +#: ../src\wxUI\dialogs\lists.py:131 msgid "Select a list to remove the user" msgstr "Sélectionnez une liste pour supprimer l'utilisateur" -#: ../src\wxUI\dialogs\lists.py:148 +#: ../src\wxUI\dialogs\lists.py:149 msgid "Do you really want to delete this list?" msgstr "Voulez-vous vraiment supprimer cette liste ?" -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 +#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:256 msgid "&Long tweet" msgstr "&Tweet long" -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 +#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 +#: ../src\wxUI\dialogs\message.py:257 msgid "&Upload image..." msgstr "&Joindre une image..." -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 +#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 +#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 +#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:432 msgid "Check &spelling..." msgstr "Correction &orthographique..." -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 +#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 +#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 msgid "&Attach audio..." msgstr "&Joindre un audio..." -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 +#: ../src\wxUI\dialogs\message.py:79 ../src\wxUI\dialogs\message.py:138 +#: ../src\wxUI\dialogs\message.py:198 ../src\wxUI\dialogs\message.py:260 msgid "Sh&orten URL" msgstr "&Réduire URL" -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 +#: ../src\wxUI\dialogs\message.py:80 ../src\wxUI\dialogs\message.py:139 +#: ../src\wxUI\dialogs\message.py:199 ../src\wxUI\dialogs\message.py:261 +#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 msgid "&Expand URL" msgstr "&Élargir URL" -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 +#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 +#: ../src\wxUI\dialogs\message.py:202 ../src\wxUI\dialogs\message.py:264 +#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:435 msgid "&Translate..." msgstr "&Traduire..." -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 +#: ../src\wxUI\dialogs\message.py:84 ../src\wxUI\dialogs\message.py:143 +#: ../src\wxUI\dialogs\message.py:188 ../src\wxUI\dialogs\message.py:265 msgid "Auto&complete users" msgstr "Sai&sie automatique utilisateurs" -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 +#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 +#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 msgid "Sen&d" msgstr "Envoye&r" -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 +#: ../src\wxUI\dialogs\message.py:87 ../src\wxUI\dialogs\message.py:146 +#: ../src\wxUI\dialogs\message.py:205 ../src\wxUI\dialogs\message.py:268 +#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:436 msgid "C&lose" msgstr "F&ermer" -#: ../src\wxUI\dialogs\message.py:184 +#: ../src\wxUI\dialogs\message.py:186 msgid "&Recipient" msgstr "&Destinataire" -#: ../src\wxUI\dialogs\message.py:245 +#: ../src\wxUI\dialogs\message.py:247 msgid "&Mention to all" msgstr "&Répondre à tout le monde" -#: ../src\wxUI\dialogs\message.py:299 +#: ../src\wxUI\dialogs\message.py:301 msgid "Tweet - %i characters " msgstr "Tweet - %i caractères " -#: ../src\wxUI\dialogs\message.py:316 +#: ../src\wxUI\dialogs\message.py:318 msgid "Image description" msgstr "Description de l'image" -#: ../src\wxUI\dialogs\message.py:327 +#: ../src\wxUI\dialogs\message.py:329 msgid "Retweets: " msgstr "Retweets: " -#: ../src\wxUI\dialogs\message.py:332 +#: ../src\wxUI\dialogs\message.py:334 msgid "Likes: " msgstr "Favoris: " -#: ../src\wxUI\dialogs\message.py:337 +#: ../src\wxUI\dialogs\message.py:339 msgid "Source: " msgstr "Source: " -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 +#: ../src\wxUI\dialogs\message.py:344 ../src\wxUI\dialogs\message.py:422 msgid "Date: " msgstr "Date: " -#: ../src\wxUI\dialogs\message.py:405 +#: ../src\wxUI\dialogs\message.py:407 msgid "View" msgstr "Voir" -#: ../src\wxUI\dialogs\message.py:407 +#: ../src\wxUI\dialogs\message.py:409 msgid "Item" msgstr "Élément" -#: ../src\wxUI\dialogs\search.py:13 +#: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "Rechercher sur Twitter" -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 +#: ../src\wxUI\dialogs\search.py:13 ../src\wxUI\view.py:21 msgid "&Search" msgstr "&Rechercher" @@ -2890,414 +2973,435 @@ msgstr "Récents" msgid "Popular" msgstr "Populaire" -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 +#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:25 +#: ../src\wxUI\dialogs\userActions.py:41 +#: ../src\wxUI\dialogs\userSelection.py:33 msgid "&OK" msgstr "&OK" -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 +#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:19 +#: ../src\wxUI\dialogs\trends.py:27 ../src\wxUI\dialogs\update_profile.py:37 +#: ../src\wxUI\dialogs\userActions.py:43 +#: ../src\wxUI\dialogs\userSelection.py:35 msgid "&Close" msgstr "&Fermer" -#: ../src\wxUI\dialogs\show_user.py:11 +#: ../src\wxUI\dialogs\show_user.py:12 msgid "Details" msgstr "Détails" -#: ../src\wxUI\dialogs\show_user.py:16 +#: ../src\wxUI\dialogs\show_user.py:17 msgid "&Go to URL" msgstr "&Aller à l'URL" -#: ../src\wxUI\dialogs\trends.py:12 +#: ../src\wxUI\dialogs\trends.py:10 msgid "View trending topics" msgstr "Afficher les tendances" -#: ../src\wxUI\dialogs\trends.py:13 +#: ../src\wxUI\dialogs\trends.py:11 msgid "Trending topics by" msgstr "Tendances par" -#: ../src\wxUI\dialogs\trends.py:15 +#: ../src\wxUI\dialogs\trends.py:12 msgid "Country" msgstr "Pays" -#: ../src\wxUI\dialogs\trends.py:16 +#: ../src\wxUI\dialogs\trends.py:13 msgid "City" msgstr "Ville" -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 +#: ../src\wxUI\dialogs\trends.py:19 ../src\wxUI\dialogs\update_profile.py:18 msgid "&Location" msgstr "&Localisation" -#: ../src\wxUI\dialogs\update_profile.py:9 +#: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "Actualiser votre profil" -#: ../src\wxUI\dialogs\update_profile.py:11 +#: ../src\wxUI\dialogs\update_profile.py:12 msgid "&Name (50 characters maximum)" msgstr "&Nom (50 caractères maximum)" -#: ../src\wxUI\dialogs\update_profile.py:22 +#: ../src\wxUI\dialogs\update_profile.py:23 msgid "&Website" msgstr "Site &Web" -#: ../src\wxUI\dialogs\update_profile.py:27 +#: ../src\wxUI\dialogs\update_profile.py:28 msgid "&Bio (160 characters maximum)" msgstr "&Biographie (maximum 160 caractères)" -#: ../src\wxUI\dialogs\update_profile.py:33 +#: ../src\wxUI\dialogs\update_profile.py:34 msgid "Upload a &picture" msgstr "Charger une &photo" -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 +#: ../src\wxUI\dialogs\update_profile.py:35 ../src\wxUI\view.py:19 msgid "&Update profile" msgstr "Actualiser le &profil" -#: ../src\wxUI\dialogs\update_profile.py:76 +#: ../src\wxUI\dialogs\update_profile.py:77 msgid "Upload a picture" msgstr "Charger une photo" -#: ../src\wxUI\dialogs\update_profile.py:78 +#: ../src\wxUI\dialogs\update_profile.py:79 msgid "Discard image" msgstr "Ignorer la photo" -#: ../src\wxUI\dialogs\urlList.py:5 +#: ../src\wxUI\dialogs\urlList.py:6 msgid "Select URL" msgstr "Sélectionnez l'URL" -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 +#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:86 msgid "&User" msgstr "&Utilisateur" -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 +#: ../src\wxUI\dialogs\userActions.py:14 +#: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 +#: ../src\wxUI\dialogs\utils.py:58 msgid "&Autocomplete users" msgstr "&Saisie automatique utilisateurs" -#: ../src\wxUI\dialogs\userActions.py:19 +#: ../src\wxUI\dialogs\userActions.py:20 msgid "&Follow" msgstr "&Suivre" -#: ../src\wxUI\dialogs\userActions.py:20 +#: ../src\wxUI\dialogs\userActions.py:21 msgid "U&nfollow" msgstr "Ne pas su&ivre" -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 +#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:62 msgid "&Mute" msgstr "&Masquer" -#: ../src\wxUI\dialogs\userActions.py:22 +#: ../src\wxUI\dialogs\userActions.py:23 msgid "Unmu&te" msgstr "&Démasquer" -#: ../src\wxUI\dialogs\userActions.py:23 +#: ../src\wxUI\dialogs\userActions.py:24 msgid "&Block" msgstr "&Bloquer" -#: ../src\wxUI\dialogs\userActions.py:24 +#: ../src\wxUI\dialogs\userActions.py:25 msgid "Unbl&ock" msgstr "Débl&oquer" -#: ../src\wxUI\dialogs\userActions.py:25 +#: ../src\wxUI\dialogs\userActions.py:26 msgid "&Report as spam" msgstr "&Signaler comme spam" -#: ../src\wxUI\dialogs\userActions.py:26 +#: ../src\wxUI\dialogs\userActions.py:27 msgid "&Ignore tweets from this client" msgstr "&Ignorer les tweets de ce client" -#: ../src\wxUI\dialogs\userSelection.py:9 +#: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "Chronologie pour %s" -#: ../src\wxUI\dialogs\userSelection.py:18 +#: ../src\wxUI\dialogs\userSelection.py:19 msgid "Buffer type" msgstr "Type de tampon" -#: ../src\wxUI\dialogs\userSelection.py:19 +#: ../src\wxUI\dialogs\userSelection.py:20 msgid "&Tweets" msgstr "&Tweets" -#: ../src\wxUI\dialogs\userSelection.py:20 +#: ../src\wxUI\dialogs\userSelection.py:21 msgid "&Likes" msgstr "&Favoris" -#: ../src\wxUI\dialogs\userSelection.py:21 +#: ../src\wxUI\dialogs\userSelection.py:22 msgid "&Followers" msgstr "&Abonnés" -#: ../src\wxUI\dialogs\userSelection.py:22 +#: ../src\wxUI\dialogs\userSelection.py:23 msgid "F&riends" msgstr "A&bonnements" -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 +#: ../src\wxUI\dialogs\utils.py:63 +msgid "Alias" +msgstr "Alias" + +#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:32 msgid "&Retweet" msgstr "&Retweet" -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 +#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:31 msgid "Re&ply" msgstr "Ré&pondre" -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 +#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:33 msgid "&Like" msgstr "A&jouter aux favoris" -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 +#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:34 msgid "&Unlike" msgstr "S&upprimer des favoris" -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 +#: ../src\wxUI\menus.py:16 ../src\wxUI\menus.py:36 ../src\wxUI\menus.py:52 msgid "&Open URL" msgstr "&Ouvrir l'URL" -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 +#: ../src\wxUI\menus.py:18 ../src\wxUI\menus.py:54 ../src\wxUI\menus.py:87 msgid "&Open in Twitter" msgstr "Ou&vrir dans Twitter" -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 +#: ../src\wxUI\menus.py:20 ../src\wxUI\menus.py:38 ../src\wxUI\menus.py:56 msgid "&Play audio" msgstr "&Lire audio" -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 +#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:35 msgid "&Show tweet" msgstr "A&fficher tweet" -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 +#: ../src\wxUI\menus.py:24 ../src\wxUI\menus.py:42 ../src\wxUI\menus.py:60 +#: ../src\wxUI\menus.py:70 ../src\wxUI\menus.py:89 ../src\wxUI\menus.py:103 msgid "&Copy to clipboard" msgstr "&Copier dans le Presse-papiers" -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 +#: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 +#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:39 msgid "&Delete" msgstr "&Supprimer Tweet" -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 +#: ../src\wxUI\menus.py:28 ../src\wxUI\menus.py:46 ../src\wxUI\menus.py:91 msgid "&User actions..." msgstr "&Actions de l'utilisateur..." -#: ../src\wxUI\menus.py:39 +#: ../src\wxUI\menus.py:40 msgid "&Show direct message" msgstr "&Afficher le message privé" -#: ../src\wxUI\menus.py:67 +#: ../src\wxUI\menus.py:68 msgid "&Show event" msgstr "&Afficher l'événement" -#: ../src\wxUI\menus.py:77 +#: ../src\wxUI\menus.py:78 msgid "Direct &message" msgstr "&Message privé" -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 +#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:49 msgid "&View lists" msgstr "&Voir listes" -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 +#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:50 msgid "Show user &profile" msgstr "Voir le &profil de l'utilisateur" -#: ../src\wxUI\menus.py:84 +#: ../src\wxUI\menus.py:85 msgid "&Show user" msgstr "&Afficher l'utilisateur" -#: ../src\wxUI\menus.py:98 +#: ../src\wxUI\menus.py:99 msgid "&Tweet about this trend" msgstr "&Tweet sur cette tendance" -#: ../src\wxUI\menus.py:100 +#: ../src\wxUI\menus.py:101 msgid "&Show item" msgstr "&Afficher l'élément" -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 +#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:25 msgid "&Global settings" msgstr "Paramètres &globaux" -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 +#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:24 msgid "Account se&ttings" msgstr "Paramètres du c&ompte" -#: ../src\wxUI\sysTrayIcon.py:37 +#: ../src\wxUI\sysTrayIcon.py:38 msgid "Update &profile" msgstr "&Actualiser le profil" -#: ../src\wxUI\sysTrayIcon.py:38 +#: ../src\wxUI\sysTrayIcon.py:39 msgid "&Show / hide" msgstr "&Afficher / masquer" -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 +#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:74 msgid "&Documentation" msgstr "&Documentation" -#: ../src\wxUI\sysTrayIcon.py:40 +#: ../src\wxUI\sysTrayIcon.py:41 msgid "Check for &updates" msgstr "Vérifier les &mises à jour" -#: ../src\wxUI\sysTrayIcon.py:41 +#: ../src\wxUI\sysTrayIcon.py:42 msgid "&Exit" msgstr "&Quitter" -#: ../src\wxUI\view.py:16 +#: ../src\wxUI\view.py:18 msgid "&Manage accounts" msgstr "Gérer les &comptes" -#: ../src\wxUI\view.py:18 +#: ../src\wxUI\view.py:20 msgid "&Hide window" msgstr "Masquer la &fenêtre" -#: ../src\wxUI\view.py:20 +#: ../src\wxUI\view.py:22 msgid "&Lists manager" msgstr "Gérer les &listes" -#: ../src\wxUI\view.py:21 +#: ../src\wxUI\view.py:23 msgid "&Edit keystrokes" msgstr "&Éditer les raccourcis clavier" -#: ../src\wxUI\view.py:24 +#: ../src\wxUI\view.py:26 msgid "E&xit" msgstr "&Quitter" -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 +#: ../src\wxUI\view.py:30 ../src\wxUI\view.py:85 msgid "&Tweet" msgstr "&Tweet" -#: ../src\wxUI\view.py:34 +#: ../src\wxUI\view.py:36 msgid "View &address" msgstr "Voir &adresse" -#: ../src\wxUI\view.py:35 +#: ../src\wxUI\view.py:37 msgid "View conversa&tion" msgstr "Voir &conversation" -#: ../src\wxUI\view.py:36 +#: ../src\wxUI\view.py:38 msgid "Read text in picture" msgstr "Lire le texte dans l'&image" -#: ../src\wxUI\view.py:41 +#: ../src\wxUI\view.py:43 msgid "&Actions..." msgstr "&Actions..." -#: ../src\wxUI\view.py:42 +#: ../src\wxUI\view.py:44 msgid "&View timeline..." msgstr "Voir &chronologie..." -#: ../src\wxUI\view.py:43 +#: ../src\wxUI\view.py:45 msgid "Direct me&ssage" msgstr "&Message privé" -#: ../src\wxUI\view.py:44 +#: ../src\wxUI\view.py:46 +msgid "Add a&lias" +msgstr "Ajouter un a&lias" + +#: ../src\wxUI\view.py:47 msgid "&Add to list" msgstr "A&jouter à la liste" -#: ../src\wxUI\view.py:45 +#: ../src\wxUI\view.py:48 msgid "R&emove from list" msgstr "S&upprimer de la liste" -#: ../src\wxUI\view.py:48 +#: ../src\wxUI\view.py:51 msgid "V&iew likes" msgstr "Voir &favoris" -#: ../src\wxUI\view.py:52 +#: ../src\wxUI\view.py:55 msgid "&Update buffer" msgstr "&Mise à jour du tampon" -#: ../src\wxUI\view.py:53 +#: ../src\wxUI\view.py:56 msgid "New &trending topics buffer..." msgstr "Nouveau tampon de &tendances..." -#: ../src\wxUI\view.py:54 +#: ../src\wxUI\view.py:57 msgid "Create a &filter" msgstr "Créer un &filtre" -#: ../src\wxUI\view.py:55 +#: ../src\wxUI\view.py:58 msgid "&Manage filters" msgstr "&Gérer les filtres" -#: ../src\wxUI\view.py:56 +#: ../src\wxUI\view.py:59 msgid "Find a string in the currently focused buffer..." msgstr "Trouver une chaîne dans le tampon ayant actuellement le f&ocus..." -#: ../src\wxUI\view.py:57 +#: ../src\wxUI\view.py:60 msgid "&Load previous items" msgstr "&Charger des éléments plus anciens" -#: ../src\wxUI\view.py:60 +#: ../src\wxUI\view.py:63 msgid "&Autoread" msgstr "&Lecture automatique" -#: ../src\wxUI\view.py:61 +#: ../src\wxUI\view.py:64 msgid "&Clear buffer" msgstr "&Effacer le tampon" -#: ../src\wxUI\view.py:62 +#: ../src\wxUI\view.py:65 msgid "&Destroy" msgstr "&Détruire" -#: ../src\wxUI\view.py:66 +#: ../src\wxUI\view.py:69 msgid "&Seek back 5 seconds" msgstr "&Reculer de 5 secondes" -#: ../src\wxUI\view.py:67 +#: ../src\wxUI\view.py:70 msgid "&Seek forward 5 seconds" msgstr "&Avancer de 5 secondes" -#: ../src\wxUI\view.py:72 +#: ../src\wxUI\view.py:75 msgid "Sounds &tutorial" msgstr "&Apprentissage des sons" -#: ../src\wxUI\view.py:73 +#: ../src\wxUI\view.py:76 msgid "&What's new in this version?" msgstr "&Quoi de neuf dans cette version ?" -#: ../src\wxUI\view.py:74 +#: ../src\wxUI\view.py:77 msgid "&Check for updates" msgstr "&Vérifier les mises à jour" -#: ../src\wxUI\view.py:75 +#: ../src\wxUI\view.py:78 msgid "&Report an error" msgstr "&Signaler une erreur" -#: ../src\wxUI\view.py:76 +#: ../src\wxUI\view.py:79 msgid "{0}'s &website" msgstr "Site &Web de {0}" -#: ../src\wxUI\view.py:77 +#: ../src\wxUI\view.py:80 msgid "Get soundpacks for TWBlue" msgstr "Obtenir des packs de son pour TWBlue" -#: ../src\wxUI\view.py:78 +#: ../src\wxUI\view.py:81 msgid "About &{0}" msgstr "À propos de &{0}" -#: ../src\wxUI\view.py:81 +#: ../src\wxUI\view.py:84 msgid "&Application" msgstr "&Application" -#: ../src\wxUI\view.py:84 +#: ../src\wxUI\view.py:87 msgid "&Buffer" msgstr "Ta&mpon" -#: ../src\wxUI\view.py:85 +#: ../src\wxUI\view.py:88 msgid "&Audio" msgstr "Au&dio" -#: ../src\wxUI\view.py:86 +#: ../src\wxUI\view.py:89 msgid "&Help" msgstr "A&ide" -#: ../src\wxUI\view.py:172 +#: ../src\wxUI\view.py:175 msgid "Address" msgstr "Adresse" -#: ../src\wxUI\view.py:203 +#: ../src\wxUI\view.py:206 msgid "Update" msgstr "Mise à jour" -#: ../src\wxUI\view.py:203 +#: ../src\wxUI\view.py:206 msgid "Your {0} version is up to date" msgstr "Votre version de {0} est à jour" +#~ msgid "Events" +#~ msgstr "Événements" + +#~ msgid "This tweet doesn't contain images" +#~ msgstr "Ce tweet ne contient pas d'images" + +#~ msgid "Direct connection" +#~ msgstr "Connexion directe" + +#~ msgid "There are no more items to retrieve in this buffer." +#~ msgstr "Il n'y a aucun nouvel élément a récupéré dans ce tampon" + #~ msgid "Empty" #~ msgstr "Vide" From 10511d3022f1d6fb69c3f2fa5e53e73584f53b45 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 25 Aug 2021 11:13:12 -0500 Subject: [PATCH 132/245] Improvements to reading tweets with many mentions on them --- doc/changelog.md | 1 + src/sessions/twitter/compose.py | 10 +++++----- src/sessions/twitter/utils.py | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index e0b555bd..a68f71c6 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* When reading a tweet, if the tweet contains more than 2 consecutive mentions, TWBlue will announce how many more users the tweet includes, as opposed to read every user in the conversation. You still can display the tweet to read all users. * Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. Users are displayed with their display name in people buffers only. This action is supported in all keymaps, although it is undefined by default. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) * It is possible to undefine keystrokes in the current keymap in TWBlue. This allows you, for example, to redefine keystrokes completely. * Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385)) diff --git a/src/sessions/twitter/compose.py b/src/sessions/twitter/compose.py index b6ceb4ae..1b761390 100644 --- a/src/sessions/twitter/compose.py +++ b/src/sessions/twitter/compose.py @@ -45,9 +45,9 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No else: value = "text" if hasattr(tweet, "retweeted_status") and value != "message": - text = StripChars(getattr(tweet.retweeted_status, value)) + text = utils.clean_mentions(StripChars(getattr(tweet.retweeted_status, value))) else: - text = StripChars(getattr(tweet, value)) + text = utils.clean_mentions(StripChars(getattr(tweet, value))) if show_screen_names: user = session.get_user(tweet.user).screen_name else: @@ -111,7 +111,7 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, value = "full_text" else: value = "text" - text = StripChars(getattr(quoted_tweet, value)) + text = utils.clean_mentions(StripChars(getattr(quoted_tweet, value))) if show_screen_names: quoting_user = session.get_user(quoted_tweet.user).screen_name else: @@ -124,9 +124,9 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, if hasattr(original_tweet, "message"): original_text = original_tweet.message elif hasattr(original_tweet, "full_text"): - original_text = StripChars(original_tweet.full_text) + original_text = utils.clean_mentions(StripChars(original_tweet.full_text)) else: - original_text = StripChars(original_tweet.text) + original_text = utils.clean_mentions(StripChars(original_tweet.text)) quoted_tweet.message = _(u"{0}. Quoted tweet from @{1}: {2}").format( text, original_user, original_text) quoted_tweet = tweets.clear_url(quoted_tweet) if hasattr(original_tweet, "entities") and original_tweet.entities.get("urls"): diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 70ebfb1e..05c4c52c 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -244,3 +244,20 @@ def expand_urls(text, entities): if url["url"] in text: text = text.replace(url["url"], url["expanded_url"]) return text + +def clean_mentions(text): + new_text = text + mentionned_people = [u for u in re.finditer("(?<=^|(?<=[^a-zA-Z0-9-\.]))@([A-Za-z0-9_]+)", text)] + if len(mentionned_people) <= 2: + return text + end = -2 + total_users = 0 + for user in mentionned_people: + if abs(user.start()-end) < 3: + new_text = new_text.replace(user.group(0), "") + total_users = total_users+1 + end = user.end() + if total_users < 1: + return text + new_text = _("{user_1}, {user_2} and {all_users} more: {text}").format(user_1=mentionned_people[0].group(0), user_2=mentionned_people[1].group(0), all_users=total_users-2, text=new_text) + return new_text \ No newline at end of file From f4ecf1088543147d9ac00783982e35c37163a0e5 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 25 Aug 2021 16:30:37 -0500 Subject: [PATCH 133/245] Allow to copy tweet URLS from tweet displayer dialog --- doc/changelog.md | 1 + src/controller/buffers/twitter/base.py | 8 ++++++-- src/controller/buffers/twitter/people.py | 5 ++--- src/controller/mainController.py | 7 +++++-- src/controller/messages.py | 11 ++++++++++- src/wxUI/dialogs/message.py | 8 ++++++-- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 4f9951ec..6e7ca628 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -3,6 +3,7 @@ ## changes in this version * When reading a tweet, if the tweet contains more than 2 consecutive mentions, TWBlue will announce how many more users the tweet includes, as opposed to read every user in the conversation. You still can display the tweet to read all users. +* In the tweet displayer, It is possible to copy a link to the current tweet or person by pressing a button called "copy link to clipboard". * Added a keymap capable to work under Windows 11. ([#391](https://github.com/manuelcortez/TWBlue/pull/391)) * Added user aliases to TWBlue. This feature allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. For adding an alias to an user, select the "add alias" option in the user menu, located in the menu bar. This feature works only if you have set display screen names unchecked. Users are displayed with their display name in people buffers only. This action is supported in all keymaps, although it is undefined by default. ([#389](https://github.com/manuelcortez/TWBlue/pull/389)) * There are some changes to the autocomplete users feature: diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index b7b535e1..fa872844 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -644,8 +644,12 @@ class BaseBuffer(base.Buffer): original_tweet.text = utils.find_urls_in_text(original_tweet.text, original_tweet.entities) return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"]) - def open_in_browser(self, *args, **kwargs): + def get_item_url(self): tweet = self.get_tweet() - output.speak(_(u"Opening item in web browser...")) url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=self.session.get_user(tweet.user).screen_name, tweet_id=tweet.id) + return url + + def open_in_browser(self, *args, **kwargs): + url = self.get_item_url() + output.speak(_(u"Opening item in web browser...")) webbrowser.open(url) \ No newline at end of file diff --git a/src/controller/buffers/twitter/people.py b/src/controller/buffers/twitter/people.py index 09d89c5d..eae6c718 100644 --- a/src/controller/buffers/twitter/people.py +++ b/src/controller/buffers/twitter/people.py @@ -252,8 +252,7 @@ class PeopleBuffer(base.BaseBuffer): elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False: output.speak(_(u"{0} new followers.").format(number_of_items)) - def open_in_browser(self, *args, **kwargs): + def get_item_url(self, *args, **kwargs): tweet = self.get_tweet() - output.speak(_(u"Opening item in web browser...")) url = "https://twitter.com/{screen_name}".format(screen_name=tweet.screen_name) - webbrowser.open(url) \ No newline at end of file + return url \ No newline at end of file diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 0db1a6ca..30fd3f1a 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -831,7 +831,7 @@ class Controller(object): return elif buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search": tweet, tweetsList = buffer.get_full_tweet() - msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"]) + msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"], item_url=buffer.get_item_url()) elif buffer.type == "dm": non_tweet = buffer.get_formatted_message() item = buffer.get_right_tweet() @@ -839,8 +839,11 @@ class Controller(object): date = original_date.shift(seconds=buffer.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage()) msg = messages.viewTweet(non_tweet, [], False, date=date) else: + item_url = "" + if hasattr(buffer, "get_item_url"): + item_url = buffer.get_item_url() non_tweet = buffer.get_formatted_message() - msg = messages.viewTweet(non_tweet, [], False) + msg = messages.viewTweet(non_tweet, [], False, item_url=item_url) def open_in_browser(self, *args, **kwargs): buffer = self.get_current_buffer() diff --git a/src/controller/messages.py b/src/controller/messages.py index e4a7747c..38082427 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -205,7 +205,7 @@ class dm(basicTweet): c.show_menu("dm") class viewTweet(basicTweet): - def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date=""): + def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date="", item_url=""): """ This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event. param tweet: A dictionary that represents a full tweet or a string for non-tweets. param tweetList: If is_tweet is set to True, this could be a list of quoted tweets. @@ -273,6 +273,10 @@ class viewTweet(basicTweet): text = tweet self.message = message.viewNonTweet(text, date) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) + if item_url != "": + self.message.enable_button("share") + widgetUtils.connect_event(self.message.share, widgetUtils.BUTTON_PRESSED, self.share) + self.item_url = item_url widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) if self.contain_urls() == True: self.message.enable_button("unshortenButton") @@ -290,3 +294,8 @@ class viewTweet(basicTweet): if "https://twitter.com/" in i: text = text.replace(i, "\n") return text + + def share(self, *args, **kwargs): + if hasattr(self, "item_url"): + output.copy(self.item_url) + output.speak(_("Link copied to clipboard.")) \ No newline at end of file diff --git a/src/wxUI/dialogs/message.py b/src/wxUI/dialogs/message.py index 6a74b32e..093934f5 100644 --- a/src/wxUI/dialogs/message.py +++ b/src/wxUI/dialogs/message.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals -from builtins import str import wx import widgetUtils @@ -356,6 +354,8 @@ class viewTweet(widgetUtils.BaseDialog): infoBox.Add(sourceBox, 0, wx.ALL, 5) mainBox.Add(infoBox, 0, wx.ALL, 5) mainBox.Add(dateBox, 0, wx.ALL, 5) + self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) + self.share.Enable(False) self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) self.unshortenButton.Disable() @@ -363,6 +363,7 @@ class viewTweet(widgetUtils.BaseDialog): cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) cancelButton.SetDefault() buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.share, 0, wx.ALL, 5) buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) @@ -429,6 +430,8 @@ class viewNonTweet(widgetUtils.BaseDialog): dateBox.Add(dateLabel, 0, wx.ALL, 5) dateBox.Add(date, 0, wx.ALL, 5) mainBox.Add(dateBox, 0, wx.ALL, 5) + self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) + self.share.Enable(False) self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) self.unshortenButton.Disable() @@ -436,6 +439,7 @@ class viewNonTweet(widgetUtils.BaseDialog): cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) cancelButton.SetDefault() buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.share, 0, wx.ALL, 5) buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) From 3d8519313e3e93ec0bbce7d34ea49f17f957f3eb Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 26 Aug 2021 08:56:51 -0500 Subject: [PATCH 134/245] Switched Geocoding library to OpenStreetMap's Nominatim API. Closes #390 --- doc/changelog.md | 1 + requirements.txt | 2 +- src/controller/mainController.py | 19 ++++++++----------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 6e7ca628..fc178196 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -9,6 +9,7 @@ * There are some changes to the autocomplete users feature: * Now users can search for twitter screen names or display names in the database. * It is possible to undefine keystrokes in the current keymap in TWBlue. This allows you, for example, to redefine keystrokes completely. +* We have changed our Geocoding service to the Nominatim API from OpenStreetMap. Addresses present in tweets are going to be determined by this service, as the Google Maps API now requires an API key. ([#390](https://github.com/manuelcortez/TWBlue/issues/390)) * Added a limited version of the Twitter's Streaming API: The Streaming API will work only for tweets, and will receive tweets only by people you follow. Protected users are not possible to be streamed. It is possible that during high tweet traffic, the Stream might get disconnected at times, but TWBlue should be capable of detecting this problem and reconnecting the stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385)) * Fixed an issue that made TWBlue to not show a dialog when attempting to show a profile for a suspended user. ([#387](https://github.com/manuelcortez/TWBlue/issues/387)) * Added support for Twitter audio and videos: Tweets which contains audio or videos will be detected as audio items, and you can playback those with the regular command to play audios. ([#384,](https://github.com/manuelcortez/TWBlue/pull/384)) diff --git a/requirements.txt b/requirements.txt index a3282f7b..8a5c4744 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ oauthlib requests-oauthlib requests-toolbelt pypubsub -pygeocoder +geopy arrow python-dateutil futures diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 30fd3f1a..a3df454d 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -35,17 +35,16 @@ from mysc.repeating_timer import RepeatingTimer from mysc import restart import config import widgetUtils -import pygeocoder -from pygeolib import GeocoderError import logging import webbrowser +from geopy.geocoders import Nominatim from mysc import localization import os import languageHandler log = logging.getLogger("mainController") -geocoder = pygeocoder.Geocoder() +geocoder = Nominatim(user_agent="TWBlue") class Controller(object): @@ -1001,19 +1000,17 @@ class Controller(object): if tweet.coordinates != None: x = tweet.coordinates["coordinates"][0] y = tweet.coordinates["coordinates"][1] - address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang) - if event == None: output.speak(address[0].__str__()) - else: self.view.show_address(address[0].__str__()) + address = geocoder.reverse("{}, {}".format(y, x), language = languageHandler.curLang) + if event == None: output.speak(address.address) + else: self.view.show_address(address.address) else: output.speak(_(u"There are no coordinates in this tweet")) - except GeocoderError: - output.speak(_(u"There are no results for the coordinates in this tweet")) except ValueError: output.speak(_(u"Error decoding coordinates. Try again later.")) - except KeyError: - pass +# except KeyError: +# pass except AttributeError: - pass + output.speak(_("Unable to find address in OpenStreetMap.")) def view_reverse_geocode(self, event=None): try: From f9864a887d97566d0d8c424e3197fa37589cba5f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 26 Aug 2021 09:16:02 -0500 Subject: [PATCH 135/245] Fixed a small traceback that was happening when translating a direct message --- src/controller/messages.py | 2 +- src/wxUI/dialogs/message.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 38082427..a748464d 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -102,7 +102,7 @@ class basicTweet(object): else: self.message.disable_button("shortenButton") self.message.disable_button("unshortenButton") - if self.message.get("long_tweet") == False: + if self.message.get("long_tweet") == False and hasattr(self, "max"): text = self.message.get_text() results = parse_tweet(text) self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) diff --git a/src/wxUI/dialogs/message.py b/src/wxUI/dialogs/message.py index 093934f5..8eadfdd9 100644 --- a/src/wxUI/dialogs/message.py +++ b/src/wxUI/dialogs/message.py @@ -467,5 +467,5 @@ class viewNonTweet(widgetUtils.BaseDialog): self.text.SetFocus() def enable_button(self, buttonName): - if getattr(self, buttonName): + if hasattr(self, buttonName): return getattr(self, buttonName).Enable() From 3a5c1c10d3c105d63bd69183f26a66b14b1d3e1a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 26 Aug 2021 15:13:34 -0500 Subject: [PATCH 136/245] Released a new snapshot --- src/application.py | 2 +- updates/snapshots.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/application.py b/src/application.py index a7baf074..e4253581 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "9" + version = "10" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] diff --git a/updates/snapshots.json b/updates/snapshots.json index b3a3ff75..1b0348d7 100644 --- a/updates/snapshots.json +++ b/updates/snapshots.json @@ -1,4 +1,4 @@ -{"current_version": "8", +{"current_version": "10", "description": "Snapshot version.", "date": "unknown", "downloads": From 7c34204d17b2d744ec92da0a06b4273ae79c8a0e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 27 Aug 2021 13:45:59 -0500 Subject: [PATCH 137/245] Allow to specify alternative configuration specs for sessions --- src/sessions/base.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sessions/base.py b/src/sessions/base.py index 63ee5142..9833edd1 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -43,6 +43,8 @@ class baseSession(object): self.logged = False self.settings = None self.db={} + # Config specification file. + self.config_spec = "conf.defaults" @property def is_logged(self): @@ -52,7 +54,7 @@ class baseSession(object): """ Get settings for a session.""" file_ = "%s/session.conf" % (self.session_id,) log.debug("Creating config file %s" % (file_,)) - self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "Conf.defaults")) + self.settings = config_utils.load_config(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), self.config_spec)) self.init_sound() self.load_persistent_data() From 17ea8af050857cd308ff585703ca8da8cb0552b5 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Sat, 28 Aug 2021 08:37:26 +0200 Subject: [PATCH 138/245] Update translation --- src/locales/fr/LC_MESSAGES/twblue.po | 200 ++++++++++++++------------- 1 file changed, 107 insertions(+), 93 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index 6b900577..b03048bf 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2021-08-02 19:18+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-08-02 19:29+0200\n" +"POT-Creation-Date: 2021-08-28 08:34+Paris, Madrid (heure d’été)\n" +"PO-Revision-Date: 2021-08-28 08:37+0200\n" "Last-Translator: Corentin BACQUÉ-CAZENAVE \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -25,56 +25,56 @@ msgid "This action is not supported for this buffer" msgstr "Cette action n'est pas supportée pour ce tampon" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:286 +#: ../src\controller\mainController.py:309 ../src\controller\settings.py:286 msgid "Home" msgstr "Accueil" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:314 ../src\controller\settings.py:287 +#: ../src\controller\mainController.py:313 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Mentions" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:318 +#: ../src\controller\mainController.py:317 msgid "Direct messages" msgstr "Messages privés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:289 +#: ../src\controller\mainController.py:321 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Messages privés envoyés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:326 ../src\controller\settings.py:290 +#: ../src\controller\mainController.py:325 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Tweets envoyés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:330 +#: ../src\controller\mainController.py:329 #: ../src\controller\mainController.py:1400 ../src\controller\settings.py:291 msgid "Likes" msgstr "Favoris" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:334 +#: ../src\controller\mainController.py:333 #: ../src\controller\mainController.py:1405 ../src\controller\settings.py:292 msgid "Followers" msgstr "Abonnés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:338 +#: ../src\controller\mainController.py:337 #: ../src\controller\mainController.py:1410 ../src\controller\settings.py:293 msgid "Friends" msgstr "Abonnements" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:342 +#: ../src\controller\mainController.py:341 #: ../src\controller\mainController.py:1415 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Utilisateurs bloqués" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:346 +#: ../src\controller\mainController.py:345 #: ../src\controller\mainController.py:1420 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Utilisateurs masqués" @@ -103,7 +103,7 @@ msgstr "Tampon inconnu" #: ../src\controller\buffers\twitter\trends.py:121 #: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 #: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 -#: ../src\wxUI\dialogs\message.py:306 ../src\wxUI\sysTrayIcon.py:35 +#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "Tweet" @@ -170,8 +170,7 @@ msgstr "Ouverture de l'URL..." msgid "User details" msgstr "Détails de l'utilisateur" -#: ../src\controller\buffers\twitter\base.py:649 -#: ../src\controller\buffers\twitter\people.py:257 +#: ../src\controller\buffers\twitter\base.py:654 msgid "Opening item in web browser..." msgstr "Ouverture de l'élément dans le navigateur Web..." @@ -210,75 +209,75 @@ msgstr "{0} nouvel abonné" msgid "This action is not supported in the buffer, yet." msgstr "Cette action n'est pas supportée pour le tampon actuel" -#: ../src\controller\mainController.py:274 +#: ../src\controller\mainController.py:273 msgid "Ready" msgstr "Prêt" -#: ../src\controller\mainController.py:349 +#: ../src\controller\mainController.py:348 msgid "Timelines" msgstr "Chronologies" -#: ../src\controller\mainController.py:353 -#: ../src\controller\mainController.py:890 +#: ../src\controller\mainController.py:352 +#: ../src\controller\mainController.py:892 #: ../src\controller\mainController.py:1596 msgid "Timeline for {}" msgstr "Chronologie de {}" -#: ../src\controller\mainController.py:356 +#: ../src\controller\mainController.py:355 msgid "Likes timelines" msgstr "Chronologies des favoris" -#: ../src\controller\mainController.py:360 -#: ../src\controller\mainController.py:909 +#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:911 #: ../src\controller\mainController.py:1598 msgid "Likes for {}" msgstr "Favoris de {}" -#: ../src\controller\mainController.py:363 +#: ../src\controller\mainController.py:362 msgid "Followers' Timelines" msgstr "Chronologies des abonnés" -#: ../src\controller\mainController.py:367 -#: ../src\controller\mainController.py:928 +#: ../src\controller\mainController.py:366 +#: ../src\controller\mainController.py:930 #: ../src\controller\mainController.py:1600 msgid "Followers for {}" msgstr "Abonnés de {}" -#: ../src\controller\mainController.py:370 +#: ../src\controller\mainController.py:369 msgid "Friends' Timelines" msgstr "Chronologies des abonnements" -#: ../src\controller\mainController.py:374 -#: ../src\controller\mainController.py:947 +#: ../src\controller\mainController.py:373 +#: ../src\controller\mainController.py:949 #: ../src\controller\mainController.py:1602 msgid "Friends for {}" msgstr "Abonnements de {}" -#: ../src\controller\mainController.py:377 ../src\wxUI\dialogs\lists.py:13 +#: ../src\controller\mainController.py:376 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Listes" -#: ../src\controller\mainController.py:382 +#: ../src\controller\mainController.py:381 #: ../src\controller\mainController.py:1432 msgid "List for {}" msgstr "Liste {}" -#: ../src\controller\mainController.py:385 +#: ../src\controller\mainController.py:384 msgid "Searches" msgstr "Recherches" -#: ../src\controller\mainController.py:389 -#: ../src\controller\mainController.py:448 +#: ../src\controller\mainController.py:388 +#: ../src\controller\mainController.py:447 msgid "Search for {}" msgstr "Recherche de {}" -#: ../src\controller\mainController.py:395 -#: ../src\controller\mainController.py:989 +#: ../src\controller\mainController.py:394 +#: ../src\controller\mainController.py:991 msgid "Trending topics for %s" msgstr "Tendances pour %s" -#: ../src\controller\mainController.py:465 -#: ../src\controller\mainController.py:481 +#: ../src\controller\mainController.py:464 +#: ../src\controller\mainController.py:480 #: ../src\controller\mainController.py:1089 #: ../src\controller\mainController.py:1108 #: ../src\controller\mainController.py:1127 @@ -290,55 +289,58 @@ msgstr "" "Aucune session n'a actuellement le focus. Sélectionnez-en une avec le " "raccourci pour la session précédente ou suivante." -#: ../src\controller\mainController.py:469 +#: ../src\controller\mainController.py:468 msgid "Empty buffer." msgstr "Tampon vide." -#: ../src\controller\mainController.py:476 +#: ../src\controller\mainController.py:475 msgid "{0} not found." msgstr "{0} introuvable." -#: ../src\controller\mainController.py:486 +#: ../src\controller\mainController.py:485 msgid "Filters cannot be applied on this buffer" msgstr "Les filtres ne peuvent pas s'appliquer à ce tampon" -#: ../src\controller\mainController.py:539 -#: ../src\controller\mainController.py:556 -#: ../src\controller\mainController.py:584 +#: ../src\controller\mainController.py:538 +#: ../src\controller\mainController.py:555 +#: ../src\controller\mainController.py:583 msgid "Select the user" msgstr "Sélectionnez l'utilisateur" -#: ../src\controller\mainController.py:768 +#: ../src\controller\mainController.py:767 msgid "Add an user alias" msgstr "Ajoute un alis pour l'utilisateur" -#: ../src\controller\mainController.py:776 +#: ../src\controller\mainController.py:775 msgid "Alias has been set correctly for {}." msgstr "L'alias pour {} a correctement été définie" -#: ../src\controller\mainController.py:839 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:838 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "D MMM YYYY à H:m" -#: ../src\controller\mainController.py:964 +#: ../src\controller\mainController.py:966 msgid "Conversation with {0}" msgstr "Conversation avec {0}" -#: ../src\controller\mainController.py:1005 +#: ../src\controller\mainController.py:1007 #: ../src\controller\mainController.py:1024 msgid "There are no coordinates in this tweet" msgstr "Il n'y a aucune coordonnée dans ce tweet" -#: ../src\controller\mainController.py:1007 -#: ../src\controller\mainController.py:1026 -msgid "There are no results for the coordinates in this tweet" -msgstr "Il n'y a aucun résultat pour les coordonnées dans ce tweet" - #: ../src\controller\mainController.py:1009 #: ../src\controller\mainController.py:1028 msgid "Error decoding coordinates. Try again later." msgstr "Erreur pendant le décodage des coordonnées. Réessayez plus tard." +#: ../src\controller\mainController.py:1013 +msgid "Unable to find address in OpenStreetMap." +msgstr "Impossible de trouver l'adresse dans OpenStreetMap" + +#: ../src\controller\mainController.py:1026 +msgid "There are no results for the coordinates in this tweet" +msgstr "Il n'y a aucun résultat pour les coordonnées dans ce tweet" + #: ../src\controller\mainController.py:1137 #: ../src\controller\mainController.py:1156 msgid "%s, %s of %s" @@ -468,6 +470,10 @@ msgstr "%s - %s caractères" msgid "View item" msgstr "Voir l'élément" +#: ../src\controller\messages.py:301 +msgid "Link copied to clipboard." +msgstr "Lien copié dans le Presse-papiers" + #: ../src\controller\settings.py:74 msgid "HTTP" msgstr "HTTP" @@ -1548,7 +1554,7 @@ msgid "New tweet" msgstr "Nouveau tweet" #: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 -#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:128 +#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 msgid "Retweet" msgstr "Retweet" @@ -1934,7 +1940,7 @@ msgstr "" "ou après la réactivation d'un compte. Veuillez supprimer manuellement ce " "compte depuis votre session Twitter pour ne plus voir ce message." -#: ../src\sessions\base.py:109 +#: ../src\sessions\base.py:111 msgid "" "An exception occurred while saving the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1944,7 +1950,7 @@ msgstr "" "{app}, elle va être détruite et recréée automatiquement. Si ce problème " "perciste, veuillez envoyer le journal d'erreur aux développeurs de {app}." -#: ../src\sessions\base.py:149 +#: ../src\sessions\base.py:151 msgid "" "An exception occurred while loading the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -2018,6 +2024,10 @@ msgstr "Aucun Tweet trouvée avec cet ID" msgid "Error code {0}" msgstr "Code d'erreur {0}" +#: ../src\sessions\twitter\utils.py:262 +msgid "{user_1}, {user_2} and {all_users} more: {text}" +msgstr "{user_1}, {user_2} et {all_users} de plus : {text}" + #: ../src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." msgstr "Compte en cours d'autorisation..." @@ -2384,14 +2394,14 @@ msgstr "&Image" msgid "Remove attachment" msgstr "Supprimer le fichier joint" -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:118 -#: ../src\wxUI\dialogs\message.py:177 ../src\wxUI\dialogs\message.py:237 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 #: ../src\wxUI\dialogs\update_profile.py:82 msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" msgstr "Fichiers image (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:118 -#: ../src\wxUI\dialogs\message.py:177 ../src\wxUI\dialogs\message.py:237 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 #: ../src\wxUI\dialogs\update_profile.py:82 msgid "Select the picture to be uploaded" msgstr "Sélectionnez la photo à charger" @@ -2840,96 +2850,100 @@ msgstr "Sélectionnez une liste pour supprimer l'utilisateur" msgid "Do you really want to delete this list?" msgstr "Voulez-vous vraiment supprimer cette liste ?" -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:256 +#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 msgid "&Long tweet" msgstr "&Tweet long" -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:257 +#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 +#: ../src\wxUI\dialogs\message.py:255 msgid "&Upload image..." msgstr "&Joindre une image..." -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:432 +#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 +#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 +#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 msgid "Check &spelling..." msgstr "Correction &orthographique..." -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 +#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 +#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 msgid "&Attach audio..." msgstr "&Joindre un audio..." -#: ../src\wxUI\dialogs\message.py:79 ../src\wxUI\dialogs\message.py:138 -#: ../src\wxUI\dialogs\message.py:198 ../src\wxUI\dialogs\message.py:260 +#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 +#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 msgid "Sh&orten URL" msgstr "&Réduire URL" -#: ../src\wxUI\dialogs\message.py:80 ../src\wxUI\dialogs\message.py:139 -#: ../src\wxUI\dialogs\message.py:199 ../src\wxUI\dialogs\message.py:261 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 +#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 +#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 +#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 msgid "&Expand URL" msgstr "&Élargir URL" -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:202 ../src\wxUI\dialogs\message.py:264 -#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:435 +#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 +#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 +#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 msgid "&Translate..." msgstr "&Traduire..." -#: ../src\wxUI\dialogs\message.py:84 ../src\wxUI\dialogs\message.py:143 -#: ../src\wxUI\dialogs\message.py:188 ../src\wxUI\dialogs\message.py:265 +#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 +#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 msgid "Auto&complete users" msgstr "Sai&sie automatique utilisateurs" -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 +#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 +#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 msgid "Sen&d" msgstr "Envoye&r" -#: ../src\wxUI\dialogs\message.py:87 ../src\wxUI\dialogs\message.py:146 -#: ../src\wxUI\dialogs\message.py:205 ../src\wxUI\dialogs\message.py:268 -#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:436 +#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 +#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 +#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 msgid "C&lose" msgstr "F&ermer" -#: ../src\wxUI\dialogs\message.py:186 +#: ../src\wxUI\dialogs\message.py:184 msgid "&Recipient" msgstr "&Destinataire" -#: ../src\wxUI\dialogs\message.py:247 +#: ../src\wxUI\dialogs\message.py:245 msgid "&Mention to all" msgstr "&Répondre à tout le monde" -#: ../src\wxUI\dialogs\message.py:301 +#: ../src\wxUI\dialogs\message.py:299 msgid "Tweet - %i characters " msgstr "Tweet - %i caractères " -#: ../src\wxUI\dialogs\message.py:318 +#: ../src\wxUI\dialogs\message.py:316 msgid "Image description" msgstr "Description de l'image" -#: ../src\wxUI\dialogs\message.py:329 +#: ../src\wxUI\dialogs\message.py:327 msgid "Retweets: " msgstr "Retweets: " -#: ../src\wxUI\dialogs\message.py:334 +#: ../src\wxUI\dialogs\message.py:332 msgid "Likes: " msgstr "Favoris: " -#: ../src\wxUI\dialogs\message.py:339 +#: ../src\wxUI\dialogs\message.py:337 msgid "Source: " msgstr "Source: " -#: ../src\wxUI\dialogs\message.py:344 ../src\wxUI\dialogs\message.py:422 +#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 msgid "Date: " msgstr "Date: " -#: ../src\wxUI\dialogs\message.py:407 +#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 +msgid "Copy link to clipboard" +msgstr "Copier le lien dans le Presse-papiers" + +#: ../src\wxUI\dialogs\message.py:408 msgid "View" msgstr "Voir" -#: ../src\wxUI\dialogs\message.py:409 +#: ../src\wxUI\dialogs\message.py:410 msgid "Item" msgstr "Élément" From 65512a9862d2eb9fd4f7b1732c528388b1dafa9b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 30 Aug 2021 10:51:26 -0500 Subject: [PATCH 139/245] Added a pubsub event to create sessions buffers --- src/controller/mainController.py | 130 +++++++++++++------------------ src/sessions/base.py | 2 + src/sessions/twitter/session.py | 1 + 3 files changed, 55 insertions(+), 78 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index a3df454d..59db9d5e 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -131,6 +131,7 @@ class Controller(object): pub.subscribe(self.manage_unfavourite, "unfavourite") pub.subscribe(self.manage_blocked_user, "blocked-user") pub.subscribe(self.manage_unblocked_user, "unblocked-user") + pub.subscribe(self.create_buffer, "createBuffer") if system == "Windows": pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed") widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide) @@ -292,6 +293,24 @@ class Controller(object): self.create_buffers(session, False) self.start_buffers(session) + def create_buffer(self, buffer_type="baseBuffer", session_type="twitter", buffer_title="", parent_tab=None, start=False, kwargs={}): + log.debug("Creating buffer of type {0} with parent_tab of {2} arguments {1}".format(buffer_type, kwargs, parent_tab)) + if not hasattr(buffers, session_type): + raise AttributeError("Session type %s does not exist yet." % (session_type)) + available_buffers = getattr(buffers, session_type) + if not hasattr(available_buffers, buffer_type): + raise AttributeError("Specified buffer type does not exist: %s" % (buffer_type,)) + buffer = getattr(available_buffers, buffer_type)(**kwargs) + self.buffers.append(buffer) + if parent_tab == None: + log.debug("Appending buffer {}...".format(buffer,)) + self.view.add_buffer(buffer.buffer, buffer_title) + else: + self.view.insert_buffer(buffer.buffer, buffer_title, parent_tab) + log.debug("Inserting buffer {0} into control {1}".format(buffer, parent_tab)) + if start: + call_threaded(buffer.get_items) + def create_buffers(self, session, createAccounts=True): """ Generates buffer objects for an user account. session SessionObject: a sessionmanager.session.Session Object""" @@ -302,96 +321,54 @@ class Controller(object): account.setup_account() self.buffers.append(account) self.view.add_buffer(account.buffer , name=session.db["user_name"]) + root_position =self.view.search(session.db["user_name"], session.db["user_name"]) for i in session.settings['general']['buffer_order']: if i == 'home': - home = buffers.twitter.BaseBuffer(self.view.nb, "home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended") - self.buffers.append(home) - self.view.insert_buffer(home.buffer, name=_(u"Home"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Home"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="home_timeline", name="home_timeline", sessionObject=session, account=session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended")) elif i == 'mentions': - mentions = buffers.twitter.BaseBuffer(self.view.nb, "mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended") - self.buffers.append(mentions) - self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Mentions"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="mentions_timeline", name="mentions", sessionObject=session, account=session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended")) elif i == 'dm': - dm = buffers.twitter.DirectMessagesBuffer(self.view.nb, "list_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg") - self.buffers.append(dm) - self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="DirectMessagesBuffer", session_type=session.type, buffer_title=_("Direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="list_direct_messages", name="direct_messages", sessionObject=session, account=session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg")) elif i == 'sent_dm': - sent_dm = buffers.twitter.SentDirectMessagesBuffer(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message") - self.buffers.append(sent_dm) - self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="SentDirectMessagesBuffer", session_type=session.type, buffer_title=_("Sent direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function=None, name="sent_direct_messages", sessionObject=session, account=session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message")) elif i == 'sent_tweets': - sent_tweets = buffers.twitter.BaseBuffer(self.view.nb, "user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended") - self.buffers.append(sent_tweets) - self.view.insert_buffer(sent_tweets.buffer, name=_(u"Sent tweets"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Sent tweets"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="user_timeline", name="sent_tweets", sessionObject=session, account=session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended")) elif i == 'favorites': - favourites = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended") - self.buffers.append(favourites) - self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="favorites", name="favourites", sessionObject=session, account=session.db["user_name"], sound="favourite.ogg", tweet_mode="extended")) elif i == 'followers': - followers = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"]) - self.buffers.append(followers) - self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="followers", name="followers", sessionObject=session, account=session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"])) elif i == 'friends': - friends = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "friends", session, session.db["user_name"], screen_name=session.db["user_name"]) - self.buffers.append(friends) - self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Following"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="friends", name="friends", sessionObject=session, account=session.db["user_name"], screen_name=session.db["user_name"])) elif i == 'blocks': - blocks = buffers.twitter.PeopleBuffer(self.view.nb, "blocks", "blocked", session, session.db["user_name"]) - self.buffers.append(blocks) - self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Blocked users"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="blocks", name="blocked", sessionObject=session, account=session.db["user_name"])) elif i == 'muted': - muted = buffers.twitter.PeopleBuffer(self.view.nb, "mutes", "muted", session, session.db["user_name"]) - self.buffers.append(muted) - self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) - timelines = buffers.base.EmptyBuffer(self.view.nb, "timelines", session.db["user_name"]) - self.buffers.append(timelines) - self.view.insert_buffer(timelines.buffer , name=_(u"Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Muted users"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="mutes", name="muted", sessionObject=session, account=session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="timelines", account=session.db["user_name"])) + timelines_position =self.view.search("timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["timelines"]: - tl = buffers.twitter.BaseBuffer(self.view.nb, "user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended") - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(i,), pos=self.view.search("timelines", session.db["user_name"])) - favs_timelines = buffers.base.EmptyBuffer(self.view.nb, "favs_timelines", session.db["user_name"]) - self.buffers.append(favs_timelines) - self.view.insert_buffer(favs_timelines.buffer , name=_(u"Likes timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_(u"Timeline for {}").format(i,), parent_tab=timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="user_timeline", name="%s-timeline" % (i,), sessionObject=session, account=session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Likes timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="favs_timelines", account=session.db["user_name"])) + favs_timelines_position =self.view.search("favs_timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["favourites_timelines"]: - tl = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended") - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Likes for {}").format(i,), pos=self.view.search("favs_timelines", session.db["user_name"])) - followers_timelines = buffers.base.EmptyBuffer(self.view.nb, "followers_timelines", session.db["user_name"]) - self.buffers.append(followers_timelines) - self.view.insert_buffer(followers_timelines.buffer , name=_(u"Followers' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes for {}").format(i,), parent_tab=favs_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="favorites", name="%s-favorite" % (i,), sessionObject=session, account=session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Followers timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="followers_timelines", account=session.db["user_name"])) + followers_timelines_position =self.view.search("followers_timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["followers_timelines"]: - tl = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Followers for {}").format(i,), pos=self.view.search("followers_timelines", session.db["user_name"])) - friends_timelines = buffers.base.EmptyBuffer(self.view.nb, "friends_timelines", session.db["user_name"]) - self.buffers.append(friends_timelines) - self.view.insert_buffer(friends_timelines.buffer , name=_(u"Friends' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers for {}").format(i,), parent_tab=followers_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="followers", name="%s-followers" % (i,), sessionObject=session, account=session.db["user_name"], sound="new_event.ogg", user_id=i)) + pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Following timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="friends_timelines", account=session.db["user_name"])) + friends_timelines_position =self.view.search("friends_timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["friends_timelines"]: - tl = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i) - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Friends for {}").format(i,), pos=self.view.search("friends_timelines", session.db["user_name"])) - lists = buffers.base.EmptyBuffer(self.view.nb, "lists", session.db["user_name"]) - self.buffers.append(lists) - self.view.insert_buffer(lists.buffer , name=_(u"Lists"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_(u"Friends for {}").format(i,), parent_tab=friends_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="friends", name="%s-friends" % (i,), sessionObject=session, account=session.db["user_name"], sound="new_event.ogg", user_id=i)) + pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Lists"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="lists", account=session.db["user_name"])) + lists_position =self.view.search("lists", session.db["user_name"]) for i in session.settings["other_buffers"]["lists"]: - tl = buffers.twitter.ListBuffer(self.view.nb, "list_timeline", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended") - session.lists.append(tl) - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(i), pos=self.view.search("lists", session.db["user_name"])) - searches = buffers.base.EmptyBuffer(self.view.nb, "searches", session.db["user_name"]) - self.buffers.append(searches) - self.view.insert_buffer(searches.buffer , name=_(u"Searches"), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="ListBuffer", session_type=session.type, buffer_title=_(u"List for {}").format(i), parent_tab=lists_position, start=False, kwargs=dict(parent=self.view.nb, function="list_timeline", name="%s-list" % (i,), sessionObject=session, account=session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Searches"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="searches", account=session.db["user_name"])) + searches_position =self.view.search("searches", session.db["user_name"]) for i in session.settings["other_buffers"]["tweet_searches"]: - tl = buffers.twitter.SearchBuffer(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended") - self.buffers.append(tl) - self.view.insert_buffer(tl.buffer, name=_(u"Search for {}").format(i), pos=self.view.search("searches", session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=session.type, buffer_title=_(u"Search for {}").format(i), parent_tab=searches_position, start=False, kwargs=dict(parent=self.view.nb, function="search", name="%s-searchterm" % (i,), sessionObject=session, account=session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended")) for i in session.settings["other_buffers"]["trending_topic_buffers"]: - buffer = buffers.twitter.TrendsBuffer(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg") - buffer.start_stream(play_sound=False) - buffer.searchfunction = self.search - self.buffers.append(buffer) - self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (buffer.name_), pos=self.view.search(session.db["user_name"], session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="TrendsBuffer", session_type=session.type, buffer_title=_("Trending topics for %s") % (buffer.name_), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="%s_tt" % (i,), sessionObject=session, account=session.db["user_name"], trendsFor=i, sound="trends_updated.ogg")) def set_buffer_positions(self, session): "Sets positions for buffers if values exist in the database." @@ -430,21 +407,18 @@ class Controller(object): if dlg.get_response() == widgetUtils.OK and dlg.get("term") != "": term = dlg.get("term") buffer = self.get_best_buffer() + searches_position =self.view.search("searches", buffer.session.db["user_name"]) if dlg.get("tweets") == True: if term not in buffer.session.settings["other_buffers"]["tweet_searches"]: buffer.session.settings["other_buffers"]["tweet_searches"].append(term) buffer.session.settings.write() args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()} - search = buffers.twitter.SearchBuffer(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args) + pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=buffer.session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=self.view.nb, function="search", name="%s-searchterm" % (term,), sessionObject=buffer.session, account=buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended")) else: log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) return elif dlg.get("users") == True: - search = buffers.twitter.SearchPeopleBuffer(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term) - search.start_stream(mandatory=True) - pos=self.view.search("searches", buffer.session.db["user_name"]) - self.insert_buffer(search, pos) - self.view.insert_buffer(search.buffer, name=_(u"Search for {}").format(term), pos=pos) + pub.sendMessage("createBuffer", buffer_type="SearchPeopleBuffer", session_type=buffer.session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=self.view.nb, function="search_users", name="%s-searchUser" % (term,), sessionObject=buffer.session, account=buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term)) dlg.Destroy() def find(self, *args, **kwargs): diff --git a/src/sessions/base.py b/src/sessions/base.py index 9833edd1..84270257 100644 --- a/src/sessions/base.py +++ b/src/sessions/base.py @@ -45,6 +45,8 @@ class baseSession(object): self.db={} # Config specification file. self.config_spec = "conf.defaults" + # Session type. + self.type = "base" @property def is_logged(self): diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 45089a23..548c9b74 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -124,6 +124,7 @@ class Session(base.baseSession): # This will be especially useful because if the user reactivates their account later, TWblue will try to retrieve such user again at startup. # If we wouldn't implement this approach, TWBlue would save permanently the "deleted user" object. self.deleted_users = {} + self.type = "twitter" pub.subscribe(self.handle_new_status, "newStatus") pub.subscribe(self.handle_connected, "streamConnected") From c7b6d6951810594b82d2b3d77b90837441b0cc89 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 30 Aug 2021 13:19:15 -0500 Subject: [PATCH 140/245] Fixed an error in new buffer creation. Closes #396 --- src/controller/mainController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 59db9d5e..f3fc8871 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -309,7 +309,7 @@ class Controller(object): self.view.insert_buffer(buffer.buffer, buffer_title, parent_tab) log.debug("Inserting buffer {0} into control {1}".format(buffer, parent_tab)) if start: - call_threaded(buffer.get_items) + call_threaded(buffer.start_stream) def create_buffers(self, session, createAccounts=True): """ Generates buffer objects for an user account. From a9a41892958157455f0c06b4aff7e4cb9705a7d2 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 31 Aug 2021 10:05:21 -0500 Subject: [PATCH 141/245] Added improvements to tweet condense feature --- src/sessions/twitter/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 05c4c52c..8436b79c 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -254,10 +254,10 @@ def clean_mentions(text): total_users = 0 for user in mentionned_people: if abs(user.start()-end) < 3: - new_text = new_text.replace(user.group(0), "") + new_text = new_text.replace(user.group(0), "", 1) total_users = total_users+1 end = user.end() - if total_users < 1: + if total_users-2 < 1: return text new_text = _("{user_1}, {user_2} and {all_users} more: {text}").format(user_1=mentionned_people[0].group(0), user_2=mentionned_people[1].group(0), all_users=total_users-2, text=new_text) return new_text \ No newline at end of file From 4cabf5b9cd656e07e2a9a39444bbf3a10ee7bfff Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 31 Aug 2021 10:31:18 -0500 Subject: [PATCH 142/245] Added code to handle user timelines in buffer creator --- src/controller/mainController.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index f3fc8871..e3227448 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -301,6 +301,15 @@ class Controller(object): if not hasattr(available_buffers, buffer_type): raise AttributeError("Specified buffer type does not exist: %s" % (buffer_type,)) buffer = getattr(available_buffers, buffer_type)(**kwargs) + if start: + if kwargs.get("function") == "user_timeline": + try: + buffer.start_stream(play_sound=False) + except ValueError: + commonMessageDialogs.unauthorized() + return + else: + call_threaded(buffer.start_stream) self.buffers.append(buffer) if parent_tab == None: log.debug("Appending buffer {}...".format(buffer,)) @@ -308,8 +317,6 @@ class Controller(object): else: self.view.insert_buffer(buffer.buffer, buffer_title, parent_tab) log.debug("Inserting buffer {0} into control {1}".format(buffer, parent_tab)) - if start: - call_threaded(buffer.start_stream) def create_buffers(self, session, createAccounts=True): """ Generates buffer objects for an user account. From 4bcae1aa97654cb2b627d987224a983fc023c8cb Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 2 Sep 2021 09:38:05 -0500 Subject: [PATCH 143/245] Fixed search filters. Closes #397 --- src/controller/mainController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index e3227448..bf99dad3 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -420,7 +420,7 @@ class Controller(object): buffer.session.settings["other_buffers"]["tweet_searches"].append(term) buffer.session.settings.write() args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()} - pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=buffer.session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=self.view.nb, function="search", name="%s-searchterm" % (term,), sessionObject=buffer.session, account=buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=buffer.session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=self.view.nb, function="search", name="%s-searchterm" % (term,), sessionObject=buffer.session, account=buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args)) else: log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) return From fbe93ea4bedfbb0f3459adef944fd4d3a4a8adcf Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 2 Sep 2021 09:59:13 -0500 Subject: [PATCH 144/245] Made FreakyBlue The default soundpack for new twitter sessions --- doc/changelog.md | 1 + src/Conf.defaults | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog.md b/doc/changelog.md index fc178196..428a2174 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* After a lot of time, TWBlue now uses a new default Soundpack, called FreakyBlue. This soundpack will be set by default in all new sessions created in the application. Thanks to [Andre Louis](https://twitter.com/FreakyFwoof) for the pack. ([#247](https://github.com/manuelcortez/TWBlue/issues/247)) * When reading a tweet, if the tweet contains more than 2 consecutive mentions, TWBlue will announce how many more users the tweet includes, as opposed to read every user in the conversation. You still can display the tweet to read all users. * In the tweet displayer, It is possible to copy a link to the current tweet or person by pressing a button called "copy link to clipboard". * Added a keymap capable to work under Windows 11. ([#391](https://github.com/manuelcortez/TWBlue/pull/391)) diff --git a/src/Conf.defaults b/src/Conf.defaults index a723b767..a2b3760a 100644 --- a/src/Conf.defaults +++ b/src/Conf.defaults @@ -21,7 +21,7 @@ volume = float(default=1.0) input_device = string(default="Default") output_device = string(default="Default") session_mute = boolean(default=False) -current_soundpack = string(default="default") +current_soundpack = string(default="FreakyBlue") indicate_audio = boolean(default=True) indicate_geo = boolean(default=True) indicate_img = boolean(default=True) From dfdbe3c5f422299dbdc0f3393962a71a25e96daf Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 10 Sep 2021 15:05:05 -0500 Subject: [PATCH 145/245] Close VLC window after video playback ends. Close #399 --- doc/changelog.md | 1 + src/sound.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/doc/changelog.md b/doc/changelog.md index 428a2174..3b8931e7 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* TWBlue now closes the VLC player window automatically when a video reaches its end. ([#399](https://github.com/manuelcortez/TWBlue/issues/399)) * After a lot of time, TWBlue now uses a new default Soundpack, called FreakyBlue. This soundpack will be set by default in all new sessions created in the application. Thanks to [Andre Louis](https://twitter.com/FreakyFwoof) for the pack. ([#247](https://github.com/manuelcortez/TWBlue/issues/247)) * When reading a tweet, if the tweet contains more than 2 consecutive mentions, TWBlue will announce how many more users the tweet includes, as opposed to read every user in the conversation. You still can display the tweet to read all users. * In the tweet displayer, It is possible to copy a link to the current tweet or person by pressing a button called "copy link to clipboard". diff --git a/src/sound.py b/src/sound.py index 1cd8ad78..df47f221 100644 --- a/src/sound.py +++ b/src/sound.py @@ -114,6 +114,8 @@ class URLStream(object): # LibVLC controls. self.instance = vlc.Instance() self.player = self.instance.media_player_new() + self.event_manager = self.player.event_manager() + self.event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, self.end_callback) def prepare(self, url): """ Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL.""" @@ -158,3 +160,9 @@ class URLStream(object): def stop_audio(self): output.speak(_(u"Stopped."), True) self.player.stop() + + def end_callback(self, event, *args, **kwargs): + call_threaded(self.player.stop) + + def __del__(self): + self.event_manager.event_detach(vlc.EventType.MediaPlayerEndReached) \ No newline at end of file From d8fca3b31afb4c0c8f81d738ea00d182eb5ecbc6 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 26 Sep 2021 03:58:25 -0500 Subject: [PATCH 146/245] Initial work to Support Tweepy 4 --- src/controller/buffers/twitter/base.py | 14 ++-- .../buffers/twitter/directMessages.py | 4 +- src/controller/buffers/twitter/list.py | 2 +- src/controller/buffers/twitter/people.py | 6 +- src/controller/buffers/twitter/trends.py | 12 +-- src/controller/listsController.py | 12 +-- src/controller/mainController.py | 58 ++++++------- src/controller/trendingTopics.py | 2 +- src/controller/user.py | 10 +-- src/controller/userActionsController.py | 16 ++-- src/sessionmanager/sessionManager.py | 4 +- src/sessions/twitter/session.py | 23 +++--- src/sessions/twitter/streaming.py | 81 +------------------ src/sessions/twitter/utils.py | 4 +- src/wxUI/dialogs/__init__.py | 2 +- src/wxUI/dialogs/userAliasDialogs.py | 36 +++++++++ src/wxUI/dialogs/utils.py | 36 +-------- 17 files changed, 124 insertions(+), 198 deletions(-) create mode 100644 src/wxUI/dialogs/userAliasDialogs.py diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index fa872844..275ac77f 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -21,7 +21,7 @@ from audio_services import youtube_utils from controller.buffers.base import base from sessions.twitter import compose, utils, reduce from mysc.thread_utils import call_threaded -from tweepy.error import TweepError +from tweepy.errors import TweepyException from tweepy.cursor import Cursor from pubsub import pub from sessions.twitter.long_tweets import twishort, tweets @@ -140,7 +140,7 @@ class BaseBuffer(base.Buffer): try: tweet = self.session.twitter.get_status(id=tweet_id, include_ext_alt_text=True, tweet_mode="extended") tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities) - except TweepError as e: + except TweepyException as e: utils.twitter_error(e) return if message != None: @@ -151,7 +151,7 @@ class BaseBuffer(base.Buffer): try: tweet = self.session.twitter.get_status(id=l, include_ext_alt_text=True, tweet_mode="extended") tweet.full_text = utils.expand_urls(tweet.full_text, tweet.entities) - except TweepError as e: + except TweepyException as e: utils.twitter_error(e) return l = tweets.is_long(tweet) @@ -191,7 +191,7 @@ class BaseBuffer(base.Buffer): log.debug("Retrieved %d items from the cursored search on function %s." %(len(val), self.function)) user_ids = [item.message_create["sender_id"] for item in val] self.session.save_users(user_ids) - except TweepError as e: + except TweepyException as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return number_of_items = self.session.order_buffer(self.name, val) @@ -229,7 +229,7 @@ class BaseBuffer(base.Buffer): last_id = self.session.db[self.name][-1].id try: items = getattr(self.session.twitter, self.function)(max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) - except TweepError as e: + except TweepyException as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return if items == None: @@ -611,13 +611,13 @@ class BaseBuffer(base.Buffer): items = self.session.db[self.name] try: if self.name == "direct_messages" or self.name == "sent_direct_messages": - self.session.twitter.destroy_direct_message(id=self.get_right_tweet().id) + self.session.twitter.delete_direct_message(id=self.get_right_tweet().id) items.pop(index) else: self.session.twitter.destroy_status(id=self.get_right_tweet().id) items.pop(index) self.buffer.list.remove_item(index) - except TweepError: + except TweepyException: self.session.sound.play("error.ogg") self.session.db[self.name] = items diff --git a/src/controller/buffers/twitter/directMessages.py b/src/controller/buffers/twitter/directMessages.py index d5e556b6..d5ba86ea 100644 --- a/src/controller/buffers/twitter/directMessages.py +++ b/src/controller/buffers/twitter/directMessages.py @@ -10,7 +10,7 @@ import logging from controller import messages from sessions.twitter import compose, utils from mysc.thread_utils import call_threaded -from tweepy.error import TweepError +from tweepy.errors import TweepyException from pubsub import pub from . import base @@ -40,7 +40,7 @@ class DirectMessagesBuffer(base.BaseBuffer): results = [i for i in items] items = results log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) - except TweepError as e: + except TweepyException as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return if items == None: diff --git a/src/controller/buffers/twitter/list.py b/src/controller/buffers/twitter/list.py index 766c34fb..a1153e6a 100644 --- a/src/controller/buffers/twitter/list.py +++ b/src/controller/buffers/twitter/list.py @@ -24,7 +24,7 @@ class ListBuffer(base.BaseBuffer): super(ListBuffer, self).start_stream(mandatory, play_sound, avoid_autoreading) def get_user_ids(self): - for i in Cursor(self.session.twitter.list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): + for i in Cursor(self.session.twitter.get_list_members, list_id=self.list_id, include_entities=False, skip_status=True, count=5000).items(): if i.id not in self.users: self.users.append(i.id) diff --git a/src/controller/buffers/twitter/people.py b/src/controller/buffers/twitter/people.py index eae6c718..2cf33867 100644 --- a/src/controller/buffers/twitter/people.py +++ b/src/controller/buffers/twitter/people.py @@ -14,7 +14,7 @@ import output import config import logging from mysc.thread_utils import call_threaded -from tweepy.error import TweepError +from tweepy.errors import TweepyException from pubsub import pub from sessions.twitter import compose from . import base @@ -125,7 +125,7 @@ class PeopleBuffer(base.BaseBuffer): val = results val.reverse() log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) - except TweepError as e: + except TweepyException as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return number_of_items = self.session.order_people(self.name, val) @@ -155,7 +155,7 @@ class PeopleBuffer(base.BaseBuffer): results = [i for i in items] items = results log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) - except TweepError as e: + except TweepyException as e: log.error("Error %s: %s" % (e.api_code, e.reason)) return if items == None: diff --git a/src/controller/buffers/twitter/trends.py b/src/controller/buffers/twitter/trends.py index 23049818..d7b913c3 100644 --- a/src/controller/buffers/twitter/trends.py +++ b/src/controller/buffers/twitter/trends.py @@ -13,17 +13,17 @@ import widgetUtils import output import logging from mysc.thread_utils import call_threaded -from tweepy.error import TweepError +from tweepy.errors import TweepyException from pubsub import pub from controller.buffers import base log = logging.getLogger("controller.buffers.twitter.trends") class TrendsBuffer(base.Buffer): - def __init__(self, parent, name, session, account, trendsFor, *args, **kwargs): - super(TrendsBuffer, self).__init__(parent=parent, session=session) + def __init__(self, parent, name, sessionObject, account, trendsFor, *args, **kwargs): + super(TrendsBuffer, self).__init__(parent=parent, sessionObject=sessionObject) self.trendsFor = trendsFor - self.session = session + self.session = sessionObject self.account = account self.invisible = True self.buffer = buffers.trendsPanel(parent, name) @@ -44,8 +44,8 @@ class TrendsBuffer(base.Buffer): if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: self.execution_time = current_time try: - data = self.session.twitter.trends_place(id=self.trendsFor) - except TweepError as err: + data = self.session.twitter.get_place_trends(id=self.trendsFor) + except TweepyException as err: log.error("Error %s: %s" % (err.api_code, err.reason)) if not hasattr(self, "name_"): self.name_ = data[0]["locations"][0]["name"] diff --git a/src/controller/listsController.py b/src/controller/listsController.py index b1d49249..509a09a7 100644 --- a/src/controller/listsController.py +++ b/src/controller/listsController.py @@ -3,7 +3,7 @@ import widgetUtils import output import logging from wxUI.dialogs import lists -from tweepy.error import TweepError +from tweepy.errors import TweepyException from sessions.twitter import compose, utils from pubsub import pub @@ -49,7 +49,7 @@ class listsController(object): new_list = self.session.twitter.create_list(name=name, description=description, mode=mode) self.session.db["lists"].append(new_list) self.dialog.lista.insert_item(False, *compose.compose_list(new_list)) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) log.exception("error %s: %s" % (e.api_code, e.reason)) dialog.destroy() @@ -70,7 +70,7 @@ class listsController(object): self.session.twitter.update_list(list_id=list.id, name=name, description=description, mode=mode) self.session.get_lists() self.dialog.populate_list(self.get_all_lists(), True) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) dialog.destroy() @@ -82,7 +82,7 @@ class listsController(object): self.session.twitter.destroy_list(list_id=list) self.session.db["lists"].pop(self.dialog.get_item()) self.dialog.lista.remove_item(self.dialog.get_item()) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) def open_list_as_buffer(self, *args, **kwargs): @@ -97,7 +97,7 @@ class listsController(object): list = self.session.twitter.subscribe_list(list_id=list_id) item = utils.find_item(list.id, self.session.db["lists"]) self.session.db["lists"].append(list) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) def unsubscribe(self, *args, **kwargs): @@ -106,5 +106,5 @@ class listsController(object): try: list = self.session.twitter.unsubscribe_list(list_id=list_id) self.session.db["lists"].remove(list) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index bf99dad3..9ee76ffa 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -29,7 +29,7 @@ from sessions.twitter import session as session_ from pubsub import pub import sound import output -from tweepy.error import TweepError +from tweepy.errors import TweepyException from mysc.thread_utils import call_threaded from mysc.repeating_timer import RepeatingTimer from mysc import restart @@ -335,21 +335,21 @@ class Controller(object): elif i == 'mentions': pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Mentions"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="mentions_timeline", name="mentions", sessionObject=session, account=session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended")) elif i == 'dm': - pub.sendMessage("createBuffer", buffer_type="DirectMessagesBuffer", session_type=session.type, buffer_title=_("Direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="list_direct_messages", name="direct_messages", sessionObject=session, account=session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg")) + pub.sendMessage("createBuffer", buffer_type="DirectMessagesBuffer", session_type=session.type, buffer_title=_("Direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="get_direct_messages", name="direct_messages", sessionObject=session, account=session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg")) elif i == 'sent_dm': pub.sendMessage("createBuffer", buffer_type="SentDirectMessagesBuffer", session_type=session.type, buffer_title=_("Sent direct messages"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function=None, name="sent_direct_messages", sessionObject=session, account=session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message")) elif i == 'sent_tweets': pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Sent tweets"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="user_timeline", name="sent_tweets", sessionObject=session, account=session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended")) elif i == 'favorites': - pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="favorites", name="favourites", sessionObject=session, account=session.db["user_name"], sound="favourite.ogg", tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="get_favorites", name="favourites", sessionObject=session, account=session.db["user_name"], sound="favourite.ogg", tweet_mode="extended")) elif i == 'followers': - pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="followers", name="followers", sessionObject=session, account=session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="get_followers", name="followers", sessionObject=session, account=session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"])) elif i == 'friends': - pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Following"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="friends", name="friends", sessionObject=session, account=session.db["user_name"], screen_name=session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Following"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="get_friends", name="friends", sessionObject=session, account=session.db["user_name"], screen_name=session.db["user_name"])) elif i == 'blocks': - pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Blocked users"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="blocks", name="blocked", sessionObject=session, account=session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Blocked users"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="get_blocks", name="blocked", sessionObject=session, account=session.db["user_name"])) elif i == 'muted': - pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Muted users"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="mutes", name="muted", sessionObject=session, account=session.db["user_name"])) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Muted users"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, function="get_mutes", name="muted", sessionObject=session, account=session.db["user_name"])) pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="timelines", account=session.db["user_name"])) timelines_position =self.view.search("timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["timelines"]: @@ -357,15 +357,15 @@ class Controller(object): pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Likes timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="favs_timelines", account=session.db["user_name"])) favs_timelines_position =self.view.search("favs_timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["favourites_timelines"]: - pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes for {}").format(i,), parent_tab=favs_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="favorites", name="%s-favorite" % (i,), sessionObject=session, account=session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="BaseBuffer", session_type=session.type, buffer_title=_("Likes for {}").format(i,), parent_tab=favs_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="get_favorites", name="%s-favorite" % (i,), sessionObject=session, account=session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended")) pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Followers timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="followers_timelines", account=session.db["user_name"])) followers_timelines_position =self.view.search("followers_timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["followers_timelines"]: - pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers for {}").format(i,), parent_tab=followers_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="followers", name="%s-followers" % (i,), sessionObject=session, account=session.db["user_name"], sound="new_event.ogg", user_id=i)) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_("Followers for {}").format(i,), parent_tab=followers_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="get_followers", name="%s-followers" % (i,), sessionObject=session, account=session.db["user_name"], sound="new_event.ogg", user_id=i)) pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Following timelines"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="friends_timelines", account=session.db["user_name"])) friends_timelines_position =self.view.search("friends_timelines", session.db["user_name"]) for i in session.settings["other_buffers"]["friends_timelines"]: - pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_(u"Friends for {}").format(i,), parent_tab=friends_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="friends", name="%s-friends" % (i,), sessionObject=session, account=session.db["user_name"], sound="new_event.ogg", user_id=i)) + pub.sendMessage("createBuffer", buffer_type="PeopleBuffer", session_type=session.type, buffer_title=_(u"Friends for {}").format(i,), parent_tab=friends_timelines_position, start=False, kwargs=dict(parent=self.view.nb, function="get_friends", name="%s-friends" % (i,), sessionObject=session, account=session.db["user_name"], sound="new_event.ogg", user_id=i)) pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Lists"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="lists", account=session.db["user_name"])) lists_position =self.view.search("lists", session.db["user_name"]) for i in session.settings["other_buffers"]["lists"]: @@ -373,9 +373,9 @@ class Controller(object): pub.sendMessage("createBuffer", buffer_type="EmptyBuffer", session_type="base", buffer_title=_("Searches"), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="searches", account=session.db["user_name"])) searches_position =self.view.search("searches", session.db["user_name"]) for i in session.settings["other_buffers"]["tweet_searches"]: - pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=session.type, buffer_title=_(u"Search for {}").format(i), parent_tab=searches_position, start=False, kwargs=dict(parent=self.view.nb, function="search", name="%s-searchterm" % (i,), sessionObject=session, account=session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended")) + pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=session.type, buffer_title=_(u"Search for {}").format(i), parent_tab=searches_position, start=False, kwargs=dict(parent=self.view.nb, function="search_tweets", name="%s-searchterm" % (i,), sessionObject=session, account=session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended")) for i in session.settings["other_buffers"]["trending_topic_buffers"]: - pub.sendMessage("createBuffer", buffer_type="TrendsBuffer", session_type=session.type, buffer_title=_("Trending topics for %s") % (buffer.name_), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="%s_tt" % (i,), sessionObject=session, account=session.db["user_name"], trendsFor=i, sound="trends_updated.ogg")) + pub.sendMessage("createBuffer", buffer_type="TrendsBuffer", session_type=session.type, buffer_title=_("Trending topics for %s") % (i), parent_tab=root_position, start=False, kwargs=dict(parent=self.view.nb, name="%s_tt" % (i,), sessionObject=session, account=session.db["user_name"], trendsFor=i, sound="trends_updated.ogg")) def set_buffer_positions(self, session): "Sets positions for buffers if values exist in the database." @@ -420,7 +420,7 @@ class Controller(object): buffer.session.settings["other_buffers"]["tweet_searches"].append(term) buffer.session.settings.write() args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()} - pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=buffer.session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=self.view.nb, function="search", name="%s-searchterm" % (term,), sessionObject=buffer.session, account=buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args)) + pub.sendMessage("createBuffer", buffer_type="SearchBuffer", session_type=buffer.session.type, buffer_title=_("Search for {}").format(term), parent_tab=searches_position, start=True, kwargs=dict(parent=self.view.nb, function="search_tweets", name="%s-searchterm" % (term,), sessionObject=buffer.session, account=buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args)) else: log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,)) return @@ -548,7 +548,7 @@ class Controller(object): if listBuffer != None: listBuffer.get_user_ids() buff.session.db["lists"].pop(older_list) buff.session.db["lists"].append(list) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) def remove_from_list(self, *args, **kwargs): @@ -576,7 +576,7 @@ class Controller(object): if listBuffer != None: listBuffer.get_user_ids() buff.session.db["lists"].pop(older_list) buff.session.db["lists"].append(list) - except TweepError as e: + except TweepyException as e: output.speak("error %s: %s" % (e.api_code, e.reason)) def list_manager(self, *args, **kwargs): @@ -745,7 +745,7 @@ class Controller(object): users = [buff.session.get_user(tweet.message_create["sender_id"]).screen_name] else: users = utils.get_all_users(tweet, buff.session) - dlg = dialogs.utils.addAliasDialog(_("Add an user alias"), users) + dlg = dialogs.userAliasDialogs.addAliasDialog(_("Add an user alias"), users) if dlg.get_response() == widgetUtils.OK: user, alias = dlg.get_user() if user == "" or alias == "": @@ -881,7 +881,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["favourites_timelines"]: commonMessageDialogs.timeline_exist() return - tl = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "%s-favorite" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, tweet_mode="extended") + tl = buffers.twitter.BaseBuffer(self.view.nb, "get_favorites", "%s-favorite" % (usr.id_str,), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr.id_str, tweet_mode="extended") try: tl.start_stream(play_sound=False) except ValueError: @@ -900,7 +900,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["followers_timelines"]: commonMessageDialogs.timeline_exist() return - tl = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "%s-followers" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) + tl = buffers.twitter.PeopleBuffer(self.view.nb, "get_followers", "%s-followers" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) try: tl.start_stream(play_sound=False) except ValueError: @@ -919,7 +919,7 @@ class Controller(object): if usr.id_str in buff.session.settings["other_buffers"]["friends_timelines"]: commonMessageDialogs.timeline_exist() return - tl = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "%s-friends" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) + tl = buffers.twitter.PeopleBuffer(self.view.nb, "get_friends", "%s-friends" % (usr.id_str,), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr.id_str) try: tl.start_stream(play_sound=False) except ValueError: @@ -939,7 +939,7 @@ class Controller(object): buffer = self.get_current_buffer() id = buffer.get_right_tweet().id user = buffer.session.get_user(buffer.get_right_tweet().user).screen_name - search = buffers.twitter.ConversationBuffer(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) + search = buffers.twitter.ConversationBuffer(self.view.nb, "search_tweets", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,)) search.tweet = buffer.get_right_tweet() search.start_stream(start=True) pos=self.view.search("searches", buffer.session.db["user_name"]) @@ -1341,7 +1341,7 @@ class Controller(object): i.start_stream() else: i.start_stream(play_sound=False) - except TweepError as err: + except TweepyException as err: log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) # Determine if this error was caused by a block applied to the current user (IE permission errors). errors_allowed = [130] @@ -1369,34 +1369,34 @@ class Controller(object): try: if sessions.sessions[i].is_logged == False: continue sessions.sessions[i].check_connection() - except TweepError: # We shouldn't allow this function to die. + except TweepyException: # We shouldn't allow this function to die. pass def create_new_buffer(self, buffer, account, create): buff = self.search_buffer("home_timeline", account) if create == True: if buffer == "favourites": - favourites = buffers.twitter.BaseBuffer(self.view.nb, "favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended") + favourites = buffers.twitter.BaseBuffer(self.view.nb, "get_favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended") self.buffers.append(favourites) self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) favourites.start_stream(play_sound=False) if buffer == "followers": - followers = buffers.twitter.PeopleBuffer(self.view.nb, "followers", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) + followers = buffers.twitter.PeopleBuffer(self.view.nb, "get_followers", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) self.buffers.append(followers) self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) followers.start_stream(play_sound=False) elif buffer == "friends": - friends = buffers.twitter.PeopleBuffer(self.view.nb, "friends", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) + friends = buffers.twitter.PeopleBuffer(self.view.nb, "get_friends", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"]) self.buffers.append(friends) self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) friends.start_stream(play_sound=False) elif buffer == "blocked": - blocks = buffers.twitter.PeopleBuffer(self.view.nb, "blocks", "blocked", buff.session, buff.session.db["user_name"]) + blocks = buffers.twitter.PeopleBuffer(self.view.nb, "get_blocks", "blocked", buff.session, buff.session.db["user_name"]) self.buffers.append(blocks) self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) blocks.start_stream(play_sound=False) elif buffer == "muted": - muted = buffers.twitter.PeopleBuffer(self.view.nb, "mutes", "muted", buff.session, buff.session.db["user_name"]) + muted = buffers.twitter.PeopleBuffer(self.view.nb, "get_mutes", "muted", buff.session, buff.session.db["user_name"]) self.buffers.append(muted) self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])) muted.start_stream(play_sound=False) @@ -1547,7 +1547,7 @@ class Controller(object): if i.session != None and i.session.is_logged == True: try: i.start_stream(mandatory=True) - except TweepError as err: + except TweepyException as err: log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) # Determine if this error was caused by a block applied to the current user (IE permission errors). errors_allowed = [130] @@ -1657,5 +1657,5 @@ class Controller(object): try: if sessions.sessions[i].is_logged == False: continue sessions.sessions[i].check_streams() - except TweepError: # We shouldn't allow this function to die. + except TweepyException: # We shouldn't allow this function to die. pass diff --git a/src/controller/trendingTopics.py b/src/controller/trendingTopics.py index 58234204..e61032b8 100644 --- a/src/controller/trendingTopics.py +++ b/src/controller/trendingTopics.py @@ -8,7 +8,7 @@ class trendingTopicsController(object): self.countries = {} self.cities = {} self.dialog = trends.trendingTopicsDialog() - self.information = session.twitter.trends_available() + self.information = session.twitter.available_trends() self.split_information() widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places) widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places) diff --git a/src/controller/user.py b/src/controller/user.py index f48346e6..14fd96cd 100644 --- a/src/controller/user.py +++ b/src/controller/user.py @@ -6,7 +6,7 @@ import output from wxUI.dialogs import update_profile, show_user import logging log = logging.getLogger("controller.user") -from tweepy.error import TweepError +from tweepy.errors import TweepyException from sessions.twitter import utils class profileController(object): @@ -24,7 +24,7 @@ class profileController(object): else: try: self.get_data(screen_name=self.user) - except TweepError as err: + except TweepyException as err: if err.api_code == 50: wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() if err.api_code == 63: @@ -44,7 +44,7 @@ class profileController(object): def get_data(self, screen_name): self.data = self.session.twitter.get_user(screen_name=screen_name) if screen_name != self.session.db["user_name"]: - self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name) + self.friendship_status = self.session.twitter.get_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name) def fill_profile_fields(self): self.dialog.set_name(self.data.name) @@ -83,11 +83,11 @@ class profileController(object): if self.file != None: try: self.session.twitter.update_profile_image(image=self.file) - except TweepError as e: + except TweepyException as e: output.speak(u"Error %s. %s" % (e.api_code, e.reason)) try: self.session.twitter.update_profile(name=name, description=description, location=location, url=url) - except TweepError as e: + except TweepyException as e: output.speak(u"Error %s. %s" % (e.api_code, e.reason)) def get_user_info(self): diff --git a/src/controller/userActionsController.py b/src/controller/userActionsController.py index 623dc818..0b7cbb58 100644 --- a/src/controller/userActionsController.py +++ b/src/controller/userActionsController.py @@ -3,7 +3,7 @@ import widgetUtils import output from wxUI.dialogs import userActions from pubsub import pub -from tweepy.error import TweepError +from tweepy.errors import TweepyException from extra import autocompletionUsers class userActionsController(object): @@ -29,43 +29,43 @@ class userActionsController(object): def follow(self, user): try: self.session.twitter.create_friendship(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def unfollow(self, user): try: id = self.session.twitter.destroy_friendship(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def mute(self, user): try: id = self.session.twitter.create_mute(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def unmute(self, user): try: id = self.session.twitter.destroy_mute(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def report(self, user): try: id = self.session.twitter.report_spam(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def block(self, user): try: id = self.session.twitter.create_block(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def unblock(self, user): try: id = self.session.twitter.destroy_block(screen_name=user ) - except TweepError as err: + except TweepyException as err: output.speak("Error %s: %s" % (err.api_code, err.reason), True) def ignore_client(self, user): diff --git a/src/sessionmanager/sessionManager.py b/src/sessionmanager/sessionManager.py index e81892c8..d4255862 100644 --- a/src/sessionmanager/sessionManager.py +++ b/src/sessionmanager/sessionManager.py @@ -17,7 +17,7 @@ from sessions.twitter import session from . import manager import config_utils import config -from tweepy.error import TweepError +from tweepy.errors import TweepyException log = logging.getLogger("sessionmanager.sessionManager") class sessionManagerController(object): @@ -83,7 +83,7 @@ class sessionManagerController(object): if i not in config.app["sessions"]["ignored_sessions"]: try: s.login() - except TweepError: + except TweepyException: self.show_auth_error(s.settings["twitter"]["user_name"]) continue sessions.sessions[i] = s diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 548c9b74..1407d632 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -10,7 +10,7 @@ import output import application from pubsub import pub import tweepy -from tweepy.error import TweepError +from tweepy.errors import TweepyException from tweepy.models import User as UserModel from mysc.thread_utils import call_threaded from keys import keyring @@ -199,7 +199,7 @@ class Session(base.baseSession): try: val = getattr(self.twitter, call_name)(*args, **kwargs) finished = True - except TweepError as e: + except TweepyException as e: output.speak(e.reason) val = None if e.error_code != 403 and e.error_code != 404: @@ -218,7 +218,7 @@ class Session(base.baseSession): def search(self, name, *args, **kwargs): """ Search in twitter, passing args and kwargs as arguments to the Twython function.""" - tl = self.twitter.search(*args, **kwargs) + tl = self.twitter.search_tweets(*args, **kwargs) tl.reverse() return tl @@ -271,12 +271,12 @@ class Session(base.baseSession): # @_require_login def get_lists(self): """ Gets the lists that the user is subscribed to and stores them in the database. Returns None.""" - self.db["lists"] = self.twitter.lists_all(reverse=True) + self.db["lists"] = self.twitter.get_lists(reverse=True) # @_require_login def get_muted_users(self): """ Gets muted users (oh really?).""" - self.db["muted_users"] = self.twitter.mutes_ids() + self.db["muted_users"] = self.twitter.get_muted_ids() # @_require_login def get_stream(self, name, function, *args, **kwargs): @@ -417,7 +417,7 @@ class Session(base.baseSession): log.debug("Requesting user id {} as it is not present in the users database.".format(id)) try: user = self.twitter.get_user(id=id) - except TweepError as err: + except TweepyException as err: user = UserModel(None) user.screen_name = "deleted_user" user.id = id @@ -483,13 +483,13 @@ class Session(base.baseSession): return log.debug("TWBlue will get %d new users from Twitter." % (len(users_to_retrieve))) try: - users = self.twitter.lookup_users(user_ids=users_to_retrieve, tweet_mode="extended") + users = self.twitter.lookup_users(user_id=users_to_retrieve, tweet_mode="extended") users_db = self.db["users"] for user in users: users_db[user.id_str] = user log.debug("Added %d new users" % (len(users))) self.db["users"] = users_db - except TweepError as err: + except TweepyException as err: if hasattr(err, "api_code") and err.api_code == 17: # Users not found. log.error("The specified users {} were not found in twitter.".format(user_ids)) # Creates a deleted user object for every user_id not found here. @@ -523,9 +523,8 @@ class Session(base.baseSession): def start_streaming(self): if config.app["app-settings"]["no_streaming"]: return - self.stream_listener = streaming.StreamListener(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"], muted_users=self.db["muted_users"]) - self.stream = streaming.Stream(auth = self.auth, listener=self.stream_listener, chunk_size=1025) - self.stream_thread = call_threaded(self.stream.filter, follow=self.stream_listener.users, stall_warnings=True) + self.stream = streaming.Stream(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"], muted_users=self.db["muted_users"], consumer_key=keyring.get("api_key"), consumer_secret=keyring.get("api_secret"), access_token=self.settings["twitter"]["user_key"], access_token_secret=self.settings["twitter"]["user_secret"], chunk_size=1025) + self.stream_thread = call_threaded(self.stream.filter, follow=self.stream.users, stall_warnings=True) def stop_streaming(self): if config.app["app-settings"]["no_streaming"]: @@ -554,7 +553,7 @@ class Session(base.baseSession): status._json = {**status._json, **status._json["extended_tweet"]} # Sends status to database, where it will be reduced and changed according to our needs. buffers_to_send = [] - if status.user.id_str in self.stream_listener.users: + if status.user.id_str in self.stream.users: buffers_to_send.append("home_timeline") if status.user.id == self.db["user_id"]: buffers_to_send.append("sent_tweets") diff --git a/src/sessions/twitter/streaming.py b/src/sessions/twitter/streaming.py index dcd5711d..137147fc 100644 --- a/src/sessions/twitter/streaming.py +++ b/src/sessions/twitter/streaming.py @@ -12,17 +12,17 @@ from pubsub import pub log = logging.getLogger("sessions.twitter.streaming") -class StreamListener(tweepy.StreamListener): +class Stream(tweepy.Stream): def __init__(self, twitter_api, user, user_id, muted_users=[], *args, **kwargs): - super(StreamListener, self).__init__(*args, **kwargs) + super(Stream, self).__init__(*args, **kwargs) log.debug("Starting streaming listener for account {}".format(user)) self.started = False self.users = [] self.api = twitter_api self.user = user self.user_id = user_id - friends = self.api.friends_ids() + friends = self.api.get_friend_ids() log.debug("Retrieved {} friends to add to the streaming listener.".format(len(friends))) self.users.append(str(self.user_id)) log.debug("Got {} muted users.".format(len(muted_users))) @@ -45,78 +45,3 @@ class StreamListener(tweepy.StreamListener): return if status.user.id_str in self.users: pub.sendMessage("newStatus", status=status, user=self.user) - - - -class Stream(tweepy.Stream): - - def _run(self): - # Authenticate - url = "https://%s%s" % (self.host, self.url) - - # Connect and process the stream - error_counter = 0 - resp = None - exc_info = None - while self.running: - if self.retry_count is not None: - if error_counter > self.retry_count: - # quit if error count greater than retry count - break - try: - auth = self.auth.apply_auth() - resp = self.session.request('POST', - url, - data=self.body, - timeout=self.timeout, - stream=True, - auth=auth, - verify=self.verify, - proxies = self.proxies) - if resp.status_code != 200: - if self.listener.on_error(resp.status_code) is False: - break - error_counter += 1 - if resp.status_code == 420: - self.retry_time = max(self.retry_420_start, - self.retry_time) - time.sleep(self.retry_time) - self.retry_time = min(self.retry_time * 2, - self.retry_time_cap) - else: - error_counter = 0 - self.retry_time = self.retry_time_start - self.snooze_time = self.snooze_time_step - self.listener.on_connect() - self._read_loop(resp) - except (requests.ConnectionError, requests.Timeout, ssl.SSLError, urllib3.exceptions.ReadTimeoutError, urllib3.exceptions.ProtocolError) as exc: - # This is still necessary, as a SSLError can actually be - # thrown when using Requests - # If it's not time out treat it like any other exception - if isinstance(exc, ssl.SSLError): - if not (exc.args and 'timed out' in str(exc.args[0])): - exc_info = sys.exc_info() - break - if self.listener.on_timeout() is False: - break - if self.running is False: - break - time.sleep(self.snooze_time) - self.snooze_time = min(self.snooze_time + self.snooze_time_step, - self.snooze_time_cap) - except Exception as exc: - exc_info = sys.exc_info() - # any other exception is fatal, so kill loop - break - - # cleanup - self.running = False - if resp: - resp.close() - - self.new_session() - - if exc_info: - # call a handler first so that the exception can be logged. - self.listener.on_exception(exc_info[1]) - six.reraise(*exc_info) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 8436b79c..4e14a697 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -6,7 +6,7 @@ import logging import requests import time import sound -from tweepy.error import TweepError +from tweepy.errors import TweepyException log = logging.getLogger("twitter.utils") """ Some utilities for the twitter interface.""" @@ -159,7 +159,7 @@ def if_user_exists(twitter, user): try: data = twitter.get_user(screen_name=user) return data - except TweepError as err: + except TweepyException as err: if err.api_code == 50: return None else: diff --git a/src/wxUI/dialogs/__init__.py b/src/wxUI/dialogs/__init__.py index a34f1b2f..a21239a7 100644 --- a/src/wxUI/dialogs/__init__.py +++ b/src/wxUI/dialogs/__init__.py @@ -1,3 +1,3 @@ from __future__ import absolute_import from __future__ import unicode_literals -from . import baseDialog, trends, configuration, lists, message, search, find, show_user, update_profile, urlList, userSelection, utils, filterDialogs +from . import baseDialog, trends, configuration, lists, message, search, find, show_user, update_profile, urlList, userSelection, utils, filterDialogs, userAliasDialogs diff --git a/src/wxUI/dialogs/userAliasDialogs.py b/src/wxUI/dialogs/userAliasDialogs.py new file mode 100644 index 00000000..6fca9237 --- /dev/null +++ b/src/wxUI/dialogs/userAliasDialogs.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import wx +from . import baseDialog + +class addAliasDialog(baseDialog.BaseWXDialog): + def __init__(self, title, users): + super(addAliasDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title) + panel = wx.Panel(self) + userSizer = wx.BoxSizer() + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize) + self.cb.SetFocus() + self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) + userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) + userSizer.Add(self.cb, 0, wx.ALL, 5) + userSizer.Add(self.autocompletion, 0, wx.ALL, 5) + aliasSizer = wx.BoxSizer(wx.HORIZONTAL) + aliasLabel = wx.StaticText(panel, wx.ID_ANY, _("Alias")) + self.alias = wx.TextCtrl(panel, wx.ID_ANY) + aliasSizer.Add(aliasLabel, 0, wx.ALL, 5) + aliasSizer.Add(self.alias, 0, wx.ALL, 5) + sizer = wx.BoxSizer(wx.VERTICAL) + ok = wx.Button(panel, wx.ID_OK, _(u"OK")) + ok.SetDefault() + cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) + btnsizer = wx.BoxSizer() + btnsizer.Add(ok, 0, wx.ALL, 5) + btnsizer.Add(cancel, 0, wx.ALL, 5) + sizer.Add(userSizer, 0, wx.ALL, 5) + sizer.Add(aliasSizer, 0, wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALL, 5) + panel.SetSizer(sizer) + self.SetClientSize(sizer.CalcMin()) + + def get_user(self): + return (self.cb.GetValue(), self.alias.GetValue()) + diff --git a/src/wxUI/dialogs/utils.py b/src/wxUI/dialogs/utils.py index 6f308685..a595acc7 100644 --- a/src/wxUI/dialogs/utils.py +++ b/src/wxUI/dialogs/utils.py @@ -46,38 +46,4 @@ class selectUserDialog(baseDialog.BaseWXDialog): self.SetClientSize(sizer.CalcMin()) def get_user(self): - return self.cb.GetValue() - -class addAliasDialog(baseDialog.BaseWXDialog): - def __init__(self, title, users): - super(addAliasDialog, self).__init__(parent=None, id=wx.ID_ANY, title=title) - panel = wx.Panel(self) - userSizer = wx.BoxSizer() - self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0], size=wx.DefaultSize) - self.cb.SetFocus() - self.autocompletion = wx.Button(panel, -1, _(u"&Autocomplete users")) - userSizer.Add(wx.StaticText(panel, -1, _(u"User")), 0, wx.ALL, 5) - userSizer.Add(self.cb, 0, wx.ALL, 5) - userSizer.Add(self.autocompletion, 0, wx.ALL, 5) - aliasSizer = wx.BoxSizer(wx.HORIZONTAL) - aliasLabel = wx.StaticText(panel, wx.ID_ANY, _("Alias")) - self.alias = wx.TextCtrl(panel, wx.ID_ANY) - aliasSizer.Add(aliasLabel, 0, wx.ALL, 5) - aliasSizer.Add(self.alias, 0, wx.ALL, 5) - sizer = wx.BoxSizer(wx.VERTICAL) - ok = wx.Button(panel, wx.ID_OK, _(u"OK")) - ok.SetDefault() -# ok.Bind(wx.EVT_BUTTON, self.onok) - cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Close")) - btnsizer = wx.BoxSizer() - btnsizer.Add(ok, 0, wx.ALL, 5) - btnsizer.Add(cancel, 0, wx.ALL, 5) - sizer.Add(userSizer, 0, wx.ALL, 5) - sizer.Add(aliasSizer, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) - - def get_user(self): - return (self.cb.GetValue(), self.alias.GetValue()) - + return self.cb.GetValue() \ No newline at end of file From 286e030f4042e22bf870f96f7353c4570c3db070 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 7 Oct 2021 09:20:06 -0500 Subject: [PATCH 147/245] Handle new Tweepy exceptions properly. #403 --- src/controller/buffers/twitter/base.py | 4 ++-- .../buffers/twitter/directMessages.py | 2 +- src/controller/buffers/twitter/people.py | 4 ++-- src/controller/buffers/twitter/trends.py | 2 +- src/controller/listsController.py | 16 ++++++++++------ src/controller/mainController.py | 18 +++++++++--------- src/controller/user.py | 12 ++++++------ src/controller/userActionsController.py | 14 +++++++------- src/sessions/twitter/session.py | 14 +++++++------- src/sessions/twitter/utils.py | 10 +++++----- 10 files changed, 50 insertions(+), 46 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 275ac77f..8da54709 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -192,7 +192,7 @@ class BaseBuffer(base.Buffer): user_ids = [item.message_create["sender_id"] for item in val] self.session.save_users(user_ids) except TweepyException as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) + log.exception("Error %s" % (str(e))) return number_of_items = self.session.order_buffer(self.name, val) log.debug("Number of items retrieved: %d" % (number_of_items,)) @@ -230,7 +230,7 @@ class BaseBuffer(base.Buffer): try: items = getattr(self.session.twitter, self.function)(max_id=last_id, count=self.session.settings["general"]["max_tweets_per_call"], *self.args, **self.kwargs) except TweepyException as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) + log.exception("Error %s" % (str(e))) return if items == None: return diff --git a/src/controller/buffers/twitter/directMessages.py b/src/controller/buffers/twitter/directMessages.py index d5ba86ea..176a3138 100644 --- a/src/controller/buffers/twitter/directMessages.py +++ b/src/controller/buffers/twitter/directMessages.py @@ -41,7 +41,7 @@ class DirectMessagesBuffer(base.BaseBuffer): items = results log.debug("Retrieved %d items for cursored search in function %s" % (len(items), self.function)) except TweepyException as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) + log.exception("Error %s" % (str(e))) return if items == None: return diff --git a/src/controller/buffers/twitter/people.py b/src/controller/buffers/twitter/people.py index 2cf33867..7f5c90b1 100644 --- a/src/controller/buffers/twitter/people.py +++ b/src/controller/buffers/twitter/people.py @@ -126,7 +126,7 @@ class PeopleBuffer(base.BaseBuffer): val.reverse() log.debug("Retrieved %d items from cursored search in function %s" % (len(val), self.function)) except TweepyException as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) + log.exception("Error %s" % (str(e))) return number_of_items = self.session.order_people(self.name, val) log.debug("Number of items retrieved: %d" % (number_of_items,)) @@ -156,7 +156,7 @@ class PeopleBuffer(base.BaseBuffer): items = results log.debug("Retrieved %d items from cursored search in function %s" % (len(items), self.function)) except TweepyException as e: - log.error("Error %s: %s" % (e.api_code, e.reason)) + log.exception("Error %s" % (str(e))) return if items == None: return diff --git a/src/controller/buffers/twitter/trends.py b/src/controller/buffers/twitter/trends.py index d7b913c3..03e07b3a 100644 --- a/src/controller/buffers/twitter/trends.py +++ b/src/controller/buffers/twitter/trends.py @@ -46,7 +46,7 @@ class TrendsBuffer(base.Buffer): try: data = self.session.twitter.get_place_trends(id=self.trendsFor) except TweepyException as err: - log.error("Error %s: %s" % (err.api_code, err.reason)) + log.exception("Error %s" % (str(err))) if not hasattr(self, "name_"): self.name_ = data[0]["locations"][0]["name"] self.trends = data[0]["trends"] diff --git a/src/controller/listsController.py b/src/controller/listsController.py index 509a09a7..ca861c31 100644 --- a/src/controller/listsController.py +++ b/src/controller/listsController.py @@ -50,8 +50,8 @@ class listsController(object): self.session.db["lists"].append(new_list) self.dialog.lista.insert_item(False, *compose.compose_list(new_list)) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) - log.exception("error %s: %s" % (e.api_code, e.reason)) + output.speak("error %s" % (str(e))) + log.exception("error %s" % (str(e))) dialog.destroy() def edit_list(self, *args, **kwargs): @@ -71,7 +71,8 @@ class listsController(object): self.session.get_lists() self.dialog.populate_list(self.get_all_lists(), True) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + output.speak("error %s" % (str(e))) + log.exception("error %s" % (str(e))) dialog.destroy() def remove_list(self, *args, **kwargs): @@ -83,7 +84,8 @@ class listsController(object): self.session.db["lists"].pop(self.dialog.get_item()) self.dialog.lista.remove_item(self.dialog.get_item()) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + output.speak("error %s" % (str(e))) + log.exception("error %s" % (str(e))) def open_list_as_buffer(self, *args, **kwargs): if self.dialog.lista.get_count() == 0: return @@ -98,7 +100,8 @@ class listsController(object): item = utils.find_item(list.id, self.session.db["lists"]) self.session.db["lists"].append(list) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + output.speak("error %s" % (str(e))) + log.exception("error %s" % (str(e))) def unsubscribe(self, *args, **kwargs): if self.dialog.lista.get_count() == 0: return @@ -107,4 +110,5 @@ class listsController(object): list = self.session.twitter.unsubscribe_list(list_id=list_id) self.session.db["lists"].remove(list) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + output.speak("error %s" % (str(e))) + log.exception("error %s" % (str(e))) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 9ee76ffa..7241707f 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -29,7 +29,7 @@ from sessions.twitter import session as session_ from pubsub import pub import sound import output -from tweepy.errors import TweepyException +from tweepy.errors import TweepyException, Forbidden from mysc.thread_utils import call_threaded from mysc.repeating_timer import RepeatingTimer from mysc import restart @@ -549,7 +549,8 @@ class Controller(object): buff.session.db["lists"].pop(older_list) buff.session.db["lists"].append(list) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + log.exception("error %s" % (str(e))) + output.speak("error %s" % (str(e))) def remove_from_list(self, *args, **kwargs): buff = self.get_best_buffer() @@ -577,7 +578,8 @@ class Controller(object): buff.session.db["lists"].pop(older_list) buff.session.db["lists"].append(list) except TweepyException as e: - output.speak("error %s: %s" % (e.api_code, e.reason)) + output.speak("error %s" % (str(e))) + log.exception("error %s" % (str(e))) def list_manager(self, *args, **kwargs): s = self.get_best_buffer().session @@ -1342,10 +1344,9 @@ class Controller(object): else: i.start_stream(play_sound=False) except TweepyException as err: - log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) + log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r." % (str(err), i.name, i.account, i.args, i.kwargs)) # Determine if this error was caused by a block applied to the current user (IE permission errors). - errors_allowed = [130] - if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. + if type(err) == Forbidden: buff = self.view.search(i.name, i.account) i.remove_buffer(force=True) commonMessageDialogs.blocked_timeline() @@ -1548,10 +1549,9 @@ class Controller(object): try: i.start_stream(mandatory=True) except TweepyException as err: - log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r due to the following reason: %s" % (err.api_code, i.name, i.account, i.args, i.kwargs, err.reason)) + log.exception("Error %s starting buffer %s on account %s, with args %r and kwargs %r." % (str(err), i.name, i.account, i.args, i.kwargs)) # Determine if this error was caused by a block applied to the current user (IE permission errors). - errors_allowed = [130] - if (err.api_code != None and err.api_code not in errors_allowed) or (err.api_code == None and 'Not authorized' in err.reason): # A twitter error, so safely try to remove the buffer. + if type(err) == Forbidden: buff = self.view.search(i.name, i.account) i.remove_buffer(force=True) commonMessageDialogs.blocked_timeline() diff --git a/src/controller/user.py b/src/controller/user.py index 14fd96cd..7bd1fb21 100644 --- a/src/controller/user.py +++ b/src/controller/user.py @@ -6,7 +6,7 @@ import output from wxUI.dialogs import update_profile, show_user import logging log = logging.getLogger("controller.user") -from tweepy.errors import TweepyException +from tweepy.errors import TweepyException, Forbidden, NotFound from sessions.twitter import utils class profileController(object): @@ -25,11 +25,11 @@ class profileController(object): try: self.get_data(screen_name=self.user) except TweepyException as err: - if err.api_code == 50: + if type(err) == NotFound: wx.MessageDialog(None, _(u"That user does not exist"), _(u"Error"), wx.ICON_ERROR).ShowModal() - if err.api_code == 63: + if type(err) == Forbidden: wx.MessageDialog(None, _(u"User has been suspended"), _(u"Error"), wx.ICON_ERROR).ShowModal() - log.error("error %d: %s" % (err.api_code, err.reason)) + log.error("error %s" % (str(err))) return self.dialog = show_user.showUserProfile() string = self.get_user_info() @@ -84,11 +84,11 @@ class profileController(object): try: self.session.twitter.update_profile_image(image=self.file) except TweepyException as e: - output.speak(u"Error %s. %s" % (e.api_code, e.reason)) + output.speak(u"Error %s" % (str(e))) try: self.session.twitter.update_profile(name=name, description=description, location=location, url=url) except TweepyException as e: - output.speak(u"Error %s. %s" % (e.api_code, e.reason)) + output.speak(u"Error %s." % (str(e))) def get_user_info(self): string = u"" diff --git a/src/controller/userActionsController.py b/src/controller/userActionsController.py index 0b7cbb58..e9cbcd45 100644 --- a/src/controller/userActionsController.py +++ b/src/controller/userActionsController.py @@ -30,43 +30,43 @@ class userActionsController(object): try: self.session.twitter.create_friendship(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def unfollow(self, user): try: id = self.session.twitter.destroy_friendship(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def mute(self, user): try: id = self.session.twitter.create_mute(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def unmute(self, user): try: id = self.session.twitter.destroy_mute(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def report(self, user): try: id = self.session.twitter.report_spam(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def block(self, user): try: id = self.session.twitter.create_block(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def unblock(self, user): try: id = self.session.twitter.destroy_block(screen_name=user ) except TweepyException as err: - output.speak("Error %s: %s" % (err.api_code, err.reason), True) + output.speak("Error %s" % (str(err)), True) def ignore_client(self, user): tweet = self.buffer.get_right_tweet() diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 1407d632..db7e85af 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -10,7 +10,7 @@ import output import application from pubsub import pub import tweepy -from tweepy.errors import TweepyException +from tweepy.errors import TweepyException, Forbidden, NotFound from tweepy.models import User as UserModel from mysc.thread_utils import call_threaded from keys import keyring @@ -200,13 +200,13 @@ class Session(base.baseSession): val = getattr(self.twitter, call_name)(*args, **kwargs) finished = True except TweepyException as e: - output.speak(e.reason) + output.speak(str(e)) val = None - if e.error_code != 403 and e.error_code != 404: + if type(e) != NotFound and type(e) != Forvidden: tries = tries+1 time.sleep(5) - elif report_failure and hasattr(e, 'reason'): - output.speak(_("%s failed. Reason: %s") % (action, e.reason)) + elif report_failure: + output.speak(_("%s failed. Reason: %s") % (action, str(e))) finished = True # except: # tries = tries + 1 @@ -422,7 +422,7 @@ class Session(base.baseSession): user.screen_name = "deleted_user" user.id = id user.name = _("Deleted account") - if hasattr(err, "api_code") and err.api_code == 50: + if type(err) == NotFound: self.deleted_users[id] = user return user else: @@ -490,7 +490,7 @@ class Session(base.baseSession): log.debug("Added %d new users" % (len(users))) self.db["users"] = users_db except TweepyException as err: - if hasattr(err, "api_code") and err.api_code == 17: # Users not found. + if type(err) == NotFound: # User not found. log.error("The specified users {} were not found in twitter.".format(user_ids)) # Creates a deleted user object for every user_id not found here. # This will make TWBlue to not waste Twitter API calls when attempting to retrieve those users again. diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index 4e14a697..f84dfaca 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -6,7 +6,7 @@ import logging import requests import time import sound -from tweepy.errors import TweepyException +from tweepy.errors import TweepyException, NotFound, Forbidden log = logging.getLogger("twitter.utils") """ Some utilities for the twitter interface.""" @@ -160,7 +160,7 @@ def if_user_exists(twitter, user): data = twitter.get_user(screen_name=user) return data except TweepyException as err: - if err.api_code == 50: + if type(err) == NotFound: return None else: return user @@ -227,12 +227,12 @@ def filter_tweet(tweet, tweet_data, settings, buffer_name): return True def twitter_error(error): - if error.api_code == 179: + if type(error) == Forbidden: msg = _(u"Sorry, you are not authorised to see this status.") - elif error.api_code == 144: + elif type(error) == NotFound: msg = _(u"No status found with that ID") else: - msg = _(u"Error code {0}").format(error.api_code,) + msg = _(u"Error {0}").format(str(error),) output.speak(msg) def expand_urls(text, entities): From a2f25bfbb5858546b7b8cea4fe90c607a00c23d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Tue, 12 Oct 2021 17:05:09 +0200 Subject: [PATCH 148/245] Added charset-normalizer to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 8a5c4744..576a6522 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,6 +47,7 @@ attrs importlib-metadata numpy pillow +charset-normalizer git+https://github.com/accessibleapps/libloader git+https://github.com/accessibleapps/platform_utils git+https://github.com/accessibleapps/accessible_output2 From 301bd5fd395fa3274ca14f1ed774b5d48113454a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 20 Oct 2021 15:52:58 -0500 Subject: [PATCH 149/245] Pushed a new snapshot --- scripts/twblue_snapshot.nsi | 10 +++++----- src/application.py | 2 +- updates/snapshots.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi index 62f88198..f7d20764 100644 --- a/scripts/twblue_snapshot.nsi +++ b/scripts/twblue_snapshot.nsi @@ -15,10 +15,10 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue Snapshot version" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "9" -VIAddVersionKey FileVersion "9" -VIProductVersion "9.0.0.0" -VIFileVersion "9.0.0.0" +VIAddVersionKey ProductVersion "11" +VIAddVersionKey FileVersion "11" +VIProductVersion "11.0.0.0" +VIFileVersion "11.0.0.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -72,7 +72,7 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "9" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "11" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "https://twblue.es" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 diff --git a/src/application.py b/src/application.py index e4253581..64d123da 100644 --- a/src/application.py +++ b/src/application.py @@ -9,7 +9,7 @@ if snapshot == False: update_url = 'https://twblue.es/updates/stable.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' else: - version = "10" + version = "11" update_url = 'https://twblue.es/updates/snapshot.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] diff --git a/updates/snapshots.json b/updates/snapshots.json index 1b0348d7..ad94bf92 100644 --- a/updates/snapshots.json +++ b/updates/snapshots.json @@ -1,4 +1,4 @@ -{"current_version": "10", +{"current_version": "11", "description": "Snapshot version.", "date": "unknown", "downloads": From d1bd393be24294118006fae2b4f0368c177fb0a3 Mon Sep 17 00:00:00 2001 From: Nikola Jovic Date: Thu, 21 Oct 2021 16:30:46 +0200 Subject: [PATCH 150/245] Updated Serbian translation --- src/locales/sr/LC_MESSAGES/twblue.mo | Bin 50471 -> 53409 bytes src/locales/sr/LC_MESSAGES/twblue.po | 1638 ++++++++++++++------------ 2 files changed, 885 insertions(+), 753 deletions(-) diff --git a/src/locales/sr/LC_MESSAGES/twblue.mo b/src/locales/sr/LC_MESSAGES/twblue.mo index 1669d1bd0f64831676bc1a12594d621d03726cfc..8e9b179927d5cfe6070ffa66fba43de842a9a9ab 100644 GIT binary patch delta 19434 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 delta 16551 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 diff --git a/src/locales/sr/LC_MESSAGES/twblue.po b/src/locales/sr/LC_MESSAGES/twblue.po index f9791a49..e74d25d3 100644 --- a/src/locales/sr/LC_MESSAGES/twblue.po +++ b/src/locales/sr/LC_MESSAGES/twblue.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: TwBlue 0.80\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" -"PO-Revision-Date: 2021-06-25 18:32+0100\n" +"POT-Creation-Date: 2021-08-28 08:34+Paris, Madrid (heure d’été)\n" +"PO-Revision-Date: 2021-10-21 13:32+0200\n" "Last-Translator: Nikola Jović \n" "Language-Team: Aleksandar Đurić \n" "Language: sr_RS@latin\n" @@ -14,190 +14,188 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 1.6.10\n" +"X-Generator: Poedit 3.0\n" "X-Poedit-Bookmarks: -1,442,-1,-1,-1,-1,-1,-1,-1,-1\n" "X-Poedit-SourceCharset: UTF-8\n" -#: ../src\controller\attach.py:23 +#: ../src\controller\attach.py:25 msgid "Photo" msgstr "Slika" -#: ../src\controller\buffers\baseBuffers.py:95 +#: ../src\controller\buffers\base\base.py:91 msgid "This action is not supported for this buffer" msgstr "Ova radnja nije podržana na ovom kanalu" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:309 ../src\controller\settings.py:286 msgid "Home" msgstr "Početak" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:313 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Spominjanja" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:317 msgid "Direct messages" msgstr "Direktne poruke" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:321 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Poslate direktne poruke" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:325 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Poslati tvitovi" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:329 +#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:291 msgid "Likes" msgstr "Sviđanja" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:333 +#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:292 msgid "Followers" msgstr "Pratioci" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:337 +#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:293 msgid "Friends" msgstr "Prijatelji" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:341 +#: ../src\controller\mainController.py:1415 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Blokirani korisnici" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:345 +#: ../src\controller\mainController.py:1420 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Utišani korisnici" -#: ../src\controller\buffers\twitterBuffers.py:75 +#: ../src\controller\buffers\twitter\base.py:76 msgid "{username}'s timeline" msgstr "Vremenska linija korisnika {username}" -#: ../src\controller\buffers\twitterBuffers.py:77 +#: ../src\controller\buffers\twitter\base.py:78 msgid "{username}'s likes" msgstr "Sviđanja korisnika {username}" -#: ../src\controller\buffers\twitterBuffers.py:79 +#: ../src\controller\buffers\twitter\base.py:80 msgid "{username}'s followers" msgstr "Pratioci korisnika {username}" -#: ../src\controller\buffers\twitterBuffers.py:81 +#: ../src\controller\buffers\twitter\base.py:82 msgid "{username}'s friends" msgstr "Prijatelji korisnika {username}" -#: ../src\controller\buffers\twitterBuffers.py:83 +#: ../src\controller\buffers\twitter\base.py:84 msgid "Unknown buffer" msgstr "Nepoznat kanal" -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:121 +#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "Tvit" -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 +#: ../src\controller\buffers\twitter\base.py:89 +#: ../src\controller\buffers\twitter\trends.py:122 msgid "Write the tweet here" msgstr "Otkucajte tvit ovde:" -#: ../src\controller\buffers\twitterBuffers.py:194 +#: ../src\controller\buffers\twitter\base.py:219 msgid "New tweet in {0}" msgstr "Novi tvit u kanalu {0}" -#: ../src\controller\buffers\twitterBuffers.py:197 +#: ../src\controller\buffers\twitter\base.py:222 msgid "{0} new tweets in {1}." msgstr "{0} novih tvitova u kanalu {1}." -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 +#: ../src\controller\buffers\twitter\base.py:261 +#: ../src\controller\buffers\twitter\directMessages.py:87 +#: ../src\controller\buffers\twitter\people.py:180 msgid "%s items retrieved" msgstr "%s primljenih stavki" -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 +#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\people.py:80 msgid "This buffer is not a timeline; it can't be deleted." msgstr "Ovaj kanal nije vremenska linija i ne može biti izbrisan." -#: ../src\controller\buffers\twitterBuffers.py:402 +#: ../src\controller\buffers\twitter\base.py:430 msgid "Reply to {arg0}" msgstr "Odgovori {arg0}" -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 +#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 msgid "Reply" msgstr "Odgovori" -#: ../src\controller\buffers\twitterBuffers.py:405 +#: ../src\controller\buffers\twitter\base.py:433 msgid "Reply to %s" msgstr "Odgovori %s" -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Direktna poruka za %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\buffers\twitter\directMessages.py:129 msgid "New direct message" msgstr "Nova direktna poruka" -#: ../src\controller\buffers\twitterBuffers.py:500 +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\messages.py:200 +msgid "Direct message to %s" +msgstr "Direktna poruka za %s" + +#: ../src\controller\buffers\twitter\base.py:520 msgid "Add your comment to the tweet" msgstr "Dodajte vaš komentar u tvit" -#: ../src\controller\buffers\twitterBuffers.py:500 +#: ../src\controller\buffers\twitter\base.py:520 msgid "Quote" msgstr "Citiraj" -#: ../src\controller\buffers\twitterBuffers.py:572 +#: ../src\controller\buffers\twitter\base.py:596 msgid "Opening URL..." msgstr "Otvaram vezu..." -#: ../src\controller\buffers\twitterBuffers.py:607 +#: ../src\controller\buffers\twitter\base.py:633 msgid "User details" msgstr "Podaci o korisniku" -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 +#: ../src\controller\buffers\twitter\base.py:654 msgid "Opening item in web browser..." msgstr "Otvaram stavku u Web pretraživaču..." -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 +#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\people.py:95 msgid "Mention to %s" msgstr "Spomeni %s" -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 +#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\people.py:95 +#: ../src\wxUI\buffers\people.py:17 msgid "Mention" msgstr "Spomeni" -#: ../src\controller\buffers\twitterBuffers.py:728 +#: ../src\controller\buffers\twitter\directMessages.py:132 msgid "{0} new direct messages." msgstr "{0} novih direktnih poruka." -#: ../src\controller\buffers\twitterBuffers.py:731 +#: ../src\controller\buffers\twitter\directMessages.py:135 msgid "This action is not supported in the buffer yet." msgstr "Ova radnja još uvek nije podržana na ovom kanalu." -#: ../src\controller\buffers\twitterBuffers.py:741 +#: ../src\controller\buffers\twitter\directMessages.py:145 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -205,11 +203,11 @@ msgstr "" "Nemoguće preuzeti dodatne stavke za ovaj kanal. Umesto toga, koristite kanal " "direktne poruke." -#: ../src\controller\buffers\twitterBuffers.py:983 +#: ../src\controller\buffers\twitter\people.py:253 msgid "{0} new followers." msgstr "{0} novih pratilaca." -#: ../src\controller\buffers\twitterBuffers.py:1266 +#: ../src\controller\buffers\twitter\trends.py:145 msgid "This action is not supported in the buffer, yet." msgstr "Ova radnja još uvek nije podržana na ovom kanalu" @@ -217,75 +215,75 @@ msgstr "Ova radnja još uvek nije podržana na ovom kanalu" msgid "Ready" msgstr "Spreman" -#: ../src\controller\mainController.py:345 +#: ../src\controller\mainController.py:348 msgid "Timelines" msgstr "Vremenske linije" -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 +#: ../src\controller\mainController.py:352 +#: ../src\controller\mainController.py:892 +#: ../src\controller\mainController.py:1596 msgid "Timeline for {}" msgstr "Vremenska linija od {}" -#: ../src\controller\mainController.py:352 +#: ../src\controller\mainController.py:355 msgid "Likes timelines" msgstr "Vremenska linija omiljenih tvitova" -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 +#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:911 +#: ../src\controller\mainController.py:1598 msgid "Likes for {}" msgstr "Sviđanja od {}" -#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:362 msgid "Followers' Timelines" msgstr "Vremenska linija pratilaca" -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 +#: ../src\controller\mainController.py:366 +#: ../src\controller\mainController.py:930 +#: ../src\controller\mainController.py:1600 msgid "Followers for {}" msgstr "Pratioci od {}" -#: ../src\controller\mainController.py:366 +#: ../src\controller\mainController.py:369 msgid "Friends' Timelines" msgstr "Vremenska linija prijatelja" -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 +#: ../src\controller\mainController.py:373 +#: ../src\controller\mainController.py:949 +#: ../src\controller\mainController.py:1602 msgid "Friends for {}" msgstr "Prijatelji od {}" -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 +#: ../src\controller\mainController.py:376 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Liste" -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 +#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:1432 msgid "List for {}" msgstr "Liste od {}" -#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:384 msgid "Searches" msgstr "Pretrage" -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 +#: ../src\controller\mainController.py:388 +#: ../src\controller\mainController.py:447 msgid "Search for {}" msgstr "Pretraga za {}" -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 +#: ../src\controller\mainController.py:394 +#: ../src\controller\mainController.py:991 msgid "Trending topics for %s" msgstr "Teme u trendu za %s" -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 +#: ../src\controller\mainController.py:464 +#: ../src\controller\mainController.py:480 +#: ../src\controller\mainController.py:1089 +#: ../src\controller\mainController.py:1108 +#: ../src\controller\mainController.py:1127 +#: ../src\controller\mainController.py:1146 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." @@ -293,238 +291,265 @@ msgstr "" "Trenutno nijedna sesija nije u fokusu. Fokusirajte neku pritiskom na prečicu " "za prethodnu ili sledeću." -#: ../src\controller\mainController.py:465 +#: ../src\controller\mainController.py:468 msgid "Empty buffer." msgstr "Prazan kanal." -#: ../src\controller\mainController.py:472 +#: ../src\controller\mainController.py:475 msgid "{0} not found." msgstr "{0} nije pronađen." -#: ../src\controller\mainController.py:482 +#: ../src\controller\mainController.py:485 msgid "Filters cannot be applied on this buffer" msgstr "Filteri se ne mogu primeniti na ovaj kanal" -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 +#: ../src\controller\mainController.py:538 +#: ../src\controller\mainController.py:555 +#: ../src\controller\mainController.py:583 msgid "Select the user" msgstr "Izaberite korisnika" -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 +#: ../src\controller\mainController.py:767 +msgid "Add an user alias" +msgstr "Dodaj nadimak za korisnika" + +#: ../src\controller\mainController.py:775 +msgid "Alias has been set correctly for {}." +msgstr "Nadimak za {} je uspešno podešen." + +#: ../src\controller\mainController.py:838 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "MMM D, YYYY. H:m" -#: ../src\controller\mainController.py:934 +#: ../src\controller\mainController.py:966 msgid "Conversation with {0}" msgstr "Razgovor sa {0}" -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 +#: ../src\controller\mainController.py:1007 +#: ../src\controller\mainController.py:1024 msgid "There are no coordinates in this tweet" msgstr "Nema koordinata u ovom tvitu." -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "Nema rezultata za te koordinate u ovom tvitu." - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1009 +#: ../src\controller\mainController.py:1028 msgid "Error decoding coordinates. Try again later." msgstr "Greška prilikom čitanja koordinata. Molimo vas da pokušate kasnije." -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 +#: ../src\controller\mainController.py:1013 +msgid "Unable to find address in OpenStreetMap." +msgstr "Nemoguće pronaći adresu u OpenStreet mapi." + +#: ../src\controller\mainController.py:1026 +msgid "There are no results for the coordinates in this tweet" +msgstr "Nema rezultata za te koordinate u ovom tvitu." + +#: ../src\controller\mainController.py:1137 +#: ../src\controller\mainController.py:1156 msgid "%s, %s of %s" msgstr "%s, %s od %s" -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 +#: ../src\controller\mainController.py:1139 +#: ../src\controller\mainController.py:1158 +#: ../src\controller\mainController.py:1183 +#: ../src\controller\mainController.py:1208 msgid "%s. Empty" msgstr "%s. Prazno." -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 -#: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1171 +#: ../src\controller\mainController.py:1175 +#: ../src\controller\mainController.py:1196 msgid "{0}: This account is not logged into Twitter." msgstr "{0}: Ovaj nalog nije prijavljen na twitter." -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 +#: ../src\controller\mainController.py:1181 +#: ../src\controller\mainController.py:1206 msgid "%s. %s, %s of %s" msgstr "%s. %s, %s od %s" -#: ../src\controller\mainController.py:1170 +#: ../src\controller\mainController.py:1200 msgid "{0}: This account is not logged into twitter." msgstr "{0}: Ovaj nalog nije prijavljen na twitter." -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Događaji" - -#: ../src\controller\mainController.py:1393 +#: ../src\controller\mainController.py:1426 msgid "This list is already opened" msgstr "Ova lista je već otvorena" -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 +#: ../src\controller\mainController.py:1456 +#: ../src\controller\mainController.py:1472 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" "Došlo je do greške pri pokušaju povezivanja na server. Molimo pokušajte " "kasnije." -#: ../src\controller\mainController.py:1475 +#: ../src\controller\mainController.py:1508 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "Automatsko čitanje novih tvitova je uključeno na ovom kanalu" -#: ../src\controller\mainController.py:1478 +#: ../src\controller\mainController.py:1511 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "Automatsko čitanje tvitova je isključeno za tvitove na ovom kanalu" -#: ../src\controller\mainController.py:1485 +#: ../src\controller\mainController.py:1518 msgid "Session mute on" msgstr "Utišavanje sesije uključeno" -#: ../src\controller\mainController.py:1488 +#: ../src\controller\mainController.py:1521 msgid "Session mute off" msgstr "Utišavanje sesije isključeno" -#: ../src\controller\mainController.py:1496 +#: ../src\controller\mainController.py:1529 msgid "Buffer mute on" msgstr "Utišavanje kanala uključeno" -#: ../src\controller\mainController.py:1499 +#: ../src\controller\mainController.py:1532 msgid "Buffer mute off" msgstr "Utišavanje kanala isključeno" -#: ../src\controller\mainController.py:1522 +#: ../src\controller\mainController.py:1555 msgid "Copied" msgstr "Kopirano" -#: ../src\controller\mainController.py:1549 +#: ../src\controller\mainController.py:1586 msgid "Unable to update this buffer." msgstr "Ne mogu da ažuriram ovaj kanal." -#: ../src\controller\mainController.py:1552 +#: ../src\controller\mainController.py:1589 msgid "Updating buffer..." msgstr "Ažuriram kanal..." -#: ../src\controller\mainController.py:1555 +#: ../src\controller\mainController.py:1592 msgid "{0} items retrieved" msgstr "{0} primljenih stavki" -#: ../src\controller\mainController.py:1572 +#: ../src\controller\mainController.py:1609 +#: ../src\controller\mainController.py:1629 msgid "Invalid buffer" msgstr "Nevažeći kanal" -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "Ovaj tvit ne sadrži slike." - -#: ../src\controller\mainController.py:1579 +#: ../src\controller\mainController.py:1620 msgid "Picture {0}" msgstr "Slika {0}" -#: ../src\controller\mainController.py:1580 +#: ../src\controller\mainController.py:1621 msgid "Select the picture" msgstr "Izaberite sliku" -#: ../src\controller\mainController.py:1596 +#: ../src\controller\mainController.py:1640 msgid "Unable to extract text" msgstr "Ne mogu da izdvojim tekst." -#: ../src\controller\messages.py:54 +#: ../src\controller\messages.py:56 msgid "Translated" msgstr "Prevedeno" -#: ../src\controller\messages.py:61 +#: ../src\controller\messages.py:63 msgid "There's no URL to be shortened" msgstr "Nema veze koja bi mogla biti skraćena" -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 +#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 msgid "URL shortened" msgstr "Veza je skraćena" -#: ../src\controller\messages.py:80 +#: ../src\controller\messages.py:82 msgid "There's no URL to be expanded" msgstr "Nema veze koja bi mogla biti proširena" -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 +#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 msgid "URL expanded" msgstr "Veza je proširena" -#: ../src\controller\messages.py:104 +#: ../src\controller\messages.py:108 msgid "%s - %s of %d characters" msgstr "%s - %s od %d znakova" -#: ../src\controller\messages.py:108 +#: ../src\controller\messages.py:112 msgid "%s - %s characters" msgstr "%s - %s znakova" -#: ../src\controller\messages.py:262 +#: ../src\controller\messages.py:272 msgid "View item" msgstr "Prikaži stavku" -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Direktna veza" +#: ../src\controller\messages.py:301 +msgid "Link copied to clipboard." +msgstr "Link kopiran u privremenu memoriju." -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:74 +msgid "HTTP" +msgstr "HTTP" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4" +msgstr "SOCKS v4" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4 with DNS support" +msgstr "SOCKS v4 sa DNS podrškom" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5" +msgstr "SOCKS v5" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5 with DNS support" +msgstr "SOCKS v5 sa DNS podrškom" + +#: ../src\controller\settings.py:74 +msgid "System default" +msgstr "Sistemski podrazumevani" + +#: ../src\controller\settings.py:145 ../src\controller\settings.py:211 +#: ../src\wxUI\dialogs\configuration.py:116 msgid "Ask" msgstr "Pitaj" -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:147 ../src\controller\settings.py:213 +#: ../src\wxUI\dialogs\configuration.py:116 msgid "Retweet without comments" msgstr "Retvituj bez komentara" -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:116 msgid "Retweet with comments" msgstr "Retvituj sa komentarima" -#: ../src\controller\settings.py:184 +#: ../src\controller\settings.py:185 msgid "Account settings for %s" msgstr "Postavke naloga za %s" -#: ../src\controller\settings.py:284 +#: ../src\controller\settings.py:288 msgid "Direct Messages" msgstr "Direktne poruke " -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 +#: ../src\controller\user.py:29 ../src\controller\user.py:31 +#: ../src\extra\SpellChecker\wx_ui.py:80 ../src\issueReporter\wx_ui.py:84 +#: ../src\issueReporter\wx_ui.py:87 ../src\wxUI\commonMessageDialogs.py:39 +#: ../src\wxUI\commonMessageDialogs.py:51 +#: ../src\wxUI\commonMessageDialogs.py:58 +#: ../src\wxUI\commonMessageDialogs.py:61 +#: ../src\wxUI\commonMessageDialogs.py:64 +#: ../src\wxUI\commonMessageDialogs.py:67 +#: ../src\wxUI\commonMessageDialogs.py:77 +#: ../src\wxUI\commonMessageDialogs.py:80 +#: ../src\wxUI\commonMessageDialogs.py:83 +#: ../src\wxUI\commonMessageDialogs.py:89 +#: ../src\wxUI\commonMessageDialogs.py:92 msgid "Error" msgstr "Greška" -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 +#: ../src\controller\user.py:29 ../src\wxUI\commonMessageDialogs.py:39 msgid "That user does not exist" msgstr "Taj korisnik ne postoji." -#: ../src\controller\user.py:30 +#: ../src\controller\user.py:31 msgid "User has been suspended" msgstr "Korisnik je suspendovan." -#: ../src\controller\user.py:36 +#: ../src\controller\user.py:37 msgid "Information for %s" msgstr "Informacija za %s" -#: ../src\controller\user.py:66 -#: ../src\extra\AudioUploader\audioUploader.py:124 +#: ../src\controller\user.py:67 ../src\extra\AudioUploader\audioUploader.py:127 msgid "Discarded" msgstr "Odbačeno" @@ -544,31 +569,31 @@ msgstr "Mesto: %s\n" msgid "URL: %s\n" msgstr "Veza: %s\n" -#: ../src\controller\user.py:102 +#: ../src\controller\user.py:104 msgid "Bio: %s\n" msgstr "Bio: %s\n" -#: ../src\controller\user.py:103 ../src\controller\user.py:118 +#: ../src\controller\user.py:105 ../src\controller\user.py:120 msgid "Yes" msgstr "Da" -#: ../src\controller\user.py:104 ../src\controller\user.py:119 +#: ../src\controller\user.py:106 ../src\controller\user.py:121 msgid "No" msgstr "Ne" -#: ../src\controller\user.py:105 +#: ../src\controller\user.py:107 msgid "Protected: %s\n" msgstr "Zaštićeno: %s\n" -#: ../src\controller\user.py:110 +#: ../src\controller\user.py:112 msgid "You follow {0}. " msgstr "Pratite {0}. " -#: ../src\controller\user.py:113 +#: ../src\controller\user.py:115 msgid "{0} is following you." msgstr "{0} vas prati." -#: ../src\controller\user.py:117 +#: ../src\controller\user.py:119 msgid "" "Followers: %s\n" " Friends: %s\n" @@ -576,335 +601,335 @@ msgstr "" "Pratioci: %s\n" " Prijatelji: %s\n" -#: ../src\controller\user.py:120 +#: ../src\controller\user.py:122 msgid "Verified: %s\n" msgstr "Potvrđen: %s\n" -#: ../src\controller\user.py:121 +#: ../src\controller\user.py:123 msgid "Tweets: %s\n" msgstr "Tvitovi: %s\n" -#: ../src\controller\user.py:122 +#: ../src\controller\user.py:124 msgid "Likes: %s" msgstr "Omiljeno: %s" -#: ../src\controller\userActionsController.py:75 +#: ../src\controller\userActionsController.py:74 msgid "You can't ignore direct messages" msgstr "Ne možete zanemariti direktne poruke." -#: ../src\extra\AudioUploader\audioUploader.py:54 +#: ../src\extra\AudioUploader\audioUploader.py:57 msgid "Attaching..." msgstr "Prilažem..." -#: ../src\extra\AudioUploader\audioUploader.py:71 +#: ../src\extra\AudioUploader\audioUploader.py:74 msgid "Pause" msgstr "Zastani" -#: ../src\extra\AudioUploader\audioUploader.py:73 +#: ../src\extra\AudioUploader\audioUploader.py:76 msgid "&Resume" msgstr "&Nastavi" -#: ../src\extra\AudioUploader\audioUploader.py:74 +#: ../src\extra\AudioUploader\audioUploader.py:77 msgid "Resume" msgstr "Nastavi" -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 +#: ../src\extra\AudioUploader\audioUploader.py:79 +#: ../src\extra\AudioUploader\audioUploader.py:106 +#: ../src\extra\AudioUploader\wx_ui.py:37 msgid "&Pause" msgstr "&zastani" -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 +#: ../src\extra\AudioUploader\audioUploader.py:94 +#: ../src\extra\AudioUploader\audioUploader.py:140 msgid "&Stop" msgstr "&Zaustavi" -#: ../src\extra\AudioUploader\audioUploader.py:92 +#: ../src\extra\AudioUploader\audioUploader.py:95 msgid "Recording" msgstr "Snimanje" -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 +#: ../src\extra\AudioUploader\audioUploader.py:100 +#: ../src\extra\AudioUploader\audioUploader.py:151 msgid "Stopped" msgstr "Zaustavljeno" -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 +#: ../src\extra\AudioUploader\audioUploader.py:102 +#: ../src\extra\AudioUploader\wx_ui.py:39 msgid "&Record" msgstr "&Snimi" -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:146 msgid "Playing..." msgstr "Reprodukujem..." -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 +#: ../src\extra\AudioUploader\audioUploader.py:144 +#: ../src\extra\AudioUploader\audioUploader.py:154 +#: ../src\extra\AudioUploader\wx_ui.py:35 msgid "&Play" msgstr "&Pusti" -#: ../src\extra\AudioUploader\audioUploader.py:156 +#: ../src\extra\AudioUploader\audioUploader.py:159 msgid "Recoding audio..." msgstr "Snimam zvučni zapis..." -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 +#: ../src\extra\AudioUploader\transfer.py:82 +#: ../src\extra\AudioUploader\transfer.py:88 msgid "Error in file upload: {0}" msgstr "Greška u otpremanju datoteke: {0}" -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 +#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 msgid "%d day, " msgstr "%d dan, " -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 +#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 msgid "%d days, " msgstr "%d dana, " -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 +#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 msgid "%d hour, " msgstr "%d čas, " -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 +#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 msgid "%d hours, " msgstr "%d časova, " -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 +#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 msgid "%d minute, " msgstr "%d minut, " -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 +#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 msgid "%d minutes, " msgstr "%d minuta, " -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 +#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 msgid "%s second" msgstr "%s sekund" -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 +#: ../src\extra\AudioUploader\utils.py:43 ../src\update\utils.py:43 msgid "%s seconds" msgstr "%s sekundi" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 msgid "File" msgstr "Datoteka" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:21 msgid "Transferred" msgstr "Preuzeto" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:26 msgid "Total file size" msgstr "Ukupna veličina datoteke" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:31 msgid "Transfer rate" msgstr "Brzina prenosa" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:36 msgid "Time left" msgstr "Preostalo vreme" -#: ../src\extra\AudioUploader\wx_ui.py:28 +#: ../src\extra\AudioUploader\wx_ui.py:29 msgid "Attach audio" msgstr "Priloži zvučni zapis" -#: ../src\extra\AudioUploader\wx_ui.py:40 +#: ../src\extra\AudioUploader\wx_ui.py:41 msgid "&Add an existing file" msgstr "&Dodaj postojeću datoteku" -#: ../src\extra\AudioUploader\wx_ui.py:41 +#: ../src\extra\AudioUploader\wx_ui.py:42 msgid "&Discard" msgstr "&Odbaci" -#: ../src\extra\AudioUploader\wx_ui.py:43 +#: ../src\extra\AudioUploader\wx_ui.py:44 msgid "Upload to" msgstr "Otpremi na" -#: ../src\extra\AudioUploader\wx_ui.py:48 +#: ../src\extra\AudioUploader\wx_ui.py:49 msgid "Attach" msgstr "Priloži" -#: ../src\extra\AudioUploader\wx_ui.py:50 +#: ../src\extra\AudioUploader\wx_ui.py:51 msgid "&Cancel" msgstr "&Otkaži" -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: ../src\extra\AudioUploader\wx_ui.py:76 msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" msgstr "Zvučni zapisi (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: ../src\extra\AudioUploader\wx_ui.py:76 msgid "Select the audio file to be uploaded" msgstr "Izaberite zvučni zapis koji želite da otpremite" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 msgid "Audio tweet." msgstr "Tvit sa zvučnim zapisom" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 msgid "User timeline buffer created." msgstr "Kanal sa korisničkom vremenskom linijom je stvoren" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 msgid "Buffer destroied." msgstr "Kanal je izbrisan" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 msgid "Direct message received." msgstr "Primljena direktna poruka." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 msgid "Direct message sent." msgstr "Direktna poruka je poslata." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 msgid "Error." msgstr "Greška." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 msgid "Tweet liked." msgstr "Tvit je označen sa sviđa mi se." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 msgid "Likes buffer updated." msgstr "Kanal sviđanja je ažuriran." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 msgid "Geotweet." msgstr "Tvit sa lokacijom" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 msgid "Tweet contains one or more images" msgstr "Tvit sadrži jednu ili više slika." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 msgid "Boundary reached." msgstr "Vrh ili dno." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 msgid "List updated." msgstr "Lista ažurirana." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 msgid "Too many characters." msgstr "Previše znakova." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 msgid "Mention received." msgstr "Neko vas je spomenuo." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 msgid "New event." msgstr "Novi događaj." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 msgid "{0} is ready." msgstr "{0} je spreman." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 msgid "Mention sent." msgstr "Spominjanje je poslato." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 msgid "Tweet retweeted." msgstr "Tvit je retvitovan." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 msgid "Search buffer updated." msgstr "Kanal pretrage je ažuriran." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 msgid "Tweet received." msgstr "Tvit je primljen." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 msgid "Tweet sent." msgstr "Tvit je poslat." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 msgid "Trending topics buffer updated." msgstr "Kanal sa temama u trendu je ažuriran." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 msgid "New tweet in user timeline buffer." msgstr "Novi tvit u kanalu korisničke vremenske linije." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 msgid "New follower." msgstr "Novi pratilac." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:31 msgid "Volume changed." msgstr "Jačina je promenjena." -#: ../src\extra\SoundsTutorial\wx_ui.py:8 +#: ../src\extra\SoundsTutorial\wx_ui.py:9 msgid "Sounds tutorial" msgstr "Zvučna uputstva" -#: ../src\extra\SoundsTutorial\wx_ui.py:11 +#: ../src\extra\SoundsTutorial\wx_ui.py:12 msgid "Press enter to listen to the sound for the selected event" msgstr "Pritisnite enter kako bi ste čuli zvuk određenog događaja." -#: ../src\extra\SpellChecker\spellchecker.py:57 +#: ../src\extra\SpellChecker\spellchecker.py:60 msgid "Misspelled word: %s" msgstr "Pogrešno napisana reč: %s" -#: ../src\extra\SpellChecker\wx_ui.py:27 +#: ../src\extra\SpellChecker\wx_ui.py:28 msgid "Misspelled word" msgstr "Pogrešno napisana reč." -#: ../src\extra\SpellChecker\wx_ui.py:32 +#: ../src\extra\SpellChecker\wx_ui.py:33 msgid "Context" msgstr "Kontekst." -#: ../src\extra\SpellChecker\wx_ui.py:37 +#: ../src\extra\SpellChecker\wx_ui.py:38 msgid "Suggestions" msgstr "Predlozi" -#: ../src\extra\SpellChecker\wx_ui.py:42 +#: ../src\extra\SpellChecker\wx_ui.py:43 msgid "&Ignore" msgstr "&Zanemari" -#: ../src\extra\SpellChecker\wx_ui.py:43 +#: ../src\extra\SpellChecker\wx_ui.py:44 msgid "I&gnore all" msgstr "Z&anemai sve" -#: ../src\extra\SpellChecker\wx_ui.py:44 +#: ../src\extra\SpellChecker\wx_ui.py:45 msgid "&Replace" msgstr "&Zameni" -#: ../src\extra\SpellChecker\wx_ui.py:45 +#: ../src\extra\SpellChecker\wx_ui.py:46 msgid "R&eplace all" msgstr "Zam&eni sve" -#: ../src\extra\SpellChecker\wx_ui.py:46 +#: ../src\extra\SpellChecker\wx_ui.py:47 msgid "&Add to personal dictionary" msgstr "&Dodaj u lični rečnik" -#: ../src\extra\SpellChecker\wx_ui.py:79 +#: ../src\extra\SpellChecker\wx_ui.py:80 msgid "" "An error has occurred. There are no dictionaries available for the selected " "language in {0}" msgstr "Došlo je do greške. Nema rečnika za odabrani jezik {0}" -#: ../src\extra\SpellChecker\wx_ui.py:82 +#: ../src\extra\SpellChecker\wx_ui.py:83 msgid "Spell check complete." msgstr "Provera pravopisa je završena." -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 +#: ../src\extra\autocompletionUsers\completion.py:20 +#: ../src\extra\autocompletionUsers\completion.py:38 msgid "You have to start writing" msgstr "Morate da počnete da pišete." -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 +#: ../src\extra\autocompletionUsers\completion.py:30 +#: ../src\extra\autocompletionUsers\completion.py:47 msgid "There are no results in your users database" msgstr "Nema rezultata u vašoj bazi korisnika-." -#: ../src\extra\autocompletionUsers\completion.py:33 +#: ../src\extra\autocompletionUsers\completion.py:32 msgid "Autocompletion only works for users." msgstr "Automatsko dovršavanje radi samo za korisnike." -#: ../src\extra\autocompletionUsers\settings.py:27 +#: ../src\extra\autocompletionUsers\settings.py:25 msgid "" "Updating database... You can close this window now. A message will tell you " "when the process finishes." @@ -912,45 +937,45 @@ msgstr "" "Ažuriram bazu podataka... Sada možete zatvoriti ovaj prozor. Dobićete " "obaveštenje kada se proces završi." -#: ../src\extra\autocompletionUsers\wx_manage.py:8 +#: ../src\extra\autocompletionUsers\wx_manage.py:9 msgid "Manage Autocompletion database" msgstr "Upravljaj bazom automatskog dovršavanja" -#: ../src\extra\autocompletionUsers\wx_manage.py:11 +#: ../src\extra\autocompletionUsers\wx_manage.py:12 msgid "Editing {0} users database" msgstr "Uređujem {0} bazu korisničkih podataka" -#: ../src\extra\autocompletionUsers\wx_manage.py:12 +#: ../src\extra\autocompletionUsers\wx_manage.py:13 msgid "Username" msgstr "Korisničko ime" -#: ../src\extra\autocompletionUsers\wx_manage.py:12 +#: ../src\extra\autocompletionUsers\wx_manage.py:13 #: ../src\wxUI\dialogs\configuration.py:144 msgid "Name" msgstr "Ime" -#: ../src\extra\autocompletionUsers\wx_manage.py:15 +#: ../src\extra\autocompletionUsers\wx_manage.py:16 msgid "Add user" msgstr "Dodaj korisnika" -#: ../src\extra\autocompletionUsers\wx_manage.py:16 +#: ../src\extra\autocompletionUsers\wx_manage.py:17 msgid "Remove user" msgstr "Ukloni korisnika" -#: ../src\extra\autocompletionUsers\wx_manage.py:37 +#: ../src\extra\autocompletionUsers\wx_manage.py:38 msgid "Add user to database" msgstr "Dodaj korisnika u bazu podataka" -#: ../src\extra\autocompletionUsers\wx_manage.py:37 +#: ../src\extra\autocompletionUsers\wx_manage.py:38 msgid "Twitter username" msgstr "Twitter korisničko ime" -#: ../src\extra\autocompletionUsers\wx_manage.py:43 +#: ../src\extra\autocompletionUsers\wx_manage.py:44 msgid "The user does not exist" msgstr "Korisnik ne postoji." -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 +#: ../src\extra\autocompletionUsers\wx_manage.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "Error!" msgstr "Greška" @@ -978,449 +1003,449 @@ msgstr "Dovršeno" msgid "{0}'s database of users has been updated." msgstr "{0}'s korisničkih baza podataka je ažurirano." -#: ../src\extra\ocr\OCRSpace.py:5 +#: ../src\extra\ocr\OCRSpace.py:7 msgid "Detect automatically" msgstr "Otkrij automatski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:41 msgid "Danish" msgstr "danski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:43 msgid "Dutch" msgstr "Holandski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:44 msgid "English" msgstr "engleski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:48 msgid "Finnish" msgstr "finski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:49 msgid "French" msgstr "francuski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:52 msgid "German" msgstr "nemački" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:58 msgid "Hungarian" msgstr "mađarski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:63 msgid "Italian" msgstr "italijanski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:64 msgid "Japanese" msgstr "japanski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:68 msgid "Korean" msgstr "korejski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:85 msgid "Polish" msgstr "poljski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:86 msgid "Portuguese" msgstr "portugalski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:89 msgid "Russian" msgstr "ruski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:96 msgid "Spanish" msgstr "španski" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:105 msgid "Turkish" msgstr "turski" -#: ../src\extra\translator\translator.py:12 +#: ../src\extra\translator\translator.py:22 msgid "Afrikaans" msgstr "Afrički" -#: ../src\extra\translator\translator.py:13 +#: ../src\extra\translator\translator.py:23 msgid "Albanian" msgstr "Albanski" -#: ../src\extra\translator\translator.py:14 +#: ../src\extra\translator\translator.py:24 msgid "Amharic" msgstr "Amharic" -#: ../src\extra\translator\translator.py:15 +#: ../src\extra\translator\translator.py:25 msgid "Arabic" msgstr "arapski" -#: ../src\extra\translator\translator.py:16 +#: ../src\extra\translator\translator.py:26 msgid "Armenian" msgstr "jermenski" -#: ../src\extra\translator\translator.py:17 +#: ../src\extra\translator\translator.py:27 msgid "Azerbaijani" msgstr "azerbejdžanski" -#: ../src\extra\translator\translator.py:18 +#: ../src\extra\translator\translator.py:28 msgid "Basque" msgstr "Baskijski" -#: ../src\extra\translator\translator.py:19 +#: ../src\extra\translator\translator.py:29 msgid "Belarusian" msgstr "Beloruski" -#: ../src\extra\translator\translator.py:20 +#: ../src\extra\translator\translator.py:30 msgid "Bengali" msgstr "Bengalski" -#: ../src\extra\translator\translator.py:21 +#: ../src\extra\translator\translator.py:31 msgid "Bihari" msgstr "Bihari" -#: ../src\extra\translator\translator.py:22 +#: ../src\extra\translator\translator.py:32 msgid "Bulgarian" msgstr "Bugarski" -#: ../src\extra\translator\translator.py:23 +#: ../src\extra\translator\translator.py:33 msgid "Burmese" msgstr "Burmese" -#: ../src\extra\translator\translator.py:24 +#: ../src\extra\translator\translator.py:34 msgid "Catalan" msgstr "Katalonski" -#: ../src\extra\translator\translator.py:25 +#: ../src\extra\translator\translator.py:35 msgid "Cherokee" msgstr "Cherokee" -#: ../src\extra\translator\translator.py:26 +#: ../src\extra\translator\translator.py:36 msgid "Chinese" msgstr "Kineski" -#: ../src\extra\translator\translator.py:27 +#: ../src\extra\translator\translator.py:37 msgid "Chinese_simplified" msgstr "kineski pojednostavljeni" -#: ../src\extra\translator\translator.py:28 +#: ../src\extra\translator\translator.py:38 msgid "Chinese_traditional" msgstr "kineski tradicionalni" -#: ../src\extra\translator\translator.py:29 +#: ../src\extra\translator\translator.py:39 msgid "Croatian" msgstr "hrvatski" -#: ../src\extra\translator\translator.py:30 +#: ../src\extra\translator\translator.py:40 msgid "Czech" msgstr "češki" -#: ../src\extra\translator\translator.py:32 +#: ../src\extra\translator\translator.py:42 msgid "Dhivehi" msgstr "Dhivehi" -#: ../src\extra\translator\translator.py:35 +#: ../src\extra\translator\translator.py:45 msgid "Esperanto" msgstr "Esperanto" -#: ../src\extra\translator\translator.py:36 +#: ../src\extra\translator\translator.py:46 msgid "Estonian" msgstr "estonski" -#: ../src\extra\translator\translator.py:37 +#: ../src\extra\translator\translator.py:47 msgid "Filipino" msgstr "filipinski" -#: ../src\extra\translator\translator.py:40 +#: ../src\extra\translator\translator.py:50 msgid "Galician" msgstr "galicijski" -#: ../src\extra\translator\translator.py:41 +#: ../src\extra\translator\translator.py:51 msgid "Georgian" msgstr "gruzijski" -#: ../src\extra\translator\translator.py:43 +#: ../src\extra\translator\translator.py:53 msgid "Greek" msgstr "grčki" -#: ../src\extra\translator\translator.py:44 +#: ../src\extra\translator\translator.py:54 msgid "Guarani" msgstr "Guarani" -#: ../src\extra\translator\translator.py:45 +#: ../src\extra\translator\translator.py:55 msgid "Gujarati" msgstr "Gujarati" -#: ../src\extra\translator\translator.py:46 +#: ../src\extra\translator\translator.py:56 msgid "Hebrew" msgstr "jevrejski" -#: ../src\extra\translator\translator.py:47 +#: ../src\extra\translator\translator.py:57 msgid "Hindi" msgstr "indijski" -#: ../src\extra\translator\translator.py:49 +#: ../src\extra\translator\translator.py:59 msgid "Icelandic" msgstr "islandski" -#: ../src\extra\translator\translator.py:50 +#: ../src\extra\translator\translator.py:60 msgid "Indonesian" msgstr "indonežanski" -#: ../src\extra\translator\translator.py:51 +#: ../src\extra\translator\translator.py:61 msgid "Inuktitut" msgstr "Inuktitut" -#: ../src\extra\translator\translator.py:52 +#: ../src\extra\translator\translator.py:62 msgid "Irish" msgstr "irski" -#: ../src\extra\translator\translator.py:55 +#: ../src\extra\translator\translator.py:65 msgid "Kannada" msgstr "Kannada" -#: ../src\extra\translator\translator.py:56 +#: ../src\extra\translator\translator.py:66 msgid "Kazakh" msgstr "Kazakh" -#: ../src\extra\translator\translator.py:57 +#: ../src\extra\translator\translator.py:67 msgid "Khmer" msgstr "Khmer" -#: ../src\extra\translator\translator.py:59 +#: ../src\extra\translator\translator.py:69 msgid "Kurdish" msgstr "kurdski" -#: ../src\extra\translator\translator.py:60 +#: ../src\extra\translator\translator.py:70 msgid "Kyrgyz" msgstr "kirgistanski" -#: ../src\extra\translator\translator.py:61 +#: ../src\extra\translator\translator.py:71 msgid "Laothian" msgstr "Laothian" -#: ../src\extra\translator\translator.py:62 +#: ../src\extra\translator\translator.py:72 msgid "Latvian" msgstr "letonski" -#: ../src\extra\translator\translator.py:63 +#: ../src\extra\translator\translator.py:73 msgid "Lithuanian" msgstr "litvanski" -#: ../src\extra\translator\translator.py:64 +#: ../src\extra\translator\translator.py:74 msgid "Macedonian" msgstr "makedonski" -#: ../src\extra\translator\translator.py:65 +#: ../src\extra\translator\translator.py:75 msgid "Malay" msgstr "Malay" -#: ../src\extra\translator\translator.py:66 +#: ../src\extra\translator\translator.py:76 msgid "Malayalam" msgstr "Malayalam" -#: ../src\extra\translator\translator.py:67 +#: ../src\extra\translator\translator.py:77 msgid "Maltese" msgstr "malteški" -#: ../src\extra\translator\translator.py:68 +#: ../src\extra\translator\translator.py:78 msgid "Marathi" msgstr "Marathi" -#: ../src\extra\translator\translator.py:69 +#: ../src\extra\translator\translator.py:79 msgid "Mongolian" msgstr "mongolski" -#: ../src\extra\translator\translator.py:70 +#: ../src\extra\translator\translator.py:80 msgid "Nepali" msgstr "nepalski" -#: ../src\extra\translator\translator.py:71 +#: ../src\extra\translator\translator.py:81 msgid "Norwegian" msgstr "norveški" -#: ../src\extra\translator\translator.py:72 +#: ../src\extra\translator\translator.py:82 msgid "Oriya" msgstr "Oriya" -#: ../src\extra\translator\translator.py:73 +#: ../src\extra\translator\translator.py:83 msgid "Pashto" msgstr "Pashto" -#: ../src\extra\translator\translator.py:74 +#: ../src\extra\translator\translator.py:84 msgid "Persian" msgstr "persijski" -#: ../src\extra\translator\translator.py:77 +#: ../src\extra\translator\translator.py:87 msgid "Punjabi" msgstr "Punjabi" -#: ../src\extra\translator\translator.py:78 +#: ../src\extra\translator\translator.py:88 msgid "Romanian" msgstr "rumunski" -#: ../src\extra\translator\translator.py:80 +#: ../src\extra\translator\translator.py:90 msgid "Sanskrit" msgstr "Sanskrit" -#: ../src\extra\translator\translator.py:81 +#: ../src\extra\translator\translator.py:91 msgid "Serbian" msgstr "srpski" -#: ../src\extra\translator\translator.py:82 +#: ../src\extra\translator\translator.py:92 msgid "Sindhi" msgstr "Sindhi" -#: ../src\extra\translator\translator.py:83 +#: ../src\extra\translator\translator.py:93 msgid "Sinhalese" msgstr "Sinhalese" -#: ../src\extra\translator\translator.py:84 +#: ../src\extra\translator\translator.py:94 msgid "Slovak" msgstr "slovački" -#: ../src\extra\translator\translator.py:85 +#: ../src\extra\translator\translator.py:95 msgid "Slovenian" msgstr "slovenački" -#: ../src\extra\translator\translator.py:87 +#: ../src\extra\translator\translator.py:97 msgid "Swahili" msgstr "Swahili" -#: ../src\extra\translator\translator.py:88 +#: ../src\extra\translator\translator.py:98 msgid "Swedish" msgstr "švedski" -#: ../src\extra\translator\translator.py:89 +#: ../src\extra\translator\translator.py:99 msgid "Tajik" msgstr "Tajik" -#: ../src\extra\translator\translator.py:90 +#: ../src\extra\translator\translator.py:100 msgid "Tamil" msgstr "Tamil" -#: ../src\extra\translator\translator.py:91 +#: ../src\extra\translator\translator.py:101 msgid "Tagalog" msgstr "Tagalog" -#: ../src\extra\translator\translator.py:92 +#: ../src\extra\translator\translator.py:102 msgid "Telugu" msgstr "Telugu" -#: ../src\extra\translator\translator.py:93 +#: ../src\extra\translator\translator.py:103 msgid "Thai" msgstr "Thai" -#: ../src\extra\translator\translator.py:94 +#: ../src\extra\translator\translator.py:104 msgid "Tibetan" msgstr "tibetanski" -#: ../src\extra\translator\translator.py:96 +#: ../src\extra\translator\translator.py:106 msgid "Ukrainian" msgstr "ukrajinski" -#: ../src\extra\translator\translator.py:97 +#: ../src\extra\translator\translator.py:107 msgid "Urdu" msgstr "Urdu" -#: ../src\extra\translator\translator.py:98 +#: ../src\extra\translator\translator.py:108 msgid "Uzbek" msgstr "uzbekitanski" -#: ../src\extra\translator\translator.py:99 +#: ../src\extra\translator\translator.py:109 msgid "Uighur" msgstr "Uighur" -#: ../src\extra\translator\translator.py:100 +#: ../src\extra\translator\translator.py:110 msgid "Vietnamese" msgstr "vijetnamski" -#: ../src\extra\translator\translator.py:101 +#: ../src\extra\translator\translator.py:111 msgid "Welsh" msgstr "velški" -#: ../src\extra\translator\translator.py:102 +#: ../src\extra\translator\translator.py:112 msgid "Yiddish" msgstr "Yiddish" -#: ../src\extra\translator\wx_ui.py:44 +#: ../src\extra\translator\wx_ui.py:29 msgid "Translate message" msgstr "prevedi poruku" -#: ../src\extra\translator\wx_ui.py:47 +#: ../src\extra\translator\wx_ui.py:32 msgid "Target language" msgstr "Odredišni jezik" -#: ../src\issueReporter\issueReporter.py:30 +#: ../src\issueReporter\issueReporter.py:32 #: ../src\wxUI\dialogs\configuration.py:359 #: ../src\wxUI\dialogs\configuration.py:368 msgid "General" msgstr "opšte" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "always" msgstr "Uvek" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "have not tried" msgstr "Nismo pokušali" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "random" msgstr "slučajno" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "sometimes" msgstr "Ponekad" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "unable to duplicate" msgstr "Ne mogu da dupliram" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "block" msgstr "blokiraj" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "crash" msgstr "pad" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "feature" msgstr "Mogućnost" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "major" msgstr "glavno" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "minor" msgstr "sporedno" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "text" msgstr "tekst" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "trivial" msgstr "beznačajno" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "tweak" msgstr "podešavanje" -#: ../src\issueReporter\wx_ui.py:25 +#: ../src\issueReporter\wx_ui.py:26 msgid "Report an error" msgstr "Prijavi grešku" -#: ../src\issueReporter\wx_ui.py:28 +#: ../src\issueReporter\wx_ui.py:29 msgid "Select a category" msgstr "Izaberite vrstu" -#: ../src\issueReporter\wx_ui.py:36 +#: ../src\issueReporter\wx_ui.py:37 msgid "" "Briefly describe what happened. You will be able to thoroughly explain it " "later" @@ -1428,19 +1453,19 @@ msgstr "" "Ukratko objasnite šta se dogodilo. Bićete u mogućnosti da iznesete više " "pojedinosti kasnije." -#: ../src\issueReporter\wx_ui.py:45 +#: ../src\issueReporter\wx_ui.py:46 msgid "Here, you can describe the bug in detail" msgstr "Ovde, možete opisati sve pojedinosti greške." -#: ../src\issueReporter\wx_ui.py:55 +#: ../src\issueReporter\wx_ui.py:56 msgid "how often does this bug happen?" msgstr "Koliko se često ova greška dešava?" -#: ../src\issueReporter\wx_ui.py:62 +#: ../src\issueReporter\wx_ui.py:63 msgid "Select the importance that you think this bug has" msgstr "Izaberite važnost greške" -#: ../src\issueReporter\wx_ui.py:69 +#: ../src\issueReporter\wx_ui.py:70 msgid "" "I know that the {0} bug system will get my Twitter username to contact me " "and fix the bug quickly" @@ -1448,20 +1473,20 @@ msgstr "" "Znam da će {0} sistem za prijavljivanje grešaka imati moje Twitter " "korisničko ime za kontakt i popraviti grešku brzo" -#: ../src\issueReporter\wx_ui.py:72 +#: ../src\issueReporter\wx_ui.py:73 msgid "Send report" msgstr "Pošalji izveštaj" -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "Otkaži" -#: ../src\issueReporter\wx_ui.py:83 +#: ../src\issueReporter\wx_ui.py:84 msgid "You must fill out both fields" msgstr "Morate ispuniti oba polja." -#: ../src\issueReporter\wx_ui.py:86 +#: ../src\issueReporter\wx_ui.py:87 msgid "" "You need to mark the checkbox to provide us your twitter username to contact " "you if it is necessary." @@ -1469,7 +1494,7 @@ msgstr "" "Morate označiti kvadratić u kome prihvatate da nam pošaljete vaše twitter " "korisničko ime, kako bi vas kontaktirali ako je to neophodno." -#: ../src\issueReporter\wx_ui.py:89 +#: ../src\issueReporter\wx_ui.py:90 msgid "" "Thanks for reporting this bug! In future versions, you may be able to find " "it in the changes list. You've reported the bug number %i" @@ -1477,15 +1502,15 @@ msgstr "" "Hvala vam što ste prijavili ovu grešku! U narednim verzijama, videćete " "ispravku na spisku promena. Prijavili ste grešku pod brojem %i" -#: ../src\issueReporter\wx_ui.py:89 +#: ../src\issueReporter\wx_ui.py:90 msgid "reported" msgstr "Prijavljeno" -#: ../src\issueReporter\wx_ui.py:93 +#: ../src\issueReporter\wx_ui.py:94 msgid "Error while reporting" msgstr "Greška prilikom prijavljivanja" -#: ../src\issueReporter\wx_ui.py:93 +#: ../src\issueReporter\wx_ui.py:94 msgid "" "Something unexpected occurred while trying to report the bug. Please, try " "again later" @@ -1525,8 +1550,8 @@ msgstr "Prikaži ili sakrij okruženje" msgid "New tweet" msgstr "Novi tvit" -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 +#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 +#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 msgid "Retweet" msgstr "Retvituj" @@ -1718,6 +1743,10 @@ msgstr "Ažurira kanal i preuzima moguće izgubljene stavke." msgid "Extracts the text from a picture and displays the result in a dialog." msgstr "Izdvaja tekst iz slike i prikazuje rezultat u dijaloškom prozoru." +#: ../src\keystrokeEditor\constants.py:59 +msgid "Adds an alias to an user" +msgstr "Dodaje nadimak za korisnika" + #: ../src\keystrokeEditor\wx_ui.py:8 msgid "Keystroke editor" msgstr "Uređivač prečica" @@ -1730,63 +1759,76 @@ msgstr "Izaberite prečicu koju želite da izmenite" msgid "Keystroke" msgstr "Prečica" -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 +#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:10 +#: ../src\wxUI\dialogs\userActions.py:19 ../src\wxUI\dialogs\userActions.py:20 msgid "Action" msgstr "Radnja" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\wxUI\dialogs\lists.py:20 msgid "Edit" msgstr "Izmeni" -#: ../src\keystrokeEditor\wx_ui.py:20 +#: ../src\keystrokeEditor\wx_ui.py:20 ../src\keystrokeEditor\wx_ui.py:50 +msgid "Undefine keystroke" +msgstr "Izbriši prečicu" + +#: ../src\keystrokeEditor\wx_ui.py:21 msgid "Execute action" msgstr "Izvrši radnju" -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 +#: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 +#: ../src\wxUI\dialogs\utils.py:39 ../src\wxUI\dialogs\utils.py:71 msgid "Close" msgstr "Zatvori" -#: ../src\keystrokeEditor\wx_ui.py:48 +#: ../src\keystrokeEditor\wx_ui.py:42 +msgid "Undefined" +msgstr "Izbrisana" + +#: ../src\keystrokeEditor\wx_ui.py:50 +msgid "Are you sure you want to undefine this keystroke?" +msgstr "Da li zaista želite da izbrišete ovu prečicu?" + +#: ../src\keystrokeEditor\wx_ui.py:54 msgid "Editing keystroke" msgstr "Uređujem prečicu" -#: ../src\keystrokeEditor\wx_ui.py:51 +#: ../src\keystrokeEditor\wx_ui.py:57 msgid "Control" msgstr "Control" -#: ../src\keystrokeEditor\wx_ui.py:52 +#: ../src\keystrokeEditor\wx_ui.py:58 msgid "Alt" msgstr "Alt" -#: ../src\keystrokeEditor\wx_ui.py:53 +#: ../src\keystrokeEditor\wx_ui.py:59 msgid "Shift" msgstr "Shift" -#: ../src\keystrokeEditor\wx_ui.py:54 +#: ../src\keystrokeEditor\wx_ui.py:60 msgid "Windows" msgstr "Windows" -#: ../src\keystrokeEditor\wx_ui.py:60 +#: ../src\keystrokeEditor\wx_ui.py:66 msgid "Key" msgstr "Taster" -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\utils.py:36 +#: ../src\wxUI\dialogs\utils.py:68 msgid "OK" msgstr "U redu" -#: ../src\keystrokeEditor\wx_ui.py:78 +#: ../src\keystrokeEditor\wx_ui.py:84 msgid "You need to use the Windows key" msgstr "Morate koristiti Windows taster" -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 +#: ../src\keystrokeEditor\wx_ui.py:84 ../src\keystrokeEditor\wx_ui.py:87 msgid "Invalid keystroke" msgstr "Pogrešna prečica" -#: ../src\keystrokeEditor\wx_ui.py:81 +#: ../src\keystrokeEditor\wx_ui.py:87 msgid "You must provide a character for the keystroke" msgstr "Morate omogućiti znak u prečici" @@ -1794,11 +1836,11 @@ msgstr "Morate omogućiti znak u prečici" msgid "User default" msgstr "Podrazumevano" -#: ../src\main.py:105 +#: ../src\main.py:120 msgid "https://twblue.es/donate" msgstr "https://twblue.es/donate" -#: ../src\main.py:122 +#: ../src\main.py:137 msgid "" "{0} is already running. Close the other instance before starting this one. " "If you're sure that {0} isn't running, try deleting the file at {1}. If " @@ -1809,43 +1851,43 @@ msgstr "" "datoteku koja se nalazi na {1}. Ako niste sigurni kako ovo da uradite, " "kontaktirajte {0} programere." -#: ../src\sessionmanager\wxUI.py:8 +#: ../src\sessionmanager\wxUI.py:9 msgid "Session manager" msgstr "Upravljanje sesijama" -#: ../src\sessionmanager\wxUI.py:11 +#: ../src\sessionmanager\wxUI.py:12 msgid "Accounts list" msgstr "Lista naloga" -#: ../src\sessionmanager\wxUI.py:13 +#: ../src\sessionmanager\wxUI.py:14 msgid "Account" msgstr "Nalog" -#: ../src\sessionmanager\wxUI.py:17 +#: ../src\sessionmanager\wxUI.py:18 msgid "New account" msgstr "Novi nalog" -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 +#: ../src\sessionmanager\wxUI.py:19 ../src\sessionmanager\wxUI.py:65 msgid "Remove account" msgstr "Ukloni nalog" -#: ../src\sessionmanager\wxUI.py:19 +#: ../src\sessionmanager\wxUI.py:20 msgid "Global Settings" msgstr "Globalna podešavanja" -#: ../src\sessionmanager\wxUI.py:42 +#: ../src\sessionmanager\wxUI.py:43 msgid "Account Error" msgstr "Greška naloga" -#: ../src\sessionmanager\wxUI.py:42 +#: ../src\sessionmanager\wxUI.py:43 msgid "You need to configure an account." msgstr "Morate podesiti nalog." -#: ../src\sessionmanager\wxUI.py:48 +#: ../src\sessionmanager\wxUI.py:49 msgid "Authorization" msgstr "Autorizacija" -#: ../src\sessionmanager\wxUI.py:48 +#: ../src\sessionmanager\wxUI.py:49 msgid "" "The request to authorize your Twitter account will be opened in your " "browser. You only need to do this once. Would you like to continue?" @@ -1853,15 +1895,15 @@ msgstr "" "Zahtev za autorizaciju vašeg Twitter naloga će biti otvoren u vašem " "pregledniku. Potrebno je da to uradite samo jednom. Želite li da nastavite?" -#: ../src\sessionmanager\wxUI.py:52 +#: ../src\sessionmanager\wxUI.py:53 msgid "Authorized account %d" msgstr "Autorizovan nalog %d" -#: ../src\sessionmanager\wxUI.py:58 +#: ../src\sessionmanager\wxUI.py:59 msgid "Invalid user token" msgstr "Pogrešan korisnički token" -#: ../src\sessionmanager\wxUI.py:58 +#: ../src\sessionmanager\wxUI.py:59 msgid "" "Your access token is invalid or the authorization has failed. Please try " "again." @@ -1869,30 +1911,66 @@ msgstr "" "Vaš pristupni token je pogrešan ili autorizacija nije uspela. Molimo vas, " "pokušajte ponovo." -#: ../src\sessionmanager\wxUI.py:64 +#: ../src\sessionmanager\wxUI.py:65 msgid "Do you really want to delete this account?" msgstr "Želite li zaista da izbrišete ovaj nalog?" -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 +#: ../src\sessionmanager\wxUI.py:81 +msgid "Authentication error for session {}" +msgstr "Greška u autentikaciji za sesiju {}" + +#: ../src\sessionmanager\wxUI.py:81 +msgid "" +"TWBlue is unable to authenticate the account for {} in Twitter. It might be " +"due to an invalid or expired token, revoqued access to the application, or " +"after an account reactivation. Please remove the account manually from your " +"Twitter sessions in order to stop seeing this message." +msgstr "" +"TWBlue ne može da izvrši autentikaciju naloga za {} na Twitteru. Ovo se može " +"desiti zbog neispravnog ili isteklog tokena, odbijanja pristupa aplikacije, " +"ili nakon ponovne aktivacije naloga. Molimo ručno uklonite nalog iz vaših " +"Twitter sesija kako biste prestali da dobijate ovu poruku." + +#: ../src\sessions\base.py:111 +msgid "" +"An exception occurred while saving the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"Došlo je do greške pri čuvanju {app} baze podataka. Biće obrisana i " +"automatski ponovno napravljena. Ako se ova greška nastavi, pošaljite " +"dnevnike sa greškama {app} programerima." + +#: ../src\sessions\base.py:151 +msgid "" +"An exception occurred while loading the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"Došlo je do greške pri čuvanju {app} baze podataka. Biće obrisana i " +"automatski ponovno napravljena. Ako se ova greška nastavi, pošaljite " +"dnevnike sa greškama {app} programerima." + +#: ../src\sessions\twitter\compose.py:38 ../src\sessions\twitter\compose.py:81 +#: ../src\sessions\twitter\compose.py:146 +#: ../src\sessions\twitter\compose.py:155 msgid "dddd, MMMM D, YYYY H:m:s" msgstr "dddd, MMMM D, YYYY H:m:s" -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 +#: ../src\sessions\twitter\compose.py:89 ../src\sessions\twitter\compose.py:91 msgid "Dm to %s " msgstr "Direktna poruka za %s " -#: ../src\sessions\twitter\compose.py:141 +#: ../src\sessions\twitter\compose.py:130 msgid "{0}. Quoted tweet from @{1}: {2}" msgstr "{0}. citira tvit od @{1}: {2}" -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 +#: ../src\sessions\twitter\compose.py:157 +#: ../src\sessions\twitter\compose.py:159 msgid "Unavailable" msgstr "Nedostupno" -#: ../src\sessions\twitter\compose.py:166 +#: ../src\sessions\twitter\compose.py:160 msgid "" "%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " "Twitter %s" @@ -1900,47 +1978,52 @@ msgstr "" "%s (@%s). %s pratilaca, %s prijatelja, %s tvitova. Poslednji tvit %s. " "Pridružio se twitteru %s" -#: ../src\sessions\twitter\compose.py:170 +#: ../src\sessions\twitter\compose.py:164 msgid "No description available" msgstr "Opis nije dostupan" -#: ../src\sessions\twitter\compose.py:174 +#: ../src\sessions\twitter\compose.py:168 msgid "private" msgstr "Privatno" -#: ../src\sessions\twitter\compose.py:175 +#: ../src\sessions\twitter\compose.py:169 msgid "public" msgstr "Javno" -#: ../src\sessions\twitter\session.py:169 -msgid "There are no more items to retrieve in this buffer." -msgstr "Nema više stavki koje se mogu preuzeti u ovom kanalu." - -#: ../src\sessions\twitter\session.py:215 +#: ../src\sessions\twitter\session.py:208 msgid "%s failed. Reason: %s" msgstr "%s nije uspelo. Razlog: %s" -#: ../src\sessions\twitter\session.py:221 +#: ../src\sessions\twitter\session.py:214 msgid "%s succeeded." msgstr "%s uspelo." -#: ../src\sessions\twitter\utils.py:225 +#: ../src\sessions\twitter\session.py:423 +#: ../src\sessions\twitter\session.py:501 +msgid "Deleted account" +msgstr "Obrisan nalog" + +#: ../src\sessions\twitter\utils.py:231 msgid "Sorry, you are not authorised to see this status." msgstr "Izvinite, nije vam dozvoljeno da vidite ovaj status." -#: ../src\sessions\twitter\utils.py:227 +#: ../src\sessions\twitter\utils.py:233 msgid "No status found with that ID" msgstr "Status nije pronađen pod tim brojem." -#: ../src\sessions\twitter\utils.py:229 +#: ../src\sessions\twitter\utils.py:235 msgid "Error code {0}" msgstr "Kod greške {0}" -#: ../src\sessions\twitter\wxUI.py:6 +#: ../src\sessions\twitter\utils.py:262 +msgid "{user_1}, {user_2} and {all_users} more: {text}" +msgstr "{user_1}, {user_2} i još {all_users}: {text}" + +#: ../src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." msgstr "Autorizacija naloga..." -#: ../src\sessions\twitter\wxUI.py:9 +#: ../src\sessions\twitter\wxUI.py:10 msgid "Enter your PIN code here" msgstr "Ovde upišite vaš PIN kod" @@ -1948,11 +2031,11 @@ msgstr "Ovde upišite vaš PIN kod" msgid "Stopped." msgstr "Zaustavljeno" -#: ../src\update\wxUpdater.py:10 +#: ../src\update\wxUpdater.py:14 msgid "New version for %s" msgstr "Nova verzija za %s" -#: ../src\update\wxUpdater.py:10 +#: ../src\update\wxUpdater.py:14 msgid "" "There's a new %s version available, released on %s. Would you like to " "download it now?\n" @@ -1969,84 +2052,85 @@ msgstr "" "Promene:\n" "%s" -#: ../src\update\wxUpdater.py:18 +#: ../src\update\wxUpdater.py:22 msgid "Download in Progress" msgstr "Preuzimanje u toku" -#: ../src\update\wxUpdater.py:18 +#: ../src\update\wxUpdater.py:22 msgid "Downloading the new version..." msgstr "Preuzimam novu verziju..." -#: ../src\update\wxUpdater.py:28 +#: ../src\update\wxUpdater.py:32 msgid "Updating... %s of %s" msgstr "Ažuriram... %s od %s" -#: ../src\update\wxUpdater.py:31 +#: ../src\update\wxUpdater.py:35 msgid "Done!" msgstr "Dovršeno" -#: ../src\update\wxUpdater.py:31 +#: ../src\update\wxUpdater.py:35 msgid "" "The update has been downloaded and installed successfully. Press OK to " "continue." msgstr "" "Ažuriranje je preuzeto i uspešno instalirano. Pritisnite u redu za nastavak." -#: ../src\wxUI\buffers\base.py:11 +#: ../src\wxUI\buffers\base.py:12 msgid "Client" msgstr "Klijent" -#: ../src\wxUI\buffers\base.py:11 +#: ../src\wxUI\buffers\base.py:12 msgid "Text" msgstr "Tekst" -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 msgid "Date" msgstr "Datum" -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 +#: ../src\wxUI\buffers\user_searches.py:11 +#: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 +#: ../src\wxUI\dialogs\utils.py:59 msgid "User" msgstr "Korisnik" -#: ../src\wxUI\buffers\base.py:27 +#: ../src\wxUI\buffers\base.py:28 msgid "Direct message" msgstr "Direktna poruka" -#: ../src\wxUI\buffers\events.py:13 +#: ../src\wxUI\buffers\events.py:14 msgid "Event" msgstr "Događaj" -#: ../src\wxUI\buffers\events.py:15 +#: ../src\wxUI\buffers\events.py:16 msgid "Remove event" msgstr "Ukloni događaj" -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 +#: ../src\wxUI\buffers\panels.py:12 ../src\wxUI\buffers\panels.py:20 msgid "Login" msgstr "Prijavi se" -#: ../src\wxUI\buffers\panels.py:13 +#: ../src\wxUI\buffers\panels.py:14 msgid "Log in automatically" msgstr "Prijavi se automatski" -#: ../src\wxUI\buffers\panels.py:21 +#: ../src\wxUI\buffers\panels.py:22 msgid "Logout" msgstr "Odjavi se" -#: ../src\wxUI\buffers\trends.py:8 +#: ../src\wxUI\buffers\trends.py:9 msgid "Trending topic" msgstr "Tema trenda" -#: ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\buffers\trends.py:19 msgid "Tweet about this trend" msgstr "Tvituj o ovom trendu" -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 +#: ../src\wxUI\buffers\trends.py:20 ../src\wxUI\menus.py:97 msgid "Search topic" msgstr "tema Pretrage" -#: ../src\wxUI\commonMessageDialogs.py:6 +#: ../src\wxUI\commonMessageDialogs.py:7 msgid "" "This retweet is over 140 characters. Would you like to post it as a mention " "to the poster with your comments and a link to the original tweet?" @@ -2054,11 +2138,11 @@ msgstr "" "Ovaj retvit ima preko 140 znakova. Želite li da pošaljete to kao spominjanje " "na pošiljaoca sa vašim komentarom i linkom do izvornog tvita?" -#: ../src\wxUI\commonMessageDialogs.py:9 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Would you like to add a comment to this tweet?" msgstr "Želite li da dodate komentar na ovaj tvit?" -#: ../src\wxUI\commonMessageDialogs.py:12 +#: ../src\wxUI\commonMessageDialogs.py:13 msgid "" "Do you really want to delete this tweet? It will be deleted from Twitter as " "well." @@ -2066,27 +2150,27 @@ msgstr "" "Želite li zaista da izbrišete ovaj tvit? On će biti izbrisan sa Twitera " "takođe." -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 +#: ../src\wxUI\commonMessageDialogs.py:13 ../src\wxUI\dialogs\lists.py:149 msgid "Delete" msgstr "Izbriši" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Do you really want to close {0}?" msgstr "Želite li stvarno da zatvorite {0}?" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Exit" msgstr "Izlaz" -#: ../src\wxUI\commonMessageDialogs.py:19 +#: ../src\wxUI\commonMessageDialogs.py:20 msgid " {0} must be restarted for these changes to take effect." msgstr " {0} se mora ponovo pokrenuti kako bi ove promene stupile na snagu." -#: ../src\wxUI\commonMessageDialogs.py:19 +#: ../src\wxUI\commonMessageDialogs.py:20 msgid "Restart {0} " msgstr "Ponovo pokreni {0} " -#: ../src\wxUI\commonMessageDialogs.py:22 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "" "Are you sure you want to delete this user from the database? This user will " "not appear in autocomplete results anymore." @@ -2095,20 +2179,20 @@ msgstr "" "Ovaj korisnik se više neće pojavljivati u rezultatima automatskog " "dovršavanja." -#: ../src\wxUI\commonMessageDialogs.py:22 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "Confirm" msgstr "Potvrdi" -#: ../src\wxUI\commonMessageDialogs.py:25 +#: ../src\wxUI\commonMessageDialogs.py:26 msgid "Enter the name of the client : " msgstr "Unesite ime klijenta" -#: ../src\wxUI\commonMessageDialogs.py:25 +#: ../src\wxUI\commonMessageDialogs.py:26 #: ../src\wxUI\dialogs\configuration.py:246 msgid "Add client" msgstr "Dodaj program" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "" "Do you really want to empty this buffer? It's items will be removed from " "the list but not from Twitter" @@ -2116,35 +2200,35 @@ msgstr "" "Želite li zaista da očistite ovaj kanal? Njegove stavke će biti uklonjene sa " "kanala, ali ne i sa twittera." -#: ../src\wxUI\commonMessageDialogs.py:31 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "Empty buffer" msgstr "Očisti kanal" -#: ../src\wxUI\commonMessageDialogs.py:35 +#: ../src\wxUI\commonMessageDialogs.py:36 msgid "Do you really want to destroy this buffer?" msgstr "Želite li zaista da izbrišete ovaj kanal?" -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 +#: ../src\wxUI\commonMessageDialogs.py:36 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Attention" msgstr "Pažnja" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "A timeline for this user already exists. You can't open another" msgstr "" "Vremenska linija za tog korisnika već postoji. Ne možete otvoriti još jednu." -#: ../src\wxUI\commonMessageDialogs.py:41 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "Existing timeline" msgstr "Postojeća vremenska linija." -#: ../src\wxUI\commonMessageDialogs.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "This user has no tweets, so you can't open a timeline for them." msgstr "" "Ovaj korisnik nema nijedan tvit, te s toga ne možete otvoriti njegovu " "vremensku liniju." -#: ../src\wxUI\commonMessageDialogs.py:47 +#: ../src\wxUI\commonMessageDialogs.py:48 msgid "" "This is a protected Twitter user, which means you can't open a timeline " "using the Streaming API. The user's tweets will not update due to a twitter " @@ -2154,12 +2238,12 @@ msgstr "" "vremensku liniju koristeći Streaming API. Tvitovi korisnika neće biti " "ažurirani zbog politike tvitera. Želite li da nastavite??" -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 +#: ../src\wxUI\commonMessageDialogs.py:48 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "Warning" msgstr "Upozorenje" -#: ../src\wxUI\commonMessageDialogs.py:50 +#: ../src\wxUI\commonMessageDialogs.py:51 msgid "" "This is a protected user account, you need to follow this user to view their " "tweets or likes." @@ -2167,7 +2251,7 @@ msgstr "" "Ovaj korisnik je zaštitio svoj nalog. Morate ga zapratiti kako bi videli " "njegove tvitove ili omiljene stvari." -#: ../src\wxUI\commonMessageDialogs.py:53 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "" "If you like {0} we need your help to keep it going. Help us by donating to " "the project. This will help us pay for the server, the domain and some other " @@ -2181,42 +2265,42 @@ msgstr "" "motivaciju da nastavimo sa razvojem {0}, i da sačuvamo {0} besplatnim. " "Želite li da donirate sada?" -#: ../src\wxUI\commonMessageDialogs.py:53 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "We need your help" msgstr "Potrebna nam je vaša pomoć" -#: ../src\wxUI\commonMessageDialogs.py:57 +#: ../src\wxUI\commonMessageDialogs.py:58 msgid "This user has no tweets. {0} can't create a timeline." msgstr "Ovaj korisnik nema tvitove. {0} ne može da napravi vremensku liniju." -#: ../src\wxUI\commonMessageDialogs.py:60 +#: ../src\wxUI\commonMessageDialogs.py:61 msgid "This user has no favorited tweets. {0} can't create a timeline." msgstr "" "Ovaj korisnik nema omiljenih tvitova. {0} ne može da napravi vremensku " "liniju." -#: ../src\wxUI\commonMessageDialogs.py:63 +#: ../src\wxUI\commonMessageDialogs.py:64 msgid "This user has no followers. {0} can't create a timeline." msgstr "Ovog korisnika niko ne prati. {0} ne može da kreira vremensku liniju." -#: ../src\wxUI\commonMessageDialogs.py:66 +#: ../src\wxUI\commonMessageDialogs.py:67 msgid "This user has no friends. {0} can't create a timeline." msgstr "" "Ovaj korisnik nema prijatelje. {0} ne može da napravi vremensku liniju." -#: ../src\wxUI\commonMessageDialogs.py:70 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geo data for this tweet" msgstr "Geografski podaci o ovom tvitu" -#: ../src\wxUI\commonMessageDialogs.py:70 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geolocation data: {0}" msgstr "Podaci o geografskoj lokaciji: {0}" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "Information" msgstr "Informacija" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "" "TWBlue has detected that you're running windows 10 and has changed the " "default keymap to the Windows 10 keymap. It means that some keyboard " @@ -2229,11 +2313,11 @@ msgstr "" "prečica pritiskanjem Alt+Win+K i pogledate sve dostupne prečice za ovja " "način rada." -#: ../src\wxUI\commonMessageDialogs.py:76 +#: ../src\wxUI\commonMessageDialogs.py:77 msgid "You have been blocked from viewing this content" msgstr "Blokirani ste i ne možete videti ovaj sadržaj." -#: ../src\wxUI\commonMessageDialogs.py:79 +#: ../src\wxUI\commonMessageDialogs.py:80 msgid "" "You have been blocked from viewing someone's content. In order to avoid " "conflicts with the full session, TWBlue will remove the affected timeline." @@ -2242,7 +2326,7 @@ msgstr "" "izbegli konflikte sa sesijom, TWBlue će ukloniti vremensku liniju na koju " "ovo utiče." -#: ../src\wxUI\commonMessageDialogs.py:82 +#: ../src\wxUI\commonMessageDialogs.py:83 msgid "" "TWBlue cannot load this timeline because the user has been suspended from " "Twitter." @@ -2250,15 +2334,15 @@ msgstr "" "TWBlue ne može da učita ovu vremensku liniju zbog toga što je korisnik " "suspendovan sa tvitera." -#: ../src\wxUI\commonMessageDialogs.py:85 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Do you really want to delete this filter?" msgstr "Da li zaista želite da izbrišete ovaj filter?" -#: ../src\wxUI\commonMessageDialogs.py:88 +#: ../src\wxUI\commonMessageDialogs.py:89 msgid "This filter already exists. Please use a different title" msgstr "Ovaj filter već postoji. Molimo koristite drugi naziv" -#: ../src\wxUI\commonMessageDialogs.py:94 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." @@ -2266,147 +2350,147 @@ msgstr "" "{0} je neočekivano zatvoren pri poslednjem pokretanju. Ako se problem " "nastavi, molimo prijavite ga{0} programerima." -#: ../src\wxUI\dialogs\attach.py:9 +#: ../src\wxUI\dialogs\attach.py:10 msgid "Add an attachment" msgstr "Dodaj prilog" -#: ../src\wxUI\dialogs\attach.py:12 +#: ../src\wxUI\dialogs\attach.py:13 msgid "Attachments" msgstr "Prilozi" -#: ../src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Title" msgstr "Naslov" -#: ../src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Type" msgstr "Vrsta" -#: ../src\wxUI\dialogs\attach.py:18 +#: ../src\wxUI\dialogs\attach.py:19 msgid "Add attachments" msgstr "Dodaj priloge" -#: ../src\wxUI\dialogs\attach.py:19 +#: ../src\wxUI\dialogs\attach.py:20 msgid "&Photo" msgstr "Slika" -#: ../src\wxUI\dialogs\attach.py:20 +#: ../src\wxUI\dialogs\attach.py:21 msgid "Remove attachment" msgstr "Ukloni prilog" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 #: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" msgstr "Datoteke sa slikama" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 #: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Select the picture to be uploaded" msgstr "Izaberite sliku koju želite da otpremite" -#: ../src\wxUI\dialogs\attach.py:43 +#: ../src\wxUI\dialogs\attach.py:44 msgid "please provide a description" msgstr "Molimo vas navedite opis:" -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 +#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:70 msgid "Description" msgstr "Opis" -#: ../src\wxUI\dialogs\configuration.py:16 +#: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "Jezik" -#: ../src\wxUI\dialogs\configuration.py:23 +#: ../src\wxUI\dialogs\configuration.py:22 msgid "Run {0} at Windows startup" msgstr "Pokreni {0} prilikom pokretanja Windowsa" -#: ../src\wxUI\dialogs\configuration.py:24 +#: ../src\wxUI\dialogs\configuration.py:23 msgid "ask before exiting {0}" msgstr "Pitaj pre zatvaranja {0}" -#: ../src\wxUI\dialogs\configuration.py:27 +#: ../src\wxUI\dialogs\configuration.py:26 msgid "Disable Streaming functions" msgstr "Onemogući streaming funkcije" -#: ../src\wxUI\dialogs\configuration.py:30 +#: ../src\wxUI\dialogs\configuration.py:29 msgid "Buffer update interval, in minutes" msgstr "Interval ažuriranja kanala, u minutima" -#: ../src\wxUI\dialogs\configuration.py:36 +#: ../src\wxUI\dialogs\configuration.py:35 msgid "Play a sound when {0} launches" msgstr "Reprodukuj zvuk kada se {0} pokrene" -#: ../src\wxUI\dialogs\configuration.py:38 +#: ../src\wxUI\dialogs\configuration.py:37 msgid "Speak a message when {0} launches" msgstr "Izgovori poruku kada se {0} pokrene" -#: ../src\wxUI\dialogs\configuration.py:40 +#: ../src\wxUI\dialogs\configuration.py:39 msgid "Use invisible interface's keyboard shortcuts while GUI is visible" msgstr "" "Koristi prečice nevidljivog okruženja dok je grafičko okruženje prikazano" -#: ../src\wxUI\dialogs\configuration.py:42 +#: ../src\wxUI\dialogs\configuration.py:41 msgid "Activate Sapi5 when any other screen reader is not being run" msgstr "Aktiviraj SAPI 5 u slučaju da nijedan čitač ekrana nije pokrenut" -#: ../src\wxUI\dialogs\configuration.py:44 +#: ../src\wxUI\dialogs\configuration.py:43 msgid "Hide GUI on launch" msgstr "Sakrij grafičko okruženje prilikom pokretanja" -#: ../src\wxUI\dialogs\configuration.py:46 +#: ../src\wxUI\dialogs\configuration.py:45 msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" msgstr "" "Koristi Codeofdusk's upravljanje dugim tvitovima (može usporiti performanse " "programa)" -#: ../src\wxUI\dialogs\configuration.py:48 +#: ../src\wxUI\dialogs\configuration.py:47 msgid "Remember state for mention all and long tweet" msgstr "Pamti stanje opcija spomeni sve i dug tvit" -#: ../src\wxUI\dialogs\configuration.py:51 +#: ../src\wxUI\dialogs\configuration.py:50 msgid "Keymap" msgstr "Tasterske prečice" -#: ../src\wxUI\dialogs\configuration.py:56 +#: ../src\wxUI\dialogs\configuration.py:55 msgid "Check for updates when {0} launches" msgstr "Proveri postojanje nove verzije kada se {0} pokrene" -#: ../src\wxUI\dialogs\configuration.py:66 +#: ../src\wxUI\dialogs\configuration.py:65 msgid "Proxy type: " msgstr "Vrsta proksija:" -#: ../src\wxUI\dialogs\configuration.py:73 +#: ../src\wxUI\dialogs\configuration.py:72 msgid "Proxy server: " msgstr "Proksi server:" -#: ../src\wxUI\dialogs\configuration.py:79 +#: ../src\wxUI\dialogs\configuration.py:78 msgid "Port: " msgstr "Port:" -#: ../src\wxUI\dialogs\configuration.py:85 +#: ../src\wxUI\dialogs\configuration.py:84 msgid "User: " msgstr "Korisnik:" -#: ../src\wxUI\dialogs\configuration.py:91 +#: ../src\wxUI\dialogs\configuration.py:90 msgid "Password: " msgstr "Lozinka:" -#: ../src\wxUI\dialogs\configuration.py:103 +#: ../src\wxUI\dialogs\configuration.py:102 msgid "Autocompletion settings..." msgstr "Postavke automatskod dovršavanja..." -#: ../src\wxUI\dialogs\configuration.py:105 +#: ../src\wxUI\dialogs\configuration.py:104 msgid "Relative timestamps" msgstr "Relativne vremenske oznake" -#: ../src\wxUI\dialogs\configuration.py:108 +#: ../src\wxUI\dialogs\configuration.py:107 msgid "Items on each API call" msgstr "Stavke po svakom API pozivu" -#: ../src\wxUI\dialogs\configuration.py:114 +#: ../src\wxUI\dialogs\configuration.py:113 msgid "" "Inverted buffers: The newest tweets will be shown at the beginning while the " "oldest at the end" @@ -2414,15 +2498,15 @@ msgstr "" "Okreni kanal: Najnoviji tvitovi će biti prikazani na vrhu a najstariji na " "dnu." -#: ../src\wxUI\dialogs\configuration.py:116 +#: ../src\wxUI\dialogs\configuration.py:115 msgid "Retweet mode" msgstr "Način retvitovanja" -#: ../src\wxUI\dialogs\configuration.py:122 +#: ../src\wxUI\dialogs\configuration.py:121 msgid "Show screen names instead of full names" msgstr "Prikaži Twitter korisničko ime umesto punog imena" -#: ../src\wxUI\dialogs\configuration.py:124 +#: ../src\wxUI\dialogs\configuration.py:123 msgid "" "Number of items per buffer to cache in database (0 to disable caching, blank " "for unlimited)" @@ -2430,6 +2514,14 @@ msgstr "" "Broj stavki po kanalu u bazi podataka (0 za isključivanje memorije, prazno " "za neograničeno)" +#: ../src\wxUI\dialogs\configuration.py:127 +msgid "" +"Load cache for tweets in memory (much faster in big datasets but requires " +"more RAM)" +msgstr "" +"Učitavaj keš za Tvitove iz memorije (dosta brže sa većim količinama podataka " +"ali zahteva više RAM memorije)" + #: ../src\wxUI\dialogs\configuration.py:134 msgid "Enable automatic speech feedback" msgstr "Omogući automatske govorne povratne informacije" @@ -2443,7 +2535,7 @@ msgid "Status" msgstr "Status" #: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Buffer" msgstr "Kanal" @@ -2568,175 +2660,175 @@ msgstr "Dodaci" msgid "Save" msgstr "Sačuvaj" -#: ../src\wxUI\dialogs\filterDialogs.py:15 +#: ../src\wxUI\dialogs\filterDialogs.py:16 msgid "Create a filter for this buffer" msgstr "Napravi filter za ovaj kanal" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:17 msgid "Filter title" msgstr "Naziv filtera" -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by word" msgstr "Filtriraj na osnovu reči" -#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:27 msgid "Ignore tweets wich contain the following word" msgstr "Zanemari tvitove koji sadrže sledeću reč" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:28 msgid "Ignore tweets without the following word" msgstr "Zanemari tvitove bez sledeće reči" -#: ../src\wxUI\dialogs\filterDialogs.py:32 +#: ../src\wxUI\dialogs\filterDialogs.py:33 msgid "word" msgstr "Reč" -#: ../src\wxUI\dialogs\filterDialogs.py:37 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow retweets" msgstr "Dozvoli retvitove" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:39 msgid "Allow quoted tweets" msgstr "Dozvoli citirane tvitove" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:40 msgid "Allow replies" msgstr "Dozvoli odgovore" -#: ../src\wxUI\dialogs\filterDialogs.py:47 +#: ../src\wxUI\dialogs\filterDialogs.py:48 msgid "Use this term as a regular expression" msgstr "Koristi ovaj termin kao regulara nizraz" -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by language" msgstr "Filtriraj na osnovu jezika" -#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Load tweets in the following languages" msgstr "Učitaj tvitove na sledećim jezicima" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:52 msgid "Ignore tweets in the following languages" msgstr "Zanemari tvitove na sledećim jezicima" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:53 msgid "Don't filter by language" msgstr "Ne filtriraj na osnovu jezika" -#: ../src\wxUI\dialogs\filterDialogs.py:63 +#: ../src\wxUI\dialogs\filterDialogs.py:64 msgid "Supported languages" msgstr "Podržani jezici" -#: ../src\wxUI\dialogs\filterDialogs.py:68 +#: ../src\wxUI\dialogs\filterDialogs.py:69 msgid "Add selected language to filter" msgstr "Dodaj izabrani jezik u filter" -#: ../src\wxUI\dialogs\filterDialogs.py:72 +#: ../src\wxUI\dialogs\filterDialogs.py:73 msgid "Selected languages" msgstr "Izabrani jezici" -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 +#: ../src\wxUI\dialogs\filterDialogs.py:75 +#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:132 msgid "Remove" msgstr "Ukloni" -#: ../src\wxUI\dialogs\filterDialogs.py:122 +#: ../src\wxUI\dialogs\filterDialogs.py:123 msgid "Manage filters" msgstr "Upravljanje filterima" -#: ../src\wxUI\dialogs\filterDialogs.py:124 +#: ../src\wxUI\dialogs\filterDialogs.py:125 msgid "Filters" msgstr "Filteri" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter" msgstr "Filter" -#: ../src\wxUI\dialogs\find.py:12 +#: ../src\wxUI\dialogs\find.py:13 msgid "Find in current buffer" msgstr "Pronađi u trenutnom kanalu" -#: ../src\wxUI\dialogs\find.py:13 +#: ../src\wxUI\dialogs\find.py:14 msgid "String" msgstr "Pojam" -#: ../src\wxUI\dialogs\lists.py:10 +#: ../src\wxUI\dialogs\lists.py:11 msgid "Lists manager" msgstr "Upravljanje listama" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "List" msgstr "Lista" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Members" msgstr "Članovi" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Owner" msgstr "Vlasnik" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "mode" msgstr "Način" -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 +#: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "Stvori novu listu" -#: ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:22 msgid "Open in buffer" msgstr "Otvori u kanalu" -#: ../src\wxUI\dialogs\lists.py:51 +#: ../src\wxUI\dialogs\lists.py:52 msgid "Viewing lists for %s" msgstr "Prikazivanje lista za %s" -#: ../src\wxUI\dialogs\lists.py:52 +#: ../src\wxUI\dialogs\lists.py:53 msgid "Subscribe" msgstr "Prijavi se" -#: ../src\wxUI\dialogs\lists.py:53 +#: ../src\wxUI\dialogs\lists.py:54 msgid "Unsubscribe" msgstr "Odjavi se" -#: ../src\wxUI\dialogs\lists.py:64 +#: ../src\wxUI\dialogs\lists.py:65 msgid "Name (20 characters maximun)" msgstr "Ime, najviše 20 znakova" -#: ../src\wxUI\dialogs\lists.py:74 +#: ../src\wxUI\dialogs\lists.py:75 msgid "Mode" msgstr "Način" -#: ../src\wxUI\dialogs\lists.py:75 +#: ../src\wxUI\dialogs\lists.py:76 msgid "Public" msgstr "Javna" -#: ../src\wxUI\dialogs\lists.py:76 +#: ../src\wxUI\dialogs\lists.py:77 msgid "Private" msgstr "Privatna" -#: ../src\wxUI\dialogs\lists.py:96 +#: ../src\wxUI\dialogs\lists.py:97 msgid "Editing the list %s" msgstr "Uređivanje liste %s" -#: ../src\wxUI\dialogs\lists.py:107 +#: ../src\wxUI\dialogs\lists.py:108 msgid "Select a list to add the user" msgstr "Izaberite listu na koju želite da dodate korisnika" -#: ../src\wxUI\dialogs\lists.py:108 +#: ../src\wxUI\dialogs\lists.py:109 msgid "Add" msgstr "Dodaj" -#: ../src\wxUI\dialogs\lists.py:130 +#: ../src\wxUI\dialogs\lists.py:131 msgid "Select a list to remove the user" msgstr "Izaberite listu sa koje želite da uklonite korisnika" -#: ../src\wxUI\dialogs\lists.py:148 +#: ../src\wxUI\dialogs\lists.py:149 msgid "Do you really want to delete this list?" msgstr "Želite li zaista da izbrišete ovu listu?" @@ -2751,7 +2843,7 @@ msgstr "Otpremi sliku..." #: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 #: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 +#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 msgid "Check &spelling..." msgstr "Proveri pravopis..." @@ -2767,13 +2859,13 @@ msgstr "Skrati vezu" #: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 #: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 +#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 msgid "&Expand URL" msgstr "Proširi vezu" #: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 #: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 +#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 msgid "&Translate..." msgstr "Prevedi..." @@ -2789,7 +2881,7 @@ msgstr "Pošalji" #: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 #: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 +#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 msgid "C&lose" msgstr "Zatvori" @@ -2821,23 +2913,27 @@ msgstr "Sviđanja:" msgid "Source: " msgstr "Izvor:" -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 +#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 msgid "Date: " msgstr "Datum:" -#: ../src\wxUI\dialogs\message.py:405 +#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 +msgid "Copy link to clipboard" +msgstr "Kopiraj link u privremenu memoriju" + +#: ../src\wxUI\dialogs\message.py:408 msgid "View" msgstr "Vidi" -#: ../src\wxUI\dialogs\message.py:407 +#: ../src\wxUI\dialogs\message.py:410 msgid "Item" msgstr "Stavka" -#: ../src\wxUI\dialogs\search.py:13 +#: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "Pretraži ttwitter" -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 +#: ../src\wxUI\dialogs\search.py:13 ../src\wxUI\view.py:21 msgid "&Search" msgstr "Pretraži" @@ -2873,414 +2969,450 @@ msgstr "Nedavno" msgid "Popular" msgstr "Popularno" -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 +#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:25 +#: ../src\wxUI\dialogs\userActions.py:41 +#: ../src\wxUI\dialogs\userSelection.py:33 msgid "&OK" msgstr "U redu" -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 +#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:19 +#: ../src\wxUI\dialogs\trends.py:27 ../src\wxUI\dialogs\update_profile.py:37 +#: ../src\wxUI\dialogs\userActions.py:43 +#: ../src\wxUI\dialogs\userSelection.py:35 msgid "&Close" msgstr "Zatvori" -#: ../src\wxUI\dialogs\show_user.py:11 +#: ../src\wxUI\dialogs\show_user.py:12 msgid "Details" msgstr "Pojedoinosti" -#: ../src\wxUI\dialogs\show_user.py:16 +#: ../src\wxUI\dialogs\show_user.py:17 msgid "&Go to URL" msgstr "Idi na vezu" -#: ../src\wxUI\dialogs\trends.py:12 +#: ../src\wxUI\dialogs\trends.py:10 msgid "View trending topics" msgstr "Pogledaj teme u trendu" -#: ../src\wxUI\dialogs\trends.py:13 +#: ../src\wxUI\dialogs\trends.py:11 msgid "Trending topics by" msgstr "Teme u trendu po" -#: ../src\wxUI\dialogs\trends.py:15 +#: ../src\wxUI\dialogs\trends.py:12 msgid "Country" msgstr "Zemlji" -#: ../src\wxUI\dialogs\trends.py:16 +#: ../src\wxUI\dialogs\trends.py:13 msgid "City" msgstr "Gradu" -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 +#: ../src\wxUI\dialogs\trends.py:19 ../src\wxUI\dialogs\update_profile.py:18 msgid "&Location" msgstr "Mesto" -#: ../src\wxUI\dialogs\update_profile.py:9 +#: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "Ažurirajte vaš profil" -#: ../src\wxUI\dialogs\update_profile.py:11 +#: ../src\wxUI\dialogs\update_profile.py:12 msgid "&Name (50 characters maximum)" msgstr "&Ime(najviše 50 znakova)" -#: ../src\wxUI\dialogs\update_profile.py:22 +#: ../src\wxUI\dialogs\update_profile.py:23 msgid "&Website" msgstr "Web:" -#: ../src\wxUI\dialogs\update_profile.py:27 +#: ../src\wxUI\dialogs\update_profile.py:28 msgid "&Bio (160 characters maximum)" msgstr "Biografija, najviše 160 znakova" -#: ../src\wxUI\dialogs\update_profile.py:33 +#: ../src\wxUI\dialogs\update_profile.py:34 msgid "Upload a &picture" msgstr "Otpremi sliku" -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 +#: ../src\wxUI\dialogs\update_profile.py:35 ../src\wxUI\view.py:19 msgid "&Update profile" msgstr "Ažuriraj profil" -#: ../src\wxUI\dialogs\update_profile.py:76 +#: ../src\wxUI\dialogs\update_profile.py:77 msgid "Upload a picture" msgstr "Otpremi sliku" -#: ../src\wxUI\dialogs\update_profile.py:78 +#: ../src\wxUI\dialogs\update_profile.py:79 msgid "Discard image" msgstr "Odbaci sliku" -#: ../src\wxUI\dialogs\urlList.py:5 +#: ../src\wxUI\dialogs\urlList.py:6 msgid "Select URL" msgstr "Izaberite vezu" -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 +#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:86 msgid "&User" msgstr "Korisnik" -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 +#: ../src\wxUI\dialogs\userActions.py:14 +#: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 +#: ../src\wxUI\dialogs\utils.py:58 msgid "&Autocomplete users" msgstr "&Automatsko dovršavanje" -#: ../src\wxUI\dialogs\userActions.py:19 +#: ../src\wxUI\dialogs\userActions.py:20 msgid "&Follow" msgstr "Prati" -#: ../src\wxUI\dialogs\userActions.py:20 +#: ../src\wxUI\dialogs\userActions.py:21 msgid "U&nfollow" msgstr "Otprati" -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 +#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:62 msgid "&Mute" msgstr "Utišaj" -#: ../src\wxUI\dialogs\userActions.py:22 +#: ../src\wxUI\dialogs\userActions.py:23 msgid "Unmu&te" msgstr "Ukloni utišavanje" -#: ../src\wxUI\dialogs\userActions.py:23 +#: ../src\wxUI\dialogs\userActions.py:24 msgid "&Block" msgstr "Blokiraj" -#: ../src\wxUI\dialogs\userActions.py:24 +#: ../src\wxUI\dialogs\userActions.py:25 msgid "Unbl&ock" msgstr "Odblokiraj" -#: ../src\wxUI\dialogs\userActions.py:25 +#: ../src\wxUI\dialogs\userActions.py:26 msgid "&Report as spam" msgstr "Prijavi kao neželjeno" -#: ../src\wxUI\dialogs\userActions.py:26 +#: ../src\wxUI\dialogs\userActions.py:27 msgid "&Ignore tweets from this client" msgstr "Zanemari tvitove iz ovog klijenta" -#: ../src\wxUI\dialogs\userSelection.py:9 +#: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "Vremenska crta od %s" -#: ../src\wxUI\dialogs\userSelection.py:18 +#: ../src\wxUI\dialogs\userSelection.py:19 msgid "Buffer type" msgstr "Vrsta kanala" -#: ../src\wxUI\dialogs\userSelection.py:19 +#: ../src\wxUI\dialogs\userSelection.py:20 msgid "&Tweets" msgstr "Tvitovi" -#: ../src\wxUI\dialogs\userSelection.py:20 +#: ../src\wxUI\dialogs\userSelection.py:21 msgid "&Likes" msgstr "Sviđanja" -#: ../src\wxUI\dialogs\userSelection.py:21 +#: ../src\wxUI\dialogs\userSelection.py:22 msgid "&Followers" msgstr "Pratioci" -#: ../src\wxUI\dialogs\userSelection.py:22 +#: ../src\wxUI\dialogs\userSelection.py:23 msgid "F&riends" msgstr "Prijatelji" -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 +#: ../src\wxUI\dialogs\utils.py:63 +msgid "Alias" +msgstr "Nadimak" + +#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:32 msgid "&Retweet" msgstr "Retvituj" -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 +#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:31 msgid "Re&ply" msgstr "Odgovori" -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 +#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:33 msgid "&Like" msgstr "Sviđa mi se" -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 +#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:34 msgid "&Unlike" msgstr "Ne sviđa mi se" -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 +#: ../src\wxUI\menus.py:16 ../src\wxUI\menus.py:36 ../src\wxUI\menus.py:52 msgid "&Open URL" msgstr "otvori vezu" -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 +#: ../src\wxUI\menus.py:18 ../src\wxUI\menus.py:54 ../src\wxUI\menus.py:87 msgid "&Open in Twitter" msgstr "&Otvori na Twitteru" -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 +#: ../src\wxUI\menus.py:20 ../src\wxUI\menus.py:38 ../src\wxUI\menus.py:56 msgid "&Play audio" msgstr "reprodukuj zvučni zapis" -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 +#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:35 msgid "&Show tweet" msgstr "Prikaži tvit" -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 +#: ../src\wxUI\menus.py:24 ../src\wxUI\menus.py:42 ../src\wxUI\menus.py:60 +#: ../src\wxUI\menus.py:70 ../src\wxUI\menus.py:89 ../src\wxUI\menus.py:103 msgid "&Copy to clipboard" msgstr "Kopiraj u ostavu" -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 +#: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 +#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:39 msgid "&Delete" msgstr "Izbriši" -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 +#: ../src\wxUI\menus.py:28 ../src\wxUI\menus.py:46 ../src\wxUI\menus.py:91 msgid "&User actions..." msgstr "Radnje korisnika..." -#: ../src\wxUI\menus.py:39 +#: ../src\wxUI\menus.py:40 msgid "&Show direct message" msgstr "Prikaži direktnu poruku" -#: ../src\wxUI\menus.py:67 +#: ../src\wxUI\menus.py:68 msgid "&Show event" msgstr "Prikaži događaj" -#: ../src\wxUI\menus.py:77 +#: ../src\wxUI\menus.py:78 msgid "Direct &message" msgstr "Direktna poruka" -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 +#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:49 msgid "&View lists" msgstr "Vidi liste" -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 +#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:50 msgid "Show user &profile" msgstr "Prikaži profil korisnika" -#: ../src\wxUI\menus.py:84 +#: ../src\wxUI\menus.py:85 msgid "&Show user" msgstr "Prikaži korisnika" -#: ../src\wxUI\menus.py:98 +#: ../src\wxUI\menus.py:99 msgid "&Tweet about this trend" msgstr "Tvituj o ovom trendu" -#: ../src\wxUI\menus.py:100 +#: ../src\wxUI\menus.py:101 msgid "&Show item" msgstr "Prikaži stavku" -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 +#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:25 msgid "&Global settings" msgstr "Globalna podešavanja" -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 +#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:24 msgid "Account se&ttings" msgstr "Postavke naloga" -#: ../src\wxUI\sysTrayIcon.py:37 +#: ../src\wxUI\sysTrayIcon.py:38 msgid "Update &profile" msgstr "Ažuriraj profil" -#: ../src\wxUI\sysTrayIcon.py:38 +#: ../src\wxUI\sysTrayIcon.py:39 msgid "&Show / hide" msgstr "Prikaži ili sakrij" -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 +#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:74 msgid "&Documentation" msgstr "Dokumentacija" -#: ../src\wxUI\sysTrayIcon.py:40 +#: ../src\wxUI\sysTrayIcon.py:41 msgid "Check for &updates" msgstr "Proveri da li postoje nadogradnje" -#: ../src\wxUI\sysTrayIcon.py:41 +#: ../src\wxUI\sysTrayIcon.py:42 msgid "&Exit" msgstr "Izlaz" -#: ../src\wxUI\view.py:16 +#: ../src\wxUI\view.py:18 msgid "&Manage accounts" msgstr "Upravljaj nalozima" -#: ../src\wxUI\view.py:18 +#: ../src\wxUI\view.py:20 msgid "&Hide window" msgstr "Sakrij prozor" -#: ../src\wxUI\view.py:20 +#: ../src\wxUI\view.py:22 msgid "&Lists manager" msgstr "Upravljanje listama" -#: ../src\wxUI\view.py:21 +#: ../src\wxUI\view.py:23 msgid "&Edit keystrokes" msgstr "Izmeni tasterske prečice" -#: ../src\wxUI\view.py:24 +#: ../src\wxUI\view.py:26 msgid "E&xit" msgstr "Izlaz" -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 +#: ../src\wxUI\view.py:30 ../src\wxUI\view.py:85 msgid "&Tweet" msgstr "Tvit" -#: ../src\wxUI\view.py:34 +#: ../src\wxUI\view.py:36 msgid "View &address" msgstr "Vidi adresu" -#: ../src\wxUI\view.py:35 +#: ../src\wxUI\view.py:37 msgid "View conversa&tion" msgstr "Vidi razgovor" -#: ../src\wxUI\view.py:36 +#: ../src\wxUI\view.py:38 msgid "Read text in picture" msgstr "Čitaj tekst u slici" -#: ../src\wxUI\view.py:41 +#: ../src\wxUI\view.py:43 msgid "&Actions..." msgstr "Radnje..." -#: ../src\wxUI\view.py:42 +#: ../src\wxUI\view.py:44 msgid "&View timeline..." msgstr "Vidi vremensku liniju..." -#: ../src\wxUI\view.py:43 +#: ../src\wxUI\view.py:45 msgid "Direct me&ssage" msgstr "Direktna poruka" -#: ../src\wxUI\view.py:44 +#: ../src\wxUI\view.py:46 +msgid "Add a&lias" +msgstr "Dodaj &nadimak" + +#: ../src\wxUI\view.py:47 msgid "&Add to list" msgstr "Dodaj na listu" -#: ../src\wxUI\view.py:45 +#: ../src\wxUI\view.py:48 msgid "R&emove from list" msgstr "Ukloni sa liste" -#: ../src\wxUI\view.py:48 +#: ../src\wxUI\view.py:51 msgid "V&iew likes" msgstr "Vidi sviđanja" -#: ../src\wxUI\view.py:52 +#: ../src\wxUI\view.py:55 msgid "&Update buffer" msgstr "Ažuriraj kanal" -#: ../src\wxUI\view.py:53 +#: ../src\wxUI\view.py:56 msgid "New &trending topics buffer..." msgstr "Novi kanal sa temama u trendu" -#: ../src\wxUI\view.py:54 +#: ../src\wxUI\view.py:57 msgid "Create a &filter" msgstr "Napravi &filter" -#: ../src\wxUI\view.py:55 +#: ../src\wxUI\view.py:58 msgid "&Manage filters" msgstr "&Upravljanje filterima" -#: ../src\wxUI\view.py:56 +#: ../src\wxUI\view.py:59 msgid "Find a string in the currently focused buffer..." msgstr "Pronađi pojam u trenutno označenom kanalu..." -#: ../src\wxUI\view.py:57 +#: ../src\wxUI\view.py:60 msgid "&Load previous items" msgstr "Učitaj prethodne stavke" -#: ../src\wxUI\view.py:60 +#: ../src\wxUI\view.py:63 msgid "&Autoread" msgstr "Automatski čitaj" -#: ../src\wxUI\view.py:61 +#: ../src\wxUI\view.py:64 msgid "&Clear buffer" msgstr "Očisti kanal" -#: ../src\wxUI\view.py:62 +#: ../src\wxUI\view.py:65 msgid "&Destroy" msgstr "Izbriši" -#: ../src\wxUI\view.py:66 +#: ../src\wxUI\view.py:69 msgid "&Seek back 5 seconds" msgstr "Premotaj unazad za 5 sekundi" -#: ../src\wxUI\view.py:67 +#: ../src\wxUI\view.py:70 msgid "&Seek forward 5 seconds" msgstr "Premotaj unapred za 5 sekundi" -#: ../src\wxUI\view.py:72 +#: ../src\wxUI\view.py:75 msgid "Sounds &tutorial" msgstr "Zvučna uputstva" -#: ../src\wxUI\view.py:73 +#: ../src\wxUI\view.py:76 msgid "&What's new in this version?" msgstr "Šta je novo u ovoj verziji" -#: ../src\wxUI\view.py:74 +#: ../src\wxUI\view.py:77 msgid "&Check for updates" msgstr "Proveri da li postoje nadogradnje" -#: ../src\wxUI\view.py:75 +#: ../src\wxUI\view.py:78 msgid "&Report an error" msgstr "Prijavi grešku" -#: ../src\wxUI\view.py:76 +#: ../src\wxUI\view.py:79 msgid "{0}'s &website" msgstr "{0} &website" -#: ../src\wxUI\view.py:77 +#: ../src\wxUI\view.py:80 msgid "Get soundpacks for TWBlue" msgstr "Nabavi zvučne pakete za TW Blue" -#: ../src\wxUI\view.py:78 +#: ../src\wxUI\view.py:81 msgid "About &{0}" msgstr "O &{0}" -#: ../src\wxUI\view.py:81 +#: ../src\wxUI\view.py:84 msgid "&Application" msgstr "Aplikacija" -#: ../src\wxUI\view.py:84 +#: ../src\wxUI\view.py:87 msgid "&Buffer" msgstr "Kanal" -#: ../src\wxUI\view.py:85 +#: ../src\wxUI\view.py:88 msgid "&Audio" msgstr "Audio" -#: ../src\wxUI\view.py:86 +#: ../src\wxUI\view.py:89 msgid "&Help" msgstr "Pomoć" -#: ../src\wxUI\view.py:172 +#: ../src\wxUI\view.py:175 msgid "Address" msgstr "Adresa" -#: ../src\wxUI\view.py:203 +#: ../src\wxUI\view.py:206 msgid "Update" msgstr "Ažuriraj" -#: ../src\wxUI\view.py:203 +#: ../src\wxUI\view.py:206 msgid "Your {0} version is up to date" msgstr "Imate najnoviju verziju {0}." +msgid "Waiting for account authorisation..." +msgstr "En attente d'autorisation du compte..." + +msgid "Contains" +msgstr "Contient" + +msgid "Doesn't contain" +msgstr "Ne contient pas" + +msgid "Create a filter" +msgstr "Créer un filtre" + +msgid "&Name (20 characters maximum)" +msgstr "&Nom (maximum 20 caractères)" + +#~ msgid "Events" +#~ msgstr "Događaji" + +#~ msgid "This tweet doesn't contain images" +#~ msgstr "Ovaj tvit ne sadrži slike." + +#~ msgid "Direct connection" +#~ msgstr "Direktna veza" + +#~ msgid "There are no more items to retrieve in this buffer." +#~ msgstr "Nema više stavki koje se mogu preuzeti u ovom kanalu." + #~ msgid "Empty" #~ msgstr "Prazno" From 89fa6435b46d8c7df66ad8853e70f49e99186998 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 21 Oct 2021 16:58:32 +0200 Subject: [PATCH 151/245] Update french interface --- src/locales/fr/LC_MESSAGES/twblue.po | 243 ++++++++++++++------------- 1 file changed, 126 insertions(+), 117 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index b03048bf..e44b14b1 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2021-08-28 08:34+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-08-28 08:37+0200\n" +"POT-Creation-Date: 2021-10-21 16:55+Paris, Madrid (heure d’été)\n" +"PO-Revision-Date: 2021-10-21 16:57+0200\n" "Last-Translator: Corentin BACQUÉ-CAZENAVE \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -25,60 +25,59 @@ msgid "This action is not supported for this buffer" msgstr "Cette action n'est pas supportée pour ce tampon" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:309 ../src\controller\settings.py:286 +#: ../src\controller\mainController.py:334 ../src\controller\settings.py:286 msgid "Home" msgstr "Accueil" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:313 ../src\controller\settings.py:287 +#: ../src\controller\mainController.py:336 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Mentions" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:317 +#: ../src\controller\mainController.py:338 msgid "Direct messages" msgstr "Messages privés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:321 ../src\controller\settings.py:289 +#: ../src\controller\mainController.py:340 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Messages privés envoyés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:325 ../src\controller\settings.py:290 +#: ../src\controller\mainController.py:342 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Tweets envoyés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:329 -#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:291 +#: ../src\controller\mainController.py:344 +#: ../src\controller\mainController.py:1382 ../src\controller\settings.py:291 msgid "Likes" msgstr "Favoris" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:333 -#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:292 +#: ../src\controller\mainController.py:346 +#: ../src\controller\mainController.py:1387 ../src\controller\settings.py:292 msgid "Followers" msgstr "Abonnés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:337 -#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:293 -msgid "Friends" -msgstr "Abonnements" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:341 -#: ../src\controller\mainController.py:1415 ../src\controller\settings.py:294 +#: ../src\controller\mainController.py:350 +#: ../src\controller\mainController.py:1397 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Utilisateurs bloqués" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:345 -#: ../src\controller\mainController.py:1420 ../src\controller\settings.py:295 +#: ../src\controller\mainController.py:352 +#: ../src\controller\mainController.py:1402 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Utilisateurs masqués" +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:1392 ../src\controller\settings.py:293 +msgid "Friends" +msgstr "Abonnements" + #: ../src\controller\buffers\twitter\base.py:76 msgid "{username}'s timeline" msgstr "Chronologie de {username}" @@ -209,79 +208,86 @@ msgstr "{0} nouvel abonné" msgid "This action is not supported in the buffer, yet." msgstr "Cette action n'est pas supportée pour le tampon actuel" -#: ../src\controller\mainController.py:273 +#: ../src\controller\mainController.py:274 msgid "Ready" msgstr "Prêt" #: ../src\controller\mainController.py:348 +msgid "Following" +msgstr "Suivi" + +#: ../src\controller\mainController.py:353 msgid "Timelines" msgstr "Chronologies" -#: ../src\controller\mainController.py:352 -#: ../src\controller\mainController.py:892 -#: ../src\controller\mainController.py:1596 +#: ../src\controller\mainController.py:356 +#: ../src\controller\mainController.py:875 +#: ../src\controller\mainController.py:1577 msgid "Timeline for {}" msgstr "Chronologie de {}" -#: ../src\controller\mainController.py:355 +#: ../src\controller\mainController.py:357 msgid "Likes timelines" msgstr "Chronologies des favoris" -#: ../src\controller\mainController.py:359 -#: ../src\controller\mainController.py:911 -#: ../src\controller\mainController.py:1598 +#: ../src\controller\mainController.py:360 +#: ../src\controller\mainController.py:894 +#: ../src\controller\mainController.py:1579 msgid "Likes for {}" msgstr "Favoris de {}" -#: ../src\controller\mainController.py:362 -msgid "Followers' Timelines" +#: ../src\controller\mainController.py:361 +#, fuzzy +#| msgid "Followers' Timelines" +msgid "Followers timelines" msgstr "Chronologies des abonnés" -#: ../src\controller\mainController.py:366 -#: ../src\controller\mainController.py:930 -#: ../src\controller\mainController.py:1600 +#: ../src\controller\mainController.py:364 +#: ../src\controller\mainController.py:913 +#: ../src\controller\mainController.py:1581 msgid "Followers for {}" msgstr "Abonnés de {}" -#: ../src\controller\mainController.py:369 -msgid "Friends' Timelines" +#: ../src\controller\mainController.py:365 +msgid "Following timelines" msgstr "Chronologies des abonnements" -#: ../src\controller\mainController.py:373 -#: ../src\controller\mainController.py:949 -#: ../src\controller\mainController.py:1602 +#: ../src\controller\mainController.py:368 +#: ../src\controller\mainController.py:932 +#: ../src\controller\mainController.py:1583 msgid "Friends for {}" msgstr "Abonnements de {}" -#: ../src\controller\mainController.py:376 ../src\wxUI\dialogs\lists.py:13 +#: ../src\controller\mainController.py:369 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Listes" -#: ../src\controller\mainController.py:381 -#: ../src\controller\mainController.py:1432 +#: ../src\controller\mainController.py:372 +#: ../src\controller\mainController.py:1414 msgid "List for {}" msgstr "Liste {}" -#: ../src\controller\mainController.py:384 +#: ../src\controller\mainController.py:373 msgid "Searches" msgstr "Recherches" -#: ../src\controller\mainController.py:388 -#: ../src\controller\mainController.py:447 +#: ../src\controller\mainController.py:376 +#: ../src\controller\mainController.py:423 +#: ../src\controller\mainController.py:428 msgid "Search for {}" msgstr "Recherche de {}" -#: ../src\controller\mainController.py:394 -#: ../src\controller\mainController.py:991 +#: ../src\controller\mainController.py:378 +#: ../src\controller\mainController.py:974 msgid "Trending topics for %s" msgstr "Tendances pour %s" -#: ../src\controller\mainController.py:464 -#: ../src\controller\mainController.py:480 -#: ../src\controller\mainController.py:1089 -#: ../src\controller\mainController.py:1108 -#: ../src\controller\mainController.py:1127 -#: ../src\controller\mainController.py:1146 +#: ../src\controller\mainController.py:445 +#: ../src\controller\mainController.py:461 +#: ../src\controller\mainController.py:1072 +#: ../src\controller\mainController.py:1091 +#: ../src\controller\mainController.py:1110 +#: ../src\controller\mainController.py:1129 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." @@ -289,152 +295,152 @@ msgstr "" "Aucune session n'a actuellement le focus. Sélectionnez-en une avec le " "raccourci pour la session précédente ou suivante." -#: ../src\controller\mainController.py:468 +#: ../src\controller\mainController.py:449 msgid "Empty buffer." msgstr "Tampon vide." -#: ../src\controller\mainController.py:475 +#: ../src\controller\mainController.py:456 msgid "{0} not found." msgstr "{0} introuvable." -#: ../src\controller\mainController.py:485 +#: ../src\controller\mainController.py:466 msgid "Filters cannot be applied on this buffer" msgstr "Les filtres ne peuvent pas s'appliquer à ce tampon" -#: ../src\controller\mainController.py:538 -#: ../src\controller\mainController.py:555 -#: ../src\controller\mainController.py:583 +#: ../src\controller\mainController.py:519 +#: ../src\controller\mainController.py:536 +#: ../src\controller\mainController.py:565 msgid "Select the user" msgstr "Sélectionnez l'utilisateur" -#: ../src\controller\mainController.py:767 +#: ../src\controller\mainController.py:750 msgid "Add an user alias" msgstr "Ajoute un alis pour l'utilisateur" -#: ../src\controller\mainController.py:775 +#: ../src\controller\mainController.py:758 msgid "Alias has been set correctly for {}." msgstr "L'alias pour {} a correctement été définie" -#: ../src\controller\mainController.py:838 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:821 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "D MMM YYYY à H:m" -#: ../src\controller\mainController.py:966 +#: ../src\controller\mainController.py:949 msgid "Conversation with {0}" msgstr "Conversation avec {0}" +#: ../src\controller\mainController.py:990 #: ../src\controller\mainController.py:1007 -#: ../src\controller\mainController.py:1024 msgid "There are no coordinates in this tweet" msgstr "Il n'y a aucune coordonnée dans ce tweet" -#: ../src\controller\mainController.py:1009 -#: ../src\controller\mainController.py:1028 +#: ../src\controller\mainController.py:992 +#: ../src\controller\mainController.py:1011 msgid "Error decoding coordinates. Try again later." msgstr "Erreur pendant le décodage des coordonnées. Réessayez plus tard." -#: ../src\controller\mainController.py:1013 +#: ../src\controller\mainController.py:996 msgid "Unable to find address in OpenStreetMap." msgstr "Impossible de trouver l'adresse dans OpenStreetMap" -#: ../src\controller\mainController.py:1026 +#: ../src\controller\mainController.py:1009 msgid "There are no results for the coordinates in this tweet" msgstr "Il n'y a aucun résultat pour les coordonnées dans ce tweet" -#: ../src\controller\mainController.py:1137 -#: ../src\controller\mainController.py:1156 +#: ../src\controller\mainController.py:1120 +#: ../src\controller\mainController.py:1139 msgid "%s, %s of %s" msgstr "%s, %s de %s" -#: ../src\controller\mainController.py:1139 -#: ../src\controller\mainController.py:1158 -#: ../src\controller\mainController.py:1183 -#: ../src\controller\mainController.py:1208 +#: ../src\controller\mainController.py:1122 +#: ../src\controller\mainController.py:1141 +#: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1191 msgid "%s. Empty" msgstr "%s. Vide" -#: ../src\controller\mainController.py:1171 -#: ../src\controller\mainController.py:1175 -#: ../src\controller\mainController.py:1196 +#: ../src\controller\mainController.py:1154 +#: ../src\controller\mainController.py:1158 +#: ../src\controller\mainController.py:1179 msgid "{0}: This account is not logged into Twitter." msgstr "{0}: Ce compte n'est pas connecté à twitter." -#: ../src\controller\mainController.py:1181 -#: ../src\controller\mainController.py:1206 +#: ../src\controller\mainController.py:1164 +#: ../src\controller\mainController.py:1189 msgid "%s. %s, %s of %s" msgstr "%s. %s, %s de %s" -#: ../src\controller\mainController.py:1200 +#: ../src\controller\mainController.py:1183 msgid "{0}: This account is not logged into twitter." msgstr "{0}: Ce compte n'est pas connecté à twitter." -#: ../src\controller\mainController.py:1426 +#: ../src\controller\mainController.py:1408 msgid "This list is already opened" msgstr "Cette liste est déjà ouverte" -#: ../src\controller\mainController.py:1456 -#: ../src\controller\mainController.py:1472 +#: ../src\controller\mainController.py:1438 +#: ../src\controller\mainController.py:1454 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" "Une erreur s'est produite en essayant de se connecter au serveur. Veuillez " "réessayer plus tard." -#: ../src\controller\mainController.py:1508 +#: ../src\controller\mainController.py:1490 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "La lecture automatique des nouveaux tweets est activée pour ce tampon" -#: ../src\controller\mainController.py:1511 +#: ../src\controller\mainController.py:1493 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "" "La lecture automatique des nouveaux tweets est désactivée pour ce tampon" -#: ../src\controller\mainController.py:1518 +#: ../src\controller\mainController.py:1500 msgid "Session mute on" msgstr "Session muet" -#: ../src\controller\mainController.py:1521 +#: ../src\controller\mainController.py:1503 msgid "Session mute off" msgstr "Session non muet" -#: ../src\controller\mainController.py:1529 +#: ../src\controller\mainController.py:1511 msgid "Buffer mute on" msgstr "Tampon muet" -#: ../src\controller\mainController.py:1532 +#: ../src\controller\mainController.py:1514 msgid "Buffer mute off" msgstr "Tampon non muet" -#: ../src\controller\mainController.py:1555 +#: ../src\controller\mainController.py:1537 msgid "Copied" msgstr "Copié" -#: ../src\controller\mainController.py:1586 +#: ../src\controller\mainController.py:1567 msgid "Unable to update this buffer." msgstr "Impossible de mettre à jour ce tampon." -#: ../src\controller\mainController.py:1589 +#: ../src\controller\mainController.py:1570 msgid "Updating buffer..." msgstr "Actualisation..." -#: ../src\controller\mainController.py:1592 +#: ../src\controller\mainController.py:1573 msgid "{0} items retrieved" msgstr "{0} éléments récupérés" -#: ../src\controller\mainController.py:1609 -#: ../src\controller\mainController.py:1629 +#: ../src\controller\mainController.py:1590 +#: ../src\controller\mainController.py:1610 msgid "Invalid buffer" msgstr "Tampon invalide" -#: ../src\controller\mainController.py:1620 +#: ../src\controller\mainController.py:1601 msgid "Picture {0}" msgstr "Photo {0}" -#: ../src\controller\mainController.py:1621 +#: ../src\controller\mainController.py:1602 msgid "Select the picture" msgstr "Sélectionner la photo" -#: ../src\controller\mainController.py:1640 +#: ../src\controller\mainController.py:1621 msgid "Unable to extract text" msgstr "Impossible d'extraire le texte" @@ -657,7 +663,7 @@ msgstr "Arrêté" msgid "&Record" msgstr "&Enregistrer" -#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:146 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 msgid "Playing..." msgstr "Lecture..." @@ -1786,7 +1792,7 @@ msgid "Execute action" msgstr "Exécuter une action" #: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:39 ../src\wxUI\dialogs\utils.py:71 +#: ../src\wxUI\dialogs\userAliasDialogs.py:24 ../src\wxUI\dialogs\utils.py:39 msgid "Close" msgstr "Fermer" @@ -1823,8 +1829,8 @@ msgid "Key" msgstr "Touche" #: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 -#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\utils.py:36 -#: ../src\wxUI\dialogs\utils.py:68 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:22 +#: ../src\wxUI\dialogs\utils.py:36 msgid "OK" msgstr "OK" @@ -1940,7 +1946,7 @@ msgstr "" "ou après la réactivation d'un compte. Veuillez supprimer manuellement ce " "compte depuis votre session Twitter pour ne plus voir ce message." -#: ../src\sessions\base.py:111 +#: ../src\sessions\base.py:113 msgid "" "An exception occurred while saving the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1950,7 +1956,7 @@ msgstr "" "{app}, elle va être détruite et recréée automatiquement. Si ce problème " "perciste, veuillez envoyer le journal d'erreur aux développeurs de {app}." -#: ../src\sessions\base.py:151 +#: ../src\sessions\base.py:153 msgid "" "An exception occurred while loading the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1999,16 +2005,16 @@ msgstr "privé" msgid "public" msgstr "public" -#: ../src\sessions\twitter\session.py:208 +#: ../src\sessions\twitter\session.py:209 msgid "%s failed. Reason: %s" msgstr "%s erreur. Raison: %s" -#: ../src\sessions\twitter\session.py:214 +#: ../src\sessions\twitter\session.py:215 msgid "%s succeeded." msgstr "%s réussi." -#: ../src\sessions\twitter\session.py:423 -#: ../src\sessions\twitter\session.py:501 +#: ../src\sessions\twitter\session.py:424 +#: ../src\sessions\twitter\session.py:502 msgid "Deleted account" msgstr "Compte supprimé" @@ -2021,8 +2027,8 @@ msgid "No status found with that ID" msgstr "Aucun Tweet trouvée avec cet ID" #: ../src\sessions\twitter\utils.py:235 -msgid "Error code {0}" -msgstr "Code d'erreur {0}" +msgid "Error {0}" +msgstr "Erreur {0}" #: ../src\sessions\twitter\utils.py:262 msgid "{user_1}, {user_2} and {all_users} more: {text}" @@ -2036,7 +2042,7 @@ msgstr "Compte en cours d'autorisation..." msgid "Enter your PIN code here" msgstr "Entrer votre code PIN ici" -#: ../src\sound.py:159 +#: ../src\sound.py:161 msgid "Stopped." msgstr "Arrêté." @@ -2100,8 +2106,8 @@ msgstr "Date" #: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 #: ../src\wxUI\buffers\user_searches.py:11 +#: ../src\wxUI\dialogs\userAliasDialogs.py:13 #: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 -#: ../src\wxUI\dialogs\utils.py:59 msgid "User" msgstr "Utilisateur" @@ -3069,8 +3075,8 @@ msgid "&User" msgstr "&Utilisateur" #: ../src\wxUI\dialogs\userActions.py:14 +#: ../src\wxUI\dialogs\userAliasDialogs.py:12 #: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 -#: ../src\wxUI\dialogs\utils.py:58 msgid "&Autocomplete users" msgstr "&Saisie automatique utilisateurs" @@ -3106,6 +3112,10 @@ msgstr "&Signaler comme spam" msgid "&Ignore tweets from this client" msgstr "&Ignorer les tweets de ce client" +#: ../src\wxUI\dialogs\userAliasDialogs.py:17 +msgid "Alias" +msgstr "Alias" + #: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "Chronologie pour %s" @@ -3130,10 +3140,6 @@ msgstr "&Abonnés" msgid "F&riends" msgstr "A&bonnements" -#: ../src\wxUI\dialogs\utils.py:63 -msgid "Alias" -msgstr "Alias" - #: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:32 msgid "&Retweet" msgstr "&Retweet" @@ -3404,6 +3410,9 @@ msgstr "Mise à jour" msgid "Your {0} version is up to date" msgstr "Votre version de {0} est à jour" +#~ msgid "Friends' Timelines" +#~ msgstr "Chronologies des abonnements" + #~ msgid "Events" #~ msgstr "Événements" From a8d876a7b78dff216bbb6bf85d7cf2845a9e8b20 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 21 Oct 2021 17:02:03 +0200 Subject: [PATCH 152/245] Fix last-translator e-mail --- src/locales/fr/LC_MESSAGES/twblue.po | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index e44b14b1..a9c57970 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" "POT-Creation-Date: 2021-10-21 16:55+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-10-21 16:57+0200\n" -"Last-Translator: Corentin BACQUÉ-CAZENAVE \n" +"PO-Revision-Date: 2021-10-21 17:01+0200\n" +"Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" "MIME-Version: 1.0\n" @@ -237,8 +237,6 @@ msgid "Likes for {}" msgstr "Favoris de {}" #: ../src\controller\mainController.py:361 -#, fuzzy -#| msgid "Followers' Timelines" msgid "Followers timelines" msgstr "Chronologies des abonnés" From e3e0ac94579de99dadef7d6ee538116e1152f57c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 10:45:11 -0500 Subject: [PATCH 153/245] Added an alias manager dialog in the application menu --- doc/changelog.md | 1 + src/controller/mainController.py | 8 ++++ src/controller/userAliasController.py | 53 ++++++++++++++++++++++++ src/wxUI/dialogs/userAliasDialogs.py | 59 +++++++++++++++++++++++++++ src/wxUI/view.py | 1 + 5 files changed, 122 insertions(+) create mode 100644 src/controller/userAliasController.py diff --git a/doc/changelog.md b/doc/changelog.md index 3b8931e7..e0c489bc 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,7 @@ ## changes in this version +* Added an user alias manager, located in the application menu in the menu bar. From this dialog, it is possible to review, add, edit or remove user aliases for the current account. ([#401](https://github.com/manuelcortez/TWBlue/issues/401)) * TWBlue now closes the VLC player window automatically when a video reaches its end. ([#399](https://github.com/manuelcortez/TWBlue/issues/399)) * After a lot of time, TWBlue now uses a new default Soundpack, called FreakyBlue. This soundpack will be set by default in all new sessions created in the application. Thanks to [Andre Louis](https://twitter.com/FreakyFwoof) for the pack. ([#247](https://github.com/manuelcortez/TWBlue/issues/247)) * When reading a tweet, if the tweet contains more than 2 consecutive mentions, TWBlue will announce how many more users the tweet includes, as opposed to read every user in the conversation. You still can display the tweet to read all users. diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 7241707f..c3d97ff9 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -2,6 +2,7 @@ import platform system = platform.system() import application +import wx import requests from audio_services import youtube_utils import arrow @@ -24,6 +25,7 @@ from sessions.twitter import utils, compose from sessionmanager import manager, sessionManager from controller import buffers from . import messages +from . import userAliasController import sessions from sessions.twitter import session as session_ from pubsub import pub @@ -189,6 +191,7 @@ class Controller(object): widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_list, self.view.addToList) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_list, self.view.removeFromList) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_buffer, self.view.update_buffer) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_aliases, self.view.manageAliases) def set_systray_icon(self): self.systrayIcon = sysTrayIcon.SysTrayIcon() @@ -756,6 +759,11 @@ class Controller(object): buff.session.settings["user-aliases"][str(user_id)] = alias buff.session.settings.write() output.speak(_("Alias has been set correctly for {}.").format(user)) + pub.sendMessage("alias-added") + + def manage_aliases(self, *args, **kwargs): + buff = self.get_best_buffer() + alias_controller = userAliasController.userAliasController(buff.session.settings) def post_tweet(self, event=None): buffer = self.get_best_buffer() diff --git a/src/controller/userAliasController.py b/src/controller/userAliasController.py new file mode 100644 index 00000000..69a4fa8f --- /dev/null +++ b/src/controller/userAliasController.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +import widgetUtils +from pubsub import pub +from wxUI.dialogs import userAliasDialogs +from extra import autocompletionUsers + +class userAliasController(object): + def __init__(self, settings): + super(userAliasController, self).__init__() + self.settings = settings + self.dialog = userAliasDialogs.userAliasEditorDialog() + self.update_aliases_manager() + widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.on_add) + widgetUtils.connect_event(self.dialog.edit, widgetUtils.BUTTON_PRESSED, self.on_edit) + widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.on_remove) + pub.subscribe(self.update_aliases_manager, "alias-added") + self.dialog.ShowModal() + + def update_aliases_manager(self): + self.dialog.users.Clear() + aliases = [self.settings["user-aliases"].get(k) for k in self.settings["user-aliases"].keys()] + if len(aliases) > 0: + self.dialog.users.InsertItems(aliases, 0) + self.dialog.on_selection_changes() + + def on_add(self, *args, **kwargs): + pub.sendMessage("execute-action", action="add_alias") + + def on_edit(self, *args, **kwargs): + selection = self.dialog.get_selected_user() + if selection != "": + edited = self.dialog.edit_alias_dialog(_("Edit alias for {}").format(selection)) + if edited == None or edited == "": + return + for user_key in self.settings["user-aliases"].keys(): + if self.settings["user-aliases"][user_key] == selection: + self.settings["user-aliases"][user_key] = edited + self.settings.write() + self.update_aliases_manager() + break + + def on_remove(self, *args, **kwargs): + selection = self.dialog.get_selected_user() + if selection == None or selection == "": + return + should_remove = self.dialog.remove_alias_dialog() + if should_remove: + for user_key in self.settings["user-aliases"].keys(): + if self.settings["user-aliases"][user_key] == selection: + self.settings["user-aliases"].pop(user_key) + self.settings.write() + self.update_aliases_manager() + break diff --git a/src/wxUI/dialogs/userAliasDialogs.py b/src/wxUI/dialogs/userAliasDialogs.py index 6fca9237..9156c0b5 100644 --- a/src/wxUI/dialogs/userAliasDialogs.py +++ b/src/wxUI/dialogs/userAliasDialogs.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import wx +import gettext from . import baseDialog class addAliasDialog(baseDialog.BaseWXDialog): @@ -34,3 +35,61 @@ class addAliasDialog(baseDialog.BaseWXDialog): def get_user(self): return (self.cb.GetValue(), self.alias.GetValue()) +class userAliasEditorDialog(wx.Dialog): + def __init__(self, *args, **kwds): + super(userAliasEditorDialog, self).__init__(parent=None) + self.SetTitle(_("Edit user aliases")) + main_sizer = wx.BoxSizer(wx.VERTICAL) + userListSizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Users")), wx.VERTICAL) + main_sizer.Add(userListSizer, 1, wx.EXPAND, 0) + self.users = wx.ListBox(self, wx.ID_ANY, choices=[]) + self.users.Bind(wx.EVT_LISTBOX, self.on_selection_changes) + userListSizer.Add(self.users, 0, 0, 0) + actionsSizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Actions")), wx.HORIZONTAL) + main_sizer.Add(actionsSizer, 1, wx.EXPAND, 0) + self.add = wx.Button(self, wx.ID_ANY, _("Add alias")) + self.add.SetToolTip(_("Adds a new user alias")) + actionsSizer.Add(self.add, 0, 0, 0) + self.edit = wx.Button(self, wx.ID_ANY, _("Edit")) + self.edit.SetToolTip(_("Edit the currently focused user Alias.")) + self.edit.Enable(False) + actionsSizer.Add(self.edit, 0, 0, 0) + self.remove = wx.Button(self, wx.ID_ANY, _("Remove")) + self.remove.SetToolTip(_("Remove the currently focused user alias.")) + self.remove.Enable(False) + actionsSizer.Add(self.remove, 0, 0, 0) + btnSizer = wx.StdDialogButtonSizer() + main_sizer.Add(btnSizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.button_CLOSE = wx.Button(self, wx.ID_CLOSE, "") + btnSizer.AddButton(self.button_CLOSE) + btnSizer.Realize() + self.SetSizer(main_sizer) + main_sizer.Fit(self) + self.SetEscapeId(self.button_CLOSE.GetId()) + self.Layout() + + def on_selection_changes(self, *args, **kwargs): + selection = self.users.GetSelection() + if selection == -1: + self.enable_action_buttons(False) + else: + self.enable_action_buttons(True) + + def get_selected_user(self): + return self.users.GetStringSelection() + + def remove_alias_dialog(self, *args, **kwargs): + dlg = wx.MessageDialog(self, _("Are you sure you want to delete this user alias?"), _("Remove user alias"), wx.YES_NO) + if dlg.ShowModal() == wx.ID_YES: + return True + else: + return False + + def enable_action_buttons(self, enabled=True): + self.edit.Enable(enabled) + self.remove.Enable(enabled) + + def edit_alias_dialog(self, title): + dlg = wx.TextEntryDialog(self, title, _("User alias")) + if dlg.ShowModal() == wx.ID_OK: + return dlg.GetValue() \ No newline at end of file diff --git a/src/wxUI/view.py b/src/wxUI/view.py index 5e5f034b..2d260023 100644 --- a/src/wxUI/view.py +++ b/src/wxUI/view.py @@ -20,6 +20,7 @@ class mainFrame(wx.Frame): self.show_hide = app.Append(wx.ID_ANY, _(u"&Hide window")) self.menuitem_search = app.Append(wx.ID_ANY, _(u"&Search")) self.lists = app.Append(wx.ID_ANY, _(u"&Lists manager")) + self.manageAliases = app.Append(wx.ID_ANY, _("Manage user aliases")) self.keystroke_editor = app.Append(wx.ID_ANY, _(u"&Edit keystrokes")) self.account_settings = app.Append(wx.ID_ANY, _(u"Account se&ttings")) self.prefs = app.Append(wx.ID_PREFERENCES, _(u"&Global settings")) From b23be9c896abb60599f9f731acd5bc42d3a8f8d3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 12:40:57 -0500 Subject: [PATCH 154/245] Started to remove stable and snapshot update information files --- updates/stable.json | 6 ------ updates/{snapshots.json => updates.json} | 0 2 files changed, 6 deletions(-) delete mode 100644 updates/stable.json rename updates/{snapshots.json => updates.json} (100%) diff --git a/updates/stable.json b/updates/stable.json deleted file mode 100644 index ef63523b..00000000 --- a/updates/stable.json +++ /dev/null @@ -1,6 +0,0 @@ -{"current_version": "0.95", -"description": "The first version for the new generation of TWBlue.", -"date": "day_name_abr month day_numb, 2016", -"downloads": -{"Windows32": "http://twblue.es/pubs/twblue_ngen_0.80_x86.zip", -"Windows64": "http://twblue.es/pubs/twblue_ngen_0.80_x64.zip"}} \ No newline at end of file diff --git a/updates/snapshots.json b/updates/updates.json similarity index 100% rename from updates/snapshots.json rename to updates/updates.json From daac312658378cd1bc0e1b2a4b3bb6ded88cdbe3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 12:43:03 -0500 Subject: [PATCH 155/245] Removes snapshot information from app info --- src/application.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/application.py b/src/application.py index 64d123da..f2f3b370 100644 --- a/src/application.py +++ b/src/application.py @@ -3,15 +3,9 @@ import datetime name = 'TWBlue' short_name='twblue' -snapshot = True -if snapshot == False: - version = "0.95" - update_url = 'https://twblue.es/updates/stable.php' - mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json' -else: - version = "11" - update_url = 'https://twblue.es/updates/snapshot.php' - mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json' +version = "11" +update_url = 'https://twblue.es/updates/updates.php' +mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/updates.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] authorEmail = "manuel@manuelcortez.net" copyright = "Copyright (C) 2013-2021, Manuel cortéz." From 2b059ee42e7a7ea8b9f7d724c23652bb1cbd1ef6 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:02:24 -0500 Subject: [PATCH 156/245] Modified Nsis scripts to remove references to old snapshots code --- scripts/twblue.nsi | 14 +++--- scripts/twblue_snapshot.nsi | 95 ------------------------------------- 2 files changed, 7 insertions(+), 102 deletions(-) delete mode 100644 scripts/twblue_snapshot.nsi diff --git a/scripts/twblue.nsi b/scripts/twblue.nsi index f83fe05b..b1d35335 100644 --- a/scripts/twblue.nsi +++ b/scripts/twblue.nsi @@ -15,10 +15,10 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "0.95" -VIAddVersionKey FileVersion "0.95" -VIProductVersion "0.95.0.0" -VIFileVersion "0.95.0.0" +VIAddVersionKey ProductVersion "11" +VIAddVersionKey FileVersion "11" +VIProductVersion "11.0.0.0" +VIFileVersion "11.0.0.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -72,10 +72,10 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.95" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.es" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "11" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "https://twblue.es" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 -WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 95 +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1 SectionEnd diff --git a/scripts/twblue_snapshot.nsi b/scripts/twblue_snapshot.nsi deleted file mode 100644 index f7d20764..00000000 --- a/scripts/twblue_snapshot.nsi +++ /dev/null @@ -1,95 +0,0 @@ -!include "MUI2.nsh" -!include "LogicLib.nsh" -!include "x64.nsh" -Unicode true -CRCCheck on -ManifestSupportedOS all -XPStyle on -Name "TWBlue" -OutFile "TWBlue_snapshot_setup.exe" -InstallDir "$PROGRAMFILES\twblue" -InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "InstallLocation" -RequestExecutionLevel admin -SetCompress auto -SetCompressor /solid lzma -SetDatablockOptimize on -VIAddVersionKey ProductName "TWBlue Snapshot version" -VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "11" -VIAddVersionKey FileVersion "11" -VIProductVersion "11.0.0.0" -VIFileVersion "11.0.0.0" -!insertmacro MUI_PAGE_WELCOME -!define MUI_LICENSEPAGE_RADIOBUTTONS -!insertmacro MUI_PAGE_LICENSE "license.txt" -!insertmacro MUI_PAGE_DIRECTORY -var StartMenuFolder -!insertmacro MUI_PAGE_STARTMENU startmenu $StartMenuFolder -!insertmacro MUI_PAGE_INSTFILES -!define MUI_FINISHPAGE_LINK "Visit TWBlue website" -!define MUI_FINISHPAGE_LINK_LOCATION "https://twblue.es" -!define MUI_FINISHPAGE_RUN "$INSTDIR\TWBlue.exe" -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_LANGUAGE "English" -!insertmacro MUI_LANGUAGE "French" -!insertmacro MUI_LANGUAGE "Spanish" -!insertmacro MUI_LANGUAGE "Italian" -!insertmacro MUI_LANGUAGE "Finnish" -!insertmacro MUI_LANGUAGE "Russian" -!insertmacro MUI_LANGUAGE "PortugueseBR" -!insertmacro MUI_LANGUAGE "Polish" -!insertmacro MUI_LANGUAGE "German" -!insertmacro MUI_LANGUAGE "Hungarian" -!insertmacro MUI_LANGUAGE "Turkish" -!insertmacro MUI_LANGUAGE "Arabic" -!insertmacro MUI_LANGUAGE "Galician" -!insertmacro MUI_LANGUAGE "Catalan" -!insertmacro MUI_LANGUAGE "Basque" -!insertmacro MUI_LANGUAGE "Croatian" -!insertmacro MUI_LANGUAGE "Japanese" -!insertmacro MUI_LANGUAGE "SerbianLatin" -!insertmacro MUI_LANGUAGE "Romanian" -!insertmacro MUI_RESERVEFILE_LANGDLL -Section -SetShellVarContext All -SetOutPath "$INSTDIR" -${If} ${RunningX64} -File /r TWBlue64\* -${Else} -File /r TWBlue\* -${EndIf} -CreateShortCut "$DESKTOP\TWBlue.lnk" "$INSTDIR\TWBlue.exe" -!insertmacro MUI_STARTMENU_WRITE_BEGIN startmenu -CreateDirectory "$SMPROGRAMS\$StartMenuFolder" -CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TWBlue.lnk" "$INSTDIR\TWBlue.exe" -CreateShortCut "$SMPROGRAMS\$StartMenuFolder\TWBlue on the web.lnk" "http://twblue.es" -CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe" -!insertmacro MUI_STARTMENU_WRITE_END -WriteUninstaller "$INSTDIR\Uninstall.exe" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayName" "TWBlue" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "11" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "https://twblue.es" -WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 -WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 -WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1 -WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1 -SectionEnd -Section "Uninstall" -SetShellVarContext All -DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" -RMDir /r /REBOOTOK $INSTDIR -Delete "$DESKTOP\TWBlue.lnk" -!insertmacro MUI_STARTMENU_GETFOLDER startmenu $StartMenuFolder -RMDir /r "$SMPROGRAMS\$StartMenuFolder" -SectionEnd -Function .onInit -${If} ${RunningX64} -StrCpy $instdir "$programfiles64\twblue" -${EndIf} -!insertmacro MUI_LANGDLL_DISPLAY -FunctionEnd From d222740887a5c69708c3545aed845b2ab259fe6c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:04:49 -0500 Subject: [PATCH 157/245] Updated gitlab CI --- .gitlab-ci.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f377e5a..06567285 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,7 +8,7 @@ stages: - make_installer - upload -snapshot32: +twblue32: tags: - shared-windows - windows @@ -21,7 +21,6 @@ snapshot32: - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' - - '&$env:PYTHON -m pip uninstall enum34 -y' stage: build interruptible: true script: @@ -37,7 +36,7 @@ snapshot32: - '&$env:PYTHON make_archive.py' - cd .. - mv src/dist artifacts/TWBlue - - move src/twblue.zip artifacts/twblue_snapshot_x86.zip + - move src/twblue.zip artifacts/twblue_x86.zip only: - tags artifacts: @@ -45,7 +44,7 @@ snapshot32: - artifacts expire_in: 1 day -snapshot64: +twblue64: tags: - shared-windows - windows @@ -73,7 +72,7 @@ snapshot64: - '&$env:PYTHON make_archive.py' - cd .. - mv src/dist artifacts/TWBlue64 - - move src/twblue.zip artifacts/twblue_snapshot_x64.zip + - move src/twblue.zip artifacts/twblue_x64.zip only: - tags artifacts: @@ -96,8 +95,8 @@ generate_versions: - move artifacts/TWBlue scripts/ - move artifacts/TWBlue64 scripts/ - cd scripts - - '&$env:NSIS twblue_snapshot.nsi' - - move twblue_snapshot_setup.exe ../artifacts + - '&$env:NSIS twblue.nsi' + - move twblue_setup.exe ../artifacts only: - tags artifacts: From 72e6d030d51d0f3bf10633e03bfcc0e3cae0c21c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:10:57 -0500 Subject: [PATCH 158/245] Updater no longer will try to compare float numbers for updates --- src/update/update.py | 5 ++--- src/update/updater.py | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/update/update.py b/src/update/update.py index 64bfd7de..7f1b7cf2 100644 --- a/src/update/update.py +++ b/src/update/update.py @@ -1,4 +1,3 @@ -from __future__ import unicode_literals from logging import getLogger logger = getLogger('update') @@ -24,8 +23,8 @@ def perform_update(endpoint, current_version, app_name='', password=None, update if not available_update: logger.debug("No update available") return False - available_version = float(available_update['current_version']) - if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: + available_version = available_update['current_version'] + if available_version == current_version or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: logger.debug("No update for this architecture") return False available_description = available_update.get('description', None) diff --git a/src/update/updater.py b/src/update/updater.py index 2bef784b..5214c1de 100644 --- a/src/update/updater.py +++ b/src/update/updater.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals import application from . import update import platform From a82efd4dccc25fc2ca445593c3c3de1c0bca2e75 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:16:31 -0500 Subject: [PATCH 159/245] Fixed a typo --- src/update/update.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/update/update.py b/src/update/update.py index 7f1b7cf2..d6b47f5c 100644 --- a/src/update/update.py +++ b/src/update/update.py @@ -41,10 +41,10 @@ def perform_update(endpoint, current_version, app_name='', password=None, update downloaded = download_update(update_url, download_path, requests_session=requests_session, progress_callback=progress_callback) extracted = extract_update(downloaded, update_path, password=password) bootstrap_path = move_bootstrap(extracted) - execute_bootstrap(bootstrap_path, extracted) - logger.info("Update prepared for installation.") if callable(update_complete_callback): update_complete_callback() + execute_bootstrap(bootstrap_path, extracted) + logger.info("Update prepared for installation.") def create_requests_session(app_name=None, version=None): user_agent = '' From cb1312d0c935d518132e5b30038251adb7786189 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:38:21 -0500 Subject: [PATCH 160/245] Changed version in installer so it will be easier to replace it later by the authomatic script --- scripts/twblue.nsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/twblue.nsi b/scripts/twblue.nsi index b1d35335..a2789cef 100644 --- a/scripts/twblue.nsi +++ b/scripts/twblue.nsi @@ -15,10 +15,10 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "11" -VIAddVersionKey FileVersion "11" -VIProductVersion "11.0.0.0" -VIFileVersion "11.0.0.0" +VIAddVersionKey ProductVersion "0.95" +VIAddVersionKey FileVersion "0.95" +VIProductVersion "0.95" +VIFileVersion "0.95" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -72,7 +72,7 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "11" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.95" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "https://twblue.es" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 0 From 9f48784ce453f2673faf55c818eb891bb7634724 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:39:50 -0500 Subject: [PATCH 161/245] Added script to add next version in application.py and installer generation files --- src/write_version_data.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/write_version_data.py diff --git a/src/write_version_data.py b/src/write_version_data.py new file mode 100644 index 00000000..b13675b3 --- /dev/null +++ b/src/write_version_data.py @@ -0,0 +1,29 @@ +#! /usr/bin/env python# -*- coding: iso-8859-1 -*- +""" Write version info (taken from the last commit) to application.py. This method has been implemented this way for running updates. +This file is not intended to be called by the user. It will be used only by the Gitlab CI runner.""" +import requests +from codecs import open + +print("Writing version data for update...") +commit_info = requests.get("https://gitlab.com/api/v4/projects/23482196/repository/commits/next-gen") +commit_info = commit_info.json() +commit = commit_info["short_id"] +print("Got new version info: {commit}".format(commit=commit,)) +file = open("application.py", "r", encoding="utf-8") +lines = file.readlines() +lines[-1] = 'version = "{}"'.format(commit_info["created_at"][:10].replace("-", ".")) +file.close() +file2 = open("application.py", "w", encoding="utf-8") +file2.writelines(lines) +file2.close() +print("Wrote application.py with the new version info.") + +print("Updating next version on installer setup...") +file = open("..\\scripts\\twblue.nsi", "r", encoding="utf-8") +contents = file.read() +contents = contents.replace("0.95", commit_info["created_at"][:10].replace("-", ".")) +file.close() +file2 = open("..\\scripts\\twblue.nsi", "w", encoding="utf-8") +file2.write(contents) +file2.close() +print("done") From f7f303929ef09a6f29458989e625c89032c22935 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 13:41:22 -0500 Subject: [PATCH 162/245] Updated CI config --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 06567285..25061019 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,6 +29,7 @@ twblue32: - '&$env:PYTHON documentation_importer.py' - cd ..\src - '&$env:PYTHON ..\doc\generator.py' + - '&$env:PYTHON write_version_data.py' - '&$env:PYTHON setup.py build' - cd .. - mkdir artifacts @@ -65,6 +66,7 @@ twblue64: - '&$env:PYTHON documentation_importer.py' - cd ..\src - '&$env:PYTHON ..\doc\generator.py' + - '&$env:PYTHON write_version_data.py' - '&$env:PYTHON setup.py build' - cd .. - mkdir artifacts From b9ee0dae5b7165a349d18066e3ef96c2a8344e8d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 14:48:58 -0500 Subject: [PATCH 163/245] Fixed a typo in installer script --- scripts/twblue.nsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/twblue.nsi b/scripts/twblue.nsi index a2789cef..bae7d97e 100644 --- a/scripts/twblue.nsi +++ b/scripts/twblue.nsi @@ -18,7 +18,7 @@ VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." VIAddVersionKey ProductVersion "0.95" VIAddVersionKey FileVersion "0.95" VIProductVersion "0.95" -VIFileVersion "0.95" +VIFileVersion "0.95.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS !insertmacro MUI_PAGE_LICENSE "license.txt" @@ -32,7 +32,7 @@ var StartMenuFolder !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "Italian" From ef79e0696ef1e11f6cbfcffeb84c0a800e92017f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 15:19:57 -0500 Subject: [PATCH 164/245] Move updated Nsis script to artifacts in build stage --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25061019..bafc7765 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,6 +38,8 @@ twblue32: - cd .. - mv src/dist artifacts/TWBlue - move src/twblue.zip artifacts/twblue_x86.zip + # Move the generated script nsis file to artifacts, so we won't need python when generating the installer. + - move scripts/twblue.nsi artifacts/twblue.nsi only: - tags artifacts: @@ -96,6 +98,7 @@ generate_versions: script: - move artifacts/TWBlue scripts/ - move artifacts/TWBlue64 scripts/ + - move artifacts/twblue.nsi scripts/ - cd scripts - '&$env:NSIS twblue.nsi' - move twblue_setup.exe ../artifacts From 351974607814403055692356d29b8da7ff60587f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 15:47:03 -0500 Subject: [PATCH 165/245] Move installer Nsis file to a new name --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bafc7765..a838c655 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -98,9 +98,9 @@ generate_versions: script: - move artifacts/TWBlue scripts/ - move artifacts/TWBlue64 scripts/ - - move artifacts/twblue.nsi scripts/ + - move artifacts/twblue.nsi scripts/installer.nsi - cd scripts - - '&$env:NSIS twblue.nsi' + - '&$env:NSIS installer.nsi' - move twblue_setup.exe ../artifacts only: - tags From 528ecc2a335c6517b456c54be9a58b29dc4a655d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 16:16:03 -0500 Subject: [PATCH 166/245] Updated NSI file --- scripts/twblue.nsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/twblue.nsi b/scripts/twblue.nsi index bae7d97e..9f1bfe95 100644 --- a/scripts/twblue.nsi +++ b/scripts/twblue.nsi @@ -15,9 +15,9 @@ SetCompressor /solid lzma SetDatablockOptimize on VIAddVersionKey ProductName "TWBlue" VIAddVersionKey LegalCopyright "Copyright 2014-2021 Manuel Cortéz." -VIAddVersionKey ProductVersion "0.95" -VIAddVersionKey FileVersion "0.95" -VIProductVersion "0.95" +VIAddVersionKey ProductVersion "0.95.0" +VIAddVersionKey FileVersion "0.95.0" +VIProductVersion "0.95.0" VIFileVersion "0.95.0" !insertmacro MUI_PAGE_WELCOME !define MUI_LICENSEPAGE_RADIOBUTTONS From a5ba80feeec1e0ceae9a436e214a096d2b1256a8 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 26 Oct 2021 16:18:53 -0500 Subject: [PATCH 167/245] Final touches --- src/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/application.py b/src/application.py index f2f3b370..07632f4c 100644 --- a/src/application.py +++ b/src/application.py @@ -3,7 +3,6 @@ import datetime name = 'TWBlue' short_name='twblue' -version = "11" update_url = 'https://twblue.es/updates/updates.php' mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/updates.json' authors = ["Manuel Cortéz", "José Manuel Delicado"] @@ -14,3 +13,4 @@ translators = ["Manuel Cortéz (English)", "Mohammed Al Shara, Hatoun Felemban ( url = u"https://twblue.es" report_bugs_url = "https://github.com/manuelcortez/twblue/issues" supported_languages = [] +version = "11" From d888563fdae4007a9247f421bbb54cc12f4fa071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Wed, 27 Oct 2021 22:00:58 +0200 Subject: [PATCH 168/245] Updated Api keys --- mysc/keys/api_keys.c | 13 ------------- mysc/keys/api_keys.h | 4 ---- 2 files changed, 17 deletions(-) diff --git a/mysc/keys/api_keys.c b/mysc/keys/api_keys.c index a3c5ad09..f07628c9 100644 --- a/mysc/keys/api_keys.c +++ b/mysc/keys/api_keys.c @@ -5,19 +5,6 @@ return "key\0"; char *get_api_secret(){ return "secret_key\0"; } -char *get_dropbox_api_key(){ -return "key\0"; -} -char *get_dropbox_api_secret(){ -return "secret_key\0"; -} char *get_twishort_api_key(){ return "key\0"; } -char *get_bts_user(){ -return "user\0"; -} -char *get_bts_password(){ -return "pass\0"; -} - diff --git a/mysc/keys/api_keys.h b/mysc/keys/api_keys.h index 963403ce..9073733d 100644 --- a/mysc/keys/api_keys.h +++ b/mysc/keys/api_keys.h @@ -3,10 +3,6 @@ char *get_api_key(); char *get_api_secret(); -char *get_dropbox_api_key(); -char *get_dropbox_api_secret(); char *get_twishort_api_key(); -char *get_bts_user(); -char *get_bts_password(); #endif From e23a52e38f0aeeaf3a8053f1a0f69780cc7a4efb Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 27 Oct 2021 15:29:15 -0500 Subject: [PATCH 169/245] Changes in TWBlue keys --- src/sessions/twitter/session.py | 8 +++++--- src/write_version_data.py | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index db7e85af..a219016c 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -8,6 +8,7 @@ import wx import config import output import application +import appkeys from pubsub import pub import tweepy from tweepy.errors import TweepyException, Forbidden, NotFound @@ -135,9 +136,10 @@ class Session(base.baseSession): if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None: try: log.debug("Logging in to twitter...") - self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) + self.auth = tweepy.OAuthHandler(appkeys.twitter_api_key, appkeys.twitter_api_secret) self.auth.set_access_token(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"]) self.twitter = tweepy.API(self.auth) + self.twitter_v2 = tweepy.Client(consumer_key=appkeys.twitter_api_key, consumer_secret=appkeys.twitter_api_secret, access_token=self.settings["twitter"]["user_key"], access_token_secret=self.settings["twitter"]["user_secret"]) if verify_credentials == True: self.credentials = self.twitter.verify_credentials() self.logged = True @@ -156,7 +158,7 @@ class Session(base.baseSession): if self.logged == True: raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.") else: - self.auth = tweepy.OAuthHandler(keyring.get("api_key"), keyring.get("api_secret")) + self.auth = tweepy.OAuthHandler(appkeys.twitter_api_key, appkeys.twitter_api_secret) redirect_url = self.auth.get_authorization_url() webbrowser.open_new_tab(redirect_url) self.authorisation_dialog = authorisationDialog() @@ -523,7 +525,7 @@ class Session(base.baseSession): def start_streaming(self): if config.app["app-settings"]["no_streaming"]: return - self.stream = streaming.Stream(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"], muted_users=self.db["muted_users"], consumer_key=keyring.get("api_key"), consumer_secret=keyring.get("api_secret"), access_token=self.settings["twitter"]["user_key"], access_token_secret=self.settings["twitter"]["user_secret"], chunk_size=1025) + self.stream = streaming.Stream(twitter_api=self.twitter, user=self.db["user_name"], user_id=self.db["user_id"], muted_users=self.db["muted_users"], consumer_key=appkeys.twitter_api_key, consumer_secret=appkeys.twitter_api_secret, access_token=self.settings["twitter"]["user_key"], access_token_secret=self.settings["twitter"]["user_secret"], chunk_size=1025) self.stream_thread = call_threaded(self.stream.filter, follow=self.stream.users, stall_warnings=True) def stop_streaming(self): diff --git a/src/write_version_data.py b/src/write_version_data.py index b13675b3..4e123157 100644 --- a/src/write_version_data.py +++ b/src/write_version_data.py @@ -27,3 +27,9 @@ file2 = open("..\\scripts\\twblue.nsi", "w", encoding="utf-8") file2.write(contents) file2.close() print("done") +file3 = open("appkeys.py", "w") +keys = """twitter_api_key = "daMHlXsFlalEWtaqTL7xd6TqZ" +twitter_api_secret = "lOcpsIlhr1lBpA53oNWwmKh9yM6Gqk3IRFOzq9TvAO8B5gisFD" +""" +file3.write(keys) +file3.close() \ No newline at end of file From 39a02ea33a05e8ccdb489cba84a8390a635fe322 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 28 Oct 2021 12:33:52 +0200 Subject: [PATCH 170/245] Update french interface --- src/locales/fr/LC_MESSAGES/twblue.po | 352 +++++++++++++++------------ 1 file changed, 198 insertions(+), 154 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index a9c57970..62eb43ad 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2021-10-21 16:55+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-10-21 17:01+0200\n" +"POT-Creation-Date: 2021-10-28 12:29+Paris, Madrid (heure d’été)\n" +"PO-Revision-Date: 2021-10-28 12:33+0200\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -25,56 +25,56 @@ msgid "This action is not supported for this buffer" msgstr "Cette action n'est pas supportée pour ce tampon" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:334 ../src\controller\settings.py:286 +#: ../src\controller\mainController.py:337 ../src\controller\settings.py:286 msgid "Home" msgstr "Accueil" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:336 ../src\controller\settings.py:287 +#: ../src\controller\mainController.py:339 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Mentions" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:338 +#: ../src\controller\mainController.py:341 msgid "Direct messages" msgstr "Messages privés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:340 ../src\controller\settings.py:289 +#: ../src\controller\mainController.py:343 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Messages privés envoyés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:342 ../src\controller\settings.py:290 +#: ../src\controller\mainController.py:345 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Tweets envoyés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:344 -#: ../src\controller\mainController.py:1382 ../src\controller\settings.py:291 +#: ../src\controller\mainController.py:347 +#: ../src\controller\mainController.py:1390 ../src\controller\settings.py:291 msgid "Likes" msgstr "Favoris" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:346 -#: ../src\controller\mainController.py:1387 ../src\controller\settings.py:292 +#: ../src\controller\mainController.py:349 +#: ../src\controller\mainController.py:1395 ../src\controller\settings.py:292 msgid "Followers" msgstr "Abonnés" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:350 -#: ../src\controller\mainController.py:1397 ../src\controller\settings.py:294 +#: ../src\controller\mainController.py:353 +#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Utilisateurs bloqués" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:352 -#: ../src\controller\mainController.py:1402 ../src\controller\settings.py:295 +#: ../src\controller\mainController.py:355 +#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Utilisateurs masqués" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:1392 ../src\controller\settings.py:293 +#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:293 msgid "Friends" msgstr "Abonnements" @@ -208,84 +208,84 @@ msgstr "{0} nouvel abonné" msgid "This action is not supported in the buffer, yet." msgstr "Cette action n'est pas supportée pour le tampon actuel" -#: ../src\controller\mainController.py:274 +#: ../src\controller\mainController.py:277 msgid "Ready" msgstr "Prêt" -#: ../src\controller\mainController.py:348 +#: ../src\controller\mainController.py:351 msgid "Following" msgstr "Suivi" -#: ../src\controller\mainController.py:353 +#: ../src\controller\mainController.py:356 msgid "Timelines" msgstr "Chronologies" -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:875 -#: ../src\controller\mainController.py:1577 +#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:883 +#: ../src\controller\mainController.py:1585 msgid "Timeline for {}" msgstr "Chronologie de {}" -#: ../src\controller\mainController.py:357 +#: ../src\controller\mainController.py:360 msgid "Likes timelines" msgstr "Chronologies des favoris" -#: ../src\controller\mainController.py:360 -#: ../src\controller\mainController.py:894 -#: ../src\controller\mainController.py:1579 +#: ../src\controller\mainController.py:363 +#: ../src\controller\mainController.py:902 +#: ../src\controller\mainController.py:1587 msgid "Likes for {}" msgstr "Favoris de {}" -#: ../src\controller\mainController.py:361 +#: ../src\controller\mainController.py:364 msgid "Followers timelines" msgstr "Chronologies des abonnés" -#: ../src\controller\mainController.py:364 -#: ../src\controller\mainController.py:913 -#: ../src\controller\mainController.py:1581 +#: ../src\controller\mainController.py:367 +#: ../src\controller\mainController.py:921 +#: ../src\controller\mainController.py:1589 msgid "Followers for {}" msgstr "Abonnés de {}" -#: ../src\controller\mainController.py:365 +#: ../src\controller\mainController.py:368 msgid "Following timelines" msgstr "Chronologies des abonnements" -#: ../src\controller\mainController.py:368 -#: ../src\controller\mainController.py:932 -#: ../src\controller\mainController.py:1583 +#: ../src\controller\mainController.py:371 +#: ../src\controller\mainController.py:940 +#: ../src\controller\mainController.py:1591 msgid "Friends for {}" msgstr "Abonnements de {}" -#: ../src\controller\mainController.py:369 ../src\wxUI\dialogs\lists.py:13 +#: ../src\controller\mainController.py:372 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Listes" -#: ../src\controller\mainController.py:372 -#: ../src\controller\mainController.py:1414 +#: ../src\controller\mainController.py:375 +#: ../src\controller\mainController.py:1422 msgid "List for {}" msgstr "Liste {}" -#: ../src\controller\mainController.py:373 +#: ../src\controller\mainController.py:376 msgid "Searches" msgstr "Recherches" -#: ../src\controller\mainController.py:376 -#: ../src\controller\mainController.py:423 -#: ../src\controller\mainController.py:428 +#: ../src\controller\mainController.py:379 +#: ../src\controller\mainController.py:426 +#: ../src\controller\mainController.py:431 msgid "Search for {}" msgstr "Recherche de {}" -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:974 +#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:982 msgid "Trending topics for %s" msgstr "Tendances pour %s" -#: ../src\controller\mainController.py:445 -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:1072 -#: ../src\controller\mainController.py:1091 -#: ../src\controller\mainController.py:1110 -#: ../src\controller\mainController.py:1129 +#: ../src\controller\mainController.py:448 +#: ../src\controller\mainController.py:464 +#: ../src\controller\mainController.py:1080 +#: ../src\controller\mainController.py:1099 +#: ../src\controller\mainController.py:1118 +#: ../src\controller\mainController.py:1137 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." @@ -293,152 +293,152 @@ msgstr "" "Aucune session n'a actuellement le focus. Sélectionnez-en une avec le " "raccourci pour la session précédente ou suivante." -#: ../src\controller\mainController.py:449 +#: ../src\controller\mainController.py:452 msgid "Empty buffer." msgstr "Tampon vide." -#: ../src\controller\mainController.py:456 +#: ../src\controller\mainController.py:459 msgid "{0} not found." msgstr "{0} introuvable." -#: ../src\controller\mainController.py:466 +#: ../src\controller\mainController.py:469 msgid "Filters cannot be applied on this buffer" msgstr "Les filtres ne peuvent pas s'appliquer à ce tampon" -#: ../src\controller\mainController.py:519 -#: ../src\controller\mainController.py:536 -#: ../src\controller\mainController.py:565 +#: ../src\controller\mainController.py:522 +#: ../src\controller\mainController.py:539 +#: ../src\controller\mainController.py:568 msgid "Select the user" msgstr "Sélectionnez l'utilisateur" -#: ../src\controller\mainController.py:750 +#: ../src\controller\mainController.py:753 msgid "Add an user alias" -msgstr "Ajoute un alis pour l'utilisateur" +msgstr "Ajoute un alias pour l'utilisateur" -#: ../src\controller\mainController.py:758 +#: ../src\controller\mainController.py:761 msgid "Alias has been set correctly for {}." msgstr "L'alias pour {} a correctement été définie" -#: ../src\controller\mainController.py:821 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "D MMM YYYY à H:m" -#: ../src\controller\mainController.py:949 +#: ../src\controller\mainController.py:957 msgid "Conversation with {0}" msgstr "Conversation avec {0}" -#: ../src\controller\mainController.py:990 -#: ../src\controller\mainController.py:1007 +#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1015 msgid "There are no coordinates in this tweet" msgstr "Il n'y a aucune coordonnée dans ce tweet" -#: ../src\controller\mainController.py:992 -#: ../src\controller\mainController.py:1011 +#: ../src\controller\mainController.py:1000 +#: ../src\controller\mainController.py:1019 msgid "Error decoding coordinates. Try again later." msgstr "Erreur pendant le décodage des coordonnées. Réessayez plus tard." -#: ../src\controller\mainController.py:996 +#: ../src\controller\mainController.py:1004 msgid "Unable to find address in OpenStreetMap." msgstr "Impossible de trouver l'adresse dans OpenStreetMap" -#: ../src\controller\mainController.py:1009 +#: ../src\controller\mainController.py:1017 msgid "There are no results for the coordinates in this tweet" msgstr "Il n'y a aucun résultat pour les coordonnées dans ce tweet" -#: ../src\controller\mainController.py:1120 -#: ../src\controller\mainController.py:1139 +#: ../src\controller\mainController.py:1128 +#: ../src\controller\mainController.py:1147 msgid "%s, %s of %s" msgstr "%s, %s de %s" -#: ../src\controller\mainController.py:1122 -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1166 -#: ../src\controller\mainController.py:1191 +#: ../src\controller\mainController.py:1130 +#: ../src\controller\mainController.py:1149 +#: ../src\controller\mainController.py:1174 +#: ../src\controller\mainController.py:1199 msgid "%s. Empty" msgstr "%s. Vide" -#: ../src\controller\mainController.py:1154 -#: ../src\controller\mainController.py:1158 -#: ../src\controller\mainController.py:1179 +#: ../src\controller\mainController.py:1162 +#: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1187 msgid "{0}: This account is not logged into Twitter." msgstr "{0}: Ce compte n'est pas connecté à twitter." -#: ../src\controller\mainController.py:1164 -#: ../src\controller\mainController.py:1189 +#: ../src\controller\mainController.py:1172 +#: ../src\controller\mainController.py:1197 msgid "%s. %s, %s of %s" msgstr "%s. %s, %s de %s" -#: ../src\controller\mainController.py:1183 +#: ../src\controller\mainController.py:1191 msgid "{0}: This account is not logged into twitter." msgstr "{0}: Ce compte n'est pas connecté à twitter." -#: ../src\controller\mainController.py:1408 +#: ../src\controller\mainController.py:1416 msgid "This list is already opened" msgstr "Cette liste est déjà ouverte" -#: ../src\controller\mainController.py:1438 -#: ../src\controller\mainController.py:1454 +#: ../src\controller\mainController.py:1446 +#: ../src\controller\mainController.py:1462 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" "Une erreur s'est produite en essayant de se connecter au serveur. Veuillez " "réessayer plus tard." -#: ../src\controller\mainController.py:1490 +#: ../src\controller\mainController.py:1498 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "La lecture automatique des nouveaux tweets est activée pour ce tampon" -#: ../src\controller\mainController.py:1493 +#: ../src\controller\mainController.py:1501 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "" "La lecture automatique des nouveaux tweets est désactivée pour ce tampon" -#: ../src\controller\mainController.py:1500 +#: ../src\controller\mainController.py:1508 msgid "Session mute on" msgstr "Session muet" -#: ../src\controller\mainController.py:1503 +#: ../src\controller\mainController.py:1511 msgid "Session mute off" msgstr "Session non muet" -#: ../src\controller\mainController.py:1511 +#: ../src\controller\mainController.py:1519 msgid "Buffer mute on" msgstr "Tampon muet" -#: ../src\controller\mainController.py:1514 +#: ../src\controller\mainController.py:1522 msgid "Buffer mute off" msgstr "Tampon non muet" -#: ../src\controller\mainController.py:1537 +#: ../src\controller\mainController.py:1545 msgid "Copied" msgstr "Copié" -#: ../src\controller\mainController.py:1567 +#: ../src\controller\mainController.py:1575 msgid "Unable to update this buffer." msgstr "Impossible de mettre à jour ce tampon." -#: ../src\controller\mainController.py:1570 +#: ../src\controller\mainController.py:1578 msgid "Updating buffer..." msgstr "Actualisation..." -#: ../src\controller\mainController.py:1573 +#: ../src\controller\mainController.py:1581 msgid "{0} items retrieved" msgstr "{0} éléments récupérés" -#: ../src\controller\mainController.py:1590 -#: ../src\controller\mainController.py:1610 +#: ../src\controller\mainController.py:1598 +#: ../src\controller\mainController.py:1618 msgid "Invalid buffer" msgstr "Tampon invalide" -#: ../src\controller\mainController.py:1601 +#: ../src\controller\mainController.py:1609 msgid "Picture {0}" msgstr "Photo {0}" -#: ../src\controller\mainController.py:1602 +#: ../src\controller\mainController.py:1610 msgid "Select the picture" msgstr "Sélectionner la photo" -#: ../src\controller\mainController.py:1621 +#: ../src\controller\mainController.py:1629 msgid "Unable to extract text" msgstr "Impossible d'extraire le texte" @@ -620,6 +620,10 @@ msgstr "Favoris: %s" msgid "You can't ignore direct messages" msgstr "Vous ne pouvez pas ignorer les messages privés" +#: ../src\controller\userAliasController.py:32 +msgid "Edit alias for {}" +msgstr "Éditer l'alias pour {}" + #: ../src\extra\AudioUploader\audioUploader.py:57 msgid "Attaching..." msgstr "Ajout en cours..." @@ -1777,7 +1781,7 @@ msgid "Action" msgstr "Action" #: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 -#: ../src\wxUI\dialogs\lists.py:20 +#: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 msgid "Edit" msgstr "Modifier" @@ -1790,7 +1794,7 @@ msgid "Execute action" msgstr "Exécuter une action" #: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\userAliasDialogs.py:24 ../src\wxUI\dialogs\utils.py:39 +#: ../src\wxUI\dialogs\userAliasDialogs.py:25 ../src\wxUI\dialogs\utils.py:39 msgid "Close" msgstr "Fermer" @@ -1827,7 +1831,7 @@ msgid "Key" msgstr "Touche" #: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 -#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:22 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 #: ../src\wxUI\dialogs\utils.py:36 msgid "OK" msgstr "OK" @@ -2104,7 +2108,7 @@ msgstr "Date" #: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 #: ../src\wxUI\buffers\user_searches.py:11 -#: ../src\wxUI\dialogs\userAliasDialogs.py:13 +#: ../src\wxUI\dialogs\userAliasDialogs.py:14 #: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 msgid "User" msgstr "Utilisateur" @@ -2754,7 +2758,7 @@ msgstr "Langue sélectionnée" #: ../src\wxUI\dialogs\filterDialogs.py:75 #: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 -#: ../src\wxUI\dialogs\lists.py:132 +#: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "Effacer" @@ -2963,7 +2967,7 @@ msgstr "&Rechercher" msgid "Tweets" msgstr "Tweets" -#: ../src\wxUI\dialogs\search.py:22 +#: ../src\wxUI\dialogs\search.py:22 ../src\wxUI\dialogs\userAliasDialogs.py:43 msgid "Users" msgstr "Utilisateurs" @@ -3068,12 +3072,12 @@ msgstr "Ignorer la photo" msgid "Select URL" msgstr "Sélectionnez l'URL" -#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:86 +#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:87 msgid "&User" msgstr "&Utilisateur" #: ../src\wxUI\dialogs\userActions.py:14 -#: ../src\wxUI\dialogs\userAliasDialogs.py:12 +#: ../src\wxUI\dialogs\userAliasDialogs.py:13 #: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 msgid "&Autocomplete users" msgstr "&Saisie automatique utilisateurs" @@ -3086,7 +3090,7 @@ msgstr "&Suivre" msgid "U&nfollow" msgstr "Ne pas su&ivre" -#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:62 +#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:63 msgid "&Mute" msgstr "&Masquer" @@ -3110,10 +3114,46 @@ msgstr "&Signaler comme spam" msgid "&Ignore tweets from this client" msgstr "&Ignorer les tweets de ce client" -#: ../src\wxUI\dialogs\userAliasDialogs.py:17 +#: ../src\wxUI\dialogs\userAliasDialogs.py:18 msgid "Alias" msgstr "Alias" +#: ../src\wxUI\dialogs\userAliasDialogs.py:41 +msgid "Edit user aliases" +msgstr "Éditer les alias utilisateur" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:48 +msgid "Actions" +msgstr "Actions" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:50 +msgid "Add alias" +msgstr "Ajouter un alias" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:51 +msgid "Adds a new user alias" +msgstr "Ajoute un nouvel alias utilisateur" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:54 +msgid "Edit the currently focused user Alias." +msgstr "Éditer l'alias utilisateur ayant actuellement le focus." + +#: ../src\wxUI\dialogs\userAliasDialogs.py:58 +msgid "Remove the currently focused user alias." +msgstr "Supprimer l'alias utilisateur ayant actuellement le focus." + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Are you sure you want to delete this user alias?" +msgstr "Êtes-vous sûr de vouloir supprimer cet alias utilisateur ?" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Remove user alias" +msgstr "Supprimer l'alias utilisateur" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:93 +msgid "User alias" +msgstr "Alias utilisateur" + #: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "Chronologie pour %s" @@ -3138,19 +3178,19 @@ msgstr "&Abonnés" msgid "F&riends" msgstr "A&bonnements" -#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:32 +#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:33 msgid "&Retweet" msgstr "&Retweet" -#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:31 +#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:32 msgid "Re&ply" msgstr "Ré&pondre" -#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:33 +#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:34 msgid "&Like" msgstr "A&jouter aux favoris" -#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:34 +#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:35 msgid "&Unlike" msgstr "S&upprimer des favoris" @@ -3166,7 +3206,7 @@ msgstr "Ou&vrir dans Twitter" msgid "&Play audio" msgstr "&Lire audio" -#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:35 +#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:36 msgid "&Show tweet" msgstr "A&fficher tweet" @@ -3176,7 +3216,7 @@ msgid "&Copy to clipboard" msgstr "&Copier dans le Presse-papiers" #: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 -#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:39 +#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:40 msgid "&Delete" msgstr "&Supprimer Tweet" @@ -3196,11 +3236,11 @@ msgstr "&Afficher l'événement" msgid "Direct &message" msgstr "&Message privé" -#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:49 +#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:50 msgid "&View lists" msgstr "&Voir listes" -#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:50 +#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:51 msgid "Show user &profile" msgstr "Voir le &profil de l'utilisateur" @@ -3216,11 +3256,11 @@ msgstr "&Tweet sur cette tendance" msgid "&Show item" msgstr "&Afficher l'élément" -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:25 +#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:26 msgid "&Global settings" msgstr "Paramètres &globaux" -#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:24 +#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:25 msgid "Account se&ttings" msgstr "Paramètres du c&ompte" @@ -3232,7 +3272,7 @@ msgstr "&Actualiser le profil" msgid "&Show / hide" msgstr "&Afficher / masquer" -#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:74 +#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:75 msgid "&Documentation" msgstr "&Documentation" @@ -3257,154 +3297,158 @@ msgid "&Lists manager" msgstr "Gérer les &listes" #: ../src\wxUI\view.py:23 +msgid "Manage user aliases" +msgstr "Gérer les alias utilisateur" + +#: ../src\wxUI\view.py:24 msgid "&Edit keystrokes" msgstr "&Éditer les raccourcis clavier" -#: ../src\wxUI\view.py:26 +#: ../src\wxUI\view.py:27 msgid "E&xit" msgstr "&Quitter" -#: ../src\wxUI\view.py:30 ../src\wxUI\view.py:85 +#: ../src\wxUI\view.py:31 ../src\wxUI\view.py:86 msgid "&Tweet" msgstr "&Tweet" -#: ../src\wxUI\view.py:36 +#: ../src\wxUI\view.py:37 msgid "View &address" msgstr "Voir &adresse" -#: ../src\wxUI\view.py:37 +#: ../src\wxUI\view.py:38 msgid "View conversa&tion" msgstr "Voir &conversation" -#: ../src\wxUI\view.py:38 +#: ../src\wxUI\view.py:39 msgid "Read text in picture" msgstr "Lire le texte dans l'&image" -#: ../src\wxUI\view.py:43 +#: ../src\wxUI\view.py:44 msgid "&Actions..." msgstr "&Actions..." -#: ../src\wxUI\view.py:44 +#: ../src\wxUI\view.py:45 msgid "&View timeline..." msgstr "Voir &chronologie..." -#: ../src\wxUI\view.py:45 +#: ../src\wxUI\view.py:46 msgid "Direct me&ssage" msgstr "&Message privé" -#: ../src\wxUI\view.py:46 +#: ../src\wxUI\view.py:47 msgid "Add a&lias" msgstr "Ajouter un a&lias" -#: ../src\wxUI\view.py:47 +#: ../src\wxUI\view.py:48 msgid "&Add to list" msgstr "A&jouter à la liste" -#: ../src\wxUI\view.py:48 +#: ../src\wxUI\view.py:49 msgid "R&emove from list" msgstr "S&upprimer de la liste" -#: ../src\wxUI\view.py:51 +#: ../src\wxUI\view.py:52 msgid "V&iew likes" msgstr "Voir &favoris" -#: ../src\wxUI\view.py:55 +#: ../src\wxUI\view.py:56 msgid "&Update buffer" msgstr "&Mise à jour du tampon" -#: ../src\wxUI\view.py:56 +#: ../src\wxUI\view.py:57 msgid "New &trending topics buffer..." msgstr "Nouveau tampon de &tendances..." -#: ../src\wxUI\view.py:57 +#: ../src\wxUI\view.py:58 msgid "Create a &filter" msgstr "Créer un &filtre" -#: ../src\wxUI\view.py:58 +#: ../src\wxUI\view.py:59 msgid "&Manage filters" msgstr "&Gérer les filtres" -#: ../src\wxUI\view.py:59 +#: ../src\wxUI\view.py:60 msgid "Find a string in the currently focused buffer..." msgstr "Trouver une chaîne dans le tampon ayant actuellement le f&ocus..." -#: ../src\wxUI\view.py:60 +#: ../src\wxUI\view.py:61 msgid "&Load previous items" msgstr "&Charger des éléments plus anciens" -#: ../src\wxUI\view.py:63 +#: ../src\wxUI\view.py:64 msgid "&Autoread" msgstr "&Lecture automatique" -#: ../src\wxUI\view.py:64 +#: ../src\wxUI\view.py:65 msgid "&Clear buffer" msgstr "&Effacer le tampon" -#: ../src\wxUI\view.py:65 +#: ../src\wxUI\view.py:66 msgid "&Destroy" msgstr "&Détruire" -#: ../src\wxUI\view.py:69 +#: ../src\wxUI\view.py:70 msgid "&Seek back 5 seconds" msgstr "&Reculer de 5 secondes" -#: ../src\wxUI\view.py:70 +#: ../src\wxUI\view.py:71 msgid "&Seek forward 5 seconds" msgstr "&Avancer de 5 secondes" -#: ../src\wxUI\view.py:75 +#: ../src\wxUI\view.py:76 msgid "Sounds &tutorial" msgstr "&Apprentissage des sons" -#: ../src\wxUI\view.py:76 +#: ../src\wxUI\view.py:77 msgid "&What's new in this version?" msgstr "&Quoi de neuf dans cette version ?" -#: ../src\wxUI\view.py:77 +#: ../src\wxUI\view.py:78 msgid "&Check for updates" msgstr "&Vérifier les mises à jour" -#: ../src\wxUI\view.py:78 +#: ../src\wxUI\view.py:79 msgid "&Report an error" msgstr "&Signaler une erreur" -#: ../src\wxUI\view.py:79 +#: ../src\wxUI\view.py:80 msgid "{0}'s &website" msgstr "Site &Web de {0}" -#: ../src\wxUI\view.py:80 +#: ../src\wxUI\view.py:81 msgid "Get soundpacks for TWBlue" msgstr "Obtenir des packs de son pour TWBlue" -#: ../src\wxUI\view.py:81 +#: ../src\wxUI\view.py:82 msgid "About &{0}" msgstr "À propos de &{0}" -#: ../src\wxUI\view.py:84 +#: ../src\wxUI\view.py:85 msgid "&Application" msgstr "&Application" -#: ../src\wxUI\view.py:87 +#: ../src\wxUI\view.py:88 msgid "&Buffer" msgstr "Ta&mpon" -#: ../src\wxUI\view.py:88 +#: ../src\wxUI\view.py:89 msgid "&Audio" msgstr "Au&dio" -#: ../src\wxUI\view.py:89 +#: ../src\wxUI\view.py:90 msgid "&Help" msgstr "A&ide" -#: ../src\wxUI\view.py:175 +#: ../src\wxUI\view.py:176 msgid "Address" msgstr "Adresse" -#: ../src\wxUI\view.py:206 +#: ../src\wxUI\view.py:207 msgid "Update" msgstr "Mise à jour" -#: ../src\wxUI\view.py:206 +#: ../src\wxUI\view.py:207 msgid "Your {0} version is up to date" msgstr "Votre version de {0} est à jour" From c6a3a44c21acc53ccbe106bf79bf14481c8dff88 Mon Sep 17 00:00:00 2001 From: Nikola Jovic Date: Thu, 28 Oct 2021 16:58:11 +0200 Subject: [PATCH 171/245] Updated Serbian translation --- src/locales/sr/LC_MESSAGES/twblue.mo | Bin 53409 -> 53991 bytes src/locales/sr/LC_MESSAGES/twblue.po | 426 +++++++++++++++------------ 2 files changed, 239 insertions(+), 187 deletions(-) diff --git a/src/locales/sr/LC_MESSAGES/twblue.mo b/src/locales/sr/LC_MESSAGES/twblue.mo index 8e9b179927d5cfe6070ffa66fba43de842a9a9ab..c04251a0b56dad50ea1b8b62cbda91aea43ef6e0 100644 GIT binary patch delta 17537 zcma*u37Aji|Nrqbt1-ij-Pk|&5ysdfk}y)T?@J8x!5A~cj6HmWWDkQZAz6|l8p%?Y zNF;=)Y{^uLD1;RGJzt;m*4O`g{eRc>JJ)r4-1qyw&%K@doEiFlSF8xSv^vOlK40*B zhbuJ5af)NhXvfJJ>^NiM6m^_8o^qVWaRr9qY0Qb)=2Z-*d

iu(9Lh!boh3#V{YH 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 diff --git a/src/locales/sr/LC_MESSAGES/twblue.po b/src/locales/sr/LC_MESSAGES/twblue.po index e74d25d3..290ace6a 100644 --- a/src/locales/sr/LC_MESSAGES/twblue.po +++ b/src/locales/sr/LC_MESSAGES/twblue.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: TwBlue 0.80\n" -"POT-Creation-Date: 2021-08-28 08:34+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-10-21 13:32+0200\n" +"POT-Creation-Date: 2021-10-28 16:43+Central Europe Daylight Time\n" +"PO-Revision-Date: 2021-10-28 16:57+0100\n" "Last-Translator: Nikola Jović \n" "Language-Team: Aleksandar Đurić \n" "Language: sr_RS@latin\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 3.0\n" +"X-Generator: Poedit 1.6.10\n" "X-Poedit-Bookmarks: -1,442,-1,-1,-1,-1,-1,-1,-1,-1\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -27,60 +27,59 @@ msgid "This action is not supported for this buffer" msgstr "Ova radnja nije podržana na ovom kanalu" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:309 ../src\controller\settings.py:286 +#: ../src\controller\mainController.py:337 ../src\controller\settings.py:286 msgid "Home" msgstr "Početak" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:313 ../src\controller\settings.py:287 +#: ../src\controller\mainController.py:339 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Spominjanja" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:317 +#: ../src\controller\mainController.py:341 msgid "Direct messages" msgstr "Direktne poruke" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:321 ../src\controller\settings.py:289 +#: ../src\controller\mainController.py:343 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Poslate direktne poruke" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:325 ../src\controller\settings.py:290 +#: ../src\controller\mainController.py:345 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Poslati tvitovi" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:329 -#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:291 +#: ../src\controller\mainController.py:347 +#: ../src\controller\mainController.py:1390 ../src\controller\settings.py:291 msgid "Likes" msgstr "Sviđanja" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:333 -#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:292 +#: ../src\controller\mainController.py:349 +#: ../src\controller\mainController.py:1395 ../src\controller\settings.py:292 msgid "Followers" msgstr "Pratioci" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:337 -#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:293 -msgid "Friends" -msgstr "Prijatelji" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:341 -#: ../src\controller\mainController.py:1415 ../src\controller\settings.py:294 +#: ../src\controller\mainController.py:353 +#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Blokirani korisnici" #: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:345 -#: ../src\controller\mainController.py:1420 ../src\controller\settings.py:295 +#: ../src\controller\mainController.py:355 +#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Utišani korisnici" +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:293 +msgid "Friends" +msgstr "Prijatelji" + #: ../src\controller\buffers\twitter\base.py:76 msgid "{username}'s timeline" msgstr "Vremenska linija korisnika {username}" @@ -211,79 +210,84 @@ msgstr "{0} novih pratilaca." msgid "This action is not supported in the buffer, yet." msgstr "Ova radnja još uvek nije podržana na ovom kanalu" -#: ../src\controller\mainController.py:273 +#: ../src\controller\mainController.py:277 msgid "Ready" msgstr "Spreman" -#: ../src\controller\mainController.py:348 +#: ../src\controller\mainController.py:351 +msgid "Following" +msgstr "Praćenja" + +#: ../src\controller\mainController.py:356 msgid "Timelines" msgstr "Vremenske linije" -#: ../src\controller\mainController.py:352 -#: ../src\controller\mainController.py:892 -#: ../src\controller\mainController.py:1596 +#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:883 +#: ../src\controller\mainController.py:1585 msgid "Timeline for {}" msgstr "Vremenska linija od {}" -#: ../src\controller\mainController.py:355 +#: ../src\controller\mainController.py:360 msgid "Likes timelines" msgstr "Vremenska linija omiljenih tvitova" -#: ../src\controller\mainController.py:359 -#: ../src\controller\mainController.py:911 -#: ../src\controller\mainController.py:1598 +#: ../src\controller\mainController.py:363 +#: ../src\controller\mainController.py:902 +#: ../src\controller\mainController.py:1587 msgid "Likes for {}" msgstr "Sviđanja od {}" -#: ../src\controller\mainController.py:362 -msgid "Followers' Timelines" -msgstr "Vremenska linija pratilaca" +#: ../src\controller\mainController.py:364 +msgid "Followers timelines" +msgstr "Vremenske linije pratilaca" -#: ../src\controller\mainController.py:366 -#: ../src\controller\mainController.py:930 -#: ../src\controller\mainController.py:1600 +#: ../src\controller\mainController.py:367 +#: ../src\controller\mainController.py:921 +#: ../src\controller\mainController.py:1589 msgid "Followers for {}" msgstr "Pratioci od {}" -#: ../src\controller\mainController.py:369 -msgid "Friends' Timelines" -msgstr "Vremenska linija prijatelja" +#: ../src\controller\mainController.py:368 +msgid "Following timelines" +msgstr "Vremenske linije praćenih korisnika" -#: ../src\controller\mainController.py:373 -#: ../src\controller\mainController.py:949 -#: ../src\controller\mainController.py:1602 +#: ../src\controller\mainController.py:371 +#: ../src\controller\mainController.py:940 +#: ../src\controller\mainController.py:1591 msgid "Friends for {}" msgstr "Prijatelji od {}" -#: ../src\controller\mainController.py:376 ../src\wxUI\dialogs\lists.py:13 +#: ../src\controller\mainController.py:372 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Liste" -#: ../src\controller\mainController.py:381 -#: ../src\controller\mainController.py:1432 +#: ../src\controller\mainController.py:375 +#: ../src\controller\mainController.py:1422 msgid "List for {}" msgstr "Liste od {}" -#: ../src\controller\mainController.py:384 +#: ../src\controller\mainController.py:376 msgid "Searches" msgstr "Pretrage" -#: ../src\controller\mainController.py:388 -#: ../src\controller\mainController.py:447 +#: ../src\controller\mainController.py:379 +#: ../src\controller\mainController.py:426 +#: ../src\controller\mainController.py:431 msgid "Search for {}" msgstr "Pretraga za {}" -#: ../src\controller\mainController.py:394 -#: ../src\controller\mainController.py:991 +#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:982 msgid "Trending topics for %s" msgstr "Teme u trendu za %s" +#: ../src\controller\mainController.py:448 #: ../src\controller\mainController.py:464 -#: ../src\controller\mainController.py:480 -#: ../src\controller\mainController.py:1089 -#: ../src\controller\mainController.py:1108 -#: ../src\controller\mainController.py:1127 -#: ../src\controller\mainController.py:1146 +#: ../src\controller\mainController.py:1080 +#: ../src\controller\mainController.py:1099 +#: ../src\controller\mainController.py:1118 +#: ../src\controller\mainController.py:1137 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." @@ -291,151 +295,151 @@ msgstr "" "Trenutno nijedna sesija nije u fokusu. Fokusirajte neku pritiskom na prečicu " "za prethodnu ili sledeću." -#: ../src\controller\mainController.py:468 +#: ../src\controller\mainController.py:452 msgid "Empty buffer." msgstr "Prazan kanal." -#: ../src\controller\mainController.py:475 +#: ../src\controller\mainController.py:459 msgid "{0} not found." msgstr "{0} nije pronađen." -#: ../src\controller\mainController.py:485 +#: ../src\controller\mainController.py:469 msgid "Filters cannot be applied on this buffer" msgstr "Filteri se ne mogu primeniti na ovaj kanal" -#: ../src\controller\mainController.py:538 -#: ../src\controller\mainController.py:555 -#: ../src\controller\mainController.py:583 +#: ../src\controller\mainController.py:522 +#: ../src\controller\mainController.py:539 +#: ../src\controller\mainController.py:568 msgid "Select the user" msgstr "Izaberite korisnika" -#: ../src\controller\mainController.py:767 +#: ../src\controller\mainController.py:753 msgid "Add an user alias" msgstr "Dodaj nadimak za korisnika" -#: ../src\controller\mainController.py:775 +#: ../src\controller\mainController.py:761 msgid "Alias has been set correctly for {}." msgstr "Nadimak za {} je uspešno podešen." -#: ../src\controller\mainController.py:838 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "MMM D, YYYY. H:m" -#: ../src\controller\mainController.py:966 +#: ../src\controller\mainController.py:957 msgid "Conversation with {0}" msgstr "Razgovor sa {0}" -#: ../src\controller\mainController.py:1007 -#: ../src\controller\mainController.py:1024 +#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1015 msgid "There are no coordinates in this tweet" msgstr "Nema koordinata u ovom tvitu." -#: ../src\controller\mainController.py:1009 -#: ../src\controller\mainController.py:1028 +#: ../src\controller\mainController.py:1000 +#: ../src\controller\mainController.py:1019 msgid "Error decoding coordinates. Try again later." msgstr "Greška prilikom čitanja koordinata. Molimo vas da pokušate kasnije." -#: ../src\controller\mainController.py:1013 +#: ../src\controller\mainController.py:1004 msgid "Unable to find address in OpenStreetMap." msgstr "Nemoguće pronaći adresu u OpenStreet mapi." -#: ../src\controller\mainController.py:1026 +#: ../src\controller\mainController.py:1017 msgid "There are no results for the coordinates in this tweet" msgstr "Nema rezultata za te koordinate u ovom tvitu." -#: ../src\controller\mainController.py:1137 -#: ../src\controller\mainController.py:1156 +#: ../src\controller\mainController.py:1128 +#: ../src\controller\mainController.py:1147 msgid "%s, %s of %s" msgstr "%s, %s od %s" -#: ../src\controller\mainController.py:1139 -#: ../src\controller\mainController.py:1158 -#: ../src\controller\mainController.py:1183 -#: ../src\controller\mainController.py:1208 +#: ../src\controller\mainController.py:1130 +#: ../src\controller\mainController.py:1149 +#: ../src\controller\mainController.py:1174 +#: ../src\controller\mainController.py:1199 msgid "%s. Empty" msgstr "%s. Prazno." -#: ../src\controller\mainController.py:1171 -#: ../src\controller\mainController.py:1175 -#: ../src\controller\mainController.py:1196 +#: ../src\controller\mainController.py:1162 +#: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1187 msgid "{0}: This account is not logged into Twitter." msgstr "{0}: Ovaj nalog nije prijavljen na twitter." -#: ../src\controller\mainController.py:1181 -#: ../src\controller\mainController.py:1206 +#: ../src\controller\mainController.py:1172 +#: ../src\controller\mainController.py:1197 msgid "%s. %s, %s of %s" msgstr "%s. %s, %s od %s" -#: ../src\controller\mainController.py:1200 +#: ../src\controller\mainController.py:1191 msgid "{0}: This account is not logged into twitter." msgstr "{0}: Ovaj nalog nije prijavljen na twitter." -#: ../src\controller\mainController.py:1426 +#: ../src\controller\mainController.py:1416 msgid "This list is already opened" msgstr "Ova lista je već otvorena" -#: ../src\controller\mainController.py:1456 -#: ../src\controller\mainController.py:1472 +#: ../src\controller\mainController.py:1446 +#: ../src\controller\mainController.py:1462 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" "Došlo je do greške pri pokušaju povezivanja na server. Molimo pokušajte " "kasnije." -#: ../src\controller\mainController.py:1508 +#: ../src\controller\mainController.py:1498 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "Automatsko čitanje novih tvitova je uključeno na ovom kanalu" -#: ../src\controller\mainController.py:1511 +#: ../src\controller\mainController.py:1501 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "Automatsko čitanje tvitova je isključeno za tvitove na ovom kanalu" -#: ../src\controller\mainController.py:1518 +#: ../src\controller\mainController.py:1508 msgid "Session mute on" msgstr "Utišavanje sesije uključeno" -#: ../src\controller\mainController.py:1521 +#: ../src\controller\mainController.py:1511 msgid "Session mute off" msgstr "Utišavanje sesije isključeno" -#: ../src\controller\mainController.py:1529 +#: ../src\controller\mainController.py:1519 msgid "Buffer mute on" msgstr "Utišavanje kanala uključeno" -#: ../src\controller\mainController.py:1532 +#: ../src\controller\mainController.py:1522 msgid "Buffer mute off" msgstr "Utišavanje kanala isključeno" -#: ../src\controller\mainController.py:1555 +#: ../src\controller\mainController.py:1545 msgid "Copied" msgstr "Kopirano" -#: ../src\controller\mainController.py:1586 +#: ../src\controller\mainController.py:1575 msgid "Unable to update this buffer." msgstr "Ne mogu da ažuriram ovaj kanal." -#: ../src\controller\mainController.py:1589 +#: ../src\controller\mainController.py:1578 msgid "Updating buffer..." msgstr "Ažuriram kanal..." -#: ../src\controller\mainController.py:1592 +#: ../src\controller\mainController.py:1581 msgid "{0} items retrieved" msgstr "{0} primljenih stavki" -#: ../src\controller\mainController.py:1609 -#: ../src\controller\mainController.py:1629 +#: ../src\controller\mainController.py:1598 +#: ../src\controller\mainController.py:1618 msgid "Invalid buffer" msgstr "Nevažeći kanal" -#: ../src\controller\mainController.py:1620 +#: ../src\controller\mainController.py:1609 msgid "Picture {0}" msgstr "Slika {0}" -#: ../src\controller\mainController.py:1621 +#: ../src\controller\mainController.py:1610 msgid "Select the picture" msgstr "Izaberite sliku" -#: ../src\controller\mainController.py:1640 +#: ../src\controller\mainController.py:1629 msgid "Unable to extract text" msgstr "Ne mogu da izdvojim tekst." @@ -549,7 +553,8 @@ msgstr "Korisnik je suspendovan." msgid "Information for %s" msgstr "Informacija za %s" -#: ../src\controller\user.py:67 ../src\extra\AudioUploader\audioUploader.py:127 +#: ../src\controller\user.py:67 +#: ../src\extra\AudioUploader\audioUploader.py:127 msgid "Discarded" msgstr "Odbačeno" @@ -617,6 +622,10 @@ msgstr "Omiljeno: %s" msgid "You can't ignore direct messages" msgstr "Ne možete zanemariti direktne poruke." +#: ../src\controller\userAliasController.py:32 +msgid "Edit alias for {}" +msgstr "Uredi nadimak za {}" + #: ../src\extra\AudioUploader\audioUploader.py:57 msgid "Attaching..." msgstr "Prilažem..." @@ -658,7 +667,7 @@ msgstr "Zaustavljeno" msgid "&Record" msgstr "&Snimi" -#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:146 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 msgid "Playing..." msgstr "Reprodukujem..." @@ -1765,7 +1774,7 @@ msgid "Action" msgstr "Radnja" #: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 -#: ../src\wxUI\dialogs\lists.py:20 +#: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 msgid "Edit" msgstr "Izmeni" @@ -1778,7 +1787,7 @@ msgid "Execute action" msgstr "Izvrši radnju" #: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:39 ../src\wxUI\dialogs\utils.py:71 +#: ../src\wxUI\dialogs\userAliasDialogs.py:25 ../src\wxUI\dialogs\utils.py:39 msgid "Close" msgstr "Zatvori" @@ -1815,8 +1824,8 @@ msgid "Key" msgstr "Taster" #: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 -#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\utils.py:36 -#: ../src\wxUI\dialogs\utils.py:68 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 +#: ../src\wxUI\dialogs\utils.py:36 msgid "OK" msgstr "U redu" @@ -1931,7 +1940,7 @@ msgstr "" "ili nakon ponovne aktivacije naloga. Molimo ručno uklonite nalog iz vaših " "Twitter sesija kako biste prestali da dobijate ovu poruku." -#: ../src\sessions\base.py:111 +#: ../src\sessions\base.py:113 msgid "" "An exception occurred while saving the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1941,7 +1950,7 @@ msgstr "" "automatski ponovno napravljena. Ako se ova greška nastavi, pošaljite " "dnevnike sa greškama {app} programerima." -#: ../src\sessions\base.py:151 +#: ../src\sessions\base.py:153 msgid "" "An exception occurred while loading the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1990,16 +1999,16 @@ msgstr "Privatno" msgid "public" msgstr "Javno" -#: ../src\sessions\twitter\session.py:208 +#: ../src\sessions\twitter\session.py:209 msgid "%s failed. Reason: %s" msgstr "%s nije uspelo. Razlog: %s" -#: ../src\sessions\twitter\session.py:214 +#: ../src\sessions\twitter\session.py:215 msgid "%s succeeded." msgstr "%s uspelo." -#: ../src\sessions\twitter\session.py:423 -#: ../src\sessions\twitter\session.py:501 +#: ../src\sessions\twitter\session.py:424 +#: ../src\sessions\twitter\session.py:502 msgid "Deleted account" msgstr "Obrisan nalog" @@ -2012,8 +2021,8 @@ msgid "No status found with that ID" msgstr "Status nije pronađen pod tim brojem." #: ../src\sessions\twitter\utils.py:235 -msgid "Error code {0}" -msgstr "Kod greške {0}" +msgid "Error {0}" +msgstr "Greška {0}" #: ../src\sessions\twitter\utils.py:262 msgid "{user_1}, {user_2} and {all_users} more: {text}" @@ -2027,7 +2036,7 @@ msgstr "Autorizacija naloga..." msgid "Enter your PIN code here" msgstr "Ovde upišite vaš PIN kod" -#: ../src\sound.py:159 +#: ../src\sound.py:161 msgid "Stopped." msgstr "Zaustavljeno" @@ -2089,8 +2098,8 @@ msgstr "Datum" #: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 #: ../src\wxUI\buffers\user_searches.py:11 +#: ../src\wxUI\dialogs\userAliasDialogs.py:14 #: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 -#: ../src\wxUI\dialogs\utils.py:59 msgid "User" msgstr "Korisnik" @@ -2128,7 +2137,7 @@ msgstr "Tvituj o ovom trendu" #: ../src\wxUI\buffers\trends.py:20 ../src\wxUI\menus.py:97 msgid "Search topic" -msgstr "tema Pretrage" +msgstr "Pretraži temu" #: ../src\wxUI\commonMessageDialogs.py:7 msgid "" @@ -2310,7 +2319,7 @@ msgstr "" "TWBlue je otkrio da koristite windows 10 i promenio je podrazumevane " "tasterske prečice na Windows 10 način rada. To znači da neke tasterske " "prečice mogu biti drugačije. Molimo vas da proverite uređivač tasterskih " -"prečica pritiskanjem Alt+Win+K i pogledate sve dostupne prečice za ovja " +"prečica pritiskanjem Alt+Win+K i pogledate sve dostupne prečice za ovaj " "način rada." #: ../src\wxUI\commonMessageDialogs.py:77 @@ -2732,7 +2741,7 @@ msgstr "Izabrani jezici" #: ../src\wxUI\dialogs\filterDialogs.py:75 #: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 -#: ../src\wxUI\dialogs\lists.py:132 +#: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "Ukloni" @@ -2941,7 +2950,7 @@ msgstr "Pretraži" msgid "Tweets" msgstr "Tvitovi" -#: ../src\wxUI\dialogs\search.py:22 +#: ../src\wxUI\dialogs\search.py:22 ../src\wxUI\dialogs\userAliasDialogs.py:43 msgid "Users" msgstr "Korisnici" @@ -3046,13 +3055,13 @@ msgstr "Odbaci sliku" msgid "Select URL" msgstr "Izaberite vezu" -#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:86 +#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:87 msgid "&User" msgstr "Korisnik" #: ../src\wxUI\dialogs\userActions.py:14 +#: ../src\wxUI\dialogs\userAliasDialogs.py:13 #: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 -#: ../src\wxUI\dialogs\utils.py:58 msgid "&Autocomplete users" msgstr "&Automatsko dovršavanje" @@ -3064,7 +3073,7 @@ msgstr "Prati" msgid "U&nfollow" msgstr "Otprati" -#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:62 +#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:63 msgid "&Mute" msgstr "Utišaj" @@ -3088,6 +3097,46 @@ msgstr "Prijavi kao neželjeno" msgid "&Ignore tweets from this client" msgstr "Zanemari tvitove iz ovog klijenta" +#: ../src\wxUI\dialogs\userAliasDialogs.py:18 +msgid "Alias" +msgstr "Nadimak" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:41 +msgid "Edit user aliases" +msgstr "Uredi korisničke nadimke" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:48 +msgid "Actions" +msgstr "Radnje" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:50 +msgid "Add alias" +msgstr "Dodaj nadimak" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:51 +msgid "Adds a new user alias" +msgstr "Dodaje novi nadimak za korisnika" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:54 +msgid "Edit the currently focused user Alias." +msgstr "Uredi trenutno fokusirani korisnički nadimak." + +#: ../src\wxUI\dialogs\userAliasDialogs.py:58 +msgid "Remove the currently focused user alias." +msgstr "Ukloni trenutno fokusirani korisnički nadimak." + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Are you sure you want to delete this user alias?" +msgstr "Da li zaista želite da izbrišete ovaj korisnički nadimak?" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Remove user alias" +msgstr "Ukloni korisnički nadimak" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:93 +msgid "User alias" +msgstr "Korisnički nadimak" + #: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "Vremenska crta od %s" @@ -3112,23 +3161,19 @@ msgstr "Pratioci" msgid "F&riends" msgstr "Prijatelji" -#: ../src\wxUI\dialogs\utils.py:63 -msgid "Alias" -msgstr "Nadimak" - -#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:32 +#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:33 msgid "&Retweet" msgstr "Retvituj" -#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:31 +#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:32 msgid "Re&ply" msgstr "Odgovori" -#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:33 +#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:34 msgid "&Like" msgstr "Sviđa mi se" -#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:34 +#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:35 msgid "&Unlike" msgstr "Ne sviđa mi se" @@ -3144,7 +3189,7 @@ msgstr "&Otvori na Twitteru" msgid "&Play audio" msgstr "reprodukuj zvučni zapis" -#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:35 +#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:36 msgid "&Show tweet" msgstr "Prikaži tvit" @@ -3154,7 +3199,7 @@ msgid "&Copy to clipboard" msgstr "Kopiraj u ostavu" #: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 -#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:39 +#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:40 msgid "&Delete" msgstr "Izbriši" @@ -3174,11 +3219,11 @@ msgstr "Prikaži događaj" msgid "Direct &message" msgstr "Direktna poruka" -#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:49 +#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:50 msgid "&View lists" msgstr "Vidi liste" -#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:50 +#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:51 msgid "Show user &profile" msgstr "Prikaži profil korisnika" @@ -3194,11 +3239,11 @@ msgstr "Tvituj o ovom trendu" msgid "&Show item" msgstr "Prikaži stavku" -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:25 +#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:26 msgid "&Global settings" msgstr "Globalna podešavanja" -#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:24 +#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:25 msgid "Account se&ttings" msgstr "Postavke naloga" @@ -3210,7 +3255,7 @@ msgstr "Ažuriraj profil" msgid "&Show / hide" msgstr "Prikaži ili sakrij" -#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:74 +#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:75 msgid "&Documentation" msgstr "Dokumentacija" @@ -3235,171 +3280,178 @@ msgid "&Lists manager" msgstr "Upravljanje listama" #: ../src\wxUI\view.py:23 +msgid "Manage user aliases" +msgstr "Upravljanje korisničkim nadimcima" + +#: ../src\wxUI\view.py:24 msgid "&Edit keystrokes" msgstr "Izmeni tasterske prečice" -#: ../src\wxUI\view.py:26 +#: ../src\wxUI\view.py:27 msgid "E&xit" msgstr "Izlaz" -#: ../src\wxUI\view.py:30 ../src\wxUI\view.py:85 +#: ../src\wxUI\view.py:31 ../src\wxUI\view.py:86 msgid "&Tweet" msgstr "Tvit" -#: ../src\wxUI\view.py:36 +#: ../src\wxUI\view.py:37 msgid "View &address" msgstr "Vidi adresu" -#: ../src\wxUI\view.py:37 +#: ../src\wxUI\view.py:38 msgid "View conversa&tion" msgstr "Vidi razgovor" -#: ../src\wxUI\view.py:38 +#: ../src\wxUI\view.py:39 msgid "Read text in picture" msgstr "Čitaj tekst u slici" -#: ../src\wxUI\view.py:43 +#: ../src\wxUI\view.py:44 msgid "&Actions..." msgstr "Radnje..." -#: ../src\wxUI\view.py:44 +#: ../src\wxUI\view.py:45 msgid "&View timeline..." msgstr "Vidi vremensku liniju..." -#: ../src\wxUI\view.py:45 +#: ../src\wxUI\view.py:46 msgid "Direct me&ssage" msgstr "Direktna poruka" -#: ../src\wxUI\view.py:46 +#: ../src\wxUI\view.py:47 msgid "Add a&lias" msgstr "Dodaj &nadimak" -#: ../src\wxUI\view.py:47 +#: ../src\wxUI\view.py:48 msgid "&Add to list" msgstr "Dodaj na listu" -#: ../src\wxUI\view.py:48 +#: ../src\wxUI\view.py:49 msgid "R&emove from list" msgstr "Ukloni sa liste" -#: ../src\wxUI\view.py:51 +#: ../src\wxUI\view.py:52 msgid "V&iew likes" msgstr "Vidi sviđanja" -#: ../src\wxUI\view.py:55 +#: ../src\wxUI\view.py:56 msgid "&Update buffer" msgstr "Ažuriraj kanal" -#: ../src\wxUI\view.py:56 +#: ../src\wxUI\view.py:57 msgid "New &trending topics buffer..." msgstr "Novi kanal sa temama u trendu" -#: ../src\wxUI\view.py:57 +#: ../src\wxUI\view.py:58 msgid "Create a &filter" msgstr "Napravi &filter" -#: ../src\wxUI\view.py:58 +#: ../src\wxUI\view.py:59 msgid "&Manage filters" msgstr "&Upravljanje filterima" -#: ../src\wxUI\view.py:59 +#: ../src\wxUI\view.py:60 msgid "Find a string in the currently focused buffer..." msgstr "Pronađi pojam u trenutno označenom kanalu..." -#: ../src\wxUI\view.py:60 +#: ../src\wxUI\view.py:61 msgid "&Load previous items" msgstr "Učitaj prethodne stavke" -#: ../src\wxUI\view.py:63 +#: ../src\wxUI\view.py:64 msgid "&Autoread" msgstr "Automatski čitaj" -#: ../src\wxUI\view.py:64 +#: ../src\wxUI\view.py:65 msgid "&Clear buffer" msgstr "Očisti kanal" -#: ../src\wxUI\view.py:65 +#: ../src\wxUI\view.py:66 msgid "&Destroy" msgstr "Izbriši" -#: ../src\wxUI\view.py:69 +#: ../src\wxUI\view.py:70 msgid "&Seek back 5 seconds" msgstr "Premotaj unazad za 5 sekundi" -#: ../src\wxUI\view.py:70 +#: ../src\wxUI\view.py:71 msgid "&Seek forward 5 seconds" msgstr "Premotaj unapred za 5 sekundi" -#: ../src\wxUI\view.py:75 +#: ../src\wxUI\view.py:76 msgid "Sounds &tutorial" msgstr "Zvučna uputstva" -#: ../src\wxUI\view.py:76 +#: ../src\wxUI\view.py:77 msgid "&What's new in this version?" msgstr "Šta je novo u ovoj verziji" -#: ../src\wxUI\view.py:77 +#: ../src\wxUI\view.py:78 msgid "&Check for updates" msgstr "Proveri da li postoje nadogradnje" -#: ../src\wxUI\view.py:78 +#: ../src\wxUI\view.py:79 msgid "&Report an error" msgstr "Prijavi grešku" -#: ../src\wxUI\view.py:79 +#: ../src\wxUI\view.py:80 msgid "{0}'s &website" msgstr "{0} &website" -#: ../src\wxUI\view.py:80 +#: ../src\wxUI\view.py:81 msgid "Get soundpacks for TWBlue" msgstr "Nabavi zvučne pakete za TW Blue" -#: ../src\wxUI\view.py:81 +#: ../src\wxUI\view.py:82 msgid "About &{0}" msgstr "O &{0}" -#: ../src\wxUI\view.py:84 +#: ../src\wxUI\view.py:85 msgid "&Application" msgstr "Aplikacija" -#: ../src\wxUI\view.py:87 +#: ../src\wxUI\view.py:88 msgid "&Buffer" msgstr "Kanal" -#: ../src\wxUI\view.py:88 +#: ../src\wxUI\view.py:89 msgid "&Audio" msgstr "Audio" -#: ../src\wxUI\view.py:89 +#: ../src\wxUI\view.py:90 msgid "&Help" msgstr "Pomoć" -#: ../src\wxUI\view.py:175 +#: ../src\wxUI\view.py:176 msgid "Address" msgstr "Adresa" -#: ../src\wxUI\view.py:206 +#: ../src\wxUI\view.py:207 msgid "Update" msgstr "Ažuriraj" -#: ../src\wxUI\view.py:206 +#: ../src\wxUI\view.py:207 msgid "Your {0} version is up to date" msgstr "Imate najnoviju verziju {0}." -msgid "Waiting for account authorisation..." -msgstr "En attente d'autorisation du compte..." +#~ msgid "Friends' Timelines" +#~ msgstr "Vremenska linija prijatelja" -msgid "Contains" -msgstr "Contient" +#~ msgid "Waiting for account authorisation..." +#~ msgstr "En attente d'autorisation du compte..." -msgid "Doesn't contain" -msgstr "Ne contient pas" +#~ msgid "Contains" +#~ msgstr "Contient" -msgid "Create a filter" -msgstr "Créer un filtre" +#~ msgid "Doesn't contain" +#~ msgstr "Ne contient pas" -msgid "&Name (20 characters maximum)" -msgstr "&Nom (maximum 20 caractères)" +#~ msgid "Create a filter" +#~ msgstr "Créer un filtre" + +#~ msgid "&Name (20 characters maximum)" +#~ msgstr "&Nom (maximum 20 caractères)" #~ msgid "Events" #~ msgstr "Događaji" From 66581f8b1c976dc24b6e6026611d3e9abd1353eb Mon Sep 17 00:00:00 2001 From: Nikola Jovic Date: Thu, 28 Oct 2021 17:03:52 +0200 Subject: [PATCH 172/245] Clarify a string better --- src/locales/sr/LC_MESSAGES/twblue.mo | Bin 53991 -> 54001 bytes src/locales/sr/LC_MESSAGES/twblue.po | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/sr/LC_MESSAGES/twblue.mo b/src/locales/sr/LC_MESSAGES/twblue.mo index c04251a0b56dad50ea1b8b62cbda91aea43ef6e0..7701f9b14bede7ec7876a98982ea0b1f7f0d5221 100644 GIT binary patch delta 77 zcmaF9l=\n" "Language-Team: Aleksandar Đurić \n" "Language: sr_RS@latin\n" @@ -2026,7 +2026,7 @@ msgstr "Greška {0}" #: ../src\sessions\twitter\utils.py:262 msgid "{user_1}, {user_2} and {all_users} more: {text}" -msgstr "{user_1}, {user_2} i još {all_users}: {text}" +msgstr "{user_1}, {user_2} i još {all_users} korisnika: {text}" #: ../src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." From b512c69447ad14c60efa1e30ba57b2f8e0b69809 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 28 Oct 2021 18:28:34 +0200 Subject: [PATCH 173/245] Remove old translations --- src/locales/fr/LC_MESSAGES/twblue.po | 117 +-------------------------- 1 file changed, 1 insertion(+), 116 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index 62eb43ad..6b0454ac 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" "POT-Creation-Date: 2021-10-28 12:29+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-10-28 12:33+0200\n" +"PO-Revision-Date: 2021-10-28 18:28+0200\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -3451,118 +3451,3 @@ msgstr "Mise à jour" #: ../src\wxUI\view.py:207 msgid "Your {0} version is up to date" msgstr "Votre version de {0} est à jour" - -#~ msgid "Friends' Timelines" -#~ msgstr "Chronologies des abonnements" - -#~ msgid "Events" -#~ msgstr "Événements" - -#~ msgid "This tweet doesn't contain images" -#~ msgstr "Ce tweet ne contient pas d'images" - -#~ msgid "Direct connection" -#~ msgstr "Connexion directe" - -#~ msgid "There are no more items to retrieve in this buffer." -#~ msgstr "Il n'y a aucun nouvel élément a récupéré dans ce tampon" - -#~ msgid "Empty" -#~ msgstr "Vide" - -#~ msgid "One mention from %s " -#~ msgstr "Une mention de %s" - -#~ msgid "One tweet from %s" -#~ msgstr "Un tweet de %s" - -#~ msgid "You've blocked %s" -#~ msgstr "Vous avez bloqué à %s" - -#~ msgid "You've unblocked %s" -#~ msgstr "Vous avez débloqué à %s" - -#~ msgid "%s(@%s) has followed you" -#~ msgstr "%s(@%s) vous suit" - -#~ msgid "You've followed %s(@%s)" -#~ msgstr "Vous suivez %s(@%s)" - -#~ msgid "You've unfollowed %s (@%s)" -#~ msgstr "Vous ne suivez plus %s(@%s)" - -#~ msgid "You've liked: %s, %s" -#~ msgstr "Vous avez ajouté aux favoris: %s, %s" - -#~ msgid "%s(@%s) has liked: %s" -#~ msgstr "%s(@%s) a ajouté aux favoris: %s" - -#~ msgid "You've unliked: %s, %s" -#~ msgstr "Vous avez retiré des favoris: %s, %s" - -#~ msgid "%s(@%s) has unliked: %s" -#~ msgstr "%s(@%s) a retiré des favoris: %s" - -#~ msgid "You've created the list %s" -#~ msgstr "Vous avez créé la liste %s" - -#~ msgid "You've deleted the list %s" -#~ msgstr "Vous avez supprimé la liste %s" - -#~ msgid "You've updated the list %s" -#~ msgstr "Vous avez mis à jour la liste %s" - -#~ msgid "You've added %s(@%s) to the list %s" -#~ msgstr "Vous avez ajouté %s(@%s) à la liste %s" - -#~ msgid "%s(@%s) has added you to the list %s" -#~ msgstr "%s(@%s) vous a ajouté à la liste %s" - -#~ msgid "You'be removed %s(@%s) from the list %s" -#~ msgstr "Vous avez supprimé à %s(@%s) de la liste %s" - -#~ msgid "%s(@%s) has removed you from the list %s" -#~ msgstr "%s(@%s) vous a supprimé de la liste %s" - -#~ msgid "You've subscribed to the list %s, which is owned by %s(@%s)" -#~ msgstr "Vous êtes abonné à la liste %s, qui est la propriété de %s(@%s)" - -#~ msgid "%s(@%s) has subscribed you to the list %s" -#~ msgstr "%s(@%s) vous a abonné à la liste %s" - -#~ msgid "You've unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "Vous êtes désabonné de la liste %s, qui est la propriété de %s(@%s)" - -#~ msgid "You've been unsubscribed from the list %s, which is owned by %s(@%s)" -#~ msgstr "" -#~ "Vous avez été désabonné de la liste %s, qui est la propriété de %s(@%s)" - -#~ msgid "You have retweeted a retweet from %s(@%s): %s" -#~ msgstr "Vous avez retweeté un retweet de %s(@%s): %s" - -#~ msgid "%s(@%s) has retweeted your retweet: %s" -#~ msgstr "%s(@%s) a retweeté votre retweet: %s" - -#~ msgid "" -#~ "API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):" -#~ msgstr "" -#~ "Appels à l'API (un appel à l'API équivaut à 200 tweets, 2 appels à l'API " -#~ "équivaut à 400 tweets, etc.):" - -#~ msgid "Unable to upload the audio" -#~ msgstr "Impossible de charger l'audio" - -#~ msgid "Waiting for account authorisation..." -#~ msgstr "En attente d'autorisation du compte..." - -#~ msgid "Contains" -#~ msgstr "Contient" - -#~ msgid "Doesn't contain" -#~ msgstr "Ne contient pas" - -#~ msgid "Create a filter" -#~ msgstr "Créer un filtre" - -#~ msgid "&Name (20 characters maximum)" -#~ msgstr "&Nom (maximum 20 caractères)" From 483b1962038740e07cd3c8fcf5474021a59e39ef Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 28 Oct 2021 18:30:05 +0200 Subject: [PATCH 174/245] Fix small error --- src/locales/fr/LC_MESSAGES/twblue.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index 6b0454ac..cd6eb5be 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" "POT-Creation-Date: 2021-10-28 12:29+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-10-28 18:28+0200\n" +"PO-Revision-Date: 2021-10-28 18:29+0200\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -214,7 +214,7 @@ msgstr "Prêt" #: ../src\controller\mainController.py:351 msgid "Following" -msgstr "Suivi" +msgstr "Abonnements" #: ../src\controller\mainController.py:356 msgid "Timelines" From 0b03e7505ffb94f9487cdc921bdbe23a6d476c53 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 28 Oct 2021 12:28:19 -0500 Subject: [PATCH 175/245] Conversation support improved via V2 searches --- src/controller/buffers/twitter/search.py | 60 ++++++++++++++---------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index bbf324b6..caf0e428 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import time import platform +import locale if platform.system() == "Windows": from wxUI import commonMessageDialogs elif platform.system() == "Linux": @@ -8,6 +9,7 @@ elif platform.system() == "Linux": from gtkUI import commonMessageDialogs import widgetUtils import logging +from tweepy.errors import TweepyException from . import base, people log = logging.getLogger("controller.buffers.twitter.searchBuffer") @@ -64,35 +66,11 @@ class SearchPeopleBuffer(people.PeopleBuffer): class ConversationBuffer(SearchBuffer): def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False): - # starts stream every 3 minutes. current_time = time.time() if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: self.execution_time = current_time - if start == True: - self.statuses = [] - self.ids = [] - self.statuses.append(self.tweet) - self.ids.append(self.tweet.id) - tweet = self.tweet - if not hasattr(tweet, "in_reply_to_status_id"): - tweet.in_reply_to_status_id = None - while tweet.in_reply_to_status_id != None: - try: - tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") - except TweepError as err: - break - self.statuses.insert(0, tweet) - self.ids.append(tweet.id) - if tweet.in_reply_to_status_id == None: - self.kwargs["since_id"] = tweet.id - self.ids.append(tweet.id) - val2 = self.session.search(self.name, tweet_mode="extended", *self.args, **self.kwargs) - for i in val2: - if i.in_reply_to_status_id in self.ids: - self.statuses.append(i) - self.ids.append(i.id) - tweet = i - number_of_items = self.session.order_buffer(self.name, self.statuses) + results = self.get_replies(self.tweet) + number_of_items = self.session.order_buffer(self.name, results) log.debug("Number of items retrieved: %d" % (number_of_items,)) self.put_items_on_list(number_of_items) if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: @@ -113,3 +91,33 @@ class ConversationBuffer(SearchBuffer): return True elif dlg == widgetUtils.NO: return False + + def get_replies(self, tweet): + """ Try to retrieve the whole conversation for the passed object by using a mix between calls to API V1.1 and V2 """ + results = [] + # If the tweet that starts the conversation is a reply to something else, let's try to get the parent tweet first. + if hasattr(self, "in_reply_to_status_id") and self.tweet.in_reply_to_status_id != None: + try: + tweet2 = self.session.twitter_v2.get_tweet(id=self.tweet.in_reply_to_status_id, user_auth=True, tweet_fields=["conversation_id"]) + results.append(tweet2) + except TweepyException as e: + log.exception("There was an error attempting to retrieve a parent tweet for the conversation for {}".format(self.name)) + # Now, try to fetch the tweet initiating the conversation in V2 so we can get conversation_id + try: + tweet = self.session.twitter_v2.get_tweet(id=self.tweet.id, user_auth=True, tweet_fields=["conversation_id"]) + results.append(tweet.data) + term = "conversation_id:{}".format(tweet.data.conversation_id) + tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98) + if tweets.data != None: + results.extend(tweets.data) + except TweepyException as e: + log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name)) + new_results = [] + ids = [tweet.id for tweet in results] + try: + results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended") + results.sort(key=lambda x: x.id) + except TweepyException as e: + log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) + return [] + return results \ No newline at end of file From d11fc4477222aa67aa380a95db84aede721b626b Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 28 Oct 2021 12:44:50 -0500 Subject: [PATCH 176/245] Read keys from environment --- src/write_version_data.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/write_version_data.py b/src/write_version_data.py index 4e123157..3d12e486 100644 --- a/src/write_version_data.py +++ b/src/write_version_data.py @@ -1,6 +1,7 @@ #! /usr/bin/env python# -*- coding: iso-8859-1 -*- """ Write version info (taken from the last commit) to application.py. This method has been implemented this way for running updates. This file is not intended to be called by the user. It will be used only by the Gitlab CI runner.""" +import os import requests from codecs import open @@ -28,8 +29,8 @@ file2.write(contents) file2.close() print("done") file3 = open("appkeys.py", "w") -keys = """twitter_api_key = "daMHlXsFlalEWtaqTL7xd6TqZ" -twitter_api_secret = "lOcpsIlhr1lBpA53oNWwmKh9yM6Gqk3IRFOzq9TvAO8B5gisFD" -""" +keys = """twitter_api_key = {} +twitter_api_secret = {} +""".format(os.environ.get("TWITTER_API_KEY"), os.environ.get("TWITTER_API_SECRET")) file3.write(keys) file3.close() \ No newline at end of file From 6739045cce6f76fc8d8c53479460fc132fabe576 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 28 Oct 2021 13:18:02 -0500 Subject: [PATCH 177/245] Fixed manual addition of users to the autocomplete users database --- src/extra/autocompletionUsers/manage.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/extra/autocompletionUsers/manage.py b/src/extra/autocompletionUsers/manage.py index 1d724e4f..a1acd603 100644 --- a/src/extra/autocompletionUsers/manage.py +++ b/src/extra/autocompletionUsers/manage.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import widgetUtils +from tweepy.errors import TweepyException from . import storage, wx_manage from wxUI import commonMessageDialogs @@ -27,8 +28,9 @@ class autocompletionManage(object): if usr == False: return try: - data = self.session.twitter.twitter.get_user(screen_name=usr) - except: + data = self.session.twitter.get_user(screen_name=usr) + except TweepyException as e: + log.exception("Exception raised when attempting to add an user to the autocomplete database manually.") self.dialog.show_invalid_user_error() return self.database.set_user(data.screen_name, data.name, 0) From 5eb942981c0804e995e9bf4a84649be568eed348 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 29 Oct 2021 10:58:30 -0500 Subject: [PATCH 178/245] Added some changes to setup file for the CI config --- src/setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/setup.py b/src/setup.py index c965c06c..f5bc1f17 100644 --- a/src/setup.py +++ b/src/setup.py @@ -44,10 +44,11 @@ build_exe_options = dict( replace_paths = [("*", "")], include_files=["icon.ico", "conf.defaults", "app-configuration.defaults", "keymaps", "locales", "sounds", "documentation", ("keys/lib", "keys/lib"), find_sound_lib_datafiles(), find_accessible_output2_datafiles()]+get_architecture_files(), packages=["wxUI"], + bin_path_excludes=["C:\\Program Files", "C:\Program Files (x86)"], ) executables = [ - Executable('main.py', base=base, targetName="twblue") + Executable('main.py', base=base, target_name="twblue") ] winmsvcr.FILES = () From 36340d059656bc60ad929221b45d1fd92fbac175 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 29 Oct 2021 22:38:44 -0500 Subject: [PATCH 179/245] Moved to python 3.7.10 to test if build passes properly --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a838c655..5d0f3ea1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,6 @@ variables: GIT_SUBMODULE_STRATEGY: recursive - PYTHON: "C:\\python38\\python.exe" + PYTHON: "C:\\python37\\python.exe" NSIS: "C:\\program files (x86)\\nsis\\makensis.exe" stages: @@ -17,7 +17,7 @@ twblue32: - Set-Variable -Name "time" -Value (date -Format "%H:%m") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - choco install python --version 3.8.10 -y -ForceX86 + - choco install python --version 3.7.13 -y -ForceX86 - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' @@ -56,7 +56,7 @@ twblue64: - Set-Variable -Name "time" -Value (date -Format "%H:%m") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - choco install python --version 3.8.10 -y + - choco install python --version 3.7.13 -y - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' From 0e2ff4de8a67f7ad0bfc884e9b741e9e65b7c48d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 29 Oct 2021 22:46:12 -0500 Subject: [PATCH 180/245] Use latest available python version on package manager --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5d0f3ea1..c3c846f4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,7 +17,7 @@ twblue32: - Set-Variable -Name "time" -Value (date -Format "%H:%m") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - choco install python --version 3.7.13 -y -ForceX86 + - choco install python --version 3.7.9 -y -ForceX86 - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' @@ -56,7 +56,7 @@ twblue64: - Set-Variable -Name "time" -Value (date -Format "%H:%m") - echo ${time} - echo "started by ${GITLAB_USER_NAME}" - - choco install python --version 3.7.13 -y + - choco install python --version 3.7.9 -y - '&$env:PYTHON -V' - '&$env:PYTHON -m pip install --upgrade pip' - '&$env:PYTHON -m pip install --upgrade -r requirements.txt' From 5a6dc23524924d31ea9243a714f69a1789d2de3f Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sat, 30 Oct 2021 01:34:37 -0500 Subject: [PATCH 181/245] Write secrets from CI environment --- src/write_version_data.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/write_version_data.py b/src/write_version_data.py index 3d12e486..a634030f 100644 --- a/src/write_version_data.py +++ b/src/write_version_data.py @@ -28,9 +28,11 @@ file2 = open("..\\scripts\\twblue.nsi", "w", encoding="utf-8") file2.write(contents) file2.close() print("done") +print("Writing keys to module...") file3 = open("appkeys.py", "w") -keys = """twitter_api_key = {} -twitter_api_secret = {} +keys = """twitter_api_key = "{}" +twitter_api_secret = "{}" """.format(os.environ.get("TWITTER_API_KEY"), os.environ.get("TWITTER_API_SECRET")) file3.write(keys) -file3.close() \ No newline at end of file +file3.close() +print("Wrote set of keys for consumer of {}".format(os.environ.get("TWITTER_API_KEY"))) \ No newline at end of file From ffb11b82260841f1531934ee00f147c199fe39cc Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 31 Oct 2021 19:27:59 -0600 Subject: [PATCH 182/245] Updated changelog --- doc/changelog.md | 12 ++++++++++++ src/controller/buffers/twitter/search.py | 12 +++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index e0c489bc..f7ced3e4 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,18 @@ ## changes in this version +## changes in this version + +* fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) + +## Changes in Version 2021.10.30 + +* Fixed many errors in the way we compile TWBlue, so users of 64 bits systems and particularly windows 7 users would be able to install TWBlue again. In case of issues with versions prior to 2021.10.30, please remove everything related to TWBlue (except configs) and reinstall the version 2021.10.30 to fix any possible error. This step won't be needed again in 23 months. ([#416,](https://github.com/manuelcortez/TWBlue/issues/416), [#415,](https://github.com/manuelcortez/TWBlue/issues/415)) +* fixed an issue that was making impossible to manually add an user to the autocomplete users database. +* Started to improve support to conversations by searching for conversation_id. + +## changes in version 2021.10.27 + * Added an user alias manager, located in the application menu in the menu bar. From this dialog, it is possible to review, add, edit or remove user aliases for the current account. ([#401](https://github.com/manuelcortez/TWBlue/issues/401)) * TWBlue now closes the VLC player window automatically when a video reaches its end. ([#399](https://github.com/manuelcortez/TWBlue/issues/399)) * After a lot of time, TWBlue now uses a new default Soundpack, called FreakyBlue. This soundpack will be set by default in all new sessions created in the application. Thanks to [Andre Louis](https://twitter.com/FreakyFwoof) for the pack. ([#247](https://github.com/manuelcortez/TWBlue/issues/247)) diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index caf0e428..59a01317 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -95,19 +95,13 @@ class ConversationBuffer(SearchBuffer): def get_replies(self, tweet): """ Try to retrieve the whole conversation for the passed object by using a mix between calls to API V1.1 and V2 """ results = [] - # If the tweet that starts the conversation is a reply to something else, let's try to get the parent tweet first. - if hasattr(self, "in_reply_to_status_id") and self.tweet.in_reply_to_status_id != None: - try: - tweet2 = self.session.twitter_v2.get_tweet(id=self.tweet.in_reply_to_status_id, user_auth=True, tweet_fields=["conversation_id"]) - results.append(tweet2) - except TweepyException as e: - log.exception("There was an error attempting to retrieve a parent tweet for the conversation for {}".format(self.name)) - # Now, try to fetch the tweet initiating the conversation in V2 so we can get conversation_id try: tweet = self.session.twitter_v2.get_tweet(id=self.tweet.id, user_auth=True, tweet_fields=["conversation_id"]) results.append(tweet.data) + original_tweet = self.session.twitter_v2.get_tweet(id=tweet.data.conversation_id, user_auth=True, tweet_fields=["conversation_id"]) + results.insert(0, original_tweet.data) term = "conversation_id:{}".format(tweet.data.conversation_id) - tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98) + tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) if tweets.data != None: results.extend(tweets.data) except TweepyException as e: From b04a1c74a79b4510d8bd1f271d12ad8e04f5a911 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 31 Oct 2021 19:29:11 -0600 Subject: [PATCH 183/245] Fixed a bug when clearing direct messages buffer. Closes #418 --- src/controller/buffers/twitter/directMessages.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controller/buffers/twitter/directMessages.py b/src/controller/buffers/twitter/directMessages.py index 176a3138..b0c51e5b 100644 --- a/src/controller/buffers/twitter/directMessages.py +++ b/src/controller/buffers/twitter/directMessages.py @@ -12,6 +12,7 @@ from sessions.twitter import compose, utils from mysc.thread_utils import call_threaded from tweepy.errors import TweepyException from pubsub import pub +from wxUI import commonMessageDialogs from . import base log = logging.getLogger("controller.buffers.twitter.dmBuffer") From b39b732a93d1e7b74b2beedaff9ed192fd79e23c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 31 Oct 2021 19:32:50 -0600 Subject: [PATCH 184/245] Updated Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f871210..332f9a4b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Although most dependencies can be found in the windows-dependencies directory, w #### Dependencies packaged in windows installers -* [Python,](https://python.org) version 3.8.7 +* [Python,](https://python.org) version 3.7.9 If you want to build both x86 and x64 binaries, you can install python x86 to C:\python38 and python x64 to C:\python38x64, for example. #### Dependencies that must be installed using pip From ff0a2b56920ceb90ed53529be78cb607048edcec Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 00:11:46 -0600 Subject: [PATCH 185/245] Retrieve all tweets from a thread properly. closes #417 --- doc/changelog.md | 1 + src/controller/buffers/twitter/search.py | 67 ++++++++++++++++++------ 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index f7ced3e4..35410785 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -5,6 +5,7 @@ ## changes in this version * fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) +* TWBlue should retrieve tweets from threads and conversations in a more reliable way. Tweets in the same thread (made by the same author) will be sorted correctly, although replies to the thread (made by different people) may not be ordered in the same way they are displayed in Twitter apps. ([#417](https://github.com/manuelcortez/TWBlue/issues/417)) ## Changes in Version 2021.10.30 diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index 59a01317..7a75d702 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -94,24 +94,57 @@ class ConversationBuffer(SearchBuffer): def get_replies(self, tweet): """ Try to retrieve the whole conversation for the passed object by using a mix between calls to API V1.1 and V2 """ - results = [] + # firstly we would try to retrieve the whole thread, then we will get replies. + # this makes us to waste two search API calls, but there's no better option to retrieve the whole thread including replies, unfortunately. + thread_results = [] + reply_results = [] + # try to fetch conversation_id of the tweet initiating the buffer. try: - tweet = self.session.twitter_v2.get_tweet(id=self.tweet.id, user_auth=True, tweet_fields=["conversation_id"]) - results.append(tweet.data) - original_tweet = self.session.twitter_v2.get_tweet(id=tweet.data.conversation_id, user_auth=True, tweet_fields=["conversation_id"]) - results.insert(0, original_tweet.data) - term = "conversation_id:{}".format(tweet.data.conversation_id) - tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) - if tweets.data != None: - results.extend(tweets.data) + tweet = self.session.twitter_v2.get_tweet(id=self.tweet.id, user_auth=True, tweet_fields=["conversation_id", "author_id"]) + thread_results.append(tweet.data) + except TweepyException as e: + log.exception("Error attempting to retrieve tweet conversation ID") + thread_results.append(self.tweet) + # Return earlier cause we can't do anything if we cannot fetch the object from twitter. + return thread_results + # If tweet contains a conversation_id param, let's retrieve the original tweet which started the conversation so we will have the whole reference for later. + if hasattr(tweet.data, "conversation_id") and tweet.data.conversation_id != None: + conversation_id = tweet.data.conversation_id + original_tweet = self.session.twitter_v2.get_tweet(id=tweet.data.conversation_id, user_auth=True, tweet_fields=["conversation_id", "author_id"]) + thread_results.insert(0, original_tweet.data) + else: + conversation_id = tweet.data.id + # find all tweets replying to the original thread only. Those tweets are sent by the same author who originally posted the first tweet. + try: + term = "conversation_id:{} from:{} to:{}".format(conversation_id, original_tweet.data.author_id, original_tweet.data.author_id) + thread_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) + if thread_tweets.data != None: + thread_results.extend(thread_tweets.data) + # Search only replies to conversation_id. + term = "conversation_id:{}".format(conversation_id, original_tweet.data.author_id) + reply_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=50, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) + if reply_tweets.data != None: + reply_results.extend(reply_tweets.data) except TweepyException as e: log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name)) - new_results = [] - ids = [tweet.id for tweet in results] - try: - results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended") - results.sort(key=lambda x: x.id) - except TweepyException as e: - log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) - return [] + # convert v2 tweets in normal, V1.1 tweets so we don't have to deal with those kind of objects in our infrastructure. + # ToDo: Remove this last step once we support natively all objects fetched via Twitter API V2. + results = [] + ids = [tweet.id for tweet in thread_results] + if len(ids) > 0: + try: + thread_results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended") + thread_results.sort(key=lambda x: x.id) + results.extend(thread_results) + except TweepyException as e: + log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) + return [] + ids = [tweet.id for tweet in reply_results] + if len(ids) > 0: + try: + reply_results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended") + reply_results.sort(key=lambda x: x.id) + results.extend(reply_results) + except TweepyException as e: + log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) return results \ No newline at end of file From 84fa2fad91e6425a9a33b50e0ff55893929dcf54 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 05:18:46 -0600 Subject: [PATCH 186/245] Fixed title for Trending topic buffers after a restart. Closes #421 --- doc/changelog.md | 3 ++- src/controller/buffers/twitter/trends.py | 1 + src/controller/mainController.py | 10 ++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 35410785..e5086795 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -4,8 +4,9 @@ ## changes in this version -* fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) * TWBlue should retrieve tweets from threads and conversations in a more reliable way. Tweets in the same thread (made by the same author) will be sorted correctly, although replies to the thread (made by different people) may not be ordered in the same way they are displayed in Twitter apps. ([#417](https://github.com/manuelcortez/TWBlue/issues/417)) +* fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) +* fixed an issue that was making TWBlue to show incorrectly titles for trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/TWBlue/issues/421)) ## Changes in Version 2021.10.30 diff --git a/src/controller/buffers/twitter/trends.py b/src/controller/buffers/twitter/trends.py index 03e07b3a..e3be681d 100644 --- a/src/controller/buffers/twitter/trends.py +++ b/src/controller/buffers/twitter/trends.py @@ -49,6 +49,7 @@ class TrendsBuffer(base.Buffer): log.exception("Error %s" % (str(err))) if not hasattr(self, "name_"): self.name_ = data[0]["locations"][0]["name"] + pub.sendMessage("buffer-title-changed", buffer=self) self.trends = data[0]["trends"] self.put_items_on_the_list() if self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True: diff --git a/src/controller/mainController.py b/src/controller/mainController.py index c3d97ff9..1d0c3469 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1581,14 +1581,16 @@ class Controller(object): output.speak(_(u"{0} items retrieved").format(n,)) def buffer_title_changed(self, buffer): - if "-timeline" in buffer.name: + if buffer.name.endswith("-timeline"): title = _(u"Timeline for {}").format(buffer.username,) - elif "-favorite" in buffer.name: + elif buffer.name.endswith("-favorite"): title = _(u"Likes for {}").format(buffer.username,) - elif "-followers" in buffer.name: + elif buffer.name.endswith("-followers"): title = _(u"Followers for {}").format(buffer.username,) - elif "-friends" in buffer.name: + elif buffer.name.endswith("-friends"): title = _(u"Friends for {}").format(buffer.username,) + elif buffer.name.endswith("_tt"): + title = _("Trending topics for %s") % (buffer.name_) buffer_index = self.view.search(buffer.name, buffer.account) self.view.set_page_title(buffer_index, title) From 94ca935b2f97ec3743517ec5a5a28e42b9becf13 Mon Sep 17 00:00:00 2001 From: riku Date: Mon, 1 Nov 2021 20:37:39 +0900 Subject: [PATCH 187/245] Updated Japanese translation --- src/locales/ja/lc_messages/twblue.mo | Bin 58524 -> 61631 bytes src/locales/ja/lc_messages/twblue.po | 5082 +++++++++++++------------- 2 files changed, 2580 insertions(+), 2502 deletions(-) diff --git a/src/locales/ja/lc_messages/twblue.mo b/src/locales/ja/lc_messages/twblue.mo index 4140b2802d78542ee05d48224c6d42dfd56d9213..e85315e4c8b7b687bba9266d803ab2abfab0fab7 100644 GIT binary patch delta 19294 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 delta 16633 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

9r(Vtwjk{nUg@8U10qdoc2 z*pc{*<<1d*M13mGqv*IszdYnZbpLOY_^+}Y!IT#%HTO>}9e=Qa_Pv&WNqxQLXVRxW zMMr9KTP?rTrMwB&rtm|`aAH6HOqr(r|C*xz-{u^whok5a{@O{I$ju`Dh7w491pRbO zcKrXpYppgGv(oR?@zm;9@et)-%5_R9I{5BV=}ToWzJ9Dxzy)(t+S0b%+KZX7uXSET z{cG}@EH{(-Zt5T6mz@6zuES-oowLo=ecm%FMd`4B4mBtxty3VbCjaWlLfdu9t7E;@ z+t4SBQiXV{I-})!Kox^|V?c}tvJ$m-<OU|ly8oc4AxZwo9qIkOy4CYn=u+69r~8_uOWkv%OEYXpRBTeozQr>Z zA2>KRD!l*DsDVSmhYk*pjT*`jabyOC5AD}~NO;d-efmVjmQSi1TOz$bab%gK%OitR zCH)a!G=sm%M1RJJisdR*4v(l&Goq^h?!+5uE0wQOzEaYWNezSi!HGTm_Y?Ca-A`;A z;GaFGNYcwW?*{}YC#*=Gur7ImpUVC9OFe&&xjFpP=TA%Oy&x#9|IMl4Nqax77m$>1 z>9{ohcDFd`j2hvopfem diff --git a/src/locales/ja/lc_messages/twblue.po b/src/locales/ja/lc_messages/twblue.po index f26c1c4b..496f81c5 100644 --- a/src/locales/ja/lc_messages/twblue.po +++ b/src/locales/ja/lc_messages/twblue.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-01-23 09:00+0900\n" -"PO-Revision-Date: 2021-01-23 09:05+0900\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2021-11-01 11:40+0900\n" "Last-Translator: 陸 \n" "Language-Team: \n" "Language: ja_JP\n" @@ -15,19 +15,1837 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.4.2\n" +"X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: src\languageHandler.py:99 +#: ../src\controller\attach.py:25 +msgid "Photo" +msgstr "画像" + +#: ../src\controller\buffers\base\base.py:91 +msgid "This action is not supported for this buffer" +msgstr "この動作は、現在のバッファではサポートされていません" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:337 ../src\controller\settings.py:286 +msgid "Home" +msgstr "ホーム" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:339 ../src\controller\settings.py:287 +msgid "Mentions" +msgstr "メンション" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:341 +msgid "Direct messages" +msgstr "ダイレクトメッセージ" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:343 ../src\controller\settings.py:289 +msgid "Sent direct messages" +msgstr "送信済みのダイレクトメッセージ" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:345 ../src\controller\settings.py:290 +msgid "Sent tweets" +msgstr "送信済みのツイート" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:347 +#: ../src\controller\mainController.py:1390 ../src\controller\settings.py:291 +msgid "Likes" +msgstr "いいね" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:349 +#: ../src\controller\mainController.py:1395 ../src\controller\settings.py:292 +msgid "Followers" +msgstr "フォロワー" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:353 +#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:294 +msgid "Blocked users" +msgstr "ブロックしたユーザー" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:355 +#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:295 +msgid "Muted users" +msgstr "ミューとしたユーザー" + +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:293 +msgid "Friends" +msgstr "フォロー" + +#: ../src\controller\buffers\twitter\base.py:76 +msgid "{username}'s timeline" +msgstr "「{username}」のタイムライン" + +#: ../src\controller\buffers\twitter\base.py:78 +msgid "{username}'s likes" +msgstr "「{username}」のいいね一覧" + +#: ../src\controller\buffers\twitter\base.py:80 +msgid "{username}'s followers" +msgstr "「{username}」のフォロワー" + +#: ../src\controller\buffers\twitter\base.py:82 +msgid "{username}'s friends" +msgstr "「{username}」のフォロー" + +#: ../src\controller\buffers\twitter\base.py:84 +msgid "Unknown buffer" +msgstr "不明なバッファ" + +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:121 +#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 +msgid "Tweet" +msgstr "ツイート" + +#: ../src\controller\buffers\twitter\base.py:89 +#: ../src\controller\buffers\twitter\trends.py:122 +msgid "Write the tweet here" +msgstr "ツイートを入力" + +#: ../src\controller\buffers\twitter\base.py:219 +msgid "New tweet in {0}" +msgstr "「{0}」への新規ツイート" + +#: ../src\controller\buffers\twitter\base.py:222 +msgid "{0} new tweets in {1}." +msgstr "「{1}」への{0}個の新規ツイート。" + +#: ../src\controller\buffers\twitter\base.py:261 +#: ../src\controller\buffers\twitter\directMessages.py:87 +#: ../src\controller\buffers\twitter\people.py:180 +msgid "%s items retrieved" +msgstr "%s個のアイテムを取得しました" + +#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\people.py:80 +msgid "This buffer is not a timeline; it can't be deleted." +msgstr "このバッファは、タイムラインではないため、削除できません。" + +#: ../src\controller\buffers\twitter\base.py:430 +msgid "Reply to {arg0}" +msgstr "「{arg0}」への返信:" + +#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 +msgid "Reply" +msgstr "返信" + +#: ../src\controller\buffers\twitter\base.py:433 +msgid "Reply to %s" +msgstr "「%s」への返信" + +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\buffers\twitter\directMessages.py:129 +msgid "New direct message" +msgstr "新しいダイレクトメッセージ" + +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\messages.py:200 +msgid "Direct message to %s" +msgstr "「%s」へのダイレクトメッセージ" + +#: ../src\controller\buffers\twitter\base.py:520 +msgid "Add your comment to the tweet" +msgstr "ツイートにコメントを追加" + +#: ../src\controller\buffers\twitter\base.py:520 +msgid "Quote" +msgstr "引用" + +#: ../src\controller\buffers\twitter\base.py:596 +msgid "Opening URL..." +msgstr "URLを開いています…" + +#: ../src\controller\buffers\twitter\base.py:633 +msgid "User details" +msgstr "ユーザーの詳細" + +#: ../src\controller\buffers\twitter\base.py:654 +msgid "Opening item in web browser..." +msgstr "ブラウザでアイテムを開いています…" + +#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\people.py:95 +msgid "Mention to %s" +msgstr "%sへのメンション" + +#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\people.py:95 +#: ../src\wxUI\buffers\people.py:17 +msgid "Mention" +msgstr "メンション" + +#: ../src\controller\buffers\twitter\directMessages.py:132 +msgid "{0} new direct messages." +msgstr "{0}件の新しいダイレクトメッセージ。" + +#: ../src\controller\buffers\twitter\directMessages.py:135 +msgid "This action is not supported in the buffer yet." +msgstr "この動作は、現在のバッファではサポートされていません。" + +#: ../src\controller\buffers\twitter\directMessages.py:145 +msgid "" +"Getting more items cannot be done in this buffer. Use the direct messages " +"buffer instead." +msgstr "" +"このバッファでは、さらにアイテムを取得することはできません。代わりにダイレク" +"トメッセージバッファを使用してください。" + +#: ../src\controller\buffers\twitter\people.py:253 +msgid "{0} new followers." +msgstr "{0}人の新しいフォロワー。" + +#: ../src\controller\buffers\twitter\trends.py:145 +msgid "This action is not supported in the buffer, yet." +msgstr "この動作は、現在のバッファではサポートされていません。" + +#: ../src\controller\mainController.py:277 +msgid "Ready" +msgstr "準備完了" + +#: ../src\controller\mainController.py:351 +msgid "Following" +msgstr "フォロー中" + +#: ../src\controller\mainController.py:356 +msgid "Timelines" +msgstr "タイムライン" + +#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:883 +#: ../src\controller\mainController.py:1585 +msgid "Timeline for {}" +msgstr "「{}」のタイムライン" + +#: ../src\controller\mainController.py:360 +msgid "Likes timelines" +msgstr "ほかのユーザーのいいね一覧" + +#: ../src\controller\mainController.py:363 +#: ../src\controller\mainController.py:902 +#: ../src\controller\mainController.py:1587 +msgid "Likes for {}" +msgstr "{}のいいね一覧" + +#: ../src\controller\mainController.py:364 +msgid "Followers timelines" +msgstr "フォロワー一覧" + +#: ../src\controller\mainController.py:367 +#: ../src\controller\mainController.py:921 +#: ../src\controller\mainController.py:1589 +msgid "Followers for {}" +msgstr "{}をフォローしているユーザー" + +#: ../src\controller\mainController.py:368 +msgid "Following timelines" +msgstr "フォロー一覧" + +#: ../src\controller\mainController.py:371 +#: ../src\controller\mainController.py:940 +#: ../src\controller\mainController.py:1591 +msgid "Friends for {}" +msgstr "{}がフォローしているユーザー" + +#: ../src\controller\mainController.py:372 ../src\wxUI\dialogs\lists.py:13 +msgid "Lists" +msgstr "リスト" + +#: ../src\controller\mainController.py:375 +#: ../src\controller\mainController.py:1422 +msgid "List for {}" +msgstr "{}のリスト" + +#: ../src\controller\mainController.py:376 +msgid "Searches" +msgstr "検索" + +#: ../src\controller\mainController.py:379 +#: ../src\controller\mainController.py:426 +#: ../src\controller\mainController.py:431 +msgid "Search for {}" +msgstr "「{}」の検索結果" + +#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:982 +msgid "Trending topics for %s" +msgstr "%s のトレンド" + +#: ../src\controller\mainController.py:448 +#: ../src\controller\mainController.py:464 +#: ../src\controller\mainController.py:1080 +#: ../src\controller\mainController.py:1099 +#: ../src\controller\mainController.py:1118 +#: ../src\controller\mainController.py:1137 +msgid "" +"No session is currently in focus. Focus a session with the next or previous " +"session shortcut." +msgstr "" +"セッションが選択されていません。「次のセッション」または「前のセッション」の" +"ショートカットを利用して、セッションを選択してください。" + +#: ../src\controller\mainController.py:452 +msgid "Empty buffer." +msgstr "からのバッファ。" + +#: ../src\controller\mainController.py:459 +msgid "{0} not found." +msgstr "{0}が見つかりませんでした。" + +#: ../src\controller\mainController.py:469 +msgid "Filters cannot be applied on this buffer" +msgstr "このバッファにはフィルターを適応できません" + +#: ../src\controller\mainController.py:522 +#: ../src\controller\mainController.py:539 +#: ../src\controller\mainController.py:568 +msgid "Select the user" +msgstr "ユーザーを選択" + +#: ../src\controller\mainController.py:753 +msgid "Add an user alias" +msgstr "ユーザーエイリアスを追加" + +#: ../src\controller\mainController.py:761 +msgid "Alias has been set correctly for {}." +msgstr "{}のエイリアスが正しく設定されています。" + +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 +msgid "MMM D, YYYY. H:m" +msgstr "YYYY年MMMMD日 H時m分" + +#: ../src\controller\mainController.py:957 +msgid "Conversation with {0}" +msgstr "{0}との会話" + +#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1015 +msgid "There are no coordinates in this tweet" +msgstr "このツイートに位置情報は存在しません" + +#: ../src\controller\mainController.py:1000 +#: ../src\controller\mainController.py:1019 +msgid "Error decoding coordinates. Try again later." +msgstr "位置情報の取得に失敗しました。あとで再試行してください。" + +#: ../src\controller\mainController.py:1004 +msgid "Unable to find address in OpenStreetMap." +msgstr "OpenStreetMapでアドレスが見つかりません。" + +#: ../src\controller\mainController.py:1017 +msgid "There are no results for the coordinates in this tweet" +msgstr "このツイートの位置情報には、なにも含まれていません" + +#: ../src\controller\mainController.py:1128 +#: ../src\controller\mainController.py:1147 +msgid "%s, %s of %s" +msgstr "%s %s/%s" + +#: ../src\controller\mainController.py:1130 +#: ../src\controller\mainController.py:1149 +#: ../src\controller\mainController.py:1174 +#: ../src\controller\mainController.py:1199 +msgid "%s. Empty" +msgstr "%sは、からです" + +#: ../src\controller\mainController.py:1162 +#: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1187 +msgid "{0}: This account is not logged into Twitter." +msgstr "{0}: このアカウントは、まだTwitterにログインしていません。" + +#: ../src\controller\mainController.py:1172 +#: ../src\controller\mainController.py:1197 +msgid "%s. %s, %s of %s" +msgstr "セッション:%s %s %s/%s" + +#: ../src\controller\mainController.py:1191 +msgid "{0}: This account is not logged into twitter." +msgstr "{0}: このアカウントは、まだTwitterにログインしていません。" + +#: ../src\controller\mainController.py:1416 +msgid "This list is already opened" +msgstr "既に開かれています" + +#: ../src\controller\mainController.py:1446 +#: ../src\controller\mainController.py:1462 +msgid "" +"An error happened while trying to connect to the server. Please try later." +msgstr "" +"サーバーへの接続中に、予期しないエラーが発生しました。あとで再試行してくださ" +"い。" + +#: ../src\controller\mainController.py:1498 +msgid "The auto-reading of new tweets is enabled for this buffer" +msgstr "自動読み上げ 有効" + +#: ../src\controller\mainController.py:1501 +msgid "The auto-reading of new tweets is disabled for this buffer" +msgstr "自動読み上げ 無効" + +#: ../src\controller\mainController.py:1508 +msgid "Session mute on" +msgstr "このセッションのミュートを設定" + +#: ../src\controller\mainController.py:1511 +msgid "Session mute off" +msgstr "このセッションのミュートを解除" + +#: ../src\controller\mainController.py:1519 +msgid "Buffer mute on" +msgstr "このバッファのミュートを設定" + +#: ../src\controller\mainController.py:1522 +msgid "Buffer mute off" +msgstr "このバッファのミュートを解除" + +#: ../src\controller\mainController.py:1545 +msgid "Copied" +msgstr "コピーしました" + +#: ../src\controller\mainController.py:1575 +msgid "Unable to update this buffer." +msgstr "このバッファを更新できません。" + +#: ../src\controller\mainController.py:1578 +msgid "Updating buffer..." +msgstr "バッファを更新中…" + +#: ../src\controller\mainController.py:1581 +msgid "{0} items retrieved" +msgstr "{0}個のアイテムを取得しました" + +#: ../src\controller\mainController.py:1598 +#: ../src\controller\mainController.py:1618 +msgid "Invalid buffer" +msgstr "無効なバッファ" + +#: ../src\controller\mainController.py:1609 +msgid "Picture {0}" +msgstr "画像{0}" + +#: ../src\controller\mainController.py:1610 +msgid "Select the picture" +msgstr "画像を選択" + +#: ../src\controller\mainController.py:1629 +msgid "Unable to extract text" +msgstr "テキストを抽出できません" + +#: ../src\controller\messages.py:56 +msgid "Translated" +msgstr "翻訳完了" + +#: ../src\controller\messages.py:63 +msgid "There's no URL to be shortened" +msgstr "短縮されたURLは、ありません" + +#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 +msgid "URL shortened" +msgstr "URLを短縮しました" + +#: ../src\controller\messages.py:82 +msgid "There's no URL to be expanded" +msgstr "短縮を解除するURLはありません" + +#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 +msgid "URL expanded" +msgstr "URLの短縮を解除しました" + +#: ../src\controller\messages.py:108 +msgid "%s - %s of %d characters" +msgstr "%s - %s/%d" + +#: ../src\controller\messages.py:112 +msgid "%s - %s characters" +msgstr "%s - %s文字" + +#: ../src\controller\messages.py:272 +msgid "View item" +msgstr "アイテムを見る" + +#: ../src\controller\messages.py:301 +msgid "Link copied to clipboard." +msgstr "リンクをクリップボードへコピーしました。" + +#: ../src\controller\settings.py:74 +msgid "HTTP" +msgstr "HTTP" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4" +msgstr "SOCKS v4" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4 with DNS support" +msgstr "DNSをサポートする SOCKS v4" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5" +msgstr "SOCKS v5" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5 with DNS support" +msgstr "DNSをサポートする SOCKS v5" + +#: ../src\controller\settings.py:74 +msgid "System default" +msgstr "システムのデフォルト" + +#: ../src\controller\settings.py:145 ../src\controller\settings.py:211 +#: ../src\wxUI\dialogs\configuration.py:116 +msgid "Ask" +msgstr "その都度、質問する" + +#: ../src\controller\settings.py:147 ../src\controller\settings.py:213 +#: ../src\wxUI\dialogs\configuration.py:116 +msgid "Retweet without comments" +msgstr "コメントを付けずにリツイート(公式RT)" + +#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:116 +msgid "Retweet with comments" +msgstr "コメントをつけてリツイート(非公式RT)" + +#: ../src\controller\settings.py:185 +msgid "Account settings for %s" +msgstr "%sのアカウント設定" + +#: ../src\controller\settings.py:288 +msgid "Direct Messages" +msgstr "ダイレクトメッセージ" + +#: ../src\controller\user.py:29 ../src\controller\user.py:31 +#: ../src\extra\SpellChecker\wx_ui.py:80 ../src\issueReporter\wx_ui.py:84 +#: ../src\issueReporter\wx_ui.py:87 ../src\wxUI\commonMessageDialogs.py:39 +#: ../src\wxUI\commonMessageDialogs.py:51 +#: ../src\wxUI\commonMessageDialogs.py:58 +#: ../src\wxUI\commonMessageDialogs.py:61 +#: ../src\wxUI\commonMessageDialogs.py:64 +#: ../src\wxUI\commonMessageDialogs.py:67 +#: ../src\wxUI\commonMessageDialogs.py:77 +#: ../src\wxUI\commonMessageDialogs.py:80 +#: ../src\wxUI\commonMessageDialogs.py:83 +#: ../src\wxUI\commonMessageDialogs.py:89 +#: ../src\wxUI\commonMessageDialogs.py:92 +msgid "Error" +msgstr "エラー" + +#: ../src\controller\user.py:29 ../src\wxUI\commonMessageDialogs.py:39 +msgid "That user does not exist" +msgstr "そのユーザーは存在しません" + +#: ../src\controller\user.py:31 +msgid "User has been suspended" +msgstr "ユーザーが凍結されています" + +#: ../src\controller\user.py:37 +msgid "Information for %s" +msgstr "%sの情報" + +#: ../src\controller\user.py:67 ../src\extra\AudioUploader\audioUploader.py:127 +msgid "Discarded" +msgstr "拒否されました" + +#: ../src\controller\user.py:95 +msgid "Username: @%s\n" +msgstr "ユーザー名: @%s\n" + +#: ../src\controller\user.py:96 +msgid "Name: %s\n" +msgstr "名前: %s\n" + +#: ../src\controller\user.py:98 +msgid "Location: %s\n" +msgstr "居住地: %s\n" + +#: ../src\controller\user.py:100 +msgid "URL: %s\n" +msgstr "URL: %s\n" + +#: ../src\controller\user.py:104 +msgid "Bio: %s\n" +msgstr "自己紹介: %s\n" + +#: ../src\controller\user.py:105 ../src\controller\user.py:120 +msgid "Yes" +msgstr "はい" + +#: ../src\controller\user.py:106 ../src\controller\user.py:121 +msgid "No" +msgstr "いいえ" + +#: ../src\controller\user.py:107 +msgid "Protected: %s\n" +msgstr "保護設定: %s\n" + +#: ../src\controller\user.py:112 +msgid "You follow {0}. " +msgstr "{0}をフォロー。 " + +#: ../src\controller\user.py:115 +msgid "{0} is following you." +msgstr "{0}がフォロー。" + +#: ../src\controller\user.py:119 +msgid "" +"Followers: %s\n" +" Friends: %s\n" +msgstr "" +"フォロワー: %s\n" +"フォロー: %s\n" + +#: ../src\controller\user.py:122 +msgid "Verified: %s\n" +msgstr "認証済み: %s\n" + +#: ../src\controller\user.py:123 +msgid "Tweets: %s\n" +msgstr "ツイート数: %s\n" + +#: ../src\controller\user.py:124 +msgid "Likes: %s" +msgstr "いいね数: %s" + +#: ../src\controller\userActionsController.py:74 +msgid "You can't ignore direct messages" +msgstr "ダイレクトメッセージを無視することはできません" + +#: ../src\controller\userAliasController.py:32 +msgid "Edit alias for {}" +msgstr "{}のエイリアスを編集" + +#: ../src\extra\AudioUploader\audioUploader.py:57 +msgid "Attaching..." +msgstr "添付中…" + +#: ../src\extra\AudioUploader\audioUploader.py:74 +msgid "Pause" +msgstr "一時停止" + +#: ../src\extra\AudioUploader\audioUploader.py:76 +msgid "&Resume" +msgstr "再開(&R)" + +#: ../src\extra\AudioUploader\audioUploader.py:77 +msgid "Resume" +msgstr "再開" + +#: ../src\extra\AudioUploader\audioUploader.py:79 +#: ../src\extra\AudioUploader\audioUploader.py:106 +#: ../src\extra\AudioUploader\wx_ui.py:37 +msgid "&Pause" +msgstr "一時停止(&P)" + +#: ../src\extra\AudioUploader\audioUploader.py:94 +#: ../src\extra\AudioUploader\audioUploader.py:140 +msgid "&Stop" +msgstr "停止(&S)" + +#: ../src\extra\AudioUploader\audioUploader.py:95 +msgid "Recording" +msgstr "録音中" + +#: ../src\extra\AudioUploader\audioUploader.py:100 +#: ../src\extra\AudioUploader\audioUploader.py:151 +msgid "Stopped" +msgstr "停止" + +#: ../src\extra\AudioUploader\audioUploader.py:102 +#: ../src\extra\AudioUploader\wx_ui.py:39 +msgid "&Record" +msgstr "録音(&R)" + +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 +msgid "Playing..." +msgstr "再生中…" + +#: ../src\extra\AudioUploader\audioUploader.py:144 +#: ../src\extra\AudioUploader\audioUploader.py:154 +#: ../src\extra\AudioUploader\wx_ui.py:35 +msgid "&Play" +msgstr "再生(&P)" + +#: ../src\extra\AudioUploader\audioUploader.py:159 +msgid "Recoding audio..." +msgstr "音声を録音中…" + +#: ../src\extra\AudioUploader\transfer.py:82 +#: ../src\extra\AudioUploader\transfer.py:88 +msgid "Error in file upload: {0}" +msgstr "ファイルアップロードエラー: {0}" + +#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 +msgid "%d day, " +msgstr "%d日 " + +#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 +msgid "%d days, " +msgstr "%d日 " + +#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 +msgid "%d hour, " +msgstr "%d時間 " + +#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 +msgid "%d hours, " +msgstr "%d時間 " + +#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 +msgid "%d minute, " +msgstr "%d分 " + +#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 +msgid "%d minutes, " +msgstr "%d分 " + +#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 +msgid "%s second" +msgstr "%s秒" + +#: ../src\extra\AudioUploader\utils.py:43 ../src\update\utils.py:43 +msgid "%s seconds" +msgstr "%s秒" + +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 +msgid "File" +msgstr "ファイル" + +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:21 +msgid "Transferred" +msgstr "転送済み" + +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:26 +msgid "Total file size" +msgstr "合計サイズ" + +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:31 +msgid "Transfer rate" +msgstr "転送速度" + +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:36 +msgid "Time left" +msgstr "残り時間" + +#: ../src\extra\AudioUploader\wx_ui.py:29 +msgid "Attach audio" +msgstr "音声を添付" + +#: ../src\extra\AudioUploader\wx_ui.py:41 +msgid "&Add an existing file" +msgstr "既存のファイルを追加(&A)" + +#: ../src\extra\AudioUploader\wx_ui.py:42 +msgid "&Discard" +msgstr "拒否(&D)" + +#: ../src\extra\AudioUploader\wx_ui.py:44 +msgid "Upload to" +msgstr "アップロード先" + +#: ../src\extra\AudioUploader\wx_ui.py:49 +msgid "Attach" +msgstr "添付" + +#: ../src\extra\AudioUploader\wx_ui.py:51 +msgid "&Cancel" +msgstr "キャンセル(&C)" + +#: ../src\extra\AudioUploader\wx_ui.py:76 +msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" +msgstr "音声ファイル (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" + +#: ../src\extra\AudioUploader\wx_ui.py:76 +msgid "Select the audio file to be uploaded" +msgstr "アップロードする音声ファイルを選択" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 +msgid "Audio tweet." +msgstr "音声付きツイート。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 +msgid "User timeline buffer created." +msgstr "ユーザーのタイムラインのバッファを作成。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 +msgid "Buffer destroied." +msgstr "バッファを削除。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 +msgid "Direct message received." +msgstr "ダイレクトメッセージを受信。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 +msgid "Direct message sent." +msgstr "ダイレクトメッセージを送信。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 +msgid "Error." +msgstr "エラー。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 +msgid "Tweet liked." +msgstr "ツイートがいいねされた。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 +msgid "Likes buffer updated." +msgstr "いいねバッファが更新された。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 +msgid "Geotweet." +msgstr "位置情報付きのツイート。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 +msgid "Tweet contains one or more images" +msgstr "ツイートに1つ以上の画像が含まれています" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 +msgid "Boundary reached." +msgstr "先頭または最後のツイート。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 +msgid "List updated." +msgstr "リストが更新された。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 +msgid "Too many characters." +msgstr "文字数オーバー。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 +msgid "Mention received." +msgstr "リプライを受信した。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 +msgid "New event." +msgstr "新しいイベント。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 +msgid "{0} is ready." +msgstr "{0}の準備完了。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 +msgid "Mention sent." +msgstr "リプライを送信した。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 +msgid "Tweet retweeted." +msgstr "ツイートをリツイートした。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 +msgid "Search buffer updated." +msgstr "検索バッファが更新された。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 +msgid "Tweet received." +msgstr "ツイートを受信した。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 +msgid "Tweet sent." +msgstr "ツイートを送信した。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 +msgid "Trending topics buffer updated." +msgstr "トレンドのバッファが更新された。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 +msgid "New tweet in user timeline buffer." +msgstr "ユーザーのタイムラインに新しいツイートを受信した。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 +msgid "New follower." +msgstr "新しいフォロワー。" + +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:31 +msgid "Volume changed." +msgstr "ボリュームを変更した。" + +#: ../src\extra\SoundsTutorial\wx_ui.py:9 +msgid "Sounds tutorial" +msgstr "サウンドの確認" + +#: ../src\extra\SoundsTutorial\wx_ui.py:12 +msgid "Press enter to listen to the sound for the selected event" +msgstr "選択されたイベントのサウンドを再生するには、Enterキーを押してください" + +#: ../src\extra\SpellChecker\spellchecker.py:60 +msgid "Misspelled word: %s" +msgstr "「%s」はスペルが間違っています" + +#: ../src\extra\SpellChecker\wx_ui.py:28 +msgid "Misspelled word" +msgstr "スペルミスの単語" + +#: ../src\extra\SpellChecker\wx_ui.py:33 +msgid "Context" +msgstr "コンテキスト" + +#: ../src\extra\SpellChecker\wx_ui.py:38 +msgid "Suggestions" +msgstr "提案" + +#: ../src\extra\SpellChecker\wx_ui.py:43 +msgid "&Ignore" +msgstr "無視(&I)" + +#: ../src\extra\SpellChecker\wx_ui.py:44 +msgid "I&gnore all" +msgstr "すべて無視(&G)" + +#: ../src\extra\SpellChecker\wx_ui.py:45 +msgid "&Replace" +msgstr "置き換え(&R)" + +#: ../src\extra\SpellChecker\wx_ui.py:46 +msgid "R&eplace all" +msgstr "すべて置き換え(&E)" + +#: ../src\extra\SpellChecker\wx_ui.py:47 +msgid "&Add to personal dictionary" +msgstr "個人辞書に追加(&A)" + +#: ../src\extra\SpellChecker\wx_ui.py:80 +msgid "" +"An error has occurred. There are no dictionaries available for the selected " +"language in {0}" +msgstr "エラーが発生しました。{0}で選択した言語用の辞書がありません" + +#: ../src\extra\SpellChecker\wx_ui.py:83 +msgid "Spell check complete." +msgstr "スペルチェックが完了しました。" + +#: ../src\extra\autocompletionUsers\completion.py:20 +#: ../src\extra\autocompletionUsers\completion.py:38 +msgid "You have to start writing" +msgstr "あなたは、書き込みを開始しなければなりません" + +#: ../src\extra\autocompletionUsers\completion.py:30 +#: ../src\extra\autocompletionUsers\completion.py:47 +msgid "There are no results in your users database" +msgstr "あなたのユーザーのデータベースには、見つかりませんでした" + +#: ../src\extra\autocompletionUsers\completion.py:32 +msgid "Autocompletion only works for users." +msgstr "自動補完はユーザーのみで動作します。" + +#: ../src\extra\autocompletionUsers\settings.py:25 +msgid "" +"Updating database... You can close this window now. A message will tell you " +"when the process finishes." +msgstr "" +"データベースの更新中… なお、このウィンドウを閉じることができます。処理が終了" +"すると、メッセージが表示されます。" + +#: ../src\extra\autocompletionUsers\wx_manage.py:9 +msgid "Manage Autocompletion database" +msgstr "オートコンプリートのデータベースを管理" + +#: ../src\extra\autocompletionUsers\wx_manage.py:12 +msgid "Editing {0} users database" +msgstr "{0}のユーザーデータベースを編集中" + +#: ../src\extra\autocompletionUsers\wx_manage.py:13 +msgid "Username" +msgstr "ユーザー名" + +#: ../src\extra\autocompletionUsers\wx_manage.py:13 +#: ../src\wxUI\dialogs\configuration.py:144 +msgid "Name" +msgstr "名前" + +#: ../src\extra\autocompletionUsers\wx_manage.py:16 +msgid "Add user" +msgstr "ユーザーを追加" + +#: ../src\extra\autocompletionUsers\wx_manage.py:17 +msgid "Remove user" +msgstr "ユーザーを削除" + +#: ../src\extra\autocompletionUsers\wx_manage.py:38 +msgid "Add user to database" +msgstr "データベースにユーザーを追加" + +#: ../src\extra\autocompletionUsers\wx_manage.py:38 +msgid "Twitter username" +msgstr "Twitterのユーザー名" + +#: ../src\extra\autocompletionUsers\wx_manage.py:44 +msgid "The user does not exist" +msgstr "そのユーザーは存在しません" + +#: ../src\extra\autocompletionUsers\wx_manage.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 +msgid "Error!" +msgstr "エラー!" + +#: ../src\extra\autocompletionUsers\wx_settings.py:8 +msgid "Autocomplete users' settings" +msgstr "オートコンプリートユーザーの設定" + +#: ../src\extra\autocompletionUsers\wx_settings.py:11 +msgid "Add users from followers buffer" +msgstr "フォロワーからユーザーを追加" + +#: ../src\extra\autocompletionUsers\wx_settings.py:12 +msgid "Add users from friends buffer" +msgstr "フォロー中のユーザーからユーザーを追加" + +#: ../src\extra\autocompletionUsers\wx_settings.py:15 +msgid "Manage database..." +msgstr "データベースの管理..." + +#: ../src\extra\autocompletionUsers\wx_settings.py:27 +msgid "Done" +msgstr "完了" + +#: ../src\extra\autocompletionUsers\wx_settings.py:27 +msgid "{0}'s database of users has been updated." +msgstr "{0}のユーザーのデータベースが更新されました。" + +#: ../src\extra\ocr\OCRSpace.py:7 +msgid "Detect automatically" +msgstr "自動検出" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:41 +msgid "Danish" +msgstr "デンマーク語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:43 +msgid "Dutch" +msgstr "オランダ語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:44 +msgid "English" +msgstr "英語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:48 +msgid "Finnish" +msgstr "フィンランド語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:49 +msgid "French" +msgstr "フランス語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:52 +msgid "German" +msgstr "ドイツ語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:58 +msgid "Hungarian" +msgstr "ハンガリー語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:63 +msgid "Italian" +msgstr "イタリア語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:64 +msgid "Japanese" +msgstr "日本語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:68 +msgid "Korean" +msgstr "韓国語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:85 +msgid "Polish" +msgstr "ポーランド語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:86 +msgid "Portuguese" +msgstr "ポルトガル語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:89 +msgid "Russian" +msgstr "ロシア語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:96 +msgid "Spanish" +msgstr "スペイン語" + +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:105 +msgid "Turkish" +msgstr "トルコ語" + +#: ../src\extra\translator\translator.py:22 +msgid "Afrikaans" +msgstr "アフリカ語" + +#: ../src\extra\translator\translator.py:23 +msgid "Albanian" +msgstr "アルバニア語" + +#: ../src\extra\translator\translator.py:24 +msgid "Amharic" +msgstr "アムハラ語" + +#: ../src\extra\translator\translator.py:25 +msgid "Arabic" +msgstr "アラビア語" + +#: ../src\extra\translator\translator.py:26 +msgid "Armenian" +msgstr "アルメニア語" + +#: ../src\extra\translator\translator.py:27 +msgid "Azerbaijani" +msgstr "アゼルバイジャン語" + +#: ../src\extra\translator\translator.py:28 +msgid "Basque" +msgstr "バスク語" + +#: ../src\extra\translator\translator.py:29 +msgid "Belarusian" +msgstr "ベラルーシ語" + +#: ../src\extra\translator\translator.py:30 +msgid "Bengali" +msgstr "ベンガル語" + +#: ../src\extra\translator\translator.py:31 +msgid "Bihari" +msgstr "ビハール語" + +#: ../src\extra\translator\translator.py:32 +msgid "Bulgarian" +msgstr "ブルガリア語" + +#: ../src\extra\translator\translator.py:33 +msgid "Burmese" +msgstr "ビルマ語" + +#: ../src\extra\translator\translator.py:34 +msgid "Catalan" +msgstr "カタロニア語" + +#: ../src\extra\translator\translator.py:35 +msgid "Cherokee" +msgstr "チェロキー語" + +#: ../src\extra\translator\translator.py:36 +msgid "Chinese" +msgstr "中国語" + +#: ../src\extra\translator\translator.py:37 +msgid "Chinese_simplified" +msgstr "簡体字中国語" + +#: ../src\extra\translator\translator.py:38 +msgid "Chinese_traditional" +msgstr "繁体字中国語" + +#: ../src\extra\translator\translator.py:39 +msgid "Croatian" +msgstr "クロアチア語" + +#: ../src\extra\translator\translator.py:40 +msgid "Czech" +msgstr "チェコ語" + +#: ../src\extra\translator\translator.py:42 +msgid "Dhivehi" +msgstr "ディベヒ語" + +#: ../src\extra\translator\translator.py:45 +msgid "Esperanto" +msgstr "エスペラント語" + +#: ../src\extra\translator\translator.py:46 +msgid "Estonian" +msgstr "エストニア語" + +#: ../src\extra\translator\translator.py:47 +msgid "Filipino" +msgstr "フィリピン語" + +#: ../src\extra\translator\translator.py:50 +msgid "Galician" +msgstr "ガリシア語" + +#: ../src\extra\translator\translator.py:51 +msgid "Georgian" +msgstr "ジョージア語" + +#: ../src\extra\translator\translator.py:53 +msgid "Greek" +msgstr "ギリシャ語" + +#: ../src\extra\translator\translator.py:54 +msgid "Guarani" +msgstr "グアラニ語" + +#: ../src\extra\translator\translator.py:55 +msgid "Gujarati" +msgstr "グジャラート語" + +#: ../src\extra\translator\translator.py:56 +msgid "Hebrew" +msgstr "ヘブライ語" + +#: ../src\extra\translator\translator.py:57 +msgid "Hindi" +msgstr "ヒンディー語" + +#: ../src\extra\translator\translator.py:59 +msgid "Icelandic" +msgstr "アイスランド語" + +#: ../src\extra\translator\translator.py:60 +msgid "Indonesian" +msgstr "インドネシア語" + +#: ../src\extra\translator\translator.py:61 +msgid "Inuktitut" +msgstr "イヌクティトゥト語" + +#: ../src\extra\translator\translator.py:62 +msgid "Irish" +msgstr "アイリス語" + +#: ../src\extra\translator\translator.py:65 +msgid "Kannada" +msgstr "カンナダ語" + +#: ../src\extra\translator\translator.py:66 +msgid "Kazakh" +msgstr "カザフ語" + +#: ../src\extra\translator\translator.py:67 +msgid "Khmer" +msgstr "クメール語" + +#: ../src\extra\translator\translator.py:69 +msgid "Kurdish" +msgstr "クルド語" + +#: ../src\extra\translator\translator.py:70 +msgid "Kyrgyz" +msgstr "キルギス語" + +#: ../src\extra\translator\translator.py:71 +msgid "Laothian" +msgstr "ラオス語" + +#: ../src\extra\translator\translator.py:72 +msgid "Latvian" +msgstr "ラトビア語" + +#: ../src\extra\translator\translator.py:73 +msgid "Lithuanian" +msgstr "リトアニア語" + +#: ../src\extra\translator\translator.py:74 +msgid "Macedonian" +msgstr "マケドニア語" + +#: ../src\extra\translator\translator.py:75 +msgid "Malay" +msgstr "マレー語" + +#: ../src\extra\translator\translator.py:76 +msgid "Malayalam" +msgstr "マラヤーラム語" + +#: ../src\extra\translator\translator.py:77 +msgid "Maltese" +msgstr "マルタ語" + +#: ../src\extra\translator\translator.py:78 +msgid "Marathi" +msgstr "マラーティー語" + +#: ../src\extra\translator\translator.py:79 +msgid "Mongolian" +msgstr "モンゴル語" + +#: ../src\extra\translator\translator.py:80 +msgid "Nepali" +msgstr "ネパール語" + +#: ../src\extra\translator\translator.py:81 +msgid "Norwegian" +msgstr "ノルウェー語" + +#: ../src\extra\translator\translator.py:82 +msgid "Oriya" +msgstr "オリヤー語" + +#: ../src\extra\translator\translator.py:83 +msgid "Pashto" +msgstr "パシュトウ語" + +#: ../src\extra\translator\translator.py:84 +msgid "Persian" +msgstr "ペルシア語" + +#: ../src\extra\translator\translator.py:87 +msgid "Punjabi" +msgstr "パンジャブ語" + +#: ../src\extra\translator\translator.py:88 +msgid "Romanian" +msgstr "ルーマニア語" + +#: ../src\extra\translator\translator.py:90 +msgid "Sanskrit" +msgstr "サンスクリット語" + +#: ../src\extra\translator\translator.py:91 +msgid "Serbian" +msgstr "セルビア語" + +#: ../src\extra\translator\translator.py:92 +msgid "Sindhi" +msgstr "シンド語" + +#: ../src\extra\translator\translator.py:93 +msgid "Sinhalese" +msgstr "シンハラ語" + +#: ../src\extra\translator\translator.py:94 +msgid "Slovak" +msgstr "スロバキア語" + +#: ../src\extra\translator\translator.py:95 +msgid "Slovenian" +msgstr "スロベニア語" + +#: ../src\extra\translator\translator.py:97 +msgid "Swahili" +msgstr "スワヒリ語" + +#: ../src\extra\translator\translator.py:98 +msgid "Swedish" +msgstr "スウェーデン語" + +#: ../src\extra\translator\translator.py:99 +msgid "Tajik" +msgstr "タジク語" + +#: ../src\extra\translator\translator.py:100 +msgid "Tamil" +msgstr "タミル語" + +#: ../src\extra\translator\translator.py:101 +msgid "Tagalog" +msgstr "タガログ語" + +#: ../src\extra\translator\translator.py:102 +msgid "Telugu" +msgstr "テルグ語" + +#: ../src\extra\translator\translator.py:103 +msgid "Thai" +msgstr "タイ語" + +#: ../src\extra\translator\translator.py:104 +msgid "Tibetan" +msgstr "チベット語" + +#: ../src\extra\translator\translator.py:106 +msgid "Ukrainian" +msgstr "ウクライナ語" + +#: ../src\extra\translator\translator.py:107 +msgid "Urdu" +msgstr "ウルドゥー語" + +#: ../src\extra\translator\translator.py:108 +msgid "Uzbek" +msgstr "ウズベク語" + +#: ../src\extra\translator\translator.py:109 +msgid "Uighur" +msgstr "ウイグル語" + +#: ../src\extra\translator\translator.py:110 +msgid "Vietnamese" +msgstr "ベトナム語" + +#: ../src\extra\translator\translator.py:111 +msgid "Welsh" +msgstr "ウェールズ語" + +#: ../src\extra\translator\translator.py:112 +msgid "Yiddish" +msgstr "イディッシュ語" + +#: ../src\extra\translator\wx_ui.py:29 +msgid "Translate message" +msgstr "メッセージを翻訳" + +#: ../src\extra\translator\wx_ui.py:32 +msgid "Target language" +msgstr "翻訳先の言語" + +#: ../src\issueReporter\issueReporter.py:32 +#: ../src\wxUI\dialogs\configuration.py:359 +#: ../src\wxUI\dialogs\configuration.py:368 +msgid "General" +msgstr "一般" + +#: ../src\issueReporter\issueReporter.py:33 +msgid "always" +msgstr "常に" + +#: ../src\issueReporter\issueReporter.py:33 +msgid "have not tried" +msgstr "試したことがない" + +#: ../src\issueReporter\issueReporter.py:33 +msgid "random" +msgstr "ランダム" + +#: ../src\issueReporter\issueReporter.py:33 +msgid "sometimes" +msgstr "時々" + +#: ../src\issueReporter\issueReporter.py:33 +msgid "unable to duplicate" +msgstr "複製できません" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "block" +msgstr "ブロック" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "crash" +msgstr "クラッシュ" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "feature" +msgstr "特徴" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "major" +msgstr "メジャー" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "minor" +msgstr "マイナー" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "text" +msgstr "内容" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "trivial" +msgstr "些細な" + +#: ../src\issueReporter\issueReporter.py:34 +msgid "tweak" +msgstr "微調整" + +#: ../src\issueReporter\wx_ui.py:26 +msgid "Report an error" +msgstr "エラーを報告" + +#: ../src\issueReporter\wx_ui.py:29 +msgid "Select a category" +msgstr "カテゴリを選択" + +#: ../src\issueReporter\wx_ui.py:37 +msgid "" +"Briefly describe what happened. You will be able to thoroughly explain it " +"later" +msgstr "簡単な説明" + +#: ../src\issueReporter\wx_ui.py:46 +msgid "Here, you can describe the bug in detail" +msgstr "バグの詳細な説明" + +#: ../src\issueReporter\wx_ui.py:56 +msgid "how often does this bug happen?" +msgstr "このバグが起こる頻度" + +#: ../src\issueReporter\wx_ui.py:63 +msgid "Select the importance that you think this bug has" +msgstr "このバグの重要性を選択" + +#: ../src\issueReporter\wx_ui.py:70 +msgid "" +"I know that the {0} bug system will get my Twitter username to contact me " +"and fix the bug quickly" +msgstr "" +"私は、{0}のバグシステムが私に連絡して、すぐにバグを修正するために、Twitterの" +"ユーザー名を取得することを理解しています" + +#: ../src\issueReporter\wx_ui.py:73 +msgid "Send report" +msgstr "レポートを送信" + +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\wxUI\dialogs\find.py:23 +msgid "Cancel" +msgstr "キャンセル" + +#: ../src\issueReporter\wx_ui.py:84 +msgid "You must fill out both fields" +msgstr "あなたは、両方のフィールドに記入しなければなりません" + +#: ../src\issueReporter\wx_ui.py:87 +msgid "" +"You need to mark the checkbox to provide us your twitter username to contact " +"you if it is necessary." +msgstr "" +"必要な場合に連絡するため、Twitterのユーザー名を私たちに送信するために、チェッ" +"クボックスにチェックをつける必要があります。" + +#: ../src\issueReporter\wx_ui.py:90 +msgid "" +"Thanks for reporting this bug! In future versions, you may be able to find " +"it in the changes list. You've reported the bug number %i" +msgstr "" +"このバグを報告していただき、ありがとうございます!将来のバージョンでは、変更" +"のリストでそれを見つけることができるかもしれません。あなたは、バグ番号%iを報" +"しました" + +#: ../src\issueReporter\wx_ui.py:90 +msgid "reported" +msgstr "レポート完了" + +#: ../src\issueReporter\wx_ui.py:94 +msgid "Error while reporting" +msgstr "エラー" + +#: ../src\issueReporter\wx_ui.py:94 +msgid "" +"Something unexpected occurred while trying to report the bug. Please, try " +"again later" +msgstr "" +"バグの報告中に、予期しないエラーが発生しました。あとで再試行してください" + +#: ../src\keystrokeEditor\constants.py:3 +msgid "Go up in the current buffer" +msgstr "現在のバッファで、前のツイートに移動" + +#: ../src\keystrokeEditor\constants.py:4 +msgid "Go down in the current buffer" +msgstr "現在のバッファで、次のツイートに移動" + +#: ../src\keystrokeEditor\constants.py:5 +msgid "Go to the previous buffer" +msgstr "前のバッファに移動" + +#: ../src\keystrokeEditor\constants.py:6 +msgid "Go to the next buffer" +msgstr "次のバッファに移動" + +#: ../src\keystrokeEditor\constants.py:7 +msgid "Focus the next session" +msgstr "次のセッションにフォーカス" + +#: ../src\keystrokeEditor\constants.py:8 +msgid "Focus the previous session" +msgstr "前のセッションにフォーカス" + +#: ../src\keystrokeEditor\constants.py:9 +msgid "Show or hide the GUI" +msgstr "GUIの表示と非表示を切り替え" + +#: ../src\keystrokeEditor\constants.py:10 +msgid "New tweet" +msgstr "新規ツイート" + +#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 +#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 +msgid "Retweet" +msgstr "リツイート" + +#: ../src\keystrokeEditor\constants.py:13 +msgid "Send direct message" +msgstr "ダイレクトメッセージを作成" + +#: ../src\keystrokeEditor\constants.py:14 +msgid "Like a tweet" +msgstr "ツイートをいいねする" + +#: ../src\keystrokeEditor\constants.py:15 +msgid "Like/unlike a tweet" +msgstr "ツイートをいいね・いいね解除" + +#: ../src\keystrokeEditor\constants.py:16 +msgid "Unlike a tweet" +msgstr "ツイートのいいねを解除" + +#: ../src\keystrokeEditor\constants.py:17 +msgid "Open the user actions dialogue" +msgstr "ユーザーのアクションを選択する画面を表示" + +#: ../src\keystrokeEditor\constants.py:18 +msgid "See user details" +msgstr "ユーザーの詳細を表示" + +#: ../src\keystrokeEditor\constants.py:19 +msgid "Show tweet" +msgstr "ツイートを表示" + +#: ../src\keystrokeEditor\constants.py:20 +msgid "Quit" +msgstr "終了" + +#: ../src\keystrokeEditor\constants.py:21 +msgid "Open user timeline" +msgstr "特定のユーザーのタイムラインを開く" + +#: ../src\keystrokeEditor\constants.py:22 +msgid "Destroy buffer" +msgstr "現在のバッファを削除" + +#: ../src\keystrokeEditor\constants.py:23 +msgid "Interact with the currently focused tweet." +msgstr "現在フォーカス中のツイートを相呼応する。" + +#: ../src\keystrokeEditor\constants.py:24 +msgid "Open URL" +msgstr "URLを開く" + +#: ../src\keystrokeEditor\constants.py:25 +msgid "View in Twitter" +msgstr "Twitterで見る" + +#: ../src\keystrokeEditor\constants.py:26 +msgid "Increase volume by 5%" +msgstr "音量を5パーセント上げる" + +#: ../src\keystrokeEditor\constants.py:27 +msgid "Decrease volume by 5%" +msgstr "音量を5パーセント下げる" + +#: ../src\keystrokeEditor\constants.py:28 +msgid "Jump to the first element of a buffer" +msgstr "現在のバッファの先頭に移動" + +#: ../src\keystrokeEditor\constants.py:29 +msgid "Jump to the last element of the current buffer" +msgstr "現在のバッファの最後に移動" + +#: ../src\keystrokeEditor\constants.py:30 +msgid "Jump 20 elements up in the current buffer" +msgstr "20個前の要素に移動" + +#: ../src\keystrokeEditor\constants.py:31 +msgid "Jump 20 elements down in the current buffer" +msgstr "20個先の要素に移動" + +#: ../src\keystrokeEditor\constants.py:32 +msgid "Edit profile" +msgstr "プロフィールを編集" + +#: ../src\keystrokeEditor\constants.py:33 +msgid "Delete a tweet or direct message" +msgstr "ツイートまたはダイレクトメッセージを削除" + +#: ../src\keystrokeEditor\constants.py:34 +msgid "Empty the current buffer" +msgstr "現在のバッファをクリア" + +#: ../src\keystrokeEditor\constants.py:35 +msgid "Repeat last item" +msgstr "現在のアイテムをもう一度読み上げ" + +#: ../src\keystrokeEditor\constants.py:36 +msgid "Copy to clipboard" +msgstr "クリップボードにコピー" + +#: ../src\keystrokeEditor\constants.py:37 +msgid "Add to list" +msgstr "リストに追加" + +#: ../src\keystrokeEditor\constants.py:38 +msgid "Remove from list" +msgstr "リストから削除" + +#: ../src\keystrokeEditor\constants.py:39 +msgid "Mute/unmute the active buffer" +msgstr "現在のバッファのミュートを切り替え" + +#: ../src\keystrokeEditor\constants.py:40 +msgid "Mute/unmute the current session" +msgstr "現在のセッションのミュートを切り替え" + +#: ../src\keystrokeEditor\constants.py:41 +msgid "toggle the automatic reading of incoming tweets in the active buffer" +msgstr "新着のツイートを自動で読み上げるかどうかを設定" + +#: ../src\keystrokeEditor\constants.py:42 +msgid "Search on twitter" +msgstr "Twitterを検索" + +#: ../src\keystrokeEditor\constants.py:43 +msgid "Find a string in the currently focused buffer" +msgstr "現在のバッファ内の文字列を検索" + +#: ../src\keystrokeEditor\constants.py:44 +msgid "Show the keystroke editor" +msgstr "キーストロークエディタを表示" + +#: ../src\keystrokeEditor\constants.py:45 +msgid "Show lists for a specified user" +msgstr "特定のユーザーのリストを表示" + +#: ../src\keystrokeEditor\constants.py:46 +msgid "load previous items" +msgstr "以前のアイテムを取得" + +#: ../src\keystrokeEditor\constants.py:47 +msgid "Get geolocation" +msgstr "位置情報を取得" + +#: ../src\keystrokeEditor\constants.py:48 +msgid "Display the tweet's geolocation in a dialog" +msgstr "位置情報を表示" + +#: ../src\keystrokeEditor\constants.py:49 +msgid "Create a trending topics buffer" +msgstr "トレンドのバッファを作成" + +#: ../src\keystrokeEditor\constants.py:50 +msgid "View conversation" +msgstr "会話を見る" + +#: ../src\keystrokeEditor\constants.py:51 +msgid "Check and download updates" +msgstr "アップデートをチェックしてダウンロード" + +#: ../src\keystrokeEditor\constants.py:52 +msgid "" +"Opens the list manager, which allows you to create, edit, delete and open " +"lists in buffers." +msgstr "" +"リストを作成したり、編集したり、削除したりするために「リストの管理」を開く。" + +#: ../src\keystrokeEditor\constants.py:53 +msgid "Opens the global settings dialogue" +msgstr "「全般設定」ダイアログを開く" + +#: ../src\keystrokeEditor\constants.py:54 +msgid "Opens the list manager" +msgstr "リストの管理" + +#: ../src\keystrokeEditor\constants.py:55 +msgid "Opens the account settings dialogue" +msgstr "「アカウント設定」ダイアログを開く" + +#: ../src\keystrokeEditor\constants.py:56 +msgid "Try to play an audio file" +msgstr "音声ファイルの再生" + +#: ../src\keystrokeEditor\constants.py:57 +msgid "Updates the buffer and retrieves possible lost items there." +msgstr "バッファを更新して、取得に失敗したアイテムを取得。" + +#: ../src\keystrokeEditor\constants.py:58 +msgid "Extracts the text from a picture and displays the result in a dialog." +msgstr "画像からテキストを抽出して、結果をダイアログで表示。" + +#: ../src\keystrokeEditor\constants.py:59 +msgid "Adds an alias to an user" +msgstr "ユーザーにエイリアスを追加" + +#: ../src\keystrokeEditor\wx_ui.py:8 +msgid "Keystroke editor" +msgstr "キーストロークエディタ" + +#: ../src\keystrokeEditor\wx_ui.py:12 +msgid "Select a keystroke to edit" +msgstr "編集するキーストロークを選択" + +#: ../src\keystrokeEditor\wx_ui.py:13 +msgid "Keystroke" +msgstr "キーストローク" + +#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:10 +#: ../src\wxUI\dialogs\userActions.py:19 ../src\wxUI\dialogs\userActions.py:20 +msgid "Action" +msgstr "操作" + +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 +msgid "Edit" +msgstr "編集" + +#: ../src\keystrokeEditor\wx_ui.py:20 ../src\keystrokeEditor\wx_ui.py:50 +msgid "Undefine keystroke" +msgstr "キーストロークの定義を解除" + +#: ../src\keystrokeEditor\wx_ui.py:21 +msgid "Execute action" +msgstr "現在の動作を実行" + +#: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 +#: ../src\wxUI\dialogs\userAliasDialogs.py:25 ../src\wxUI\dialogs\utils.py:39 +msgid "Close" +msgstr "閉じる" + +#: ../src\keystrokeEditor\wx_ui.py:42 +msgid "Undefined" +msgstr "未定義" + +#: ../src\keystrokeEditor\wx_ui.py:50 +msgid "Are you sure you want to undefine this keystroke?" +msgstr "このキーストロークの定義を解除してもよろしいですか?" + +#: ../src\keystrokeEditor\wx_ui.py:54 +msgid "Editing keystroke" +msgstr "キーストロークを編集" + +#: ../src\keystrokeEditor\wx_ui.py:57 +msgid "Control" +msgstr "コントロール" + +#: ../src\keystrokeEditor\wx_ui.py:58 +msgid "Alt" +msgstr "オルト" + +#: ../src\keystrokeEditor\wx_ui.py:59 +msgid "Shift" +msgstr "シフト" + +#: ../src\keystrokeEditor\wx_ui.py:60 +msgid "Windows" +msgstr "ウィンドウズ" + +#: ../src\keystrokeEditor\wx_ui.py:66 +msgid "Key" +msgstr "キー名" + +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 +#: ../src\wxUI\dialogs\utils.py:36 +msgid "OK" +msgstr "OK" + +#: ../src\keystrokeEditor\wx_ui.py:84 +msgid "You need to use the Windows key" +msgstr "ウィンドウズキーを使用する必要があります" + +#: ../src\keystrokeEditor\wx_ui.py:84 ../src\keystrokeEditor\wx_ui.py:87 +msgid "Invalid keystroke" +msgstr "無効なキーストローク" + +#: ../src\keystrokeEditor\wx_ui.py:87 +msgid "You must provide a character for the keystroke" +msgstr "キー名が入力されていません" + +#: ../src\languageHandler.py:99 msgid "User default" msgstr "ユーザーのデフォルト" -#: src\main.py:120 +#: ../src\main.py:120 msgid "https://twblue.es/donate" msgstr "https://twblue.es/donate" -#: src\main.py:137 -#, python-brace-format +#: ../src\main.py:137 msgid "" "{0} is already running. Close the other instance before starting this one. " "If you're sure that {0} isn't running, try deleting the file at {1}. If " @@ -38,1848 +1856,43 @@ msgstr "" "削除してみてください。これを行う方法がわからない場合は、{0}開発者に連絡してく" "ださい。" -#: src\sound.py:146 src\extra\AudioUploader\audioUploader.py:136 -msgid "Playing..." -msgstr "再生中…" - -#: src\sound.py:159 -msgid "Stopped." -msgstr "停止。" - -#: src\controller\attach.py:25 -msgid "Photo" -msgstr "画像" - -#: src\controller\mainController.py:272 -msgid "Ready" -msgstr "準備完了" - -#: src\controller\mainController.py:305 src\controller\settings.py:285 -#: src\controller\buffers\twitterBuffers.py:70 -msgid "Home" -msgstr "ホーム" - -#: src\controller\mainController.py:309 src\controller\settings.py:286 -#: src\controller\buffers\twitterBuffers.py:70 -msgid "Mentions" -msgstr "メンション" - -#: src\controller\mainController.py:313 -#: src\controller\buffers\twitterBuffers.py:70 -msgid "Direct messages" -msgstr "ダイレクトメッセージ" - -#: src\controller\mainController.py:317 src\controller\settings.py:288 -#: src\controller\buffers\twitterBuffers.py:70 -msgid "Sent direct messages" -msgstr "送信済みのダイレクトメッセージ" - -#: src\controller\mainController.py:321 src\controller\settings.py:289 -#: src\controller\buffers\twitterBuffers.py:70 -msgid "Sent tweets" -msgstr "送信済みのツイート" - -#: src\controller\mainController.py:325 src\controller\mainController.py:1362 -#: src\controller\settings.py:290 src\controller\buffers\twitterBuffers.py:70 -msgid "Likes" -msgstr "いいね" - -#: src\controller\mainController.py:329 src\controller\mainController.py:1367 -#: src\controller\settings.py:291 src\controller\buffers\twitterBuffers.py:70 -msgid "Followers" -msgstr "フォロワー" - -#: src\controller\mainController.py:333 src\controller\mainController.py:1372 -#: src\controller\settings.py:292 src\controller\buffers\twitterBuffers.py:70 -msgid "Friends" -msgstr "フォロー" - -#: src\controller\mainController.py:337 src\controller\mainController.py:1377 -#: src\controller\settings.py:293 src\controller\buffers\twitterBuffers.py:70 -msgid "Blocked users" -msgstr "ブロックしたユーザー" - -#: src\controller\mainController.py:341 src\controller\mainController.py:1382 -#: src\controller\settings.py:294 src\controller\buffers\twitterBuffers.py:70 -msgid "Muted users" -msgstr "ミューとしたユーザー" - -#: src\controller\mainController.py:344 -msgid "Timelines" -msgstr "タイムライン" - -#: src\controller\mainController.py:348 src\controller\mainController.py:859 -#: src\controller\mainController.py:1558 -msgid "Timeline for {}" -msgstr "「{}」のタイムライン" - -#: src\controller\mainController.py:351 -msgid "Likes timelines" -msgstr "ほかのユーザーのいいね一覧" - -#: src\controller\mainController.py:355 src\controller\mainController.py:878 -#: src\controller\mainController.py:1560 -msgid "Likes for {}" -msgstr "{}のいいね一覧" - -#: src\controller\mainController.py:358 -msgid "Followers' Timelines" -msgstr "フォロワー一覧" - -#: src\controller\mainController.py:362 src\controller\mainController.py:897 -#: src\controller\mainController.py:1562 -msgid "Followers for {}" -msgstr "{}をフォローしているユーザー" - -#: src\controller\mainController.py:365 -msgid "Friends' Timelines" -msgstr "フォロー一覧" - -#: src\controller\mainController.py:369 src\controller\mainController.py:916 -#: src\controller\mainController.py:1564 -msgid "Friends for {}" -msgstr "{}がフォローしているユーザー" - -#: src\controller\mainController.py:372 src\wxUI\dialogs\lists.py:13 -msgid "Lists" -msgstr "リスト" - -#: src\controller\mainController.py:377 src\controller\mainController.py:1398 -msgid "List for {}" -msgstr "{}のリスト" - -#: src\controller\mainController.py:380 -msgid "Searches" -msgstr "検索" - -#: src\controller\mainController.py:384 src\controller\mainController.py:443 -msgid "Search for {}" -msgstr "「{}」の検索結果" - -#: src\controller\mainController.py:390 src\controller\mainController.py:958 -#, python-format -msgid "Trending topics for %s" -msgstr "%s のトレンド" - -#: src\controller\mainController.py:460 src\controller\mainController.py:476 -#: src\controller\mainController.py:1058 src\controller\mainController.py:1077 -#: src\controller\mainController.py:1096 src\controller\mainController.py:1115 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "" -"セッションが選択されていません。「次のセッション」または「前のセッション」の" -"ショートカットを利用して、セッションを選択してください。" - -#: src\controller\mainController.py:464 -msgid "Empty buffer." -msgstr "からのバッファ。" - -#: src\controller\mainController.py:471 -#, python-brace-format -msgid "{0} not found." -msgstr "{0}が見つかりませんでした。" - -#: src\controller\mainController.py:481 -msgid "Filters cannot be applied on this buffer" -msgstr "このバッファにはフィルターを適応できません" - -#: src\controller\mainController.py:534 src\controller\mainController.py:551 -#: src\controller\mainController.py:579 -msgid "Select the user" -msgstr "ユーザーを選択" - -#: src\controller\mainController.py:808 src\controller\messages.py:242 -msgid "MMM D, YYYY. H:m" -msgstr "YYYY年MMMMD日 H時m分" - -#: src\controller\mainController.py:933 -#, python-brace-format -msgid "Conversation with {0}" -msgstr "{0}との会話" - -#: src\controller\mainController.py:974 src\controller\mainController.py:993 -msgid "There are no coordinates in this tweet" -msgstr "このツイートに位置情報は存在しません" - -#: src\controller\mainController.py:976 src\controller\mainController.py:995 -msgid "There are no results for the coordinates in this tweet" -msgstr "このツイートの位置情報には、なにも含まれていません" - -#: src\controller\mainController.py:978 src\controller\mainController.py:997 -msgid "Error decoding coordinates. Try again later." -msgstr "位置情報の取得に失敗しました。あとで再試行してください。" - -#: src\controller\mainController.py:1106 src\controller\mainController.py:1125 -#, python-format -msgid "%s, %s of %s" -msgstr "%s %s/%s" - -#: src\controller\mainController.py:1108 src\controller\mainController.py:1127 -#: src\controller\mainController.py:1152 src\controller\mainController.py:1177 -#, python-format -msgid "%s. Empty" -msgstr "%sは、からです" - -#: src\controller\mainController.py:1140 src\controller\mainController.py:1144 -#: src\controller\mainController.py:1165 -#, python-brace-format -msgid "{0}: This account is not logged into Twitter." -msgstr "{0}: このアカウントは、まだTwitterにログインしていません。" - -#: src\controller\mainController.py:1150 src\controller\mainController.py:1175 -#, python-format -msgid "%s. %s, %s of %s" -msgstr "セッション:%s %s %s/%s" - -#: src\controller\mainController.py:1169 -#, python-brace-format -msgid "{0}: This account is not logged into twitter." -msgstr "{0}: このアカウントは、まだTwitterにログインしていません。" - -#: src\controller\mainController.py:1387 -msgid "Events" -msgstr "イベント" - -#: src\controller\mainController.py:1392 -msgid "This list is already opened" -msgstr "既に開かれています" - -#: src\controller\mainController.py:1422 src\controller\mainController.py:1438 -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "" -"サーバーへの接続中に、予期しないエラーが発生しました。あとで再試行してくださ" -"い。" - -#: src\controller\mainController.py:1474 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "自動読み上げ 有効" - -#: src\controller\mainController.py:1477 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "自動読み上げ 無効" - -#: src\controller\mainController.py:1484 -msgid "Session mute on" -msgstr "このセッションのミュートを設定" - -#: src\controller\mainController.py:1487 -msgid "Session mute off" -msgstr "このセッションのミュートを解除" - -#: src\controller\mainController.py:1495 -msgid "Buffer mute on" -msgstr "このバッファのミュートを設定" - -#: src\controller\mainController.py:1498 -msgid "Buffer mute off" -msgstr "このバッファのミュートを解除" - -#: src\controller\mainController.py:1521 -msgid "Copied" -msgstr "コピーしました" - -#: src\controller\mainController.py:1548 -msgid "Unable to update this buffer." -msgstr "このバッファを更新できません。" - -#: src\controller\mainController.py:1551 -msgid "Updating buffer..." -msgstr "バッファを更新中…" - -#: src\controller\mainController.py:1554 -#, python-brace-format -msgid "{0} items retrieved" -msgstr "{0}個のアイテムを取得しました" - -#: src\controller\mainController.py:1571 src\controller\mainController.py:1591 -msgid "Invalid buffer" -msgstr "無効なバッファ" - -#: src\controller\mainController.py:1582 -#, python-brace-format -msgid "Picture {0}" -msgstr "画像{0}" - -#: src\controller\mainController.py:1583 -msgid "Select the picture" -msgstr "画像を選択" - -#: src\controller\mainController.py:1602 -msgid "Unable to extract text" -msgstr "テキストを抽出できません" - -#: src\controller\messages.py:53 -msgid "Translated" -msgstr "翻訳完了" - -#: src\controller\messages.py:60 -msgid "There's no URL to be shortened" -msgstr "短縮されたURLは、ありません" - -#: src\controller\messages.py:64 src\controller\messages.py:72 -msgid "URL shortened" -msgstr "URLを短縮しました" - -#: src\controller\messages.py:79 -msgid "There's no URL to be expanded" -msgstr "短縮を解除するURLはありません" - -#: src\controller\messages.py:83 src\controller\messages.py:91 -msgid "URL expanded" -msgstr "URLの短縮を解除しました" - -#: src\controller\messages.py:105 -#, python-format -msgid "%s - %s of %d characters" -msgstr "%s - %s/%d" - -#: src\controller\messages.py:109 -#, python-format -msgid "%s - %s characters" -msgstr "%s - %s文字" - -#: src\controller\messages.py:197 src\controller\buffers\twitterBuffers.py:459 -#, python-format -msgid "Direct message to %s" -msgstr "「%s」へのダイレクトメッセージ" - -#: src\controller\messages.py:211 src\controller\buffers\twitterBuffers.py:88 -#: src\controller\buffers\twitterBuffers.py:1218 src\wxUI\sysTrayIcon.py:35 -#: src\wxUI\buffers\base.py:25 src\wxUI\buffers\events.py:15 -#: src\wxUI\buffers\trends.py:18 src\wxUI\dialogs\message.py:306 -msgid "Tweet" -msgstr "ツイート" - -#: src\controller\messages.py:269 -msgid "View item" -msgstr "アイテムを見る" - -#: src\controller\settings.py:77 -msgid "System default" -msgstr "システムのデフォルト" - -#: src\controller\settings.py:77 -msgid "HTTP" -msgstr "HTTP" - -#: src\controller\settings.py:77 -msgid "SOCKS v4" -msgstr "SOCKS v4" - -#: src\controller\settings.py:77 -msgid "SOCKS v4 with DNS support" -msgstr "DNSをサポートする SOCKS v4" - -#: src\controller\settings.py:77 -msgid "SOCKS v5" -msgstr "SOCKS v5" - -#: src\controller\settings.py:77 -msgid "SOCKS v5 with DNS support" -msgstr "DNSをサポートする SOCKS v5" - -#: src\controller\settings.py:148 src\controller\settings.py:210 -#: src\wxUI\dialogs\configuration.py:119 -msgid "Ask" -msgstr "その都度、質問する" - -#: src\controller\settings.py:150 src\controller\settings.py:212 -#: src\wxUI\dialogs\configuration.py:119 -msgid "Retweet without comments" -msgstr "コメントを付けずにリツイート(公式RT)" - -#: src\controller\settings.py:152 src\wxUI\dialogs\configuration.py:119 -msgid "Retweet with comments" -msgstr "コメントをつけてリツイート(非公式RT)" - -#: src\controller\settings.py:187 -#, python-format -msgid "Account settings for %s" -msgstr "%sのアカウント設定" - -#: src\controller\settings.py:287 -msgid "Direct Messages" -msgstr "ダイレクトメッセージ" - -#: src\controller\user.py:29 src\wxUI\commonMessageDialogs.py:39 -msgid "That user does not exist" -msgstr "そのユーザーは存在しません" - -#: src\controller\user.py:29 src\controller\user.py:31 -#: src\extra\SpellChecker\wx_ui.py:80 src\issueReporter\wx_ui.py:84 -#: src\issueReporter\wx_ui.py:87 src\wxUI\commonMessageDialogs.py:39 -#: src\wxUI\commonMessageDialogs.py:51 src\wxUI\commonMessageDialogs.py:58 -#: src\wxUI\commonMessageDialogs.py:61 src\wxUI\commonMessageDialogs.py:64 -#: src\wxUI\commonMessageDialogs.py:67 src\wxUI\commonMessageDialogs.py:77 -#: src\wxUI\commonMessageDialogs.py:80 src\wxUI\commonMessageDialogs.py:83 -#: src\wxUI\commonMessageDialogs.py:89 src\wxUI\commonMessageDialogs.py:92 -msgid "Error" -msgstr "エラー" - -#: src\controller\user.py:31 -msgid "User has been suspended" -msgstr "ユーザーが凍結されています" - -#: src\controller\user.py:37 -#, python-format -msgid "Information for %s" -msgstr "%sの情報" - -#: src\controller\user.py:67 src\extra\AudioUploader\audioUploader.py:127 -msgid "Discarded" -msgstr "拒否されました" - -#: src\controller\user.py:95 -#, python-format -msgid "Username: @%s\n" -msgstr "ユーザー名: @%s\n" - -#: src\controller\user.py:96 -#, python-format -msgid "Name: %s\n" -msgstr "名前: %s\n" - -#: src\controller\user.py:98 -#, python-format -msgid "Location: %s\n" -msgstr "居住地: %s\n" - -#: src\controller\user.py:100 -#, python-format -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: src\controller\user.py:104 -#, python-format -msgid "Bio: %s\n" -msgstr "自己紹介: %s\n" - -#: src\controller\user.py:105 src\controller\user.py:120 -msgid "Yes" -msgstr "はい" - -#: src\controller\user.py:106 src\controller\user.py:121 -msgid "No" -msgstr "いいえ" - -#: src\controller\user.py:107 -#, python-format -msgid "Protected: %s\n" -msgstr "保護設定: %s\n" - -#: src\controller\user.py:112 -#, python-brace-format -msgid "You follow {0}. " -msgstr "{0}をフォロー。 " - -#: src\controller\user.py:115 -#, python-brace-format -msgid "{0} is following you." -msgstr "{0}がフォロー。" - -#: src\controller\user.py:119 -#, python-format -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"フォロワー: %s\n" -"フォロー: %s\n" - -#: src\controller\user.py:122 -#, python-format -msgid "Verified: %s\n" -msgstr "認証済み: %s\n" - -#: src\controller\user.py:123 -#, python-format -msgid "Tweets: %s\n" -msgstr "ツイート数: %s\n" - -#: src\controller\user.py:124 -#, python-format -msgid "Likes: %s" -msgstr "いいね数: %s" - -#: src\controller\userActionsController.py:74 -msgid "You can't ignore direct messages" -msgstr "ダイレクトメッセージを無視することはできません" - -#: src\controller\buffers\baseBuffers.py:97 -msgid "This action is not supported for this buffer" -msgstr "この動作は、現在のバッファではサポートされていません" - -#: src\controller\buffers\twitterBuffers.py:76 -#, python-brace-format -msgid "{username}'s timeline" -msgstr "「{username}」のタイムライン" - -#: src\controller\buffers\twitterBuffers.py:78 -#, python-brace-format -msgid "{username}'s likes" -msgstr "「{username}」のいいね一覧" - -#: src\controller\buffers\twitterBuffers.py:80 -#, python-brace-format -msgid "{username}'s followers" -msgstr "「{username}」のフォロワー" - -#: src\controller\buffers\twitterBuffers.py:82 -#, python-brace-format -msgid "{username}'s friends" -msgstr "「{username}」のフォロー" - -#: src\controller\buffers\twitterBuffers.py:84 -msgid "Unknown buffer" -msgstr "不明なバッファ" - -#: src\controller\buffers\twitterBuffers.py:89 -#: src\controller\buffers\twitterBuffers.py:1219 -msgid "Write the tweet here" -msgstr "ツイートを入力" - -#: src\controller\buffers\twitterBuffers.py:208 -#, python-brace-format -msgid "New tweet in {0}" -msgstr "「{0}」への新規ツイート" - -#: src\controller\buffers\twitterBuffers.py:211 -#, python-brace-format -msgid "{0} new tweets in {1}." -msgstr "「{1}」への{0}個の新規ツイート。" - -#: src\controller\buffers\twitterBuffers.py:245 -#: src\controller\buffers\twitterBuffers.py:680 -#: src\controller\buffers\twitterBuffers.py:921 -#: src\controller\buffers\twitterBuffers.py:1102 -#, python-format -msgid "%s items retrieved" -msgstr "%s個のアイテムを取得しました" - -#: src\controller\buffers\twitterBuffers.py:277 -#: src\controller\buffers\twitterBuffers.py:834 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "このバッファは、タイムラインではないため、削除できません。" - -#: src\controller\buffers\twitterBuffers.py:411 -#, python-brace-format -msgid "Reply to {arg0}" -msgstr "「{arg0}」への返信:" - -#: src\controller\buffers\twitterBuffers.py:413 -#: src\keystrokeEditor\constants.py:12 src\wxUI\buffers\base.py:27 -msgid "Reply" -msgstr "返信" - -#: src\controller\buffers\twitterBuffers.py:414 -#, python-format -msgid "Reply to %s" -msgstr "「%s」への返信" - -#: src\controller\buffers\twitterBuffers.py:459 -#: src\controller\buffers\twitterBuffers.py:723 -msgid "New direct message" -msgstr "新しいダイレクトメッセージ" - -#: src\controller\buffers\twitterBuffers.py:497 -msgid "Quote" -msgstr "引用" - -#: src\controller\buffers\twitterBuffers.py:497 -msgid "Add your comment to the tweet" -msgstr "ツイートにコメントを追加" - -#: src\controller\buffers\twitterBuffers.py:569 -msgid "Opening URL..." -msgstr "URLを開いています…" - -#: src\controller\buffers\twitterBuffers.py:604 -msgid "User details" -msgstr "ユーザーの詳細" - -#: src\controller\buffers\twitterBuffers.py:620 -#: src\controller\buffers\twitterBuffers.py:998 -msgid "Opening item in web browser..." -msgstr "ブラウザでアイテムを開いています…" - -#: src\controller\buffers\twitterBuffers.py:686 -#: src\controller\buffers\twitterBuffers.py:849 src\wxUI\buffers\people.py:17 -msgid "Mention" -msgstr "メンション" - -#: src\controller\buffers\twitterBuffers.py:686 -#: src\controller\buffers\twitterBuffers.py:849 -#, python-format -msgid "Mention to %s" -msgstr "%sへのメンション" - -#: src\controller\buffers\twitterBuffers.py:726 -#, python-brace-format -msgid "{0} new direct messages." -msgstr "{0}件の新しいダイレクトメッセージ。" - -#: src\controller\buffers\twitterBuffers.py:729 -msgid "This action is not supported in the buffer yet." -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: src\controller\buffers\twitterBuffers.py:739 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" -"このバッファでは、さらにアイテムを取得することはできません。代わりにダイレク" -"トメッセージバッファを使用してください。" - -#: src\controller\buffers\twitterBuffers.py:994 -#, python-brace-format -msgid "{0} new followers." -msgstr "{0}人の新しいフォロワー。" - -#: src\controller\buffers\twitterBuffers.py:1242 -msgid "This action is not supported in the buffer, yet." -msgstr "この動作は、現在のバッファではサポートされていません。" - -#: src\extra\AudioUploader\audioUploader.py:57 -msgid "Attaching..." -msgstr "添付中…" - -#: src\extra\AudioUploader\audioUploader.py:74 -msgid "Pause" -msgstr "一時停止" - -#: src\extra\AudioUploader\audioUploader.py:76 -msgid "&Resume" -msgstr "再開(&R)" - -#: src\extra\AudioUploader\audioUploader.py:77 -msgid "Resume" -msgstr "再開" - -#: src\extra\AudioUploader\audioUploader.py:79 -#: src\extra\AudioUploader\audioUploader.py:106 -#: src\extra\AudioUploader\wx_ui.py:37 -msgid "&Pause" -msgstr "一時停止(&P)" - -#: src\extra\AudioUploader\audioUploader.py:94 -#: src\extra\AudioUploader\audioUploader.py:140 -msgid "&Stop" -msgstr "停止(&S)" - -#: src\extra\AudioUploader\audioUploader.py:95 -msgid "Recording" -msgstr "録音中" - -#: src\extra\AudioUploader\audioUploader.py:100 -#: src\extra\AudioUploader\audioUploader.py:151 -msgid "Stopped" -msgstr "停止" - -#: src\extra\AudioUploader\audioUploader.py:102 -#: src\extra\AudioUploader\wx_ui.py:39 -msgid "&Record" -msgstr "録音(&R)" - -#: src\extra\AudioUploader\audioUploader.py:144 -#: src\extra\AudioUploader\audioUploader.py:154 -#: src\extra\AudioUploader\wx_ui.py:35 -msgid "&Play" -msgstr "再生(&P)" - -#: src\extra\AudioUploader\audioUploader.py:159 -msgid "Recoding audio..." -msgstr "音声を録音中…" - -#: src\extra\AudioUploader\transfer.py:82 -#: src\extra\AudioUploader\transfer.py:88 -#, python-brace-format -msgid "Error in file upload: {0}" -msgstr "ファイルアップロードエラー: {0}" - -#: src\extra\AudioUploader\utils.py:29 src\update\utils.py:29 -#, python-format -msgid "%d day, " -msgstr "%d日 " - -#: src\extra\AudioUploader\utils.py:31 src\update\utils.py:31 -#, python-format -msgid "%d days, " -msgstr "%d日 " - -#: src\extra\AudioUploader\utils.py:33 src\update\utils.py:33 -#, python-format -msgid "%d hour, " -msgstr "%d時間 " - -#: src\extra\AudioUploader\utils.py:35 src\update\utils.py:35 -#, python-format -msgid "%d hours, " -msgstr "%d時間 " - -#: src\extra\AudioUploader\utils.py:37 src\update\utils.py:37 -#, python-format -msgid "%d minute, " -msgstr "%d分 " - -#: src\extra\AudioUploader\utils.py:39 src\update\utils.py:39 -#, python-format -msgid "%d minutes, " -msgstr "%d分 " - -#: src\extra\AudioUploader\utils.py:41 src\update\utils.py:41 -#, python-format -msgid "%s second" -msgstr "%s秒" - -#: src\extra\AudioUploader\utils.py:43 src\update\utils.py:43 -#, python-format -msgid "%s seconds" -msgstr "%s秒" - -#: src\extra\AudioUploader\wx_transfer_dialogs.py:15 -msgid "File" -msgstr "ファイル" - -#: src\extra\AudioUploader\wx_transfer_dialogs.py:21 -msgid "Transferred" -msgstr "転送済み" - -#: src\extra\AudioUploader\wx_transfer_dialogs.py:26 -msgid "Total file size" -msgstr "合計サイズ" - -#: src\extra\AudioUploader\wx_transfer_dialogs.py:31 -msgid "Transfer rate" -msgstr "転送速度" - -#: src\extra\AudioUploader\wx_transfer_dialogs.py:36 -msgid "Time left" -msgstr "残り時間" - -#: src\extra\AudioUploader\wx_ui.py:29 -msgid "Attach audio" -msgstr "音声を添付" - -#: src\extra\AudioUploader\wx_ui.py:41 -msgid "&Add an existing file" -msgstr "既存のファイルを追加(&A)" - -#: src\extra\AudioUploader\wx_ui.py:42 -msgid "&Discard" -msgstr "拒否(&D)" - -#: src\extra\AudioUploader\wx_ui.py:44 -msgid "Upload to" -msgstr "アップロード先" - -#: src\extra\AudioUploader\wx_ui.py:49 -msgid "Attach" -msgstr "添付" - -#: src\extra\AudioUploader\wx_ui.py:51 -msgid "&Cancel" -msgstr "キャンセル(&C)" - -#: src\extra\AudioUploader\wx_ui.py:76 -msgid "Select the audio file to be uploaded" -msgstr "アップロードする音声ファイルを選択" - -#: src\extra\AudioUploader\wx_ui.py:76 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "音声ファイル (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: src\extra\autocompletionUsers\completion.py:23 -#: src\extra\autocompletionUsers\completion.py:41 -msgid "You have to start writing" -msgstr "あなたは、書き込みを開始しなければなりません" - -#: src\extra\autocompletionUsers\completion.py:33 -#: src\extra\autocompletionUsers\completion.py:50 -msgid "There are no results in your users database" -msgstr "あなたのユーザーのデータベースには、見つかりませんでした" - -#: src\extra\autocompletionUsers\completion.py:35 -msgid "Autocompletion only works for users." -msgstr "自動補完はユーザーのみで動作します。" - -#: src\extra\autocompletionUsers\settings.py:29 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"データベースの更新中… なお、このウィンドウを閉じることができます。処理が終了" -"すると、メッセージが表示されます。" - -#: src\extra\autocompletionUsers\wx_manage.py:9 -msgid "Manage Autocompletion database" -msgstr "オートコンプリートのデータベースを管理" - -#: src\extra\autocompletionUsers\wx_manage.py:12 -#, python-brace-format -msgid "Editing {0} users database" -msgstr "{0}のユーザーデータベースを編集中" - -#: src\extra\autocompletionUsers\wx_manage.py:13 -msgid "Username" -msgstr "ユーザー名" - -#: src\extra\autocompletionUsers\wx_manage.py:13 -#: src\wxUI\dialogs\configuration.py:146 -msgid "Name" -msgstr "名前" - -#: src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Add user" -msgstr "ユーザーを追加" - -#: src\extra\autocompletionUsers\wx_manage.py:17 -msgid "Remove user" -msgstr "ユーザーを削除" - -#: src\extra\autocompletionUsers\wx_manage.py:38 -msgid "Twitter username" -msgstr "Twitterのユーザー名" - -#: src\extra\autocompletionUsers\wx_manage.py:38 -msgid "Add user to database" -msgstr "データベースにユーザーを追加" - -#: src\extra\autocompletionUsers\wx_manage.py:44 -msgid "The user does not exist" -msgstr "そのユーザーは存在しません" - -#: src\extra\autocompletionUsers\wx_manage.py:44 -#: src\wxUI\commonMessageDialogs.py:45 -msgid "Error!" -msgstr "エラー!" - -#: src\extra\autocompletionUsers\wx_settings.py:9 -msgid "Autocomplete users' settings" -msgstr "オートコンプリートユーザーの設定" - -#: src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from followers buffer" -msgstr "フォロワーからユーザーを追加" - -#: src\extra\autocompletionUsers\wx_settings.py:13 -msgid "Add users from friends buffer" -msgstr "フォロー中のユーザーからユーザーを追加" - -#: src\extra\autocompletionUsers\wx_settings.py:16 -msgid "Manage database..." -msgstr "データベースの管理..." - -#: src\extra\autocompletionUsers\wx_settings.py:28 -#, python-brace-format -msgid "{0}'s database of users has been updated." -msgstr "{0}のユーザーのデータベースが更新されました。" - -#: src\extra\autocompletionUsers\wx_settings.py:28 -msgid "Done" -msgstr "完了" - -#: src\extra\ocr\OCRSpace.py:7 -msgid "Detect automatically" -msgstr "自動検出" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:33 -msgid "Danish" -msgstr "デンマーク語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:35 -msgid "Dutch" -msgstr "オランダ語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:36 -msgid "English" -msgstr "英語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:40 -msgid "Finnish" -msgstr "フィンランド語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:41 -msgid "French" -msgstr "フランス語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:44 -msgid "German" -msgstr "ドイツ語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:50 -msgid "Hungarian" -msgstr "ハンガリー語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:60 -msgid "Korean" -msgstr "韓国語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:55 -msgid "Italian" -msgstr "イタリア語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:56 -msgid "Japanese" -msgstr "日本語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:77 -msgid "Polish" -msgstr "ポーランド語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:78 -msgid "Portuguese" -msgstr "ポルトガル語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:81 -msgid "Russian" -msgstr "ロシア語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:88 -msgid "Spanish" -msgstr "スペイン語" - -#: src\extra\ocr\OCRSpace.py:7 src\extra\translator\translator.py:97 -msgid "Turkish" -msgstr "トルコ語" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "Audio tweet." -msgstr "音声付きツイート。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "User timeline buffer created." -msgstr "ユーザーのタイムラインのバッファを作成。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Buffer destroied." -msgstr "バッファを削除。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message received." -msgstr "ダイレクトメッセージを受信。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Direct message sent." -msgstr "ダイレクトメッセージを送信。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Error." -msgstr "エラー。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Tweet liked." -msgstr "ツイートがいいねされた。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Likes buffer updated." -msgstr "いいねバッファが更新された。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Geotweet." -msgstr "位置情報付きのツイート。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Tweet contains one or more images" -msgstr "ツイートに1つ以上の画像が含まれています" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "Boundary reached." -msgstr "先頭または最後のツイート。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "List updated." -msgstr "リストが更新された。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Too many characters." -msgstr "文字数オーバー。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "Mention received." -msgstr "リプライを受信した。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "New event." -msgstr "新しいイベント。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -#, python-brace-format -msgid "{0} is ready." -msgstr "{0}の準備完了。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Mention sent." -msgstr "リプライを送信した。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Tweet retweeted." -msgstr "ツイートをリツイートした。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Search buffer updated." -msgstr "検索バッファが更新された。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet received." -msgstr "ツイートを受信した。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Tweet sent." -msgstr "ツイートを送信した。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "Trending topics buffer updated." -msgstr "トレンドのバッファが更新された。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New tweet in user timeline buffer." -msgstr "ユーザーのタイムラインに新しいツイートを受信した。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "New follower." -msgstr "新しいフォロワー。" - -#: src\extra\SoundsTutorial\soundsTutorial_constants.py:31 -msgid "Volume changed." -msgstr "ボリュームを変更した。" - -#: src\extra\SoundsTutorial\wx_ui.py:9 -msgid "Sounds tutorial" -msgstr "サウンドの確認" - -#: src\extra\SoundsTutorial\wx_ui.py:12 -msgid "Press enter to listen to the sound for the selected event" -msgstr "選択されたイベントのサウンドを再生するには、Enterキーを押してください" - -#: src\extra\SpellChecker\spellchecker.py:60 -#, python-format -msgid "Misspelled word: %s" -msgstr "「%s」はスペルが間違っています" - -#: src\extra\SpellChecker\wx_ui.py:28 -msgid "Misspelled word" -msgstr "スペルミスの単語" - -#: src\extra\SpellChecker\wx_ui.py:33 -msgid "Context" -msgstr "コンテキスト" - -#: src\extra\SpellChecker\wx_ui.py:38 -msgid "Suggestions" -msgstr "提案" - -#: src\extra\SpellChecker\wx_ui.py:43 -msgid "&Ignore" -msgstr "無視(&I)" - -#: src\extra\SpellChecker\wx_ui.py:44 -msgid "I&gnore all" -msgstr "すべて無視(&G)" - -#: src\extra\SpellChecker\wx_ui.py:45 -msgid "&Replace" -msgstr "置き換え(&R)" - -#: src\extra\SpellChecker\wx_ui.py:46 -msgid "R&eplace all" -msgstr "すべて置き換え(&E)" - -#: src\extra\SpellChecker\wx_ui.py:47 -msgid "&Add to personal dictionary" -msgstr "個人辞書に追加(&A)" - -#: src\extra\SpellChecker\wx_ui.py:80 -#, python-brace-format -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "エラーが発生しました。{0}で選択した言語用の辞書がありません" - -#: src\extra\SpellChecker\wx_ui.py:83 -msgid "Spell check complete." -msgstr "スペルチェックが完了しました。" - -#: src\extra\translator\translator.py:14 -msgid "Afrikaans" -msgstr "アフリカ語" - -#: src\extra\translator\translator.py:15 -msgid "Albanian" -msgstr "アルバニア語" - -#: src\extra\translator\translator.py:16 -msgid "Amharic" -msgstr "アムハラ語" - -#: src\extra\translator\translator.py:17 -msgid "Arabic" -msgstr "アラビア語" - -#: src\extra\translator\translator.py:18 -msgid "Armenian" -msgstr "アルメニア語" - -#: src\extra\translator\translator.py:19 -msgid "Azerbaijani" -msgstr "アゼルバイジャン語" - -#: src\extra\translator\translator.py:20 -msgid "Basque" -msgstr "バスク語" - -#: src\extra\translator\translator.py:21 -msgid "Belarusian" -msgstr "ベラルーシ語" - -#: src\extra\translator\translator.py:22 -msgid "Bengali" -msgstr "ベンガル語" - -#: src\extra\translator\translator.py:23 -msgid "Bihari" -msgstr "ビハール語" - -#: src\extra\translator\translator.py:24 -msgid "Bulgarian" -msgstr "ブルガリア語" - -#: src\extra\translator\translator.py:25 -msgid "Burmese" -msgstr "ビルマ語" - -#: src\extra\translator\translator.py:26 -msgid "Catalan" -msgstr "カタロニア語" - -#: src\extra\translator\translator.py:27 -msgid "Cherokee" -msgstr "チェロキー語" - -#: src\extra\translator\translator.py:28 -msgid "Chinese" -msgstr "中国語" - -#: src\extra\translator\translator.py:29 -msgid "Chinese_simplified" -msgstr "簡体字中国語" - -#: src\extra\translator\translator.py:30 -msgid "Chinese_traditional" -msgstr "繁体字中国語" - -#: src\extra\translator\translator.py:31 -msgid "Croatian" -msgstr "クロアチア語" - -#: src\extra\translator\translator.py:32 -msgid "Czech" -msgstr "チェコ語" - -#: src\extra\translator\translator.py:34 -msgid "Dhivehi" -msgstr "ディベヒ語" - -#: src\extra\translator\translator.py:37 -msgid "Esperanto" -msgstr "エスペラント語" - -#: src\extra\translator\translator.py:38 -msgid "Estonian" -msgstr "エストニア語" - -#: src\extra\translator\translator.py:39 -msgid "Filipino" -msgstr "フィリピン語" - -#: src\extra\translator\translator.py:42 -msgid "Galician" -msgstr "ガリシア語" - -#: src\extra\translator\translator.py:43 -msgid "Georgian" -msgstr "ジョージア語" - -#: src\extra\translator\translator.py:45 -msgid "Greek" -msgstr "ギリシャ語" - -#: src\extra\translator\translator.py:46 -msgid "Guarani" -msgstr "グアラニ語" - -#: src\extra\translator\translator.py:47 -msgid "Gujarati" -msgstr "グジャラート語" - -#: src\extra\translator\translator.py:48 -msgid "Hebrew" -msgstr "ヘブライ語" - -#: src\extra\translator\translator.py:49 -msgid "Hindi" -msgstr "ヒンディー語" - -#: src\extra\translator\translator.py:51 -msgid "Icelandic" -msgstr "アイスランド語" - -#: src\extra\translator\translator.py:52 -msgid "Indonesian" -msgstr "インドネシア語" - -#: src\extra\translator\translator.py:53 -msgid "Inuktitut" -msgstr "イヌクティトゥト語" - -#: src\extra\translator\translator.py:54 -msgid "Irish" -msgstr "アイリス語" - -#: src\extra\translator\translator.py:57 -msgid "Kannada" -msgstr "カンナダ語" - -#: src\extra\translator\translator.py:58 -msgid "Kazakh" -msgstr "カザフ語" - -#: src\extra\translator\translator.py:59 -msgid "Khmer" -msgstr "クメール語" - -#: src\extra\translator\translator.py:61 -msgid "Kurdish" -msgstr "クルド語" - -#: src\extra\translator\translator.py:62 -msgid "Kyrgyz" -msgstr "キルギス語" - -#: src\extra\translator\translator.py:63 -msgid "Laothian" -msgstr "ラオス語" - -#: src\extra\translator\translator.py:64 -msgid "Latvian" -msgstr "ラトビア語" - -#: src\extra\translator\translator.py:65 -msgid "Lithuanian" -msgstr "リトアニア語" - -#: src\extra\translator\translator.py:66 -msgid "Macedonian" -msgstr "マケドニア語" - -#: src\extra\translator\translator.py:67 -msgid "Malay" -msgstr "マレー語" - -#: src\extra\translator\translator.py:68 -msgid "Malayalam" -msgstr "マラヤーラム語" - -#: src\extra\translator\translator.py:69 -msgid "Maltese" -msgstr "マルタ語" - -#: src\extra\translator\translator.py:70 -msgid "Marathi" -msgstr "マラーティー語" - -#: src\extra\translator\translator.py:71 -msgid "Mongolian" -msgstr "モンゴル語" - -#: src\extra\translator\translator.py:72 -msgid "Nepali" -msgstr "ネパール語" - -#: src\extra\translator\translator.py:73 -msgid "Norwegian" -msgstr "ノルウェー語" - -#: src\extra\translator\translator.py:74 -msgid "Oriya" -msgstr "オリヤー語" - -#: src\extra\translator\translator.py:75 -msgid "Pashto" -msgstr "パシュトウ語" - -#: src\extra\translator\translator.py:76 -msgid "Persian" -msgstr "ペルシア語" - -#: src\extra\translator\translator.py:79 -msgid "Punjabi" -msgstr "パンジャブ語" - -#: src\extra\translator\translator.py:80 -msgid "Romanian" -msgstr "ルーマニア語" - -#: src\extra\translator\translator.py:82 -msgid "Sanskrit" -msgstr "サンスクリット語" - -#: src\extra\translator\translator.py:83 -msgid "Serbian" -msgstr "セルビア語" - -#: src\extra\translator\translator.py:84 -msgid "Sindhi" -msgstr "シンド語" - -#: src\extra\translator\translator.py:85 -msgid "Sinhalese" -msgstr "シンハラ語" - -#: src\extra\translator\translator.py:86 -msgid "Slovak" -msgstr "スロバキア語" - -#: src\extra\translator\translator.py:87 -msgid "Slovenian" -msgstr "スロベニア語" - -#: src\extra\translator\translator.py:89 -msgid "Swahili" -msgstr "スワヒリ語" - -#: src\extra\translator\translator.py:90 -msgid "Swedish" -msgstr "スウェーデン語" - -#: src\extra\translator\translator.py:91 -msgid "Tajik" -msgstr "タジク語" - -#: src\extra\translator\translator.py:92 -msgid "Tamil" -msgstr "タミル語" - -#: src\extra\translator\translator.py:93 -msgid "Tagalog" -msgstr "タガログ語" - -#: src\extra\translator\translator.py:94 -msgid "Telugu" -msgstr "テルグ語" - -#: src\extra\translator\translator.py:95 -msgid "Thai" -msgstr "タイ語" - -#: src\extra\translator\translator.py:96 -msgid "Tibetan" -msgstr "チベット語" - -#: src\extra\translator\translator.py:98 -msgid "Ukrainian" -msgstr "ウクライナ語" - -#: src\extra\translator\translator.py:99 -msgid "Urdu" -msgstr "ウルドゥー語" - -#: src\extra\translator\translator.py:100 -msgid "Uzbek" -msgstr "ウズベク語" - -#: src\extra\translator\translator.py:101 -msgid "Uighur" -msgstr "ウイグル語" - -#: src\extra\translator\translator.py:102 -msgid "Vietnamese" -msgstr "ベトナム語" - -#: src\extra\translator\translator.py:103 -msgid "Welsh" -msgstr "ウェールズ語" - -#: src\extra\translator\translator.py:104 -msgid "Yiddish" -msgstr "イディッシュ語" - -#: src\extra\translator\wx_ui.py:45 -msgid "Translate message" -msgstr "メッセージを翻訳" - -#: src\extra\translator\wx_ui.py:48 -msgid "Target language" -msgstr "翻訳先の言語" - -#: src\issueReporter\issueReporter.py:32 src\wxUI\dialogs\configuration.py:361 -#: src\wxUI\dialogs\configuration.py:370 -msgid "General" -msgstr "一般" - -#: src\issueReporter\issueReporter.py:33 -msgid "always" -msgstr "常に" - -#: src\issueReporter\issueReporter.py:33 -msgid "sometimes" -msgstr "時々" - -#: src\issueReporter\issueReporter.py:33 -msgid "random" -msgstr "ランダム" - -#: src\issueReporter\issueReporter.py:33 -msgid "have not tried" -msgstr "試したことがない" - -#: src\issueReporter\issueReporter.py:33 -msgid "unable to duplicate" -msgstr "複製できません" - -#: src\issueReporter\issueReporter.py:34 -msgid "block" -msgstr "ブロック" - -#: src\issueReporter\issueReporter.py:34 -msgid "crash" -msgstr "クラッシュ" - -#: src\issueReporter\issueReporter.py:34 -msgid "major" -msgstr "メジャー" - -#: src\issueReporter\issueReporter.py:34 -msgid "minor" -msgstr "マイナー" - -#: src\issueReporter\issueReporter.py:34 -msgid "tweak" -msgstr "微調整" - -#: src\issueReporter\issueReporter.py:34 -msgid "text" -msgstr "内容" - -#: src\issueReporter\issueReporter.py:34 -msgid "trivial" -msgstr "些細な" - -#: src\issueReporter\issueReporter.py:34 -msgid "feature" -msgstr "特徴" - -#: src\issueReporter\wx_ui.py:26 -msgid "Report an error" -msgstr "エラーを報告" - -#: src\issueReporter\wx_ui.py:29 -msgid "Select a category" -msgstr "カテゴリを選択" - -#: src\issueReporter\wx_ui.py:37 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "簡単な説明" - -#: src\issueReporter\wx_ui.py:46 -msgid "Here, you can describe the bug in detail" -msgstr "バグの詳細な説明" - -#: src\issueReporter\wx_ui.py:56 -msgid "how often does this bug happen?" -msgstr "このバグが起こる頻度" - -#: src\issueReporter\wx_ui.py:63 -msgid "Select the importance that you think this bug has" -msgstr "このバグの重要性を選択" - -#: src\issueReporter\wx_ui.py:70 -#, python-brace-format -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"私は、{0}のバグシステムが私に連絡して、すぐにバグを修正するために、Twitterの" -"ユーザー名を取得することを理解しています" - -#: src\issueReporter\wx_ui.py:73 -msgid "Send report" -msgstr "レポートを送信" - -#: src\issueReporter\wx_ui.py:75 src\wxUI\dialogs\filterDialogs.py:84 -#: src\wxUI\dialogs\find.py:23 -msgid "Cancel" -msgstr "キャンセル" - -#: src\issueReporter\wx_ui.py:84 -msgid "You must fill out both fields" -msgstr "あなたは、両方のフィールドに記入しなければなりません" - -#: src\issueReporter\wx_ui.py:87 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"必要な場合に連絡するため、Twitterのユーザー名を私たちに送信するために、チェッ" -"クボックスにチェックをつける必要があります。" - -#: src\issueReporter\wx_ui.py:90 -#, python-format -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"このバグを報告していただき、ありがとうございます!将来のバージョンでは、変更" -"のリストでそれを見つけることができるかもしれません。あなたは、バグ番号%iを報" -"しました" - -#: src\issueReporter\wx_ui.py:90 -msgid "reported" -msgstr "レポート完了" - -#: src\issueReporter\wx_ui.py:94 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"バグの報告中に、予期しないエラーが発生しました。あとで再試行してください" - -#: src\issueReporter\wx_ui.py:94 -msgid "Error while reporting" -msgstr "エラー" - -#: src\keystrokeEditor\constants.py:4 -msgid "Go up in the current buffer" -msgstr "現在のバッファで、前のツイートに移動" - -#: src\keystrokeEditor\constants.py:5 -msgid "Go down in the current buffer" -msgstr "現在のバッファで、次のツイートに移動" - -#: src\keystrokeEditor\constants.py:6 -msgid "Go to the previous buffer" -msgstr "前のバッファに移動" - -#: src\keystrokeEditor\constants.py:7 -msgid "Go to the next buffer" -msgstr "次のバッファに移動" - -#: src\keystrokeEditor\constants.py:8 -msgid "Focus the next session" -msgstr "次のセッションにフォーカス" - -#: src\keystrokeEditor\constants.py:9 -msgid "Focus the previous session" -msgstr "前のセッションにフォーカス" - -#: src\keystrokeEditor\constants.py:10 -msgid "Show or hide the GUI" -msgstr "GUIの表示と非表示を切り替え" - -#: src\keystrokeEditor\constants.py:11 -msgid "New tweet" -msgstr "新規ツイート" - -#: src\keystrokeEditor\constants.py:13 src\wxUI\commonMessageDialogs.py:10 -#: src\wxUI\buffers\base.py:26 src\wxUI\dialogs\message.py:128 -msgid "Retweet" -msgstr "リツイート" - -#: src\keystrokeEditor\constants.py:14 -msgid "Send direct message" -msgstr "ダイレクトメッセージを作成" - -#: src\keystrokeEditor\constants.py:15 -msgid "Like a tweet" -msgstr "ツイートをいいねする" - -#: src\keystrokeEditor\constants.py:16 -msgid "Like/unlike a tweet" -msgstr "ツイートをいいね・いいね解除" - -#: src\keystrokeEditor\constants.py:17 -msgid "Unlike a tweet" -msgstr "ツイートのいいねを解除" - -#: src\keystrokeEditor\constants.py:18 -msgid "Open the user actions dialogue" -msgstr "ユーザーのアクションを選択する画面を表示" - -#: src\keystrokeEditor\constants.py:19 -msgid "See user details" -msgstr "ユーザーの詳細を表示" - -#: src\keystrokeEditor\constants.py:20 -msgid "Show tweet" -msgstr "ツイートを表示" - -#: src\keystrokeEditor\constants.py:21 -msgid "Quit" -msgstr "終了" - -#: src\keystrokeEditor\constants.py:22 -msgid "Open user timeline" -msgstr "特定のユーザーのタイムラインを開く" - -#: src\keystrokeEditor\constants.py:23 -msgid "Destroy buffer" -msgstr "現在のバッファを削除" - -#: src\keystrokeEditor\constants.py:24 -msgid "Interact with the currently focused tweet." -msgstr "現在フォーカス中のツイートを相呼応する。" - -#: src\keystrokeEditor\constants.py:25 -msgid "Open URL" -msgstr "URLを開く" - -#: src\keystrokeEditor\constants.py:26 -msgid "View in Twitter" -msgstr "Twitterで見る" - -#: src\keystrokeEditor\constants.py:27 -msgid "Increase volume by 5%" -msgstr "音量を5パーセント上げる" - -#: src\keystrokeEditor\constants.py:28 -msgid "Decrease volume by 5%" -msgstr "音量を5パーセント下げる" - -#: src\keystrokeEditor\constants.py:29 -msgid "Jump to the first element of a buffer" -msgstr "現在のバッファの先頭に移動" - -#: src\keystrokeEditor\constants.py:30 -msgid "Jump to the last element of the current buffer" -msgstr "現在のバッファの最後に移動" - -#: src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements up in the current buffer" -msgstr "20個前の要素に移動" - -#: src\keystrokeEditor\constants.py:32 -msgid "Jump 20 elements down in the current buffer" -msgstr "20個先の要素に移動" - -#: src\keystrokeEditor\constants.py:33 -msgid "Edit profile" -msgstr "プロフィールを編集" - -#: src\keystrokeEditor\constants.py:34 -msgid "Delete a tweet or direct message" -msgstr "ツイートまたはダイレクトメッセージを削除" - -#: src\keystrokeEditor\constants.py:35 -msgid "Empty the current buffer" -msgstr "現在のバッファをクリア" - -#: src\keystrokeEditor\constants.py:36 -msgid "Repeat last item" -msgstr "現在のアイテムをもう一度読み上げ" - -#: src\keystrokeEditor\constants.py:37 -msgid "Copy to clipboard" -msgstr "クリップボードにコピー" - -#: src\keystrokeEditor\constants.py:38 -msgid "Add to list" -msgstr "リストに追加" - -#: src\keystrokeEditor\constants.py:39 -msgid "Remove from list" -msgstr "リストから削除" - -#: src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the active buffer" -msgstr "現在のバッファのミュートを切り替え" - -#: src\keystrokeEditor\constants.py:41 -msgid "Mute/unmute the current session" -msgstr "現在のセッションのミュートを切り替え" - -#: src\keystrokeEditor\constants.py:42 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "新着のツイートを自動で読み上げるかどうかを設定" - -#: src\keystrokeEditor\constants.py:43 -msgid "Search on twitter" -msgstr "Twitterを検索" - -#: src\keystrokeEditor\constants.py:44 -msgid "Find a string in the currently focused buffer" -msgstr "現在のバッファ内の文字列を検索" - -#: src\keystrokeEditor\constants.py:45 -msgid "Show the keystroke editor" -msgstr "キーストロークエディタを表示" - -#: src\keystrokeEditor\constants.py:46 -msgid "Show lists for a specified user" -msgstr "特定のユーザーのリストを表示" - -#: src\keystrokeEditor\constants.py:47 -msgid "load previous items" -msgstr "以前のアイテムを取得" - -#: src\keystrokeEditor\constants.py:48 -msgid "Get geolocation" -msgstr "位置情報を取得" - -#: src\keystrokeEditor\constants.py:49 -msgid "Display the tweet's geolocation in a dialog" -msgstr "位置情報を表示" - -#: src\keystrokeEditor\constants.py:50 -msgid "Create a trending topics buffer" -msgstr "トレンドのバッファを作成" - -#: src\keystrokeEditor\constants.py:51 -msgid "View conversation" -msgstr "会話を見る" - -#: src\keystrokeEditor\constants.py:52 -msgid "Check and download updates" -msgstr "アップデートをチェックしてダウンロード" - -#: src\keystrokeEditor\constants.py:53 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"リストを作成したり、編集したり、削除したりするために「リストの管理」を開く。" - -#: src\keystrokeEditor\constants.py:54 -msgid "Opens the global settings dialogue" -msgstr "「全般設定」ダイアログを開く" - -#: src\keystrokeEditor\constants.py:55 -msgid "Opens the list manager" -msgstr "リストの管理" - -#: src\keystrokeEditor\constants.py:56 -msgid "Opens the account settings dialogue" -msgstr "「アカウント設定」ダイアログを開く" - -#: src\keystrokeEditor\constants.py:57 -msgid "Try to play an audio file" -msgstr "音声ファイルの再生" - -#: src\keystrokeEditor\constants.py:58 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "バッファを更新して、取得に失敗したアイテムを取得。" - -#: src\keystrokeEditor\constants.py:59 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "画像からテキストを抽出して、結果をダイアログで表示。" - -#: src\keystrokeEditor\wx_ui.py:9 -msgid "Keystroke editor" -msgstr "キーストロークエディタ" - -#: src\keystrokeEditor\wx_ui.py:13 -msgid "Select a keystroke to edit" -msgstr "編集するキーストロークを選択" - -#: src\keystrokeEditor\wx_ui.py:14 src\wxUI\dialogs\userActions.py:10 -#: src\wxUI\dialogs\userActions.py:19 src\wxUI\dialogs\userActions.py:20 -msgid "Action" -msgstr "操作" - -#: src\keystrokeEditor\wx_ui.py:14 -msgid "Keystroke" -msgstr "キーストローク" - -#: src\keystrokeEditor\wx_ui.py:19 src\wxUI\dialogs\filterDialogs.py:131 -#: src\wxUI\dialogs\lists.py:20 -msgid "Edit" -msgstr "編集" - -#: src\keystrokeEditor\wx_ui.py:21 -msgid "Execute action" -msgstr "現在の動作を実行" - -#: src\keystrokeEditor\wx_ui.py:22 src\wxUI\dialogs\configuration.py:398 -#: src\wxUI\dialogs\utils.py:39 -msgid "Close" -msgstr "閉じる" - -#: src\keystrokeEditor\wx_ui.py:49 -msgid "Editing keystroke" -msgstr "キーストロークを編集" - -#: src\keystrokeEditor\wx_ui.py:52 -msgid "Control" -msgstr "コントロール" - -#: src\keystrokeEditor\wx_ui.py:53 -msgid "Alt" -msgstr "オルト" - -#: src\keystrokeEditor\wx_ui.py:54 -msgid "Shift" -msgstr "シフト" - -#: src\keystrokeEditor\wx_ui.py:55 -msgid "Windows" -msgstr "ウィンドウズ" - -#: src\keystrokeEditor\wx_ui.py:61 -msgid "Key" -msgstr "キー名" - -#: src\keystrokeEditor\wx_ui.py:66 src\wxUI\dialogs\filterDialogs.py:82 -#: src\wxUI\dialogs\find.py:21 src\wxUI\dialogs\utils.py:36 -msgid "OK" -msgstr "OK" - -#: src\keystrokeEditor\wx_ui.py:79 -msgid "You need to use the Windows key" -msgstr "ウィンドウズキーを使用する必要があります" - -#: src\keystrokeEditor\wx_ui.py:79 src\keystrokeEditor\wx_ui.py:82 -msgid "Invalid keystroke" -msgstr "無効なキーストローク" - -#: src\keystrokeEditor\wx_ui.py:82 -msgid "You must provide a character for the keystroke" -msgstr "キー名が入力されていません" - -#: src\sessionmanager\wxUI.py:9 +#: ../src\sessionmanager\wxUI.py:9 msgid "Session manager" msgstr "セッションの管理" -#: src\sessionmanager\wxUI.py:12 +#: ../src\sessionmanager\wxUI.py:12 msgid "Accounts list" msgstr "アカウントリスト" -#: src\sessionmanager\wxUI.py:14 +#: ../src\sessionmanager\wxUI.py:14 msgid "Account" msgstr "アカウント" -#: src\sessionmanager\wxUI.py:18 +#: ../src\sessionmanager\wxUI.py:18 msgid "New account" msgstr "新しいアカウントを連携" -#: src\sessionmanager\wxUI.py:19 src\sessionmanager\wxUI.py:65 +#: ../src\sessionmanager\wxUI.py:19 ../src\sessionmanager\wxUI.py:65 msgid "Remove account" msgstr "このアカウントを削除" -#: src\sessionmanager\wxUI.py:20 +#: ../src\sessionmanager\wxUI.py:20 msgid "Global Settings" msgstr "全体の設定" -#: src\sessionmanager\wxUI.py:43 -msgid "You need to configure an account." -msgstr "アカウントを設定する必要があります。" - -#: src\sessionmanager\wxUI.py:43 +#: ../src\sessionmanager\wxUI.py:43 msgid "Account Error" msgstr "アカウントエラー" -#: src\sessionmanager\wxUI.py:49 +#: ../src\sessionmanager\wxUI.py:43 +msgid "You need to configure an account." +msgstr "アカウントを設定する必要があります。" + +#: ../src\sessionmanager\wxUI.py:49 +msgid "Authorization" +msgstr "認証" + +#: ../src\sessionmanager\wxUI.py:49 msgid "" "The request to authorize your Twitter account will be opened in your " "browser. You only need to do this once. Would you like to continue?" @@ -1887,16 +1900,15 @@ msgstr "" "アカウントを認証するために、ブラウザを開きます。あなたは、一度だけ、これを実" "行する必要があります。続行しますか?" -#: src\sessionmanager\wxUI.py:49 -msgid "Authorization" -msgstr "認証" - -#: src\sessionmanager\wxUI.py:53 -#, python-format +#: ../src\sessionmanager\wxUI.py:53 msgid "Authorized account %d" msgstr "認証したアカウント%d" -#: src\sessionmanager\wxUI.py:59 +#: ../src\sessionmanager\wxUI.py:59 +msgid "Invalid user token" +msgstr "無効なユーザートークン" + +#: ../src\sessionmanager\wxUI.py:59 msgid "" "Your access token is invalid or the authorization has failed. Please try " "again." @@ -1904,15 +1916,15 @@ msgstr "" "あなたのアクセストークンが無効であるか、または許可が失敗しました。もう一度や" "り直してください。" -#: src\sessionmanager\wxUI.py:59 -msgid "Invalid user token" -msgstr "無効なユーザートークン" - -#: src\sessionmanager\wxUI.py:65 +#: ../src\sessionmanager\wxUI.py:65 msgid "Do you really want to delete this account?" msgstr "本当にこのアカウントを削除しますか?" -#: src\sessionmanager\wxUI.py:81 +#: ../src\sessionmanager\wxUI.py:81 +msgid "Authentication error for session {}" +msgstr "セッション {} の認証エラー" + +#: ../src\sessionmanager\wxUI.py:81 msgid "" "TWBlue is unable to authenticate the account for {} in Twitter. It might be " "due to an invalid or expired token, revoqued access to the application, or " @@ -1924,31 +1936,45 @@ msgstr "" "アクティブ化が原因である可能性があります。このメッセージの表示を停止するに" "は、Twitterセッションからアカウントを手動で削除してください。" -#: src\sessionmanager\wxUI.py:81 -msgid "Authentication error for session {}" -msgstr "セッション {} の認証エラー" +#: ../src\sessions\base.py:113 +msgid "" +"An exception occurred while saving the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"{app} データベースの保存中に例外が発生しました。自動的に削除され、再構築され" +"ます。このエラーが続く場合は、エラーログを {app} 開発者に送信してください。" -#: src\sessions\twitter\compose.py:45 src\sessions\twitter\compose.py:89 -#: src\sessions\twitter\compose.py:149 src\sessions\twitter\compose.py:158 +#: ../src\sessions\base.py:153 +msgid "" +"An exception occurred while loading the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"{app} データベースの読み込み中に例外が発生しました。自動的に削除され、再構築" +"されます。このエラーが続く場合は、エラーログを {app} 開発者に送信してくださ" +"い。" + +#: ../src\sessions\twitter\compose.py:38 ../src\sessions\twitter\compose.py:81 +#: ../src\sessions\twitter\compose.py:146 +#: ../src\sessions\twitter\compose.py:155 msgid "dddd, MMMM D, YYYY H:m:s" msgstr "YYYY年MMMMD日(dddd) H時m分s秒" -#: src\sessions\twitter\compose.py:97 src\sessions\twitter\compose.py:99 -#, python-format +#: ../src\sessions\twitter\compose.py:89 ../src\sessions\twitter\compose.py:91 msgid "Dm to %s " msgstr "「%s」へのDM " -#: src\sessions\twitter\compose.py:138 -#, python-brace-format +#: ../src\sessions\twitter\compose.py:130 msgid "{0}. Quoted tweet from @{1}: {2}" msgstr "{0} 引用:@{1}:{2}" -#: src\sessions\twitter\compose.py:160 src\sessions\twitter\compose.py:162 +#: ../src\sessions\twitter\compose.py:157 +#: ../src\sessions\twitter\compose.py:159 msgid "Unavailable" msgstr "無効" -#: src\sessions\twitter\compose.py:163 -#, python-format +#: ../src\sessions\twitter\compose.py:160 msgid "" "%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " "Twitter %s" @@ -1956,55 +1982,64 @@ msgstr "" "%s: @%s フォロワー: %s フォロー: %s ツイート数: %s 最後のツイート: %s ツイッ" "ターへの参加: %s" -#: src\sessions\twitter\compose.py:167 +#: ../src\sessions\twitter\compose.py:164 msgid "No description available" msgstr "説明はありません" -#: src\sessions\twitter\compose.py:171 +#: ../src\sessions\twitter\compose.py:168 msgid "private" msgstr "プライベート" -#: src\sessions\twitter\compose.py:172 +#: ../src\sessions\twitter\compose.py:169 msgid "public" msgstr "公式" -#: src\sessions\twitter\session.py:170 -msgid "There are no more items to retrieve in this buffer." -msgstr "このバッファで取得するアイテムはありません。" - -#: src\sessions\twitter\session.py:216 -#, python-format +#: ../src\sessions\twitter\session.py:209 msgid "%s failed. Reason: %s" msgstr "%s が失敗しました。理由: %s" -#: src\sessions\twitter\session.py:222 -#, python-format +#: ../src\sessions\twitter\session.py:215 msgid "%s succeeded." msgstr "%sに成功しました。" -#: src\sessions\twitter\utils.py:203 +#: ../src\sessions\twitter\session.py:424 +#: ../src\sessions\twitter\session.py:502 +msgid "Deleted account" +msgstr "削除されたアカウント" + +#: ../src\sessions\twitter\utils.py:231 msgid "Sorry, you are not authorised to see this status." msgstr "申し訳ありませんが、あなたはこのステータスを表示する権限がありません。" -#: src\sessions\twitter\utils.py:205 +#: ../src\sessions\twitter\utils.py:233 msgid "No status found with that ID" msgstr "そのIDのステータスが見つかりませんでした" -#: src\sessions\twitter\utils.py:207 -#, python-brace-format -msgid "Error code {0}" -msgstr "エラーコード {0}" +#: ../src\sessions\twitter\utils.py:235 +msgid "Error {0}" +msgstr "エラー {0}" -#: src\sessions\twitter\wxUI.py:7 +#: ../src\sessions\twitter\utils.py:262 +msgid "{user_1}, {user_2} and {all_users} more: {text}" +msgstr "{user_1}、{user_2}、ほか{all_users}ユーザー: {text}" + +#: ../src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." msgstr "アカウントを連携中…" -#: src\sessions\twitter\wxUI.py:10 +#: ../src\sessions\twitter\wxUI.py:10 msgid "Enter your PIN code here" msgstr "PINコードを入力" -#: src\update\wxUpdater.py:14 -#, python-format +#: ../src\sound.py:161 +msgid "Stopped." +msgstr "停止。" + +#: ../src\update\wxUpdater.py:14 +msgid "New version for %s" +msgstr "「%s」の新しいバージョン" + +#: ../src\update\wxUpdater.py:14 msgid "" "There's a new %s version available, released on %s. Would you like to " "download it now?\n" @@ -2022,25 +2057,23 @@ msgstr "" "更新履歴: \n" "%s" -#: src\update\wxUpdater.py:14 -#, python-format -msgid "New version for %s" -msgstr "「%s」の新しいバージョン" - -#: src\update\wxUpdater.py:22 +#: ../src\update\wxUpdater.py:22 msgid "Download in Progress" msgstr "ダウンロード中" -#: src\update\wxUpdater.py:22 +#: ../src\update\wxUpdater.py:22 msgid "Downloading the new version..." msgstr "新しいバージョンをダウンロード中…" -#: src\update\wxUpdater.py:32 -#, python-format +#: ../src\update\wxUpdater.py:32 msgid "Updating... %s of %s" msgstr "アップデート中… %s/%s" -#: src\update\wxUpdater.py:35 +#: ../src\update\wxUpdater.py:35 +msgid "Done!" +msgstr "完了!" + +#: ../src\update\wxUpdater.py:35 msgid "" "The update has been downloaded and installed successfully. Press OK to " "continue." @@ -2048,11 +2081,62 @@ msgstr "" "アップデートは正常にダウンロードされ、インストールされました。続行する場合" "は、「OK」を押してください。" -#: src\update\wxUpdater.py:35 -msgid "Done!" -msgstr "完了!" +#: ../src\wxUI\buffers\base.py:12 +msgid "Client" +msgstr "クライアント" -#: src\wxUI\commonMessageDialogs.py:7 +#: ../src\wxUI\buffers\base.py:12 +msgid "Text" +msgstr "内容" + +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 +msgid "Date" +msgstr "日時" + +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 +#: ../src\wxUI\buffers\user_searches.py:11 +#: ../src\wxUI\dialogs\userAliasDialogs.py:14 +#: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 +msgid "User" +msgstr "ユーザー" + +#: ../src\wxUI\buffers\base.py:28 +msgid "Direct message" +msgstr "ダイレクトメッセージ" + +#: ../src\wxUI\buffers\events.py:14 +msgid "Event" +msgstr "イベント" + +#: ../src\wxUI\buffers\events.py:16 +msgid "Remove event" +msgstr "イベントを削除" + +#: ../src\wxUI\buffers\panels.py:12 ../src\wxUI\buffers\panels.py:20 +msgid "Login" +msgstr "ログイン" + +#: ../src\wxUI\buffers\panels.py:14 +msgid "Log in automatically" +msgstr "自動的にログインする" + +#: ../src\wxUI\buffers\panels.py:22 +msgid "Logout" +msgstr "ログアウト" + +#: ../src\wxUI\buffers\trends.py:9 +msgid "Trending topic" +msgstr "トレンド" + +#: ../src\wxUI\buffers\trends.py:19 +msgid "Tweet about this trend" +msgstr "このトレンドのツイート" + +#: ../src\wxUI\buffers\trends.py:20 ../src\wxUI\menus.py:97 +msgid "Search topic" +msgstr "トピックを検索" + +#: ../src\wxUI\commonMessageDialogs.py:7 msgid "" "This retweet is over 140 characters. Would you like to post it as a mention " "to the poster with your comments and a link to the original tweet?" @@ -2060,41 +2144,38 @@ msgstr "" "このリツイートは、140文字を超えています。投稿者へのリプライとコメント、お" "よび元のツイートへのリンクで登校しますか?" -#: src\wxUI\commonMessageDialogs.py:10 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Would you like to add a comment to this tweet?" msgstr "このツイートにコメントをつけますか?" -#: src\wxUI\commonMessageDialogs.py:13 +#: ../src\wxUI\commonMessageDialogs.py:13 msgid "" "Do you really want to delete this tweet? It will be deleted from Twitter as " "well." msgstr "" "本当にこのツイートを削除しますか?このツイートは、Twitterから削除されます。" -#: src\wxUI\commonMessageDialogs.py:13 src\wxUI\dialogs\lists.py:149 +#: ../src\wxUI\commonMessageDialogs.py:13 ../src\wxUI\dialogs\lists.py:149 msgid "Delete" msgstr "削除" -#: src\wxUI\commonMessageDialogs.py:16 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Do you really want to close {0}?" msgstr "本当に「{0}」を終了しますか?" -#: src\wxUI\commonMessageDialogs.py:16 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Exit" msgstr "終了確認" -#: src\wxUI\commonMessageDialogs.py:20 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:20 msgid " {0} must be restarted for these changes to take effect." msgstr "これらの変更を有効にするには、「{0}」を再起動する必要があります。" -#: src\wxUI\commonMessageDialogs.py:20 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:20 msgid "Restart {0} " msgstr "「{0}」を再起動" -#: src\wxUI\commonMessageDialogs.py:23 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "" "Are you sure you want to delete this user from the database? This user will " "not appear in autocomplete results anymore." @@ -2102,54 +2183,56 @@ msgstr "" "データベースからこのユーザーを削除してもよろしいですか?このユーザーは、自動" "補完結果には表示されません。" -#: src\wxUI\commonMessageDialogs.py:23 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "Confirm" msgstr "確認" -#: src\wxUI\commonMessageDialogs.py:26 +#: ../src\wxUI\commonMessageDialogs.py:26 msgid "Enter the name of the client : " msgstr "クライアントの名前: " -#: src\wxUI\commonMessageDialogs.py:26 src\wxUI\dialogs\configuration.py:248 +#: ../src\wxUI\commonMessageDialogs.py:26 +#: ../src\wxUI\dialogs\configuration.py:246 msgid "Add client" msgstr "クライアントを追加" -#: src\wxUI\commonMessageDialogs.py:32 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "" "Do you really want to empty this buffer? It's items will be removed from " "the list but not from Twitter" msgstr "" "本当にこのバッファをクリアしますか?これは、Twitterからは削除されません。" -#: src\wxUI\commonMessageDialogs.py:32 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "Empty buffer" msgstr "バッファをクリア" -#: src\wxUI\commonMessageDialogs.py:36 +#: ../src\wxUI\commonMessageDialogs.py:36 msgid "Do you really want to destroy this buffer?" msgstr "本当にこのバッファを削除しますか?" -#: src\wxUI\commonMessageDialogs.py:36 src\wxUI\commonMessageDialogs.py:86 +#: ../src\wxUI\commonMessageDialogs.py:36 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Attention" msgstr "確認" -#: src\wxUI\commonMessageDialogs.py:42 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "A timeline for this user already exists. You can't open another" msgstr "" "そのユーザーのタイムラインは、既に開かれています。他のユーザーを開いてくださ" "い。" -#: src\wxUI\commonMessageDialogs.py:42 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "Existing timeline" msgstr "既存のタイムライン" -#: src\wxUI\commonMessageDialogs.py:45 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "This user has no tweets, so you can't open a timeline for them." msgstr "" "このユーザーは、何もツイートしていないため、タイムラインを開くことができませ" "ん。" -#: src\wxUI\commonMessageDialogs.py:48 +#: ../src\wxUI\commonMessageDialogs.py:48 msgid "" "This is a protected Twitter user, which means you can't open a timeline " "using the Streaming API. The user's tweets will not update due to a twitter " @@ -2159,11 +2242,12 @@ msgstr "" "ムラインを開くことができないことを意味します。ユーザーのツイートはTwitterのポ" "リシーにより更新されません。続行しますか?" -#: src\wxUI\commonMessageDialogs.py:48 src\wxUI\commonMessageDialogs.py:95 +#: ../src\wxUI\commonMessageDialogs.py:48 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "Warning" msgstr "警告" -#: src\wxUI\commonMessageDialogs.py:51 +#: ../src\wxUI\commonMessageDialogs.py:51 msgid "" "This is a protected user account, you need to follow this user to view their " "tweets or likes." @@ -2171,8 +2255,7 @@ msgstr "" "このユーザーは保護されています。このユーザーのツイートやお気に入り一覧を見る" "には、このユーザーをフォローする必要があります。" -#: src\wxUI\commonMessageDialogs.py:54 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "" "If you like {0} we need your help to keep it going. Help us by donating to " "the project. This will help us pay for the server, the domain and some other " @@ -2186,48 +2269,47 @@ msgstr "" "ののために支払うのに役立ちます。あなたの寄付は私たちに「{0}」の開発を継続する" "ための手段を与え、自由な「{0}」を維持します。今すぐ寄付しますか?" -#: src\wxUI\commonMessageDialogs.py:54 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "We need your help" msgstr "寄付のお願い" -#: src\wxUI\commonMessageDialogs.py:58 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:58 msgid "This user has no tweets. {0} can't create a timeline." msgstr "" "このユーザーにはツイートがないため、「{0}」のタイムラインを作成することはでき" "ません。" -#: src\wxUI\commonMessageDialogs.py:61 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:61 msgid "This user has no favorited tweets. {0} can't create a timeline." msgstr "" "このユーザーには、お気に入り登録されたツイートがないため、「{0}」のタイムライ" "ンを作成することはできません。" -#: src\wxUI\commonMessageDialogs.py:64 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:64 msgid "This user has no followers. {0} can't create a timeline." msgstr "" "このユーザーのフォロワーがいないため、「{0}」でタイムラインを作ることはできま" "せん。" -#: src\wxUI\commonMessageDialogs.py:67 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:67 msgid "This user has no friends. {0} can't create a timeline." msgstr "" "このユーザーは、誰もフォローしていないため、「{0}」でタイムラインを作ることは" "できません。" -#: src\wxUI\commonMessageDialogs.py:71 -#, python-brace-format -msgid "Geolocation data: {0}" -msgstr "位置情報: {0}" - -#: src\wxUI\commonMessageDialogs.py:71 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geo data for this tweet" msgstr "このツイートの位置情報" -#: src\wxUI\commonMessageDialogs.py:74 +#: ../src\wxUI\commonMessageDialogs.py:71 +msgid "Geolocation data: {0}" +msgstr "位置情報: {0}" + +#: ../src\wxUI\commonMessageDialogs.py:74 +msgid "Information" +msgstr "情報" + +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "" "TWBlue has detected that you're running windows 10 and has changed the " "default keymap to the Windows 10 keymap. It means that some keyboard " @@ -2239,15 +2321,11 @@ msgstr "" "違うことを意味します。このキーマップで使用できる全てのショートカットを見るに" "は、Alt+Win+Kで、キーストロークエディタを開いて確認してください。" -#: src\wxUI\commonMessageDialogs.py:74 -msgid "Information" -msgstr "情報" - -#: src\wxUI\commonMessageDialogs.py:77 +#: ../src\wxUI\commonMessageDialogs.py:77 msgid "You have been blocked from viewing this content" msgstr "このコンテンツの表示がブロックされています" -#: src\wxUI\commonMessageDialogs.py:80 +#: ../src\wxUI\commonMessageDialogs.py:80 msgid "" "You have been blocked from viewing someone's content. In order to avoid " "conflicts with the full session, TWBlue will remove the affected timeline." @@ -2255,23 +2333,22 @@ msgstr "" "他のユーザーのコンテンツを表示できないようになっています。フルセッションとの" "競合を避けるため、TWBlueは影響を受けるタイムラインを削除します。" -#: src\wxUI\commonMessageDialogs.py:83 +#: ../src\wxUI\commonMessageDialogs.py:83 msgid "" "TWBlue cannot load this timeline because the user has been suspended from " "Twitter." msgstr "" "ユーザーがTwitterから凍結されているため、このタイムラインをロードできません。" -#: src\wxUI\commonMessageDialogs.py:86 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Do you really want to delete this filter?" msgstr "本当に、このフィルターを削除しますか?" -#: src\wxUI\commonMessageDialogs.py:89 +#: ../src\wxUI\commonMessageDialogs.py:89 msgid "This filter already exists. Please use a different title" msgstr "このフィルターはすでに利用されています。別の名前を利用してください" -#: src\wxUI\commonMessageDialogs.py:95 -#, python-brace-format +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." @@ -2279,491 +2356,147 @@ msgstr "" "{0}は、前回の実行時に予期せず終了しました。問題が解決しない場合は、{0}開発者" "に報告してください。" -#: src\wxUI\menus.py:8 src\wxUI\view.py:32 -msgid "&Retweet" -msgstr "リツイート(&R)" - -#: src\wxUI\menus.py:10 src\wxUI\menus.py:34 src\wxUI\view.py:31 -msgid "Re&ply" -msgstr "リプライ(&P)" - -#: src\wxUI\menus.py:12 src\wxUI\view.py:33 -msgid "&Like" -msgstr "いいね(&L)" - -#: src\wxUI\menus.py:14 src\wxUI\view.py:34 -msgid "&Unlike" -msgstr "いいねを解除(&U)" - -#: src\wxUI\menus.py:16 src\wxUI\menus.py:36 src\wxUI\menus.py:52 -msgid "&Open URL" -msgstr "URLを開く(&O)" - -#: src\wxUI\menus.py:18 src\wxUI\menus.py:54 src\wxUI\menus.py:87 -msgid "&Open in Twitter" -msgstr "ツイッターを検索" - -#: src\wxUI\menus.py:20 src\wxUI\menus.py:38 src\wxUI\menus.py:56 -msgid "&Play audio" -msgstr "音声を再生(&P)" - -#: src\wxUI\menus.py:22 src\wxUI\menus.py:58 src\wxUI\view.py:35 -msgid "&Show tweet" -msgstr "ツイートを表示(&S)" - -#: src\wxUI\menus.py:24 src\wxUI\menus.py:42 src\wxUI\menus.py:60 -#: src\wxUI\menus.py:70 src\wxUI\menus.py:89 src\wxUI\menus.py:103 -msgid "&Copy to clipboard" -msgstr "クリップボードにコピー(&C)" - -#: src\wxUI\menus.py:26 src\wxUI\menus.py:44 src\wxUI\menus.py:62 -#: src\wxUI\menus.py:72 src\wxUI\view.py:39 -msgid "&Delete" -msgstr "削除(&D)" - -#: src\wxUI\menus.py:28 src\wxUI\menus.py:46 src\wxUI\menus.py:91 -msgid "&User actions..." -msgstr "ユーザーのアクション(&U)" - -#: src\wxUI\menus.py:40 -msgid "&Show direct message" -msgstr "ダイレクトメッセージを表示(&S)" - -#: src\wxUI\menus.py:68 -msgid "&Show event" -msgstr "イベントを表示(&S)" - -#: src\wxUI\menus.py:78 -msgid "Direct &message" -msgstr "ダイレクトメッセージ(&M)" - -#: src\wxUI\menus.py:80 src\wxUI\view.py:48 -msgid "&View lists" -msgstr "リストを見る(&V)" - -#: src\wxUI\menus.py:83 src\wxUI\view.py:49 -msgid "Show user &profile" -msgstr "ユーザーのプロフィールを表示(&P)" - -#: src\wxUI\menus.py:85 -msgid "&Show user" -msgstr "ユーザーを表示(&S)" - -#: src\wxUI\menus.py:97 src\wxUI\buffers\trends.py:20 -msgid "Search topic" -msgstr "トピックを検索" - -#: src\wxUI\menus.py:99 -msgid "&Tweet about this trend" -msgstr "このトレンドのツイート(&T)" - -#: src\wxUI\menus.py:101 -msgid "&Show item" -msgstr "アイテムを表示(&S)" - -#: src\wxUI\sysTrayIcon.py:36 src\wxUI\view.py:25 -msgid "&Global settings" -msgstr "全般設定(&G)" - -#: src\wxUI\sysTrayIcon.py:37 src\wxUI\view.py:24 -msgid "Account se&ttings" -msgstr "アカウント設定(&T(" - -#: src\wxUI\sysTrayIcon.py:38 -msgid "Update &profile" -msgstr "プロフィールを更新(&P)" - -#: src\wxUI\sysTrayIcon.py:39 -msgid "&Show / hide" -msgstr "表示または非表示(&S)" - -#: src\wxUI\sysTrayIcon.py:40 src\wxUI\view.py:73 -msgid "&Documentation" -msgstr "取扱説明書(&D)" - -#: src\wxUI\sysTrayIcon.py:41 -msgid "Check for &updates" -msgstr "アップデートを確認(&U)" - -#: src\wxUI\sysTrayIcon.py:42 -msgid "&Exit" -msgstr "終了(&E)" - -#: src\wxUI\view.py:18 -msgid "&Manage accounts" -msgstr "アカウントの管理(&M)" - -#: src\wxUI\view.py:19 src\wxUI\dialogs\update_profile.py:35 -msgid "&Update profile" -msgstr "プロフィールを更新(&U)" - -#: src\wxUI\view.py:20 -msgid "&Hide window" -msgstr "ウィンドウを隠す(&H)" - -#: src\wxUI\view.py:21 src\wxUI\dialogs\search.py:15 -msgid "&Search" -msgstr "検索(&S)" - -#: src\wxUI\view.py:22 -msgid "&Lists manager" -msgstr "リストの管理(&L)" - -#: src\wxUI\view.py:23 -msgid "&Edit keystrokes" -msgstr "キーストロークを編集(&E)" - -#: src\wxUI\view.py:26 -msgid "E&xit" -msgstr "終了(&X)" - -#: src\wxUI\view.py:30 src\wxUI\view.py:84 -msgid "&Tweet" -msgstr "ツイート(&T)" - -#: src\wxUI\view.py:36 -msgid "View &address" -msgstr "位置情報を表示(&A)" - -#: src\wxUI\view.py:37 -msgid "View conversa&tion" -msgstr "会話を見る(&T)" - -#: src\wxUI\view.py:38 -msgid "Read text in picture" -msgstr "画像からテキストを読み取り" - -#: src\wxUI\view.py:43 -msgid "&Actions..." -msgstr "操作(&A)" - -#: src\wxUI\view.py:44 -msgid "&View timeline..." -msgstr "タイムラインを表示(&V)" - -#: src\wxUI\view.py:45 -msgid "Direct me&ssage" -msgstr "ダイレクトメッセージ(&S)" - -#: src\wxUI\view.py:46 -msgid "&Add to list" -msgstr "リストに追加(&A)" - -#: src\wxUI\view.py:47 -msgid "R&emove from list" -msgstr "リストから削除(&E)" - -#: src\wxUI\view.py:50 -msgid "V&iew likes" -msgstr "いいね一覧を見る(&I)" - -#: src\wxUI\view.py:54 -msgid "&Update buffer" -msgstr "バッファを更新(&U)" - -#: src\wxUI\view.py:55 -msgid "New &trending topics buffer..." -msgstr "新しいトレンドのバッファ(&T)" - -#: src\wxUI\view.py:56 -msgid "Create a &filter" -msgstr "新しいフィルターを作成(&F)" - -#: src\wxUI\view.py:57 -msgid "&Manage filters" -msgstr "フィルターの管理(&M)" - -#: src\wxUI\view.py:58 -msgid "Find a string in the currently focused buffer..." -msgstr "現在フォーカス中のバッファ内の文字列を検索..." - -#: src\wxUI\view.py:59 -msgid "&Load previous items" -msgstr "以前のアイテムを取得(&L)" - -#: src\wxUI\view.py:61 src\wxUI\dialogs\userActions.py:22 -msgid "&Mute" -msgstr "ミュート(&M)" - -#: src\wxUI\view.py:62 -msgid "&Autoread" -msgstr "自動読み上げ(&A)" - -#: src\wxUI\view.py:63 -msgid "&Clear buffer" -msgstr "バッファをクリア(&C)" - -#: src\wxUI\view.py:64 -msgid "&Destroy" -msgstr "バッファを削除(&D)" - -#: src\wxUI\view.py:68 -msgid "&Seek back 5 seconds" -msgstr "5秒戻る(&S)" - -#: src\wxUI\view.py:69 -msgid "&Seek forward 5 seconds" -msgstr "5秒進む(&S)" - -#: src\wxUI\view.py:74 -msgid "Sounds &tutorial" -msgstr "サウンドの確認(&T)" - -#: src\wxUI\view.py:75 -msgid "&What's new in this version?" -msgstr "更新履歴(&W)" - -#: src\wxUI\view.py:76 -msgid "&Check for updates" -msgstr "アップデートを確認(&C)" - -#: src\wxUI\view.py:77 -msgid "&Report an error" -msgstr "エラーを報告(&R)" - -#: src\wxUI\view.py:78 -#, python-brace-format -msgid "{0}'s &website" -msgstr "「{0}」のウェブサイト(&W)" - -#: src\wxUI\view.py:79 -msgid "Get soundpacks for TWBlue" -msgstr "TWBlueのサウンドパックを入手" - -#: src\wxUI\view.py:80 -#, python-brace-format -msgid "About &{0}" -msgstr "{0}について(&A)" - -#: src\wxUI\view.py:83 -msgid "&Application" -msgstr "アプリケーション(&A)" - -#: src\wxUI\view.py:85 src\wxUI\dialogs\userActions.py:11 -msgid "&User" -msgstr "ユーザー(&U)" - -#: src\wxUI\view.py:86 -msgid "&Buffer" -msgstr "バッファ(&B)" - -#: src\wxUI\view.py:87 -msgid "&Audio" -msgstr "音声(&A)" - -#: src\wxUI\view.py:88 -msgid "&Help" -msgstr "ヘルプ(&H)" - -#: src\wxUI\view.py:174 -msgid "Address" -msgstr "アドレス" - -#: src\wxUI\view.py:205 -#, python-brace-format -msgid "Your {0} version is up to date" -msgstr "「{0}」のバージョンは最新です" - -#: src\wxUI\view.py:205 -msgid "Update" -msgstr "アップデート" - -#: src\wxUI\buffers\base.py:12 src\wxUI\buffers\people.py:12 -#: src\wxUI\buffers\user_searches.py:11 src\wxUI\dialogs\userSelection.py:11 -#: src\wxUI\dialogs\utils.py:32 -msgid "User" -msgstr "ユーザー" - -#: src\wxUI\buffers\base.py:12 -msgid "Text" -msgstr "内容" - -#: src\wxUI\buffers\base.py:12 src\wxUI\buffers\events.py:14 -msgid "Date" -msgstr "日時" - -#: src\wxUI\buffers\base.py:12 -msgid "Client" -msgstr "クライアント" - -#: src\wxUI\buffers\base.py:28 -msgid "Direct message" -msgstr "ダイレクトメッセージ" - -#: src\wxUI\buffers\events.py:14 -msgid "Event" -msgstr "イベント" - -#: src\wxUI\buffers\events.py:16 -msgid "Remove event" -msgstr "イベントを削除" - -#: src\wxUI\buffers\panels.py:12 src\wxUI\buffers\panels.py:20 -msgid "Login" -msgstr "ログイン" - -#: src\wxUI\buffers\panels.py:14 -msgid "Log in automatically" -msgstr "自動的にログインする" - -#: src\wxUI\buffers\panels.py:22 -msgid "Logout" -msgstr "ログアウト" - -#: src\wxUI\buffers\trends.py:9 -msgid "Trending topic" -msgstr "トレンド" - -#: src\wxUI\buffers\trends.py:19 -msgid "Tweet about this trend" -msgstr "このトレンドのツイート" - -#: src\wxUI\dialogs\attach.py:10 +#: ../src\wxUI\dialogs\attach.py:10 msgid "Add an attachment" msgstr "添付ファイルを追加" -#: src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:13 msgid "Attachments" msgstr "添付ファイル" -#: src\wxUI\dialogs\attach.py:14 -msgid "Type" -msgstr "形式" - -#: src\wxUI\dialogs\attach.py:14 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Title" msgstr "タイトル" -#: src\wxUI\dialogs\attach.py:19 +#: ../src\wxUI\dialogs\attach.py:14 +msgid "Type" +msgstr "形式" + +#: ../src\wxUI\dialogs\attach.py:19 msgid "Add attachments" msgstr "添付ファイルを追加" -#: src\wxUI\dialogs\attach.py:20 +#: ../src\wxUI\dialogs\attach.py:20 msgid "&Photo" msgstr "画像(&P)" -#: src\wxUI\dialogs\attach.py:21 +#: ../src\wxUI\dialogs\attach.py:21 msgid "Remove attachment" msgstr "添付ファイルを削除" -#: src\wxUI\dialogs\attach.py:37 src\wxUI\dialogs\message.py:118 -#: src\wxUI\dialogs\message.py:177 src\wxUI\dialogs\message.py:237 -#: src\wxUI\dialogs\update_profile.py:82 -msgid "Select the picture to be uploaded" -msgstr "アップロードする画像を選択" - -#: src\wxUI\dialogs\attach.py:37 src\wxUI\dialogs\message.py:118 -#: src\wxUI\dialogs\message.py:177 src\wxUI\dialogs\message.py:237 -#: src\wxUI\dialogs\update_profile.py:82 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" msgstr "画像ファイル (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -#: src\wxUI\dialogs\attach.py:44 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Select the picture to be uploaded" +msgstr "アップロードする画像を選択" + +#: ../src\wxUI\dialogs\attach.py:44 msgid "please provide a description" msgstr "説明を入力" -#: src\wxUI\dialogs\attach.py:44 src\wxUI\dialogs\lists.py:14 -#: src\wxUI\dialogs\lists.py:70 +#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:70 msgid "Description" msgstr "説明" -#: src\wxUI\dialogs\configuration.py:18 +#: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "言語" -#: src\wxUI\dialogs\configuration.py:25 -#, python-brace-format +#: ../src\wxUI\dialogs\configuration.py:22 msgid "Run {0} at Windows startup" msgstr "Windows起動時に{0}を実行" -#: src\wxUI\dialogs\configuration.py:26 -#, python-brace-format +#: ../src\wxUI\dialogs\configuration.py:23 msgid "ask before exiting {0}" msgstr "{0}を終了する前に確認" -#: src\wxUI\dialogs\configuration.py:29 +#: ../src\wxUI\dialogs\configuration.py:26 msgid "Disable Streaming functions" msgstr "ストリーミング機能を無効化する" -#: src\wxUI\dialogs\configuration.py:32 +#: ../src\wxUI\dialogs\configuration.py:29 msgid "Buffer update interval, in minutes" msgstr "バッファの更新間隔(分)" -#: src\wxUI\dialogs\configuration.py:38 -#, python-brace-format +#: ../src\wxUI\dialogs\configuration.py:35 msgid "Play a sound when {0} launches" msgstr "{0}が起動したときに、音声を再生" -#: src\wxUI\dialogs\configuration.py:40 -#, python-brace-format +#: ../src\wxUI\dialogs\configuration.py:37 msgid "Speak a message when {0} launches" msgstr "{0}が起動した際に、メッセージを読み上げ" -#: src\wxUI\dialogs\configuration.py:42 +#: ../src\wxUI\dialogs\configuration.py:39 msgid "Use invisible interface's keyboard shortcuts while GUI is visible" msgstr "GUI表示中でもGUI非表示時に利用できるショートカットを利用する" -#: src\wxUI\dialogs\configuration.py:44 +#: ../src\wxUI\dialogs\configuration.py:41 msgid "Activate Sapi5 when any other screen reader is not being run" msgstr "他のスクリーンリーダーが起動していないときは、Sapi5を利用する" -#: src\wxUI\dialogs\configuration.py:46 +#: ../src\wxUI\dialogs\configuration.py:43 msgid "Hide GUI on launch" msgstr "起動時にGUIを隠す" -#: src\wxUI\dialogs\configuration.py:48 +#: ../src\wxUI\dialogs\configuration.py:45 msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" msgstr "" "Codeofduskを利用して長いツイートをできるようにする(パフォーマンスが低下する" "場合があります)" -#: src\wxUI\dialogs\configuration.py:50 +#: ../src\wxUI\dialogs\configuration.py:47 msgid "Remember state for mention all and long tweet" msgstr "" "「全員にリプライ」および「ツイートを短縮して投稿」のチェック状態を保持する" -#: src\wxUI\dialogs\configuration.py:53 +#: ../src\wxUI\dialogs\configuration.py:50 msgid "Keymap" msgstr "キーマップ" -#: src\wxUI\dialogs\configuration.py:58 -#, python-brace-format +#: ../src\wxUI\dialogs\configuration.py:55 msgid "Check for updates when {0} launches" msgstr "{0}の起動時にアップデートを確認" -#: src\wxUI\dialogs\configuration.py:68 +#: ../src\wxUI\dialogs\configuration.py:65 msgid "Proxy type: " msgstr "プロキシタイプ: " -#: src\wxUI\dialogs\configuration.py:75 +#: ../src\wxUI\dialogs\configuration.py:72 msgid "Proxy server: " msgstr "プロキシサーバー: " -#: src\wxUI\dialogs\configuration.py:81 +#: ../src\wxUI\dialogs\configuration.py:78 msgid "Port: " msgstr "ポート: " -#: src\wxUI\dialogs\configuration.py:87 +#: ../src\wxUI\dialogs\configuration.py:84 msgid "User: " msgstr "ユーザー名: " -#: src\wxUI\dialogs\configuration.py:93 +#: ../src\wxUI\dialogs\configuration.py:90 msgid "Password: " msgstr "パスワード: " -#: src\wxUI\dialogs\configuration.py:105 +#: ../src\wxUI\dialogs\configuration.py:102 msgid "Autocompletion settings..." msgstr "自動保管の設定..." -#: src\wxUI\dialogs\configuration.py:107 +#: ../src\wxUI\dialogs\configuration.py:104 msgid "Relative timestamps" msgstr "相対的な時刻を利用する" -#: src\wxUI\dialogs\configuration.py:110 +#: ../src\wxUI\dialogs\configuration.py:107 msgid "Items on each API call" msgstr "各API呼び出しの回数" -#: src\wxUI\dialogs\configuration.py:116 +#: ../src\wxUI\dialogs\configuration.py:113 msgid "" "Inverted buffers: The newest tweets will be shown at the beginning while the " "oldest at the end" @@ -2771,15 +2504,15 @@ msgstr "" "バッファの並び順を入れ替える(新しいツイートを先頭に、古いツイートを最後に表" "示)" -#: src\wxUI\dialogs\configuration.py:118 +#: ../src\wxUI\dialogs\configuration.py:115 msgid "Retweet mode" msgstr "リツイートのモード" -#: src\wxUI\dialogs\configuration.py:124 +#: ../src\wxUI\dialogs\configuration.py:121 msgid "Show screen names instead of full names" msgstr "表示名の代わりに、ユーザー名を表示する" -#: src\wxUI\dialogs\configuration.py:126 +#: ../src\wxUI\dialogs\configuration.py:123 msgid "" "Number of items per buffer to cache in database (0 to disable caching, blank " "for unlimited)" @@ -2787,569 +2520,914 @@ msgstr "" "バッファごとにデータベースにキャッシュする項目数(0はキャッシュしない、空欄の" "場合は無制限)" -#: src\wxUI\dialogs\configuration.py:136 +#: ../src\wxUI\dialogs\configuration.py:127 +msgid "" +"Load cache for tweets in memory (much faster in big datasets but requires " +"more RAM)" +msgstr "" +"ツイートのキャッシュをメモリにロードする(大きなデータセットでははるかに高速" +"ですが、より多くのRAMが必要です)" + +#: ../src\wxUI\dialogs\configuration.py:134 msgid "Enable automatic speech feedback" msgstr "自動音声フィードバックを有効化" -#: src\wxUI\dialogs\configuration.py:138 +#: ../src\wxUI\dialogs\configuration.py:136 msgid "Enable automatic Braille feedback" msgstr "自動点字フィードバックを有効化" -#: src\wxUI\dialogs\configuration.py:146 src\wxUI\dialogs\filterDialogs.py:126 -msgid "Buffer" -msgstr "バッファ" - -#: src\wxUI\dialogs\configuration.py:146 +#: ../src\wxUI\dialogs\configuration.py:144 msgid "Status" msgstr "ステータス" -#: src\wxUI\dialogs\configuration.py:149 +#: ../src\wxUI\dialogs\configuration.py:144 +#: ../src\wxUI\dialogs\filterDialogs.py:126 +msgid "Buffer" +msgstr "バッファ" + +#: ../src\wxUI\dialogs\configuration.py:147 msgid "Show/hide" msgstr "表示または非表示" -#: src\wxUI\dialogs\configuration.py:150 +#: ../src\wxUI\dialogs\configuration.py:148 msgid "Move up" msgstr "上へ" -#: src\wxUI\dialogs\configuration.py:151 +#: ../src\wxUI\dialogs\configuration.py:149 msgid "Move down" msgstr "下へ" -#: src\wxUI\dialogs\configuration.py:161 src\wxUI\dialogs\configuration.py:226 -#: src\wxUI\dialogs\configuration.py:229 src\wxUI\dialogs\configuration.py:234 +#: ../src\wxUI\dialogs\configuration.py:159 +#: ../src\wxUI\dialogs\configuration.py:224 +#: ../src\wxUI\dialogs\configuration.py:227 +#: ../src\wxUI\dialogs\configuration.py:232 msgid "Show" msgstr "表示" -#: src\wxUI\dialogs\configuration.py:163 src\wxUI\dialogs\configuration.py:173 -#: src\wxUI\dialogs\configuration.py:197 src\wxUI\dialogs\configuration.py:227 +#: ../src\wxUI\dialogs\configuration.py:161 +#: ../src\wxUI\dialogs\configuration.py:171 +#: ../src\wxUI\dialogs\configuration.py:195 +#: ../src\wxUI\dialogs\configuration.py:225 msgid "Hide" msgstr "非表示" -#: src\wxUI\dialogs\configuration.py:171 src\wxUI\dialogs\configuration.py:195 +#: ../src\wxUI\dialogs\configuration.py:169 +#: ../src\wxUI\dialogs\configuration.py:193 msgid "Select a buffer first." msgstr "最初にバッファを選んでください。" -#: src\wxUI\dialogs\configuration.py:174 src\wxUI\dialogs\configuration.py:198 +#: ../src\wxUI\dialogs\configuration.py:172 +#: ../src\wxUI\dialogs\configuration.py:196 msgid "The buffer is hidden, show it first." msgstr "そのバッファは非表示状態です。まず最初に、表示してください。" -#: src\wxUI\dialogs\configuration.py:177 +#: ../src\wxUI\dialogs\configuration.py:175 msgid "The buffer is already at the top of the list." msgstr "既にそのバッファは、リストの先頭です。" -#: src\wxUI\dialogs\configuration.py:201 +#: ../src\wxUI\dialogs\configuration.py:199 msgid "The buffer is already at the bottom of the list." msgstr "既にそのバッファは、リストの最後です。" -#: src\wxUI\dialogs\configuration.py:242 src\wxUI\dialogs\configuration.py:383 +#: ../src\wxUI\dialogs\configuration.py:240 +#: ../src\wxUI\dialogs\configuration.py:381 msgid "Ignored clients" msgstr "無視するクライアント" -#: src\wxUI\dialogs\configuration.py:249 +#: ../src\wxUI\dialogs\configuration.py:247 msgid "Remove client" msgstr "クライアントを削除" -#: src\wxUI\dialogs\configuration.py:273 +#: ../src\wxUI\dialogs\configuration.py:271 msgid "Volume" msgstr "ボリューム" -#: src\wxUI\dialogs\configuration.py:284 +#: ../src\wxUI\dialogs\configuration.py:282 msgid "Session mute" msgstr "セッションのミュート" -#: src\wxUI\dialogs\configuration.py:286 +#: ../src\wxUI\dialogs\configuration.py:284 msgid "Output device" msgstr "出力先デバイス" -#: src\wxUI\dialogs\configuration.py:293 +#: ../src\wxUI\dialogs\configuration.py:291 msgid "Input device" msgstr "入力デバイス" -#: src\wxUI\dialogs\configuration.py:301 +#: ../src\wxUI\dialogs\configuration.py:299 msgid "Sound pack" msgstr "サウンドパック" -#: src\wxUI\dialogs\configuration.py:307 +#: ../src\wxUI\dialogs\configuration.py:305 msgid "Indicate audio tweets with sound" msgstr "音声付きツイートを音で報告" -#: src\wxUI\dialogs\configuration.py:309 +#: ../src\wxUI\dialogs\configuration.py:307 msgid "Indicate geotweets with sound" msgstr "位置情報付きツイートを音で報告" -#: src\wxUI\dialogs\configuration.py:311 +#: ../src\wxUI\dialogs\configuration.py:309 msgid "Indicate tweets containing images with sound" msgstr "画像付きツイートを音で報告" -#: src\wxUI\dialogs\configuration.py:334 +#: ../src\wxUI\dialogs\configuration.py:332 msgid "Language for OCR" msgstr "OCRの言語" -#: src\wxUI\dialogs\configuration.py:340 +#: ../src\wxUI\dialogs\configuration.py:338 msgid "API Key for SndUp" msgstr "SndUpのAPIキー" -#: src\wxUI\dialogs\configuration.py:355 -#, python-brace-format +#: ../src\wxUI\dialogs\configuration.py:353 msgid "{0} preferences" msgstr "{0}の設定" -#: src\wxUI\dialogs\configuration.py:366 +#: ../src\wxUI\dialogs\configuration.py:364 msgid "Proxy" msgstr "プロキシ" -#: src\wxUI\dialogs\configuration.py:375 +#: ../src\wxUI\dialogs\configuration.py:373 msgid "Feedback" msgstr "フィードバック" -#: src\wxUI\dialogs\configuration.py:379 +#: ../src\wxUI\dialogs\configuration.py:377 msgid "Buffers" msgstr "バッファ" -#: src\wxUI\dialogs\configuration.py:387 +#: ../src\wxUI\dialogs\configuration.py:385 msgid "Sound" msgstr "サウンド" -#: src\wxUI\dialogs\configuration.py:391 +#: ../src\wxUI\dialogs\configuration.py:389 msgid "Extras" msgstr "その他" -#: src\wxUI\dialogs\configuration.py:396 +#: ../src\wxUI\dialogs\configuration.py:394 msgid "Save" msgstr "保存" -#: src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:16 msgid "Create a filter for this buffer" msgstr "このバッファのフィルタを作成" -#: src\wxUI\dialogs\filterDialogs.py:17 +#: ../src\wxUI\dialogs\filterDialogs.py:17 msgid "Filter title" msgstr "フィルター名" -#: src\wxUI\dialogs\filterDialogs.py:26 src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by word" msgstr "単語でフィルター" -#: src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:27 msgid "Ignore tweets wich contain the following word" msgstr "次の単語が含まれるツイートを無視する" -#: src\wxUI\dialogs\filterDialogs.py:28 +#: ../src\wxUI\dialogs\filterDialogs.py:28 msgid "Ignore tweets without the following word" msgstr "次の単語が含まれないツイートを無視する" -#: src\wxUI\dialogs\filterDialogs.py:33 +#: ../src\wxUI\dialogs\filterDialogs.py:33 msgid "word" msgstr "単語" -#: src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow retweets" msgstr "リツイートを許可する" -#: src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:39 msgid "Allow quoted tweets" msgstr "引用ツイートを許可する" -#: src\wxUI\dialogs\filterDialogs.py:40 +#: ../src\wxUI\dialogs\filterDialogs.py:40 msgid "Allow replies" msgstr "リプライを許可するフォロワー一覧" -#: src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:48 msgid "Use this term as a regular expression" msgstr "正規表現を利用" -#: src\wxUI\dialogs\filterDialogs.py:50 src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by language" msgstr "言語でフィルター" -#: src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Load tweets in the following languages" msgstr "下記の言語のツイートを表示" -#: src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:52 msgid "Ignore tweets in the following languages" msgstr "下記の言語のツイートを無視する" -#: src\wxUI\dialogs\filterDialogs.py:53 +#: ../src\wxUI\dialogs\filterDialogs.py:53 msgid "Don't filter by language" msgstr "言語でフィルタしない" -#: src\wxUI\dialogs\filterDialogs.py:64 +#: ../src\wxUI\dialogs\filterDialogs.py:64 msgid "Supported languages" msgstr "サポートしている言語" -#: src\wxUI\dialogs\filterDialogs.py:69 +#: ../src\wxUI\dialogs\filterDialogs.py:69 msgid "Add selected language to filter" msgstr "選択した言語をフィルターに追加" -#: src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:73 msgid "Selected languages" msgstr "選択した言語" -#: src\wxUI\dialogs\filterDialogs.py:75 src\wxUI\dialogs\filterDialogs.py:133 -#: src\wxUI\dialogs\lists.py:21 src\wxUI\dialogs\lists.py:132 +#: ../src\wxUI\dialogs\filterDialogs.py:75 +#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "削除" -#: src\wxUI\dialogs\filterDialogs.py:123 +#: ../src\wxUI\dialogs\filterDialogs.py:123 msgid "Manage filters" msgstr "フィルターの管理" -#: src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:125 msgid "Filters" msgstr "フィルター" -#: src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter" msgstr "フィルター" -#: src\wxUI\dialogs\find.py:13 +#: ../src\wxUI\dialogs\find.py:13 msgid "Find in current buffer" msgstr "現在のバッファ内を検索" -#: src\wxUI\dialogs\find.py:14 +#: ../src\wxUI\dialogs\find.py:14 msgid "String" msgstr "検索文字" -#: src\wxUI\dialogs\lists.py:11 +#: ../src\wxUI\dialogs\lists.py:11 msgid "Lists manager" msgstr "リストの管理" -#: src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:14 msgid "List" msgstr "リスト" -#: src\wxUI\dialogs\lists.py:14 -msgid "Owner" -msgstr "所有者" - -#: src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Members" msgstr "メンバー" -#: src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:14 +msgid "Owner" +msgstr "所有者" + +#: ../src\wxUI\dialogs\lists.py:14 msgid "mode" msgstr "モード" -#: src\wxUI\dialogs\lists.py:19 src\wxUI\dialogs\lists.py:62 +#: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "新しいリストを作成" -#: src\wxUI\dialogs\lists.py:22 +#: ../src\wxUI\dialogs\lists.py:22 msgid "Open in buffer" msgstr "バッファで開く" -#: src\wxUI\dialogs\lists.py:52 -#, python-format +#: ../src\wxUI\dialogs\lists.py:52 msgid "Viewing lists for %s" msgstr "「%s」のリストを閲覧中" -#: src\wxUI\dialogs\lists.py:53 +#: ../src\wxUI\dialogs\lists.py:53 msgid "Subscribe" msgstr "登録" -#: src\wxUI\dialogs\lists.py:54 +#: ../src\wxUI\dialogs\lists.py:54 msgid "Unsubscribe" msgstr "登録解除" -#: src\wxUI\dialogs\lists.py:65 +#: ../src\wxUI\dialogs\lists.py:65 msgid "Name (20 characters maximun)" msgstr "名前(二〇文字以内)" -#: src\wxUI\dialogs\lists.py:75 +#: ../src\wxUI\dialogs\lists.py:75 msgid "Mode" msgstr "モード" -#: src\wxUI\dialogs\lists.py:76 +#: ../src\wxUI\dialogs\lists.py:76 msgid "Public" msgstr "公開" -#: src\wxUI\dialogs\lists.py:77 +#: ../src\wxUI\dialogs\lists.py:77 msgid "Private" msgstr "プライベート" -#: src\wxUI\dialogs\lists.py:97 -#, python-format +#: ../src\wxUI\dialogs\lists.py:97 msgid "Editing the list %s" msgstr "リスト「%s」を編集中" -#: src\wxUI\dialogs\lists.py:108 +#: ../src\wxUI\dialogs\lists.py:108 msgid "Select a list to add the user" msgstr "ユーザーを追加するリストを選択" -#: src\wxUI\dialogs\lists.py:109 +#: ../src\wxUI\dialogs\lists.py:109 msgid "Add" msgstr "追加" -#: src\wxUI\dialogs\lists.py:131 +#: ../src\wxUI\dialogs\lists.py:131 msgid "Select a list to remove the user" msgstr "ユーザーを削除するには、リストを選択" -#: src\wxUI\dialogs\lists.py:149 +#: ../src\wxUI\dialogs\lists.py:149 msgid "Do you really want to delete this list?" msgstr "本当に、このリストを削除しますか?" -#: src\wxUI\dialogs\message.py:75 src\wxUI\dialogs\message.py:256 +#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 msgid "&Long tweet" msgstr "ツイートを短縮して投稿(&L)" -#: src\wxUI\dialogs\message.py:76 src\wxUI\dialogs\message.py:135 -#: src\wxUI\dialogs\message.py:257 +#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 +#: ../src\wxUI\dialogs\message.py:255 msgid "&Upload image..." msgstr "画像をアップロード(&U)" -#: src\wxUI\dialogs\message.py:77 src\wxUI\dialogs\message.py:136 -#: src\wxUI\dialogs\message.py:196 src\wxUI\dialogs\message.py:258 -#: src\wxUI\dialogs\message.py:359 src\wxUI\dialogs\message.py:432 +#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 +#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 +#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 msgid "Check &spelling..." msgstr "スペルチェック(&S)" -#: src\wxUI\dialogs\message.py:78 src\wxUI\dialogs\message.py:137 -#: src\wxUI\dialogs\message.py:197 src\wxUI\dialogs\message.py:259 +#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 +#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 msgid "&Attach audio..." msgstr "音声を添付(&A)" -#: src\wxUI\dialogs\message.py:79 src\wxUI\dialogs\message.py:138 -#: src\wxUI\dialogs\message.py:198 src\wxUI\dialogs\message.py:260 +#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 +#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 msgid "Sh&orten URL" msgstr "URLを短縮(&O)" -#: src\wxUI\dialogs\message.py:80 src\wxUI\dialogs\message.py:139 -#: src\wxUI\dialogs\message.py:199 src\wxUI\dialogs\message.py:261 -#: src\wxUI\dialogs\message.py:360 src\wxUI\dialogs\message.py:433 +#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 +#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 +#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 msgid "&Expand URL" msgstr "URLを元に戻す(&E)" -#: src\wxUI\dialogs\message.py:83 src\wxUI\dialogs\message.py:142 -#: src\wxUI\dialogs\message.py:202 src\wxUI\dialogs\message.py:264 -#: src\wxUI\dialogs\message.py:362 src\wxUI\dialogs\message.py:435 +#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 +#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 +#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 msgid "&Translate..." msgstr "翻訳(&T)..." -#: src\wxUI\dialogs\message.py:84 src\wxUI\dialogs\message.py:143 -#: src\wxUI\dialogs\message.py:188 src\wxUI\dialogs\message.py:265 +#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 +#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 msgid "Auto&complete users" msgstr "ユーザーを自動保管(&C)" -#: src\wxUI\dialogs\message.py:85 src\wxUI\dialogs\message.py:144 -#: src\wxUI\dialogs\message.py:203 src\wxUI\dialogs\message.py:266 +#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 +#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 msgid "Sen&d" msgstr "送信(&D)" -#: src\wxUI\dialogs\message.py:87 src\wxUI\dialogs\message.py:146 -#: src\wxUI\dialogs\message.py:205 src\wxUI\dialogs\message.py:268 -#: src\wxUI\dialogs\message.py:363 src\wxUI\dialogs\message.py:436 +#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 +#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 +#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 msgid "C&lose" msgstr "閉じる(&C)" -#: src\wxUI\dialogs\message.py:186 +#: ../src\wxUI\dialogs\message.py:184 msgid "&Recipient" msgstr "送信先(&R)" -#: src\wxUI\dialogs\message.py:247 +#: ../src\wxUI\dialogs\message.py:245 msgid "&Mention to all" msgstr "全員にリプライ(&M)" -#: src\wxUI\dialogs\message.py:301 -#, python-format +#: ../src\wxUI\dialogs\message.py:299 msgid "Tweet - %i characters " msgstr "ツイート - %i文字" -#: src\wxUI\dialogs\message.py:318 +#: ../src\wxUI\dialogs\message.py:316 msgid "Image description" msgstr "画像の説明" -#: src\wxUI\dialogs\message.py:329 +#: ../src\wxUI\dialogs\message.py:327 msgid "Retweets: " msgstr "リツイート: " -#: src\wxUI\dialogs\message.py:334 +#: ../src\wxUI\dialogs\message.py:332 msgid "Likes: " msgstr "いいね: " -#: src\wxUI\dialogs\message.py:339 +#: ../src\wxUI\dialogs\message.py:337 msgid "Source: " msgstr "ソース: " -#: src\wxUI\dialogs\message.py:344 src\wxUI\dialogs\message.py:422 +#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 msgid "Date: " msgstr "日付: " -#: src\wxUI\dialogs\message.py:407 +#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 +msgid "Copy link to clipboard" +msgstr "リンクをクリップボードへコピー" + +#: ../src\wxUI\dialogs\message.py:408 msgid "View" msgstr "ツイート" -#: src\wxUI\dialogs\message.py:409 +#: ../src\wxUI\dialogs\message.py:410 msgid "Item" msgstr "アイテム" -#: src\wxUI\dialogs\search.py:14 +#: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "ツイッターを検索" -#: src\wxUI\dialogs\search.py:22 +#: ../src\wxUI\dialogs\search.py:13 ../src\wxUI\view.py:21 +msgid "&Search" +msgstr "検索(&S)" + +#: ../src\wxUI\dialogs\search.py:21 msgid "Tweets" msgstr "ツイート" -#: src\wxUI\dialogs\search.py:23 +#: ../src\wxUI\dialogs\search.py:22 ../src\wxUI\dialogs\userAliasDialogs.py:43 msgid "Users" msgstr "ユーザー" -#: src\wxUI\dialogs\search.py:30 +#: ../src\wxUI\dialogs\search.py:29 msgid "&Language for results: " msgstr "結果の言語(&L): " -#: src\wxUI\dialogs\search.py:32 src\wxUI\dialogs\search.py:56 +#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 msgid "any" msgstr "指定しない" -#: src\wxUI\dialogs\search.py:38 +#: ../src\wxUI\dialogs\search.py:37 msgid "Results &type: " msgstr "結果のタイプ(&T): " -#: src\wxUI\dialogs\search.py:39 src\wxUI\dialogs\search.py:64 +#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 msgid "Mixed" msgstr "混合" -#: src\wxUI\dialogs\search.py:39 src\wxUI\dialogs\search.py:65 +#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 msgid "Recent" msgstr "最近" -#: src\wxUI\dialogs\search.py:39 src\wxUI\dialogs\search.py:66 +#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 msgid "Popular" msgstr "人気" -#: src\wxUI\dialogs\search.py:44 src\wxUI\dialogs\trends.py:25 -#: src\wxUI\dialogs\userActions.py:41 src\wxUI\dialogs\userSelection.py:33 +#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:25 +#: ../src\wxUI\dialogs\userActions.py:41 +#: ../src\wxUI\dialogs\userSelection.py:33 msgid "&OK" msgstr "OK(&O)" -#: src\wxUI\dialogs\search.py:46 src\wxUI\dialogs\show_user.py:19 -#: src\wxUI\dialogs\trends.py:27 src\wxUI\dialogs\update_profile.py:37 -#: src\wxUI\dialogs\userActions.py:43 src\wxUI\dialogs\userSelection.py:35 +#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:19 +#: ../src\wxUI\dialogs\trends.py:27 ../src\wxUI\dialogs\update_profile.py:37 +#: ../src\wxUI\dialogs\userActions.py:43 +#: ../src\wxUI\dialogs\userSelection.py:35 msgid "&Close" msgstr "閉じる(&C)" -#: src\wxUI\dialogs\show_user.py:12 +#: ../src\wxUI\dialogs\show_user.py:12 msgid "Details" msgstr "詳細" -#: src\wxUI\dialogs\show_user.py:17 +#: ../src\wxUI\dialogs\show_user.py:17 msgid "&Go to URL" msgstr "URLへ移動(&G)" -#: src\wxUI\dialogs\trends.py:10 +#: ../src\wxUI\dialogs\trends.py:10 msgid "View trending topics" msgstr "トレンドを表示" -#: src\wxUI\dialogs\trends.py:11 +#: ../src\wxUI\dialogs\trends.py:11 msgid "Trending topics by" msgstr "トレンド" -#: src\wxUI\dialogs\trends.py:12 +#: ../src\wxUI\dialogs\trends.py:12 msgid "Country" msgstr "国" -#: src\wxUI\dialogs\trends.py:13 +#: ../src\wxUI\dialogs\trends.py:13 msgid "City" msgstr "都市" -#: src\wxUI\dialogs\trends.py:19 src\wxUI\dialogs\update_profile.py:18 +#: ../src\wxUI\dialogs\trends.py:19 ../src\wxUI\dialogs\update_profile.py:18 msgid "&Location" msgstr "場所(&L)" -#: src\wxUI\dialogs\update_profile.py:10 +#: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "プロフィールを更新" -#: src\wxUI\dialogs\update_profile.py:12 +#: ../src\wxUI\dialogs\update_profile.py:12 msgid "&Name (50 characters maximum)" msgstr "名前(50文字以内)(&N)" -#: src\wxUI\dialogs\update_profile.py:23 +#: ../src\wxUI\dialogs\update_profile.py:23 msgid "&Website" msgstr "ウェブサイト(&W)" -#: src\wxUI\dialogs\update_profile.py:28 +#: ../src\wxUI\dialogs\update_profile.py:28 msgid "&Bio (160 characters maximum)" msgstr "自己紹介(160文字以内)(&B)" -#: src\wxUI\dialogs\update_profile.py:34 +#: ../src\wxUI\dialogs\update_profile.py:34 msgid "Upload a &picture" msgstr "画像をアップロード(&P)" -#: src\wxUI\dialogs\update_profile.py:77 +#: ../src\wxUI\dialogs\update_profile.py:35 ../src\wxUI\view.py:19 +msgid "&Update profile" +msgstr "プロフィールを更新(&U)" + +#: ../src\wxUI\dialogs\update_profile.py:77 msgid "Upload a picture" msgstr "画像をアップロード" -#: src\wxUI\dialogs\update_profile.py:79 +#: ../src\wxUI\dialogs\update_profile.py:79 msgid "Discard image" msgstr "画像をアップロードできません" -#: src\wxUI\dialogs\urlList.py:6 +#: ../src\wxUI\dialogs\urlList.py:6 msgid "Select URL" msgstr "URLを選択" -#: src\wxUI\dialogs\userActions.py:14 src\wxUI\dialogs\userSelection.py:14 -#: src\wxUI\dialogs\utils.py:31 +#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:87 +msgid "&User" +msgstr "ユーザー(&U)" + +#: ../src\wxUI\dialogs\userActions.py:14 +#: ../src\wxUI\dialogs\userAliasDialogs.py:13 +#: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 msgid "&Autocomplete users" msgstr "自動保管されたユーザー" -#: src\wxUI\dialogs\userActions.py:20 +#: ../src\wxUI\dialogs\userActions.py:20 msgid "&Follow" msgstr "フォロー(&F)" -#: src\wxUI\dialogs\userActions.py:21 +#: ../src\wxUI\dialogs\userActions.py:21 msgid "U&nfollow" msgstr "フォロー解除(&N)" -#: src\wxUI\dialogs\userActions.py:23 +#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:63 +msgid "&Mute" +msgstr "ミュート(&M)" + +#: ../src\wxUI\dialogs\userActions.py:23 msgid "Unmu&te" msgstr "ミュート解除(&T)" -#: src\wxUI\dialogs\userActions.py:24 +#: ../src\wxUI\dialogs\userActions.py:24 msgid "&Block" msgstr "ブロック(&B)" -#: src\wxUI\dialogs\userActions.py:25 +#: ../src\wxUI\dialogs\userActions.py:25 msgid "Unbl&ock" msgstr "ブロック解除(&O)" -#: src\wxUI\dialogs\userActions.py:26 +#: ../src\wxUI\dialogs\userActions.py:26 msgid "&Report as spam" msgstr "スパムとして報告(&R)" -#: src\wxUI\dialogs\userActions.py:27 +#: ../src\wxUI\dialogs\userActions.py:27 msgid "&Ignore tweets from this client" msgstr "このクライアントからのツイートを無視(&I)" -#: src\wxUI\dialogs\userSelection.py:10 -#, python-format +#: ../src\wxUI\dialogs\userAliasDialogs.py:18 +msgid "Alias" +msgstr "エイリアス" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:41 +msgid "Edit user aliases" +msgstr "ユーザーエイリアスを編集" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:48 +msgid "Actions" +msgstr "操作" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:50 +msgid "Add alias" +msgstr "エイリアスを追加" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:51 +msgid "Adds a new user alias" +msgstr "新しいユーザーエイリアスを追加" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:54 +msgid "Edit the currently focused user Alias." +msgstr "現在フォーカスされているユーザーエイリアスを編集します。" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:58 +msgid "Remove the currently focused user alias." +msgstr "現在フォーカスされているユーザーエイリアスを削除します。" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Are you sure you want to delete this user alias?" +msgstr "このユーザーエイリアスを削除してもよろしいですか?" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Remove user alias" +msgstr "ユーザーエイリアスを削除" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:93 +msgid "User alias" +msgstr "ユーザーエイリアス" + +#: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "「%s」のタイムライン" -#: src\wxUI\dialogs\userSelection.py:19 +#: ../src\wxUI\dialogs\userSelection.py:19 msgid "Buffer type" msgstr "バッファのタイプ" -#: src\wxUI\dialogs\userSelection.py:20 +#: ../src\wxUI\dialogs\userSelection.py:20 msgid "&Tweets" msgstr "ツイート(&T)" -#: src\wxUI\dialogs\userSelection.py:21 +#: ../src\wxUI\dialogs\userSelection.py:21 msgid "&Likes" msgstr "いいね(&L)" -#: src\wxUI\dialogs\userSelection.py:22 +#: ../src\wxUI\dialogs\userSelection.py:22 msgid "&Followers" msgstr "フォロワー(&F)" -#: src\wxUI\dialogs\userSelection.py:23 +#: ../src\wxUI\dialogs\userSelection.py:23 msgid "F&riends" msgstr "フォロー(&R)" -#~ msgid "Direct connection" -#~ msgstr "直接接続" +#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:33 +msgid "&Retweet" +msgstr "リツイート(&R)" -#~ msgid "This tweet doesn't contain images" -#~ msgstr "このツイートは、画像を含んでいません" +#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:32 +msgid "Re&ply" +msgstr "リプライ(&P)" + +#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:34 +msgid "&Like" +msgstr "いいね(&L)" + +#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:35 +msgid "&Unlike" +msgstr "いいねを解除(&U)" + +#: ../src\wxUI\menus.py:16 ../src\wxUI\menus.py:36 ../src\wxUI\menus.py:52 +msgid "&Open URL" +msgstr "URLを開く(&O)" + +#: ../src\wxUI\menus.py:18 ../src\wxUI\menus.py:54 ../src\wxUI\menus.py:87 +msgid "&Open in Twitter" +msgstr "ツイッターを検索" + +#: ../src\wxUI\menus.py:20 ../src\wxUI\menus.py:38 ../src\wxUI\menus.py:56 +msgid "&Play audio" +msgstr "音声を再生(&P)" + +#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:36 +msgid "&Show tweet" +msgstr "ツイートを表示(&S)" + +#: ../src\wxUI\menus.py:24 ../src\wxUI\menus.py:42 ../src\wxUI\menus.py:60 +#: ../src\wxUI\menus.py:70 ../src\wxUI\menus.py:89 ../src\wxUI\menus.py:103 +msgid "&Copy to clipboard" +msgstr "クリップボードにコピー(&C)" + +#: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 +#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:40 +msgid "&Delete" +msgstr "削除(&D)" + +#: ../src\wxUI\menus.py:28 ../src\wxUI\menus.py:46 ../src\wxUI\menus.py:91 +msgid "&User actions..." +msgstr "ユーザーのアクション(&U)" + +#: ../src\wxUI\menus.py:40 +msgid "&Show direct message" +msgstr "ダイレクトメッセージを表示(&S)" + +#: ../src\wxUI\menus.py:68 +msgid "&Show event" +msgstr "イベントを表示(&S)" + +#: ../src\wxUI\menus.py:78 +msgid "Direct &message" +msgstr "ダイレクトメッセージ(&M)" + +#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:50 +msgid "&View lists" +msgstr "リストを見る(&V)" + +#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:51 +msgid "Show user &profile" +msgstr "ユーザーのプロフィールを表示(&P)" + +#: ../src\wxUI\menus.py:85 +msgid "&Show user" +msgstr "ユーザーを表示(&S)" + +#: ../src\wxUI\menus.py:99 +msgid "&Tweet about this trend" +msgstr "このトレンドのツイート(&T)" + +#: ../src\wxUI\menus.py:101 +msgid "&Show item" +msgstr "アイテムを表示(&S)" + +#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:26 +msgid "&Global settings" +msgstr "全般設定(&G)" + +#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:25 +msgid "Account se&ttings" +msgstr "アカウント設定(&T(" + +#: ../src\wxUI\sysTrayIcon.py:38 +msgid "Update &profile" +msgstr "プロフィールを更新(&P)" + +#: ../src\wxUI\sysTrayIcon.py:39 +msgid "&Show / hide" +msgstr "表示または非表示(&S)" + +#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:75 +msgid "&Documentation" +msgstr "取扱説明書(&D)" + +#: ../src\wxUI\sysTrayIcon.py:41 +msgid "Check for &updates" +msgstr "アップデートを確認(&U)" + +#: ../src\wxUI\sysTrayIcon.py:42 +msgid "&Exit" +msgstr "終了(&E)" + +#: ../src\wxUI\view.py:18 +msgid "&Manage accounts" +msgstr "アカウントの管理(&M)" + +#: ../src\wxUI\view.py:20 +msgid "&Hide window" +msgstr "ウィンドウを隠す(&H)" + +#: ../src\wxUI\view.py:22 +msgid "&Lists manager" +msgstr "リストの管理(&L)" + +#: ../src\wxUI\view.py:23 +msgid "Manage user aliases" +msgstr "ユーザーエイリアスの管理" + +#: ../src\wxUI\view.py:24 +msgid "&Edit keystrokes" +msgstr "キーストロークを編集(&E)" + +#: ../src\wxUI\view.py:27 +msgid "E&xit" +msgstr "終了(&X)" + +#: ../src\wxUI\view.py:31 ../src\wxUI\view.py:86 +msgid "&Tweet" +msgstr "ツイート(&T)" + +#: ../src\wxUI\view.py:37 +msgid "View &address" +msgstr "位置情報を表示(&A)" + +#: ../src\wxUI\view.py:38 +msgid "View conversa&tion" +msgstr "会話を見る(&T)" + +#: ../src\wxUI\view.py:39 +msgid "Read text in picture" +msgstr "画像からテキストを読み取り" + +#: ../src\wxUI\view.py:44 +msgid "&Actions..." +msgstr "操作(&A)" + +#: ../src\wxUI\view.py:45 +msgid "&View timeline..." +msgstr "タイムラインを表示(&V)" + +#: ../src\wxUI\view.py:46 +msgid "Direct me&ssage" +msgstr "ダイレクトメッセージ(&S)" + +#: ../src\wxUI\view.py:47 +msgid "Add a&lias" +msgstr "エイリアスを追加(&A)" + +#: ../src\wxUI\view.py:48 +msgid "&Add to list" +msgstr "リストに追加(&A)" + +#: ../src\wxUI\view.py:49 +msgid "R&emove from list" +msgstr "リストから削除(&E)" + +#: ../src\wxUI\view.py:52 +msgid "V&iew likes" +msgstr "いいね一覧を見る(&I)" + +#: ../src\wxUI\view.py:56 +msgid "&Update buffer" +msgstr "バッファを更新(&U)" + +#: ../src\wxUI\view.py:57 +msgid "New &trending topics buffer..." +msgstr "新しいトレンドのバッファ(&T)" + +#: ../src\wxUI\view.py:58 +msgid "Create a &filter" +msgstr "新しいフィルターを作成(&F)" + +#: ../src\wxUI\view.py:59 +msgid "&Manage filters" +msgstr "フィルターの管理(&M)" + +#: ../src\wxUI\view.py:60 +msgid "Find a string in the currently focused buffer..." +msgstr "現在フォーカス中のバッファ内の文字列を検索..." + +#: ../src\wxUI\view.py:61 +msgid "&Load previous items" +msgstr "以前のアイテムを取得(&L)" + +#: ../src\wxUI\view.py:64 +msgid "&Autoread" +msgstr "自動読み上げ(&A)" + +#: ../src\wxUI\view.py:65 +msgid "&Clear buffer" +msgstr "バッファをクリア(&C)" + +#: ../src\wxUI\view.py:66 +msgid "&Destroy" +msgstr "バッファを削除(&D)" + +#: ../src\wxUI\view.py:70 +msgid "&Seek back 5 seconds" +msgstr "5秒戻る(&S)" + +#: ../src\wxUI\view.py:71 +msgid "&Seek forward 5 seconds" +msgstr "5秒進む(&S)" + +#: ../src\wxUI\view.py:76 +msgid "Sounds &tutorial" +msgstr "サウンドの確認(&T)" + +#: ../src\wxUI\view.py:77 +msgid "&What's new in this version?" +msgstr "更新履歴(&W)" + +#: ../src\wxUI\view.py:78 +msgid "&Check for updates" +msgstr "アップデートを確認(&C)" + +#: ../src\wxUI\view.py:79 +msgid "&Report an error" +msgstr "エラーを報告(&R)" + +#: ../src\wxUI\view.py:80 +msgid "{0}'s &website" +msgstr "「{0}」のウェブサイト(&W)" + +#: ../src\wxUI\view.py:81 +msgid "Get soundpacks for TWBlue" +msgstr "TWBlueのサウンドパックを入手" + +#: ../src\wxUI\view.py:82 +msgid "About &{0}" +msgstr "{0}について(&A)" + +#: ../src\wxUI\view.py:85 +msgid "&Application" +msgstr "アプリケーション(&A)" + +#: ../src\wxUI\view.py:88 +msgid "&Buffer" +msgstr "バッファ(&B)" + +#: ../src\wxUI\view.py:89 +msgid "&Audio" +msgstr "音声(&A)" + +#: ../src\wxUI\view.py:90 +msgid "&Help" +msgstr "ヘルプ(&H)" + +#: ../src\wxUI\view.py:176 +msgid "Address" +msgstr "アドレス" + +#: ../src\wxUI\view.py:207 +msgid "Update" +msgstr "アップデート" + +#: ../src\wxUI\view.py:207 +msgid "Your {0} version is up to date" +msgstr "「{0}」のバージョンは最新です" From f9e58b5724bba7b70c73ebe41c425bae9454eed4 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 05:46:44 -0600 Subject: [PATCH 188/245] Updated Spanish Translation for app's interface --- src/locales/es/LC_MESSAGES/twblue.mo | Bin 51443 -> 54968 bytes src/locales/es/LC_MESSAGES/twblue.po | 1706 ++++++++++++++------------ 2 files changed, 934 insertions(+), 772 deletions(-) diff --git a/src/locales/es/LC_MESSAGES/twblue.mo b/src/locales/es/LC_MESSAGES/twblue.mo index 72cc7b91c9b6687270b876d4de720feb995b4e58..6a57f84e650ac26c3934f0a4a884f79bd6af5c08 100644 GIT binary patch delta 19981 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 NG5P!Bch6zp{{TzGKQ#aV delta 16801 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\n" +"POT-Creation-Date: 2021-11-01 05:25-0600\n" +"PO-Revision-Date: 2021-11-01 05:44-0600\n" +"Last-Translator: Manuel Cortez \n" "Language-Team: Manuel Cortez \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.2.1\n" +"X-Generator: Poedit 3.0\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop\n" "X-Poedit-Basepath: .\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: ../src\controller\attach.py:23 +#: ../src\controller\attach.py:25 msgid "Photo" msgstr "Imagen" -#: ../src\controller\buffers\baseBuffers.py:95 +#: ../src\controller\buffers\base\base.py:91 msgid "This action is not supported for this buffer" msgstr "Esta acción no se encuentra soportada para este buffer" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:306 ../src\controller\settings.py:282 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:337 ../src\controller\settings.py:286 msgid "Home" -msgstr "Principal" +msgstr "Inicio" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:310 ../src\controller\settings.py:283 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:339 ../src\controller\settings.py:287 msgid "Mentions" msgstr "Menciones" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:314 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:341 msgid "Direct messages" msgstr "Mensajes directos" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:318 ../src\controller\settings.py:285 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:343 ../src\controller\settings.py:289 msgid "Sent direct messages" msgstr "Mensajes directos enviados" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:322 ../src\controller\settings.py:286 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:345 ../src\controller\settings.py:290 msgid "Sent tweets" msgstr "Tuits enviados" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:326 -#: ../src\controller\mainController.py:1363 ../src\controller\settings.py:287 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:347 +#: ../src\controller\mainController.py:1390 ../src\controller\settings.py:291 msgid "Likes" msgstr "Tuits marcados como me gusta" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:330 -#: ../src\controller\mainController.py:1368 ../src\controller\settings.py:288 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:349 +#: ../src\controller\mainController.py:1395 ../src\controller\settings.py:292 msgid "Followers" msgstr "Seguidores" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:334 -#: ../src\controller\mainController.py:1373 ../src\controller\settings.py:289 -msgid "Friends" -msgstr "Amigos" - -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:338 -#: ../src\controller\mainController.py:1378 ../src\controller\settings.py:290 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:353 +#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:294 msgid "Blocked users" msgstr "Usuarios bloqueados" -#: ../src\controller\buffers\twitterBuffers.py:69 -#: ../src\controller\mainController.py:342 -#: ../src\controller\mainController.py:1383 ../src\controller\settings.py:291 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:355 +#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:295 msgid "Muted users" msgstr "Usuarios silenciados" -#: ../src\controller\buffers\twitterBuffers.py:75 +#: ../src\controller\buffers\twitter\base.py:70 +#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:293 +msgid "Friends" +msgstr "Amigos" + +#: ../src\controller\buffers\twitter\base.py:76 msgid "{username}'s timeline" msgstr "Línea temporal de {username}" -#: ../src\controller\buffers\twitterBuffers.py:77 +#: ../src\controller\buffers\twitter\base.py:78 msgid "{username}'s likes" msgstr "Tuits que le gustan a {username}" -#: ../src\controller\buffers\twitterBuffers.py:79 +#: ../src\controller\buffers\twitter\base.py:80 msgid "{username}'s followers" msgstr "Seguidores de {username}" -#: ../src\controller\buffers\twitterBuffers.py:81 +#: ../src\controller\buffers\twitter\base.py:82 msgid "{username}'s friends" msgstr "Amigos de {username}" -#: ../src\controller\buffers\twitterBuffers.py:83 +#: ../src\controller\buffers\twitter\base.py:84 msgid "Unknown buffer" msgstr "Buffer desconocido" -#: ../src\controller\buffers\twitterBuffers.py:86 -#: ../src\controller\buffers\twitterBuffers.py:1242 -#: ../src\controller\messages.py:205 ../src\wxUI\buffers\base.py:24 -#: ../src\wxUI\buffers\events.py:14 ../src\wxUI\buffers\trends.py:17 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:34 +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:122 +#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "Tuit" -#: ../src\controller\buffers\twitterBuffers.py:87 -#: ../src\controller\buffers\twitterBuffers.py:1243 +#: ../src\controller\buffers\twitter\base.py:89 +#: ../src\controller\buffers\twitter\trends.py:123 msgid "Write the tweet here" msgstr "Escribe el tuit aquí" -#: ../src\controller\buffers\twitterBuffers.py:194 +#: ../src\controller\buffers\twitter\base.py:219 msgid "New tweet in {0}" msgstr "Nuevo tuit en {0}" -#: ../src\controller\buffers\twitterBuffers.py:197 +#: ../src\controller\buffers\twitter\base.py:222 msgid "{0} new tweets in {1}." msgstr "{0} nuevos tuits en {1}." -#: ../src\controller\buffers\twitterBuffers.py:232 -#: ../src\controller\buffers\twitterBuffers.py:676 -#: ../src\controller\buffers\twitterBuffers.py:910 -#: ../src\controller\buffers\twitterBuffers.py:1061 -#: ../src\controller\buffers\twitterBuffers.py:1126 +#: ../src\controller\buffers\twitter\base.py:261 +#: ../src\controller\buffers\twitter\directMessages.py:88 +#: ../src\controller\buffers\twitter\people.py:180 msgid "%s items retrieved" msgstr "%s elementos recuperados" -#: ../src\controller\buffers\twitterBuffers.py:264 -#: ../src\controller\buffers\twitterBuffers.py:840 +#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\people.py:80 msgid "This buffer is not a timeline; it can't be deleted." msgstr "Este buffer no es una línea temporal. No se puede eliminar." -#: ../src\controller\buffers\twitterBuffers.py:402 +#: ../src\controller\buffers\twitter\base.py:430 msgid "Reply to {arg0}" msgstr "Responder a {arg0}" -#: ../src\controller\buffers\twitterBuffers.py:404 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:26 +#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 msgid "Reply" msgstr "Responder" -#: ../src\controller\buffers\twitterBuffers.py:405 +#: ../src\controller\buffers\twitter\base.py:433 msgid "Reply to %s" msgstr "Responder a %s" -#: ../src\controller\buffers\twitterBuffers.py:451 -msgid "Direct message to %s" -msgstr "Mensaje directo a %s" - -#: ../src\controller\buffers\twitterBuffers.py:451 -#: ../src\controller\buffers\twitterBuffers.py:725 +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\buffers\twitter\directMessages.py:130 msgid "New direct message" msgstr "Nuevo mensaje directo" -#: ../src\controller\buffers\twitterBuffers.py:500 +#: ../src\controller\buffers\twitter\base.py:480 +#: ../src\controller\messages.py:200 +msgid "Direct message to %s" +msgstr "Mensaje directo a %s" + +#: ../src\controller\buffers\twitter\base.py:520 msgid "Add your comment to the tweet" msgstr "Añade tu comentario al tuit" -#: ../src\controller\buffers\twitterBuffers.py:500 +#: ../src\controller\buffers\twitter\base.py:520 msgid "Quote" msgstr "Citar" -#: ../src\controller\buffers\twitterBuffers.py:572 +#: ../src\controller\buffers\twitter\base.py:596 msgid "Opening URL..." msgstr "Abriendo URL..." -#: ../src\controller\buffers\twitterBuffers.py:607 +#: ../src\controller\buffers\twitter\base.py:633 msgid "User details" msgstr "Detalles del usuario" -#: ../src\controller\buffers\twitterBuffers.py:634 -#: ../src\controller\buffers\twitterBuffers.py:987 +#: ../src\controller\buffers\twitter\base.py:654 msgid "Opening item in web browser..." msgstr "Abriendo elemento en el navegador..." -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 +#: ../src\controller\buffers\twitter\directMessages.py:93 +#: ../src\controller\buffers\twitter\people.py:95 msgid "Mention to %s" msgstr "Mencionar a %s" -#: ../src\controller\buffers\twitterBuffers.py:688 -#: ../src\controller\buffers\twitterBuffers.py:855 -#: ../src\wxUI\buffers\people.py:16 +#: ../src\controller\buffers\twitter\directMessages.py:93 +#: ../src\controller\buffers\twitter\people.py:95 +#: ../src\wxUI\buffers\people.py:17 msgid "Mention" msgstr "Mención" -#: ../src\controller\buffers\twitterBuffers.py:728 +#: ../src\controller\buffers\twitter\directMessages.py:133 msgid "{0} new direct messages." msgstr "{0} mensajes directos nuevos." -#: ../src\controller\buffers\twitterBuffers.py:731 +#: ../src\controller\buffers\twitter\directMessages.py:136 msgid "This action is not supported in the buffer yet." msgstr "Esta acción todavía no se soporta en este buffer." -#: ../src\controller\buffers\twitterBuffers.py:741 +#: ../src\controller\buffers\twitter\directMessages.py:146 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -202,324 +199,358 @@ msgstr "" "No se pueden obtener más elementos en este buffer. Usa el buffer de mensajes " "directos en su lugar." -#: ../src\controller\buffers\twitterBuffers.py:983 +#: ../src\controller\buffers\twitter\people.py:253 msgid "{0} new followers." msgstr "{0} nuevos seguidores." -#: ../src\controller\buffers\twitterBuffers.py:1266 +#: ../src\controller\buffers\twitter\trends.py:146 msgid "This action is not supported in the buffer, yet." msgstr "Esta acción todavía no se soporta en este buffer." -#: ../src\controller\mainController.py:273 +#: ../src\controller\mainController.py:277 msgid "Ready" msgstr "Listo" -#: ../src\controller\mainController.py:345 +#: ../src\controller\mainController.py:351 +msgid "Following" +msgstr "Siguiendo" + +#: ../src\controller\mainController.py:356 msgid "Timelines" msgstr "Líneas temporales" -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:860 -#: ../src\controller\mainController.py:1559 +#: ../src\controller\mainController.py:359 +#: ../src\controller\mainController.py:883 +#: ../src\controller\mainController.py:1585 msgid "Timeline for {}" msgstr "Línea temporal de {0}" -#: ../src\controller\mainController.py:352 +#: ../src\controller\mainController.py:360 msgid "Likes timelines" msgstr "Líneas temporales de tuits marcados con me gusta" -#: ../src\controller\mainController.py:356 -#: ../src\controller\mainController.py:879 -#: ../src\controller\mainController.py:1561 +#: ../src\controller\mainController.py:363 +#: ../src\controller\mainController.py:902 +#: ../src\controller\mainController.py:1587 msgid "Likes for {}" msgstr "Tuits que le gustan a {0}" -#: ../src\controller\mainController.py:359 -msgid "Followers' Timelines" +#: ../src\controller\mainController.py:364 +msgid "Followers timelines" msgstr "Líneas temporales de seguidores" -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:898 -#: ../src\controller\mainController.py:1563 +#: ../src\controller\mainController.py:367 +#: ../src\controller\mainController.py:921 +#: ../src\controller\mainController.py:1589 msgid "Followers for {}" msgstr "Seguidores de {0}" -#: ../src\controller\mainController.py:366 -msgid "Friends' Timelines" -msgstr "Líneas temporales de amigos" +#: ../src\controller\mainController.py:368 +msgid "Following timelines" +msgstr "Líneas temporales de siguiendo" -#: ../src\controller\mainController.py:370 -#: ../src\controller\mainController.py:917 -#: ../src\controller\mainController.py:1565 +#: ../src\controller\mainController.py:371 +#: ../src\controller\mainController.py:940 +#: ../src\controller\mainController.py:1591 msgid "Friends for {}" msgstr "Amigos de {0}" -#: ../src\controller\mainController.py:373 ../src\wxUI\dialogs\lists.py:12 +#: ../src\controller\mainController.py:372 ../src\wxUI\dialogs\lists.py:13 msgid "Lists" msgstr "Listas" -#: ../src\controller\mainController.py:378 -#: ../src\controller\mainController.py:1399 +#: ../src\controller\mainController.py:375 +#: ../src\controller\mainController.py:1422 msgid "List for {}" msgstr "Lista {0}" -#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:376 msgid "Searches" msgstr "Búsquedas" -#: ../src\controller\mainController.py:385 -#: ../src\controller\mainController.py:444 +#: ../src\controller\mainController.py:379 +#: ../src\controller\mainController.py:426 +#: ../src\controller\mainController.py:431 msgid "Search for {}" msgstr "Buscar {0}" -#: ../src\controller\mainController.py:391 -#: ../src\controller\mainController.py:959 +#: ../src\controller\mainController.py:381 +#: ../src\controller\mainController.py:982 +#: ../src\controller\mainController.py:1593 msgid "Trending topics for %s" msgstr "Tendencias para %s" -#: ../src\controller\mainController.py:461 -#: ../src\controller\mainController.py:477 -#: ../src\controller\mainController.py:1059 -#: ../src\controller\mainController.py:1078 -#: ../src\controller\mainController.py:1097 -#: ../src\controller\mainController.py:1116 +#: ../src\controller\mainController.py:448 +#: ../src\controller\mainController.py:464 +#: ../src\controller\mainController.py:1080 +#: ../src\controller\mainController.py:1099 +#: ../src\controller\mainController.py:1118 +#: ../src\controller\mainController.py:1137 msgid "" "No session is currently in focus. Focus a session with the next or previous " "session shortcut." msgstr "No estás en ninguna sesión. Cambia a una sesión activa." -#: ../src\controller\mainController.py:465 +#: ../src\controller\mainController.py:452 msgid "Empty buffer." msgstr "Buffer vacío." -#: ../src\controller\mainController.py:472 +#: ../src\controller\mainController.py:459 msgid "{0} not found." msgstr "{0} no encontrado." -#: ../src\controller\mainController.py:482 +#: ../src\controller\mainController.py:469 msgid "Filters cannot be applied on this buffer" msgstr "No pueden aplicarse filtros sobre este buffer" -#: ../src\controller\mainController.py:535 -#: ../src\controller\mainController.py:552 -#: ../src\controller\mainController.py:580 +#: ../src\controller\mainController.py:522 +#: ../src\controller\mainController.py:539 +#: ../src\controller\mainController.py:568 msgid "Select the user" msgstr "Selecciona un usuario" -#: ../src\controller\mainController.py:809 ../src\controller\messages.py:236 +#: ../src\controller\mainController.py:753 +msgid "Add an user alias" +msgstr "Añadir alias de usuario" + +#: ../src\controller\mainController.py:761 +msgid "Alias has been set correctly for {}." +msgstr "Añadido el alias para {}" + +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 msgid "MMM D, YYYY. H:m" msgstr "D MMM, YYYY. H:m" -#: ../src\controller\mainController.py:934 +#: ../src\controller\mainController.py:957 msgid "Conversation with {0}" msgstr "Conversación con {0}" -#: ../src\controller\mainController.py:975 -#: ../src\controller\mainController.py:994 +#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1015 msgid "There are no coordinates in this tweet" msgstr "No hay coordenadas en este tuit" -#: ../src\controller\mainController.py:977 -#: ../src\controller\mainController.py:996 -msgid "There are no results for the coordinates in this tweet" -msgstr "No hay resultados para las coordenadas en este tuit" - -#: ../src\controller\mainController.py:979 -#: ../src\controller\mainController.py:998 +#: ../src\controller\mainController.py:1000 +#: ../src\controller\mainController.py:1019 msgid "Error decoding coordinates. Try again later." msgstr "Error decodificando las coordenadas. Inténtalo nuevamente más tarde." -#: ../src\controller\mainController.py:1107 -#: ../src\controller\mainController.py:1126 +#: ../src\controller\mainController.py:1004 +msgid "Unable to find address in OpenStreetMap." +msgstr "Imposible encontrar dirección en Open Street Map." + +#: ../src\controller\mainController.py:1017 +msgid "There are no results for the coordinates in this tweet" +msgstr "No hay resultados para las coordenadas en este tuit" + +#: ../src\controller\mainController.py:1128 +#: ../src\controller\mainController.py:1147 msgid "%s, %s of %s" msgstr "%s, %s de %s" -#: ../src\controller\mainController.py:1109 -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1153 -#: ../src\controller\mainController.py:1178 +#: ../src\controller\mainController.py:1130 +#: ../src\controller\mainController.py:1149 +#: ../src\controller\mainController.py:1174 +#: ../src\controller\mainController.py:1199 msgid "%s. Empty" msgstr "%s. Vacío" -#: ../src\controller\mainController.py:1141 -#: ../src\controller\mainController.py:1145 +#: ../src\controller\mainController.py:1162 #: ../src\controller\mainController.py:1166 +#: ../src\controller\mainController.py:1187 msgid "{0}: This account is not logged into Twitter." msgstr "{0}: No has iniciado sesión con esta cuenta en Twitter." -#: ../src\controller\mainController.py:1151 -#: ../src\controller\mainController.py:1176 +#: ../src\controller\mainController.py:1172 +#: ../src\controller\mainController.py:1197 msgid "%s. %s, %s of %s" msgstr "%s. %s, %s de %s" -#: ../src\controller\mainController.py:1170 +#: ../src\controller\mainController.py:1191 msgid "{0}: This account is not logged into twitter." msgstr "{0}: No has iniciado sesión con esta cuenta en Twitter." -#: ../src\controller\mainController.py:1388 -msgid "Events" -msgstr "Eventos" - -#: ../src\controller\mainController.py:1393 +#: ../src\controller\mainController.py:1416 msgid "This list is already opened" msgstr "Esta lista ya ha sido abierta" -#: ../src\controller\mainController.py:1423 -#: ../src\controller\mainController.py:1439 +#: ../src\controller\mainController.py:1446 +#: ../src\controller\mainController.py:1462 msgid "" "An error happened while trying to connect to the server. Please try later." msgstr "" "Ha ocurrido un error al intentar conectarse al servidor. Por favor, " "inténtalo más tarde." -#: ../src\controller\mainController.py:1475 +#: ../src\controller\mainController.py:1498 msgid "The auto-reading of new tweets is enabled for this buffer" msgstr "La lectura automática de nuevos tuits para este buffer está activada" -#: ../src\controller\mainController.py:1478 +#: ../src\controller\mainController.py:1501 msgid "The auto-reading of new tweets is disabled for this buffer" msgstr "" "La lectura automática de nuevos tuits para este buffer está desactivada" -#: ../src\controller\mainController.py:1485 +#: ../src\controller\mainController.py:1508 msgid "Session mute on" msgstr "Silencio de sesión activo" -#: ../src\controller\mainController.py:1488 +#: ../src\controller\mainController.py:1511 msgid "Session mute off" msgstr "Silencio de sesión desactivado" -#: ../src\controller\mainController.py:1496 +#: ../src\controller\mainController.py:1519 msgid "Buffer mute on" msgstr "Silenciar buffer, activado" -#: ../src\controller\mainController.py:1499 +#: ../src\controller\mainController.py:1522 msgid "Buffer mute off" msgstr "Silenciar buffer, desactivado" -#: ../src\controller\mainController.py:1522 +#: ../src\controller\mainController.py:1545 msgid "Copied" msgstr "Copiado" -#: ../src\controller\mainController.py:1549 +#: ../src\controller\mainController.py:1575 msgid "Unable to update this buffer." msgstr "Imposible actualizar este buffer." -#: ../src\controller\mainController.py:1552 +#: ../src\controller\mainController.py:1578 msgid "Updating buffer..." msgstr "Actualizando buffer..." -#: ../src\controller\mainController.py:1555 +#: ../src\controller\mainController.py:1581 msgid "{0} items retrieved" msgstr "{0} elementos descargados" -#: ../src\controller\mainController.py:1572 +#: ../src\controller\mainController.py:1600 +#: ../src\controller\mainController.py:1620 msgid "Invalid buffer" msgstr "Buffer inválido" -#: ../src\controller\mainController.py:1576 -msgid "This tweet doesn't contain images" -msgstr "El tuit no contiene imágenes" - -#: ../src\controller\mainController.py:1579 +#: ../src\controller\mainController.py:1611 msgid "Picture {0}" msgstr "Foto {0}" -#: ../src\controller\mainController.py:1580 +#: ../src\controller\mainController.py:1612 msgid "Select the picture" msgstr "Selecciona la foto" -#: ../src\controller\mainController.py:1596 +#: ../src\controller\mainController.py:1631 msgid "Unable to extract text" msgstr "Imposible extraer texto" -#: ../src\controller\messages.py:54 +#: ../src\controller\messages.py:56 msgid "Translated" msgstr "Traducido" -#: ../src\controller\messages.py:61 +#: ../src\controller\messages.py:63 msgid "There's no URL to be shortened" msgstr "No hay ninguna URL para acortar" -#: ../src\controller\messages.py:65 ../src\controller\messages.py:73 +#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 msgid "URL shortened" msgstr "URL Acortada" -#: ../src\controller\messages.py:80 +#: ../src\controller\messages.py:82 msgid "There's no URL to be expanded" msgstr "No hay ninguna URL para expandir" -#: ../src\controller\messages.py:84 ../src\controller\messages.py:92 +#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 msgid "URL expanded" msgstr "URL expandida" -#: ../src\controller\messages.py:104 +#: ../src\controller\messages.py:108 msgid "%s - %s of %d characters" msgstr "%s - %s de %d caracteres" -#: ../src\controller\messages.py:108 +#: ../src\controller\messages.py:112 msgid "%s - %s characters" msgstr "%s - %s caracteres" -#: ../src\controller\messages.py:262 +#: ../src\controller\messages.py:272 msgid "View item" msgstr "Ver elemento" -#: ../src\controller\settings.py:75 -msgid "Direct connection" -msgstr "Conexión directa" +#: ../src\controller\messages.py:301 +msgid "Link copied to clipboard." +msgstr "Enlace copiado al portapapeles" -#: ../src\controller\settings.py:145 ../src\controller\settings.py:207 -#: ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:74 +msgid "HTTP" +msgstr "HTTP" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4" +msgstr "SOCKS v4" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v4 with DNS support" +msgstr "SOCKS v4 con soporte DNS" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5" +msgstr "SOCKS v5" + +#: ../src\controller\settings.py:74 +msgid "SOCKS v5 with DNS support" +msgstr "SOCKS v5 con soporte DNS" + +#: ../src\controller\settings.py:74 +msgid "System default" +msgstr "Predeterminado del sistema" + +#: ../src\controller\settings.py:145 ../src\controller\settings.py:211 +#: ../src\wxUI\dialogs\configuration.py:116 msgid "Ask" msgstr "Preguntar" -#: ../src\controller\settings.py:147 ../src\controller\settings.py:209 -#: ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:147 ../src\controller\settings.py:213 +#: ../src\wxUI\dialogs\configuration.py:116 msgid "Retweet without comments" msgstr "Retuitear sin comentario" -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:117 +#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:116 msgid "Retweet with comments" msgstr "Retuitear añadiendo un comentario" -#: ../src\controller\settings.py:184 +#: ../src\controller\settings.py:185 msgid "Account settings for %s" msgstr "Opciones de la cuenta de %s" -#: ../src\controller\settings.py:284 +#: ../src\controller\settings.py:288 msgid "Direct Messages" msgstr "Mensajes directos" -#: ../src\controller\user.py:28 ../src\controller\user.py:30 -#: ../src\extra\SpellChecker\wx_ui.py:79 ../src\issueReporter\wx_ui.py:83 -#: ../src\issueReporter\wx_ui.py:86 ../src\wxUI\commonMessageDialogs.py:38 -#: ../src\wxUI\commonMessageDialogs.py:50 -#: ../src\wxUI\commonMessageDialogs.py:57 -#: ../src\wxUI\commonMessageDialogs.py:60 -#: ../src\wxUI\commonMessageDialogs.py:63 -#: ../src\wxUI\commonMessageDialogs.py:66 -#: ../src\wxUI\commonMessageDialogs.py:76 -#: ../src\wxUI\commonMessageDialogs.py:79 -#: ../src\wxUI\commonMessageDialogs.py:82 -#: ../src\wxUI\commonMessageDialogs.py:88 -#: ../src\wxUI\commonMessageDialogs.py:91 +#: ../src\controller\user.py:29 ../src\controller\user.py:31 +#: ../src\extra\SpellChecker\wx_ui.py:80 ../src\issueReporter\wx_ui.py:84 +#: ../src\issueReporter\wx_ui.py:87 ../src\wxUI\commonMessageDialogs.py:39 +#: ../src\wxUI\commonMessageDialogs.py:51 +#: ../src\wxUI\commonMessageDialogs.py:58 +#: ../src\wxUI\commonMessageDialogs.py:61 +#: ../src\wxUI\commonMessageDialogs.py:64 +#: ../src\wxUI\commonMessageDialogs.py:67 +#: ../src\wxUI\commonMessageDialogs.py:77 +#: ../src\wxUI\commonMessageDialogs.py:80 +#: ../src\wxUI\commonMessageDialogs.py:83 +#: ../src\wxUI\commonMessageDialogs.py:89 +#: ../src\wxUI\commonMessageDialogs.py:92 msgid "Error" msgstr "Error" -#: ../src\controller\user.py:28 ../src\wxUI\commonMessageDialogs.py:38 +#: ../src\controller\user.py:29 ../src\wxUI\commonMessageDialogs.py:39 msgid "That user does not exist" msgstr "El usuario no existe" -#: ../src\controller\user.py:30 +#: ../src\controller\user.py:31 msgid "User has been suspended" msgstr "El usuario ha sido suspendido" -#: ../src\controller\user.py:36 +#: ../src\controller\user.py:37 msgid "Information for %s" msgstr "Detalles para %s" -#: ../src\controller\user.py:66 ../src\extra\AudioUploader\audioUploader.py:124 +#: ../src\controller\user.py:67 ../src\extra\AudioUploader\audioUploader.py:127 msgid "Discarded" msgstr "Descartado" @@ -539,31 +570,31 @@ msgstr "Ubicación: %s\n" msgid "URL: %s\n" msgstr "URL: %s\n" -#: ../src\controller\user.py:102 +#: ../src\controller\user.py:104 msgid "Bio: %s\n" msgstr "Descripción: %s\n" -#: ../src\controller\user.py:103 ../src\controller\user.py:118 +#: ../src\controller\user.py:105 ../src\controller\user.py:120 msgid "Yes" msgstr "Sí" -#: ../src\controller\user.py:104 ../src\controller\user.py:119 +#: ../src\controller\user.py:106 ../src\controller\user.py:121 msgid "No" msgstr "No" -#: ../src\controller\user.py:105 +#: ../src\controller\user.py:107 msgid "Protected: %s\n" msgstr "Protegido: %s\n" -#: ../src\controller\user.py:110 +#: ../src\controller\user.py:112 msgid "You follow {0}. " msgstr "Sigues a {0}. " -#: ../src\controller\user.py:113 +#: ../src\controller\user.py:115 msgid "{0} is following you." msgstr "{0} te sigue." -#: ../src\controller\user.py:117 +#: ../src\controller\user.py:119 msgid "" "Followers: %s\n" " Friends: %s\n" @@ -571,311 +602,315 @@ msgstr "" "Seguidores: %s\n" " Amigos: %s\n" -#: ../src\controller\user.py:120 +#: ../src\controller\user.py:122 msgid "Verified: %s\n" msgstr "Verificado: %s\n" -#: ../src\controller\user.py:121 +#: ../src\controller\user.py:123 msgid "Tweets: %s\n" msgstr "Tuits: %s\n" -#: ../src\controller\user.py:122 +#: ../src\controller\user.py:124 msgid "Likes: %s" msgstr "Me gusta: %s" -#: ../src\controller\userActionsController.py:75 +#: ../src\controller\userActionsController.py:74 msgid "You can't ignore direct messages" msgstr "No puedes ignorar los mensajes directos" -#: ../src\extra\AudioUploader\audioUploader.py:54 +#: ../src\controller\userAliasController.py:32 +msgid "Edit alias for {}" +msgstr "Editar alias para {}" + +#: ../src\extra\AudioUploader\audioUploader.py:57 msgid "Attaching..." msgstr "Adjuntando..." -#: ../src\extra\AudioUploader\audioUploader.py:71 +#: ../src\extra\AudioUploader\audioUploader.py:74 msgid "Pause" msgstr "Pausa" -#: ../src\extra\AudioUploader\audioUploader.py:73 +#: ../src\extra\AudioUploader\audioUploader.py:76 msgid "&Resume" msgstr "&Reanudar" -#: ../src\extra\AudioUploader\audioUploader.py:74 +#: ../src\extra\AudioUploader\audioUploader.py:77 msgid "Resume" msgstr "Reanudar" -#: ../src\extra\AudioUploader\audioUploader.py:76 -#: ../src\extra\AudioUploader\audioUploader.py:103 -#: ../src\extra\AudioUploader\wx_ui.py:36 +#: ../src\extra\AudioUploader\audioUploader.py:79 +#: ../src\extra\AudioUploader\audioUploader.py:106 +#: ../src\extra\AudioUploader\wx_ui.py:37 msgid "&Pause" msgstr "&Pausa" -#: ../src\extra\AudioUploader\audioUploader.py:91 -#: ../src\extra\AudioUploader\audioUploader.py:137 +#: ../src\extra\AudioUploader\audioUploader.py:94 +#: ../src\extra\AudioUploader\audioUploader.py:140 msgid "&Stop" msgstr "&Detener" -#: ../src\extra\AudioUploader\audioUploader.py:92 +#: ../src\extra\AudioUploader\audioUploader.py:95 msgid "Recording" msgstr "Grabando" -#: ../src\extra\AudioUploader\audioUploader.py:97 -#: ../src\extra\AudioUploader\audioUploader.py:148 +#: ../src\extra\AudioUploader\audioUploader.py:100 +#: ../src\extra\AudioUploader\audioUploader.py:151 msgid "Stopped" msgstr "Stopped" -#: ../src\extra\AudioUploader\audioUploader.py:99 -#: ../src\extra\AudioUploader\wx_ui.py:38 +#: ../src\extra\AudioUploader\audioUploader.py:102 +#: ../src\extra\AudioUploader\wx_ui.py:39 msgid "&Record" msgstr "&Grabar" -#: ../src\extra\AudioUploader\audioUploader.py:133 ../src\sound.py:146 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 msgid "Playing..." msgstr "Reproduciendo..." -#: ../src\extra\AudioUploader\audioUploader.py:141 -#: ../src\extra\AudioUploader\audioUploader.py:151 -#: ../src\extra\AudioUploader\wx_ui.py:34 +#: ../src\extra\AudioUploader\audioUploader.py:144 +#: ../src\extra\AudioUploader\audioUploader.py:154 +#: ../src\extra\AudioUploader\wx_ui.py:35 msgid "&Play" msgstr "&Reproducir" -#: ../src\extra\AudioUploader\audioUploader.py:156 +#: ../src\extra\AudioUploader\audioUploader.py:159 msgid "Recoding audio..." msgstr "Recodificando audio..." -#: ../src\extra\AudioUploader\transfer.py:78 -#: ../src\extra\AudioUploader\transfer.py:84 +#: ../src\extra\AudioUploader\transfer.py:82 +#: ../src\extra\AudioUploader\transfer.py:88 msgid "Error in file upload: {0}" msgstr "Error al subir el archivo: {0}" -#: ../src\extra\AudioUploader\utils.py:27 ../src\update\utils.py:27 +#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 msgid "%d day, " msgstr "%d día, " -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 +#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 msgid "%d days, " msgstr "%d días, " -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 +#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 msgid "%d hour, " msgstr "%d hora, " -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 +#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 msgid "%d hours, " msgstr "%d horas, " -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 +#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 msgid "%d minute, " msgstr "%d minuto, " -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 +#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 msgid "%d minutes, " msgstr "%d minutos, " -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 +#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 msgid "%s second" msgstr "%s segundo" -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 +#: ../src\extra\AudioUploader\utils.py:43 ../src\update\utils.py:43 msgid "%s seconds" msgstr "%s segundos" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:14 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 msgid "File" msgstr "Archivo" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:20 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:21 msgid "Transferred" msgstr "Transferido" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:25 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:26 msgid "Total file size" msgstr "Tamaño total del archivo" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:30 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:31 msgid "Transfer rate" msgstr "Velocidad de transferencia" -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:35 +#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:36 msgid "Time left" msgstr "Tiempo restante" -#: ../src\extra\AudioUploader\wx_ui.py:28 +#: ../src\extra\AudioUploader\wx_ui.py:29 msgid "Attach audio" msgstr "Adjuntar audio" -#: ../src\extra\AudioUploader\wx_ui.py:40 +#: ../src\extra\AudioUploader\wx_ui.py:41 msgid "&Add an existing file" msgstr "&Añadir un archivo existente" -#: ../src\extra\AudioUploader\wx_ui.py:41 +#: ../src\extra\AudioUploader\wx_ui.py:42 msgid "&Discard" msgstr "&Descartar" -#: ../src\extra\AudioUploader\wx_ui.py:43 +#: ../src\extra\AudioUploader\wx_ui.py:44 msgid "Upload to" msgstr "Subir a" -#: ../src\extra\AudioUploader\wx_ui.py:48 +#: ../src\extra\AudioUploader\wx_ui.py:49 msgid "Attach" msgstr "Adjuntar" -#: ../src\extra\AudioUploader\wx_ui.py:50 +#: ../src\extra\AudioUploader\wx_ui.py:51 msgid "&Cancel" msgstr "&Cancelar" -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: ../src\extra\AudioUploader\wx_ui.py:76 msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" msgstr "Archivos de audio (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -#: ../src\extra\AudioUploader\wx_ui.py:75 +#: ../src\extra\AudioUploader\wx_ui.py:76 msgid "Select the audio file to be uploaded" msgstr "Selecciona el archivo de audio que deseas subir" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:6 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 msgid "Audio tweet." msgstr "Tuit con audio." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 msgid "User timeline buffer created." msgstr "Línea temporal de un usuario creada." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 msgid "Buffer destroied." msgstr "Buffer eliminado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 msgid "Direct message received." msgstr "Mensaje directo recibido." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 msgid "Direct message sent." msgstr "Mensaje directo enviado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 msgid "Error." msgstr "Error." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 msgid "Tweet liked." msgstr "Tuit marcado como me gusta." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 msgid "Likes buffer updated." msgstr "Un Buffer de tuits marcados como me gusta se ha actualizado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 msgid "Geotweet." msgstr "Tuit con información geográfica." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 msgid "Tweet contains one or more images" msgstr "El tuit contiene una o más imágenes" -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 msgid "Boundary reached." msgstr "No hay más elementos en el buffer." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 msgid "List updated." msgstr "Lista actualizada." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 msgid "Too many characters." msgstr "Demasiados caracteres." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 msgid "Mention received." msgstr "Mención recibida." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 msgid "New event." msgstr "Nuevo evento." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 msgid "{0} is ready." msgstr "{0} está listo." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 msgid "Mention sent." msgstr "Mención enviada." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 msgid "Tweet retweeted." msgstr "Tuit retuiteado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 msgid "Search buffer updated." msgstr "Buffer de búsqueda actualizado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 msgid "Tweet received." msgstr "Tuit recibido." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 msgid "Tweet sent." msgstr "Tuit enviado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 msgid "Trending topics buffer updated." msgstr "Buffer de trending topics actualizado." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 msgid "New tweet in user timeline buffer." msgstr "Nuevo tuit en línea temporal de un usuario." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 msgid "New follower." msgstr "Nuevo seguidor." -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 +#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:31 msgid "Volume changed." msgstr "Volumen modificado." -#: ../src\extra\SoundsTutorial\wx_ui.py:8 +#: ../src\extra\SoundsTutorial\wx_ui.py:9 msgid "Sounds tutorial" msgstr "Tutorial de sonidos" -#: ../src\extra\SoundsTutorial\wx_ui.py:11 +#: ../src\extra\SoundsTutorial\wx_ui.py:12 msgid "Press enter to listen to the sound for the selected event" msgstr "Pulsa enter para escuchar el sonido para el evento seleccionado" -#: ../src\extra\SpellChecker\spellchecker.py:57 +#: ../src\extra\SpellChecker\spellchecker.py:60 msgid "Misspelled word: %s" msgstr "Palabra mal escrita: %s" -#: ../src\extra\SpellChecker\wx_ui.py:27 +#: ../src\extra\SpellChecker\wx_ui.py:28 msgid "Misspelled word" msgstr "Palabra mal escrita" -#: ../src\extra\SpellChecker\wx_ui.py:32 +#: ../src\extra\SpellChecker\wx_ui.py:33 msgid "Context" msgstr "Contexto" -#: ../src\extra\SpellChecker\wx_ui.py:37 +#: ../src\extra\SpellChecker\wx_ui.py:38 msgid "Suggestions" msgstr "Sugerencias" -#: ../src\extra\SpellChecker\wx_ui.py:42 +#: ../src\extra\SpellChecker\wx_ui.py:43 msgid "&Ignore" msgstr "&Ignorar" -#: ../src\extra\SpellChecker\wx_ui.py:43 +#: ../src\extra\SpellChecker\wx_ui.py:44 msgid "I&gnore all" msgstr "Ignorar &todo" -#: ../src\extra\SpellChecker\wx_ui.py:44 +#: ../src\extra\SpellChecker\wx_ui.py:45 msgid "&Replace" msgstr "&Reemplazar" -#: ../src\extra\SpellChecker\wx_ui.py:45 +#: ../src\extra\SpellChecker\wx_ui.py:46 msgid "R&eplace all" msgstr "R&eemplazar todo" -#: ../src\extra\SpellChecker\wx_ui.py:46 +#: ../src\extra\SpellChecker\wx_ui.py:47 msgid "&Add to personal dictionary" msgstr "Añadir al &diccionario" -#: ../src\extra\SpellChecker\wx_ui.py:79 +#: ../src\extra\SpellChecker\wx_ui.py:80 msgid "" "An error has occurred. There are no dictionaries available for the selected " "language in {0}" @@ -883,25 +918,25 @@ msgstr "" "Ha ocurrido un error. No se encuentran diccionarios disponibles para el " "idioma seleccionado en {0}." -#: ../src\extra\SpellChecker\wx_ui.py:82 +#: ../src\extra\SpellChecker\wx_ui.py:83 msgid "Spell check complete." msgstr "Corrección ortográfica finalizada." -#: ../src\extra\autocompletionUsers\completion.py:21 -#: ../src\extra\autocompletionUsers\completion.py:39 +#: ../src\extra\autocompletionUsers\completion.py:20 +#: ../src\extra\autocompletionUsers\completion.py:38 msgid "You have to start writing" msgstr "Tienes que empezar a escribir" -#: ../src\extra\autocompletionUsers\completion.py:31 -#: ../src\extra\autocompletionUsers\completion.py:48 +#: ../src\extra\autocompletionUsers\completion.py:30 +#: ../src\extra\autocompletionUsers\completion.py:47 msgid "There are no results in your users database" msgstr "No hay resultados en tu base de datos de usuarios" -#: ../src\extra\autocompletionUsers\completion.py:33 +#: ../src\extra\autocompletionUsers\completion.py:32 msgid "Autocompletion only works for users." msgstr "El autocompletado solo funciona con usuarios." -#: ../src\extra\autocompletionUsers\settings.py:27 +#: ../src\extra\autocompletionUsers\settings.py:25 msgid "" "Updating database... You can close this window now. A message will tell you " "when the process finishes." @@ -909,45 +944,45 @@ msgstr "" "Actualizando base de datos... Puedes cerrar esta ventana ahora. Un mensaje " "te informará cuando el proceso haya terminado." -#: ../src\extra\autocompletionUsers\wx_manage.py:8 +#: ../src\extra\autocompletionUsers\wx_manage.py:9 msgid "Manage Autocompletion database" msgstr "Gestionar la base de datos del autocompletado de usuarios" -#: ../src\extra\autocompletionUsers\wx_manage.py:11 +#: ../src\extra\autocompletionUsers\wx_manage.py:12 msgid "Editing {0} users database" msgstr "Editando la base de datos de usuarios de {0}" -#: ../src\extra\autocompletionUsers\wx_manage.py:12 +#: ../src\extra\autocompletionUsers\wx_manage.py:13 msgid "Username" msgstr "Nombre de usuario" -#: ../src\extra\autocompletionUsers\wx_manage.py:12 +#: ../src\extra\autocompletionUsers\wx_manage.py:13 #: ../src\wxUI\dialogs\configuration.py:144 msgid "Name" msgstr "Nombre" -#: ../src\extra\autocompletionUsers\wx_manage.py:15 +#: ../src\extra\autocompletionUsers\wx_manage.py:16 msgid "Add user" msgstr "Añadir usuario" -#: ../src\extra\autocompletionUsers\wx_manage.py:16 +#: ../src\extra\autocompletionUsers\wx_manage.py:17 msgid "Remove user" msgstr "Quitar usuario" -#: ../src\extra\autocompletionUsers\wx_manage.py:37 +#: ../src\extra\autocompletionUsers\wx_manage.py:38 msgid "Add user to database" msgstr "Añadir usuario a la base de datos" -#: ../src\extra\autocompletionUsers\wx_manage.py:37 +#: ../src\extra\autocompletionUsers\wx_manage.py:38 msgid "Twitter username" msgstr "Nombre de usuario de Twitter" -#: ../src\extra\autocompletionUsers\wx_manage.py:43 +#: ../src\extra\autocompletionUsers\wx_manage.py:44 msgid "The user does not exist" msgstr "El usuario no existe" -#: ../src\extra\autocompletionUsers\wx_manage.py:43 -#: ../src\wxUI\commonMessageDialogs.py:44 +#: ../src\extra\autocompletionUsers\wx_manage.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "Error!" msgstr "¡Error!" @@ -975,468 +1010,468 @@ msgstr "¡Hecho" msgid "{0}'s database of users has been updated." msgstr "La base de datos de usuarios de {0} ha sido actualizada." -#: ../src\extra\ocr\OCRSpace.py:5 +#: ../src\extra\ocr\OCRSpace.py:7 msgid "Detect automatically" msgstr "Detectar automáticamente" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:31 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:41 msgid "Danish" msgstr "Danés" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:33 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:43 msgid "Dutch" msgstr "Holandés" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:34 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:44 msgid "English" msgstr "Inglés" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:38 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:48 msgid "Finnish" msgstr "Finés" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:39 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:49 msgid "French" msgstr "Francés" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:42 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:52 msgid "German" msgstr "Alemán" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:48 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:58 msgid "Hungarian" msgstr "Húngaro" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:53 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:63 msgid "Italian" msgstr "Italiano" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:54 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:64 msgid "Japanese" msgstr "Japonés" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:58 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:68 msgid "Korean" msgstr "Coreano" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:75 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:85 msgid "Polish" msgstr "Polaco" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:76 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:86 msgid "Portuguese" msgstr "Portugués" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:79 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:89 msgid "Russian" msgstr "Ruso" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:86 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:96 msgid "Spanish" msgstr "Español" -#: ../src\extra\ocr\OCRSpace.py:5 ../src\extra\translator\translator.py:95 +#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:105 msgid "Turkish" msgstr "Turco" -#: ../src\extra\translator\translator.py:12 +#: ../src\extra\translator\translator.py:22 msgid "Afrikaans" msgstr "Africano" -#: ../src\extra\translator\translator.py:13 +#: ../src\extra\translator\translator.py:23 msgid "Albanian" msgstr "Albanés" -#: ../src\extra\translator\translator.py:14 +#: ../src\extra\translator\translator.py:24 msgid "Amharic" msgstr "Amárico" -#: ../src\extra\translator\translator.py:15 +#: ../src\extra\translator\translator.py:25 msgid "Arabic" msgstr "Árabe" -#: ../src\extra\translator\translator.py:16 +#: ../src\extra\translator\translator.py:26 msgid "Armenian" msgstr "Armenio" -#: ../src\extra\translator\translator.py:17 +#: ../src\extra\translator\translator.py:27 msgid "Azerbaijani" msgstr "Acerí" -#: ../src\extra\translator\translator.py:18 +#: ../src\extra\translator\translator.py:28 msgid "Basque" msgstr "Vasco" -#: ../src\extra\translator\translator.py:19 +#: ../src\extra\translator\translator.py:29 msgid "Belarusian" msgstr "Bielorruso" -#: ../src\extra\translator\translator.py:20 +#: ../src\extra\translator\translator.py:30 msgid "Bengali" msgstr "Bengalí" -#: ../src\extra\translator\translator.py:21 +#: ../src\extra\translator\translator.py:31 msgid "Bihari" msgstr "Bihari" -#: ../src\extra\translator\translator.py:22 +#: ../src\extra\translator\translator.py:32 msgid "Bulgarian" msgstr "Búlgaro" -#: ../src\extra\translator\translator.py:23 +#: ../src\extra\translator\translator.py:33 msgid "Burmese" msgstr "Birmano" -#: ../src\extra\translator\translator.py:24 +#: ../src\extra\translator\translator.py:34 msgid "Catalan" msgstr "Catalán" -#: ../src\extra\translator\translator.py:25 +#: ../src\extra\translator\translator.py:35 msgid "Cherokee" msgstr "Cheroqui" -#: ../src\extra\translator\translator.py:26 +#: ../src\extra\translator\translator.py:36 msgid "Chinese" msgstr "Chino" -#: ../src\extra\translator\translator.py:27 +#: ../src\extra\translator\translator.py:37 msgid "Chinese_simplified" msgstr "Chino simplificado" -#: ../src\extra\translator\translator.py:28 +#: ../src\extra\translator\translator.py:38 msgid "Chinese_traditional" msgstr "Chino tradicional" -#: ../src\extra\translator\translator.py:29 +#: ../src\extra\translator\translator.py:39 msgid "Croatian" msgstr "Croata" -#: ../src\extra\translator\translator.py:30 +#: ../src\extra\translator\translator.py:40 msgid "Czech" msgstr "Checo" -#: ../src\extra\translator\translator.py:32 +#: ../src\extra\translator\translator.py:42 msgid "Dhivehi" msgstr "Dhivehi" -#: ../src\extra\translator\translator.py:35 +#: ../src\extra\translator\translator.py:45 msgid "Esperanto" msgstr "Esperanto" -#: ../src\extra\translator\translator.py:36 +#: ../src\extra\translator\translator.py:46 msgid "Estonian" msgstr "Estonio" -#: ../src\extra\translator\translator.py:37 +#: ../src\extra\translator\translator.py:47 msgid "Filipino" msgstr "Filipino" -#: ../src\extra\translator\translator.py:40 +#: ../src\extra\translator\translator.py:50 msgid "Galician" msgstr "Gallego" -#: ../src\extra\translator\translator.py:41 +#: ../src\extra\translator\translator.py:51 msgid "Georgian" msgstr "Georgiano" -#: ../src\extra\translator\translator.py:43 +#: ../src\extra\translator\translator.py:53 msgid "Greek" msgstr "Griego" -#: ../src\extra\translator\translator.py:44 +#: ../src\extra\translator\translator.py:54 msgid "Guarani" msgstr "Guaraní" -#: ../src\extra\translator\translator.py:45 +#: ../src\extra\translator\translator.py:55 msgid "Gujarati" msgstr "Guyaratí" -#: ../src\extra\translator\translator.py:46 +#: ../src\extra\translator\translator.py:56 msgid "Hebrew" msgstr "Hebreo" -#: ../src\extra\translator\translator.py:47 +#: ../src\extra\translator\translator.py:57 msgid "Hindi" msgstr "Hindi" -#: ../src\extra\translator\translator.py:49 +#: ../src\extra\translator\translator.py:59 msgid "Icelandic" msgstr "Islandés" -#: ../src\extra\translator\translator.py:50 +#: ../src\extra\translator\translator.py:60 msgid "Indonesian" msgstr "Indonesio" -#: ../src\extra\translator\translator.py:51 +#: ../src\extra\translator\translator.py:61 msgid "Inuktitut" msgstr "Inuktitut" -#: ../src\extra\translator\translator.py:52 +#: ../src\extra\translator\translator.py:62 msgid "Irish" msgstr "Irlandés" -#: ../src\extra\translator\translator.py:55 +#: ../src\extra\translator\translator.py:65 msgid "Kannada" msgstr "Canarés" -#: ../src\extra\translator\translator.py:56 +#: ../src\extra\translator\translator.py:66 msgid "Kazakh" msgstr "Kazajo" -#: ../src\extra\translator\translator.py:57 +#: ../src\extra\translator\translator.py:67 msgid "Khmer" msgstr "Camboyano" -#: ../src\extra\translator\translator.py:59 +#: ../src\extra\translator\translator.py:69 msgid "Kurdish" msgstr "Kurdo" -#: ../src\extra\translator\translator.py:60 +#: ../src\extra\translator\translator.py:70 msgid "Kyrgyz" msgstr "Kirguís" -#: ../src\extra\translator\translator.py:61 +#: ../src\extra\translator\translator.py:71 msgid "Laothian" msgstr "Lao" -#: ../src\extra\translator\translator.py:62 +#: ../src\extra\translator\translator.py:72 msgid "Latvian" msgstr "Letón" -#: ../src\extra\translator\translator.py:63 +#: ../src\extra\translator\translator.py:73 msgid "Lithuanian" msgstr "Lituano" -#: ../src\extra\translator\translator.py:64 +#: ../src\extra\translator\translator.py:74 msgid "Macedonian" msgstr "Macedonio" -#: ../src\extra\translator\translator.py:65 +#: ../src\extra\translator\translator.py:75 msgid "Malay" msgstr "Malayo" -#: ../src\extra\translator\translator.py:66 +#: ../src\extra\translator\translator.py:76 msgid "Malayalam" msgstr "Malayalam" -#: ../src\extra\translator\translator.py:67 +#: ../src\extra\translator\translator.py:77 msgid "Maltese" msgstr "Maltés" -#: ../src\extra\translator\translator.py:68 +#: ../src\extra\translator\translator.py:78 msgid "Marathi" msgstr "Maratí" -#: ../src\extra\translator\translator.py:69 +#: ../src\extra\translator\translator.py:79 msgid "Mongolian" msgstr "Mongol" -#: ../src\extra\translator\translator.py:70 +#: ../src\extra\translator\translator.py:80 msgid "Nepali" msgstr "Nepalí" -#: ../src\extra\translator\translator.py:71 +#: ../src\extra\translator\translator.py:81 msgid "Norwegian" msgstr "Noruego" -#: ../src\extra\translator\translator.py:72 +#: ../src\extra\translator\translator.py:82 msgid "Oriya" msgstr "Oriya" -#: ../src\extra\translator\translator.py:73 +#: ../src\extra\translator\translator.py:83 msgid "Pashto" msgstr "Pastú" -#: ../src\extra\translator\translator.py:74 +#: ../src\extra\translator\translator.py:84 msgid "Persian" msgstr "Persa" -#: ../src\extra\translator\translator.py:77 +#: ../src\extra\translator\translator.py:87 msgid "Punjabi" msgstr "Panyabí" -#: ../src\extra\translator\translator.py:78 +#: ../src\extra\translator\translator.py:88 msgid "Romanian" msgstr "Rumano" -#: ../src\extra\translator\translator.py:80 +#: ../src\extra\translator\translator.py:90 msgid "Sanskrit" msgstr "Sánscrito" -#: ../src\extra\translator\translator.py:81 +#: ../src\extra\translator\translator.py:91 msgid "Serbian" msgstr "Serbio" -#: ../src\extra\translator\translator.py:82 +#: ../src\extra\translator\translator.py:92 msgid "Sindhi" msgstr "Sindhi" -#: ../src\extra\translator\translator.py:83 +#: ../src\extra\translator\translator.py:93 msgid "Sinhalese" msgstr "Cingalés" -#: ../src\extra\translator\translator.py:84 +#: ../src\extra\translator\translator.py:94 msgid "Slovak" msgstr "Eslovaco" -#: ../src\extra\translator\translator.py:85 +#: ../src\extra\translator\translator.py:95 msgid "Slovenian" msgstr "Esloveno" -#: ../src\extra\translator\translator.py:87 +#: ../src\extra\translator\translator.py:97 msgid "Swahili" msgstr "Suajili" -#: ../src\extra\translator\translator.py:88 +#: ../src\extra\translator\translator.py:98 msgid "Swedish" msgstr "Sueco" -#: ../src\extra\translator\translator.py:89 +#: ../src\extra\translator\translator.py:99 msgid "Tajik" msgstr "Tayiko" -#: ../src\extra\translator\translator.py:90 +#: ../src\extra\translator\translator.py:100 msgid "Tamil" msgstr "Tamil" -#: ../src\extra\translator\translator.py:91 +#: ../src\extra\translator\translator.py:101 msgid "Tagalog" msgstr "Tagalo" -#: ../src\extra\translator\translator.py:92 +#: ../src\extra\translator\translator.py:102 msgid "Telugu" msgstr "Telugú" -#: ../src\extra\translator\translator.py:93 +#: ../src\extra\translator\translator.py:103 msgid "Thai" msgstr "Tailandés" -#: ../src\extra\translator\translator.py:94 +#: ../src\extra\translator\translator.py:104 msgid "Tibetan" msgstr "Tibetano" -#: ../src\extra\translator\translator.py:96 +#: ../src\extra\translator\translator.py:106 msgid "Ukrainian" msgstr "Ucraniano" -#: ../src\extra\translator\translator.py:97 +#: ../src\extra\translator\translator.py:107 msgid "Urdu" msgstr "Urdu" -#: ../src\extra\translator\translator.py:98 +#: ../src\extra\translator\translator.py:108 msgid "Uzbek" msgstr "Uzbeco" -#: ../src\extra\translator\translator.py:99 +#: ../src\extra\translator\translator.py:109 msgid "Uighur" msgstr "Uigur" -#: ../src\extra\translator\translator.py:100 +#: ../src\extra\translator\translator.py:110 msgid "Vietnamese" msgstr "Vietnamita" -#: ../src\extra\translator\translator.py:101 +#: ../src\extra\translator\translator.py:111 msgid "Welsh" msgstr "Galés" -#: ../src\extra\translator\translator.py:102 +#: ../src\extra\translator\translator.py:112 msgid "Yiddish" msgstr "Yídish" -#: ../src\extra\translator\wx_ui.py:44 +#: ../src\extra\translator\wx_ui.py:29 msgid "Translate message" msgstr "Traducir mensaje" -#: ../src\extra\translator\wx_ui.py:47 +#: ../src\extra\translator\wx_ui.py:32 msgid "Target language" msgstr "Idioma de destino" -#: ../src\issueReporter\issueReporter.py:30 +#: ../src\issueReporter\issueReporter.py:32 #: ../src\wxUI\dialogs\configuration.py:359 #: ../src\wxUI\dialogs\configuration.py:368 msgid "General" msgstr "General" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "always" msgstr "siempre" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "have not tried" msgstr "no se ha intentado" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "random" msgstr "aleatoriamente" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "sometimes" msgstr "a veces" -#: ../src\issueReporter\issueReporter.py:31 +#: ../src\issueReporter\issueReporter.py:33 msgid "unable to duplicate" msgstr "imposible de reproducir" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "block" msgstr "bloqueo" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "crash" msgstr "fallo" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "feature" msgstr "característica" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "major" msgstr "mayor" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "minor" msgstr "menor" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "text" msgstr "texto" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "trivial" msgstr "trivial" -#: ../src\issueReporter\issueReporter.py:32 +#: ../src\issueReporter\issueReporter.py:34 msgid "tweak" msgstr "ajuste" -#: ../src\issueReporter\wx_ui.py:25 +#: ../src\issueReporter\wx_ui.py:26 msgid "Report an error" msgstr "Reportar un error" -#: ../src\issueReporter\wx_ui.py:28 +#: ../src\issueReporter\wx_ui.py:29 msgid "Select a category" msgstr "Selecciona una categoría" -#: ../src\issueReporter\wx_ui.py:36 +#: ../src\issueReporter\wx_ui.py:37 msgid "" "Briefly describe what happened. You will be able to thoroughly explain it " "later" msgstr "" "Describe en pocas palabras lo que ha pasado (después podrás profundizar)" -#: ../src\issueReporter\wx_ui.py:45 +#: ../src\issueReporter\wx_ui.py:46 msgid "Here, you can describe the bug in detail" msgstr "Aquí puedes describir el error en detalle" -#: ../src\issueReporter\wx_ui.py:55 +#: ../src\issueReporter\wx_ui.py:56 msgid "how often does this bug happen?" msgstr "¿Qué tan a menudo ocurre este error?" -#: ../src\issueReporter\wx_ui.py:62 +#: ../src\issueReporter\wx_ui.py:63 msgid "Select the importance that you think this bug has" msgstr "Selecciona la importancia que consideras que tiene este error" -#: ../src\issueReporter\wx_ui.py:69 +#: ../src\issueReporter\wx_ui.py:70 msgid "" "I know that the {0} bug system will get my Twitter username to contact me " "and fix the bug quickly" @@ -1444,20 +1479,20 @@ msgstr "" "Sé que el sistema de errores de {0} obtendrá mi nombre de usuario de Twitter " "para contactarme y resolver el error rápidamente" -#: ../src\issueReporter\wx_ui.py:72 +#: ../src\issueReporter\wx_ui.py:73 msgid "Send report" msgstr "Enviar reporte" -#: ../src\issueReporter\wx_ui.py:74 ../src\wxUI\dialogs\filterDialogs.py:83 -#: ../src\wxUI\dialogs\find.py:22 +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "Cancelar" -#: ../src\issueReporter\wx_ui.py:83 +#: ../src\issueReporter\wx_ui.py:84 msgid "You must fill out both fields" msgstr "Debes llenar ambos campos" -#: ../src\issueReporter\wx_ui.py:86 +#: ../src\issueReporter\wx_ui.py:87 msgid "" "You need to mark the checkbox to provide us your twitter username to contact " "you if it is necessary." @@ -1465,7 +1500,7 @@ msgstr "" "Debes marcar la casilla para proporcionarnos tu nombre de usuario de Twitter " "para poder contactarte si es necesario." -#: ../src\issueReporter\wx_ui.py:89 +#: ../src\issueReporter\wx_ui.py:90 msgid "" "Thanks for reporting this bug! In future versions, you may be able to find " "it in the changes list. You've reported the bug number %i" @@ -1473,15 +1508,15 @@ msgstr "" "¡Gracias por reportar este error! Quizá puedas verlo entre la lista de " "cambios de próximas versiones. Has reportado el error número %i" -#: ../src\issueReporter\wx_ui.py:89 +#: ../src\issueReporter\wx_ui.py:90 msgid "reported" msgstr "reportado" -#: ../src\issueReporter\wx_ui.py:93 +#: ../src\issueReporter\wx_ui.py:94 msgid "Error while reporting" msgstr "Error al reportar" -#: ../src\issueReporter\wx_ui.py:93 +#: ../src\issueReporter\wx_ui.py:94 msgid "" "Something unexpected occurred while trying to report the bug. Please, try " "again later" @@ -1521,8 +1556,8 @@ msgstr "Muestra o esconde la interfaz gráfica" msgid "New tweet" msgstr "Nuevo tuit" -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\commonMessageDialogs.py:9 ../src\wxUI\dialogs\message.py:126 +#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 +#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 msgid "Retweet" msgstr "Retuit" @@ -1715,6 +1750,10 @@ msgstr "Actualiza el buffer e intenta descargar los elementos perdidos." msgid "Extracts the text from a picture and displays the result in a dialog." msgstr "Extrae el texto de una foto y muestra el resultado en un diálogo." +#: ../src\keystrokeEditor\constants.py:59 +msgid "Adds an alias to an user" +msgstr "Añade un alias a un usuario específico." + #: ../src\keystrokeEditor\wx_ui.py:8 msgid "Keystroke editor" msgstr "Editor de combinaciones de teclado" @@ -1727,63 +1766,76 @@ msgstr "Selecciona una combinación de teclado para editarla" msgid "Keystroke" msgstr "Combinación de teclado" -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:9 -#: ../src\wxUI\dialogs\userActions.py:18 ../src\wxUI\dialogs\userActions.py:19 +#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:10 +#: ../src\wxUI\dialogs\userActions.py:19 ../src\wxUI\dialogs\userActions.py:20 msgid "Action" msgstr "Acción" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:130 -#: ../src\wxUI\dialogs\lists.py:19 +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 msgid "Edit" msgstr "Editar" -#: ../src\keystrokeEditor\wx_ui.py:20 +#: ../src\keystrokeEditor\wx_ui.py:20 ../src\keystrokeEditor\wx_ui.py:50 +msgid "Undefine keystroke" +msgstr "Desasignar combinación de teclas" + +#: ../src\keystrokeEditor\wx_ui.py:21 msgid "Execute action" msgstr "Ejecutar acción" -#: ../src\keystrokeEditor\wx_ui.py:21 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\utils.py:38 +#: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 +#: ../src\wxUI\dialogs\userAliasDialogs.py:25 ../src\wxUI\dialogs\utils.py:39 msgid "Close" msgstr "Cerrar" -#: ../src\keystrokeEditor\wx_ui.py:48 +#: ../src\keystrokeEditor\wx_ui.py:42 +msgid "Undefined" +msgstr "Sin definir" + +#: ../src\keystrokeEditor\wx_ui.py:50 +msgid "Are you sure you want to undefine this keystroke?" +msgstr "¿Seguro que deseas desasignar esta combinación de teclado?" + +#: ../src\keystrokeEditor\wx_ui.py:54 msgid "Editing keystroke" msgstr "Editando combinación de teclas" -#: ../src\keystrokeEditor\wx_ui.py:51 +#: ../src\keystrokeEditor\wx_ui.py:57 msgid "Control" msgstr "Control" -#: ../src\keystrokeEditor\wx_ui.py:52 +#: ../src\keystrokeEditor\wx_ui.py:58 msgid "Alt" msgstr "Alt" -#: ../src\keystrokeEditor\wx_ui.py:53 +#: ../src\keystrokeEditor\wx_ui.py:59 msgid "Shift" msgstr "Shift" -#: ../src\keystrokeEditor\wx_ui.py:54 +#: ../src\keystrokeEditor\wx_ui.py:60 msgid "Windows" msgstr "Windows" -#: ../src\keystrokeEditor\wx_ui.py:60 +#: ../src\keystrokeEditor\wx_ui.py:66 msgid "Key" msgstr "Tecla" -#: ../src\keystrokeEditor\wx_ui.py:65 ../src\wxUI\dialogs\filterDialogs.py:81 -#: ../src\wxUI\dialogs\find.py:20 ../src\wxUI\dialogs\utils.py:35 +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 +#: ../src\wxUI\dialogs\utils.py:36 msgid "OK" msgstr "Aceptar" -#: ../src\keystrokeEditor\wx_ui.py:78 +#: ../src\keystrokeEditor\wx_ui.py:84 msgid "You need to use the Windows key" msgstr "Necesitas usar la tecla de windows" -#: ../src\keystrokeEditor\wx_ui.py:78 ../src\keystrokeEditor\wx_ui.py:81 +#: ../src\keystrokeEditor\wx_ui.py:84 ../src\keystrokeEditor\wx_ui.py:87 msgid "Invalid keystroke" msgstr "Combinación de teclado inválida" -#: ../src\keystrokeEditor\wx_ui.py:81 +#: ../src\keystrokeEditor\wx_ui.py:87 msgid "You must provide a character for the keystroke" msgstr "Debes proporcionar una letra para el atajo de teclado" @@ -1791,11 +1843,11 @@ msgstr "Debes proporcionar una letra para el atajo de teclado" msgid "User default" msgstr "Idioma predeterminado" -#: ../src\main.py:105 +#: ../src\main.py:120 msgid "https://twblue.es/donate" msgstr "https://twblue.es/donate" -#: ../src\main.py:122 +#: ../src\main.py:137 msgid "" "{0} is already running. Close the other instance before starting this one. " "If you're sure that {0} isn't running, try deleting the file at {1}. If " @@ -1806,43 +1858,43 @@ msgstr "" "archivo que se encuentra en {1}. Si no sabes cómo hacerlo con seguridad, " "contacta con los desarrolladores de {0}." -#: ../src\sessionmanager\wxUI.py:8 +#: ../src\sessionmanager\wxUI.py:9 msgid "Session manager" msgstr "Gestor de sesiones" -#: ../src\sessionmanager\wxUI.py:11 +#: ../src\sessionmanager\wxUI.py:12 msgid "Accounts list" msgstr "Lista de cuentas" -#: ../src\sessionmanager\wxUI.py:13 +#: ../src\sessionmanager\wxUI.py:14 msgid "Account" msgstr "Cuenta" -#: ../src\sessionmanager\wxUI.py:17 +#: ../src\sessionmanager\wxUI.py:18 msgid "New account" msgstr "Nueva cuenta" -#: ../src\sessionmanager\wxUI.py:18 ../src\sessionmanager\wxUI.py:64 +#: ../src\sessionmanager\wxUI.py:19 ../src\sessionmanager\wxUI.py:65 msgid "Remove account" msgstr "Eliminar cuenta" -#: ../src\sessionmanager\wxUI.py:19 +#: ../src\sessionmanager\wxUI.py:20 msgid "Global Settings" msgstr "Opciones globales" -#: ../src\sessionmanager\wxUI.py:42 +#: ../src\sessionmanager\wxUI.py:43 msgid "Account Error" msgstr "Error en la cuenta" -#: ../src\sessionmanager\wxUI.py:42 +#: ../src\sessionmanager\wxUI.py:43 msgid "You need to configure an account." msgstr "Necesitas configurar una cuenta." -#: ../src\sessionmanager\wxUI.py:48 +#: ../src\sessionmanager\wxUI.py:49 msgid "Authorization" msgstr "Autorización" -#: ../src\sessionmanager\wxUI.py:48 +#: ../src\sessionmanager\wxUI.py:49 msgid "" "The request to authorize your Twitter account will be opened in your " "browser. You only need to do this once. Would you like to continue?" @@ -1850,15 +1902,15 @@ msgstr "" "La solicitud de autorización de Twitter será abierta en tu navegador. Esto " "es necesario hacerlo solo una vez. ¿Quieres continuar?" -#: ../src\sessionmanager\wxUI.py:52 +#: ../src\sessionmanager\wxUI.py:53 msgid "Authorized account %d" msgstr "Cuenta autorizada %d" -#: ../src\sessionmanager\wxUI.py:58 +#: ../src\sessionmanager\wxUI.py:59 msgid "Invalid user token" msgstr "Código de acceso inválido" -#: ../src\sessionmanager\wxUI.py:58 +#: ../src\sessionmanager\wxUI.py:59 msgid "" "Your access token is invalid or the authorization has failed. Please try " "again." @@ -1866,30 +1918,67 @@ msgstr "" "El código de autorización es inválido o el proceso ha fallado. Por favor " "inténtalo de nuevo más tarde." -#: ../src\sessionmanager\wxUI.py:64 +#: ../src\sessionmanager\wxUI.py:65 msgid "Do you really want to delete this account?" msgstr "¿Realmente deseas eliminar esta cuenta?" -#: ../src\sessions\twitter\compose.py:39 ../src\sessions\twitter\compose.py:89 -#: ../src\sessions\twitter\compose.py:152 -#: ../src\sessions\twitter\compose.py:161 +#: ../src\sessionmanager\wxUI.py:81 +msgid "Authentication error for session {}" +msgstr "Error de autenticación en la sesión {}" + +#: ../src\sessionmanager\wxUI.py:81 +msgid "" +"TWBlue is unable to authenticate the account for {} in Twitter. It might be " +"due to an invalid or expired token, revoqued access to the application, or " +"after an account reactivation. Please remove the account manually from your " +"Twitter sessions in order to stop seeing this message." +msgstr "" +"TWBlue es incapaz de autenticar los datos para la cuenta {}. Esto puede " +"deberse a un token incorrecto o que ya ha expirado; a haber revocado acceso " +"a la aplicación, o luego de reactivar una cuenta previamente suspendida. Por " +"favor, elimina esta cuenta manualmente desde tus sesiones de Twitter en la " +"aplicación para dejar de ver este mensaje." + +#: ../src\sessions\base.py:113 +msgid "" +"An exception occurred while saving the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"Ha ocurrido un error al guardar la base de datos de {app}. La base de datos " +"será creada desde cero automáticamente. Si este error persiste, contacta con " +"los desarrolladores de {app} para obtener ayuda." + +#: ../src\sessions\base.py:153 +msgid "" +"An exception occurred while loading the {app} database. It will be deleted " +"and rebuilt automatically. If this error persists, send the error log to the " +"{app} developers." +msgstr "" +"Ocurrió un error al cargar la base de datos de {app}. {app} creará una base " +"de datos nueva automáticamente. Si este error persiste, contacta con los " +"desarrolladores de {app} para obtener ayuda." + +#: ../src\sessions\twitter\compose.py:38 ../src\sessions\twitter\compose.py:81 +#: ../src\sessions\twitter\compose.py:146 +#: ../src\sessions\twitter\compose.py:155 msgid "dddd, MMMM D, YYYY H:m:s" msgstr "dddd, MMMM D, YYYY H:m:s" -#: ../src\sessions\twitter\compose.py:97 ../src\sessions\twitter\compose.py:99 +#: ../src\sessions\twitter\compose.py:89 ../src\sessions\twitter\compose.py:91 msgid "Dm to %s " msgstr "Dm a %s " -#: ../src\sessions\twitter\compose.py:141 +#: ../src\sessions\twitter\compose.py:130 msgid "{0}. Quoted tweet from @{1}: {2}" msgstr "{0} citó el tuit de {1}: {2}" -#: ../src\sessions\twitter\compose.py:163 -#: ../src\sessions\twitter\compose.py:165 +#: ../src\sessions\twitter\compose.py:157 +#: ../src\sessions\twitter\compose.py:159 msgid "Unavailable" msgstr "No disponible" -#: ../src\sessions\twitter\compose.py:166 +#: ../src\sessions\twitter\compose.py:160 msgid "" "%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " "Twitter %s" @@ -1897,59 +1986,64 @@ msgstr "" "%s (@%s). %s seguidores, %s amigos, %s tuits. Último tuit %s. Se unió a " "Twitter %s" -#: ../src\sessions\twitter\compose.py:170 +#: ../src\sessions\twitter\compose.py:164 msgid "No description available" msgstr "No hay una descripción disponible" -#: ../src\sessions\twitter\compose.py:174 +#: ../src\sessions\twitter\compose.py:168 msgid "private" msgstr "privado" -#: ../src\sessions\twitter\compose.py:175 +#: ../src\sessions\twitter\compose.py:169 msgid "public" msgstr "público" -#: ../src\sessions\twitter\session.py:169 -msgid "There are no more items to retrieve in this buffer." -msgstr "No hay más elementos que recuperar en este buffer." - -#: ../src\sessions\twitter\session.py:215 +#: ../src\sessions\twitter\session.py:211 msgid "%s failed. Reason: %s" msgstr "%s falló. Razón: %s" -#: ../src\sessions\twitter\session.py:221 +#: ../src\sessions\twitter\session.py:217 msgid "%s succeeded." msgstr "%s con éxito." -#: ../src\sessions\twitter\utils.py:225 +#: ../src\sessions\twitter\session.py:426 +#: ../src\sessions\twitter\session.py:504 +msgid "Deleted account" +msgstr "Cuenta eliminada" + +#: ../src\sessions\twitter\utils.py:231 msgid "Sorry, you are not authorised to see this status." msgstr "Lo sentimos, no estás autorizado para ver este tuit." -#: ../src\sessions\twitter\utils.py:227 +#: ../src\sessions\twitter\utils.py:233 msgid "No status found with that ID" msgstr "No existe un tuit con este ID" -#: ../src\sessions\twitter\utils.py:229 -msgid "Error code {0}" +#: ../src\sessions\twitter\utils.py:235 +msgid "Error {0}" msgstr "Código de error {0}" -#: ../src\sessions\twitter\wxUI.py:6 +#: ../src\sessions\twitter\utils.py:262 +msgid "{user_1}, {user_2} and {all_users} more: {text}" +msgstr "{user_1}, {user_2} y {all_users} más: {text}" + +#: ../src\sessions\twitter\wxUI.py:7 msgid "Authorising account..." msgstr "Autorizando cuenta..." -#: ../src\sessions\twitter\wxUI.py:9 +#: ../src\sessions\twitter\wxUI.py:10 msgid "Enter your PIN code here" msgstr "Introduce el código PIN aquí" -#: ../src\sound.py:159 +#: ../src\sound.py:161 msgid "Stopped." msgstr "Detenido." -#: ../src\update\wxUpdater.py:10 +#: ../src\update\wxUpdater.py:14 msgid "New version for %s" msgstr "Nueva versión de %s" -#: ../src\update\wxUpdater.py:10 +#: ../src\update\wxUpdater.py:14 msgid "" "There's a new %s version available, released on %s. Would you like to " "download it now?\n" @@ -1966,23 +2060,23 @@ msgstr "" "Novedades:\n" "%s" -#: ../src\update\wxUpdater.py:18 +#: ../src\update\wxUpdater.py:22 msgid "Download in Progress" msgstr "Descarga en progreso" -#: ../src\update\wxUpdater.py:18 +#: ../src\update\wxUpdater.py:22 msgid "Downloading the new version..." msgstr "Descargando la nueva versión..." -#: ../src\update\wxUpdater.py:28 +#: ../src\update\wxUpdater.py:32 msgid "Updating... %s of %s" msgstr "Actualizando... %s de %s" -#: ../src\update\wxUpdater.py:31 +#: ../src\update\wxUpdater.py:35 msgid "Done!" msgstr "¡Hecho!" -#: ../src\update\wxUpdater.py:31 +#: ../src\update\wxUpdater.py:35 msgid "" "The update has been downloaded and installed successfully. Press OK to " "continue." @@ -1990,61 +2084,62 @@ msgstr "" "La actualización ha sido descargada e instalada. Presiona aceptar para " "iniciar la aplicación." -#: ../src\wxUI\buffers\base.py:11 +#: ../src\wxUI\buffers\base.py:12 msgid "Client" msgstr "Cliente" -#: ../src\wxUI\buffers\base.py:11 +#: ../src\wxUI\buffers\base.py:12 msgid "Text" msgstr "Texto" -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\events.py:13 +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 msgid "Date" msgstr "Fecha" -#: ../src\wxUI\buffers\base.py:11 ../src\wxUI\buffers\people.py:11 -#: ../src\wxUI\buffers\user_searches.py:10 -#: ../src\wxUI\dialogs\userSelection.py:10 ../src\wxUI\dialogs\utils.py:31 +#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 +#: ../src\wxUI\buffers\user_searches.py:11 +#: ../src\wxUI\dialogs\userAliasDialogs.py:14 +#: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 msgid "User" msgstr "Usuario" -#: ../src\wxUI\buffers\base.py:27 +#: ../src\wxUI\buffers\base.py:28 msgid "Direct message" msgstr "Mensaje directo" -#: ../src\wxUI\buffers\events.py:13 +#: ../src\wxUI\buffers\events.py:14 msgid "Event" msgstr "Evento" -#: ../src\wxUI\buffers\events.py:15 +#: ../src\wxUI\buffers\events.py:16 msgid "Remove event" msgstr "Eliminar evento" -#: ../src\wxUI\buffers\panels.py:11 ../src\wxUI\buffers\panels.py:19 +#: ../src\wxUI\buffers\panels.py:12 ../src\wxUI\buffers\panels.py:20 msgid "Login" msgstr "Iniciar sesión" -#: ../src\wxUI\buffers\panels.py:13 +#: ../src\wxUI\buffers\panels.py:14 msgid "Log in automatically" msgstr "Iniciar sesión automáticamente" -#: ../src\wxUI\buffers\panels.py:21 +#: ../src\wxUI\buffers\panels.py:22 msgid "Logout" msgstr "Cerrar sesión" -#: ../src\wxUI\buffers\trends.py:8 +#: ../src\wxUI\buffers\trends.py:9 msgid "Trending topic" msgstr "Tendencia" -#: ../src\wxUI\buffers\trends.py:18 +#: ../src\wxUI\buffers\trends.py:19 msgid "Tweet about this trend" msgstr "Tuitear sobre esta tendencia" -#: ../src\wxUI\buffers\trends.py:19 ../src\wxUI\menus.py:96 +#: ../src\wxUI\buffers\trends.py:20 ../src\wxUI\menus.py:97 msgid "Search topic" msgstr "Buscar tema" -#: ../src\wxUI\commonMessageDialogs.py:6 +#: ../src\wxUI\commonMessageDialogs.py:7 msgid "" "This retweet is over 140 characters. Would you like to post it as a mention " "to the poster with your comments and a link to the original tweet?" @@ -2053,38 +2148,38 @@ msgstr "" "comentarios con una mención al usuario que publicó el tuit original y un " "enlace al mismo?" -#: ../src\wxUI\commonMessageDialogs.py:9 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Would you like to add a comment to this tweet?" msgstr "¿Te gustaría añadir un comentario a este tuit?" -#: ../src\wxUI\commonMessageDialogs.py:12 +#: ../src\wxUI\commonMessageDialogs.py:13 msgid "" "Do you really want to delete this tweet? It will be deleted from Twitter as " "well." msgstr "" "¿Realmente quieres borrar este mensaje? También se eliminará de Twitter." -#: ../src\wxUI\commonMessageDialogs.py:12 ../src\wxUI\dialogs\lists.py:148 +#: ../src\wxUI\commonMessageDialogs.py:13 ../src\wxUI\dialogs\lists.py:149 msgid "Delete" msgstr "Eliminar" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Do you really want to close {0}?" msgstr "¿Realmente deseas salir de {0}?" -#: ../src\wxUI\commonMessageDialogs.py:15 +#: ../src\wxUI\commonMessageDialogs.py:16 msgid "Exit" msgstr "Salir" -#: ../src\wxUI\commonMessageDialogs.py:19 +#: ../src\wxUI\commonMessageDialogs.py:20 msgid " {0} must be restarted for these changes to take effect." msgstr " Debes reiniciar {0} para que estos cambios tengan efecto." -#: ../src\wxUI\commonMessageDialogs.py:19 +#: ../src\wxUI\commonMessageDialogs.py:20 msgid "Restart {0} " msgstr "Reiniciar {0} " -#: ../src\wxUI\commonMessageDialogs.py:22 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "" "Are you sure you want to delete this user from the database? This user will " "not appear in autocomplete results anymore." @@ -2092,20 +2187,20 @@ msgstr "" "¿Estás seguro de querer eliminar este usuario de la base de datos? Este ya " "no aparecerá en los resultados del autocompletado." -#: ../src\wxUI\commonMessageDialogs.py:22 +#: ../src\wxUI\commonMessageDialogs.py:23 msgid "Confirm" msgstr "Confirmar" -#: ../src\wxUI\commonMessageDialogs.py:25 +#: ../src\wxUI\commonMessageDialogs.py:26 msgid "Enter the name of the client : " msgstr "Introduce el nombre del cliente: " -#: ../src\wxUI\commonMessageDialogs.py:25 +#: ../src\wxUI\commonMessageDialogs.py:26 #: ../src\wxUI\dialogs\configuration.py:246 msgid "Add client" msgstr "Añadir cliente" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "" "Do you really want to empty this buffer? It's items will be removed from " "the list but not from Twitter" @@ -2113,32 +2208,32 @@ msgstr "" "¿Realmente quieres vaciar el contenido de este buffer? Los tweets serán " "eliminados de la lista, pero no de Twitter" -#: ../src\wxUI\commonMessageDialogs.py:31 +#: ../src\wxUI\commonMessageDialogs.py:32 msgid "Empty buffer" msgstr "Vaciar buffer" -#: ../src\wxUI\commonMessageDialogs.py:35 +#: ../src\wxUI\commonMessageDialogs.py:36 msgid "Do you really want to destroy this buffer?" msgstr "¿Realmente deseas eliminar este buffer?" -#: ../src\wxUI\commonMessageDialogs.py:35 -#: ../src\wxUI\commonMessageDialogs.py:85 +#: ../src\wxUI\commonMessageDialogs.py:36 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Attention" msgstr "Atención" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "A timeline for this user already exists. You can't open another" msgstr "Ya hay una línea temporal para este usuario. No se puede abrir otra" -#: ../src\wxUI\commonMessageDialogs.py:41 +#: ../src\wxUI\commonMessageDialogs.py:42 msgid "Existing timeline" msgstr "Línea temporal existente" -#: ../src\wxUI\commonMessageDialogs.py:44 +#: ../src\wxUI\commonMessageDialogs.py:45 msgid "This user has no tweets, so you can't open a timeline for them." msgstr "Este usuario no tiene tuits. No puedes abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:47 +#: ../src\wxUI\commonMessageDialogs.py:48 msgid "" "This is a protected Twitter user, which means you can't open a timeline " "using the Streaming API. The user's tweets will not update due to a twitter " @@ -2149,12 +2244,12 @@ msgstr "" "este usuario no se actualizarán debido a una política de Twitter. ¿Deseas " "continuar?" -#: ../src\wxUI\commonMessageDialogs.py:47 -#: ../src\wxUI\commonMessageDialogs.py:94 +#: ../src\wxUI\commonMessageDialogs.py:48 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "Warning" msgstr "Atención" -#: ../src\wxUI\commonMessageDialogs.py:50 +#: ../src\wxUI\commonMessageDialogs.py:51 msgid "" "This is a protected user account, you need to follow this user to view their " "tweets or likes." @@ -2162,7 +2257,7 @@ msgstr "" "Esta es una cuenta protegida, debes seguir al usuario para poder ver sus " "tuits y los tuits marcados con me gusta." -#: ../src\wxUI\commonMessageDialogs.py:53 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "" "If you like {0} we need your help to keep it going. Help us by donating to " "the project. This will help us pay for the server, the domain and some other " @@ -2177,42 +2272,42 @@ msgstr "" "permitirá seguir escribiendo características para {0} y que estas sean " "libres en {0}. ¿Te gustaría donar ahora?" -#: ../src\wxUI\commonMessageDialogs.py:53 +#: ../src\wxUI\commonMessageDialogs.py:54 msgid "We need your help" msgstr "Necesitamos tu ayuda" -#: ../src\wxUI\commonMessageDialogs.py:57 +#: ../src\wxUI\commonMessageDialogs.py:58 msgid "This user has no tweets. {0} can't create a timeline." msgstr "Este usuario no tiene tuits. {0} no puede abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:60 +#: ../src\wxUI\commonMessageDialogs.py:61 msgid "This user has no favorited tweets. {0} can't create a timeline." msgstr "" "Este usuario no tiene tuits favoritos. {0} no puede abrirle una línea " "temporal." -#: ../src\wxUI\commonMessageDialogs.py:63 +#: ../src\wxUI\commonMessageDialogs.py:64 msgid "This user has no followers. {0} can't create a timeline." msgstr "" "Este usuario no tiene seguidores. {0} no puede abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:66 +#: ../src\wxUI\commonMessageDialogs.py:67 msgid "This user has no friends. {0} can't create a timeline." msgstr "Este usuario no tiene amigos. {0} no puede abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:70 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geo data for this tweet" msgstr "Información geográfica para este tweet" -#: ../src\wxUI\commonMessageDialogs.py:70 +#: ../src\wxUI\commonMessageDialogs.py:71 msgid "Geolocation data: {0}" msgstr "Datos de ubicación: {0}" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "Information" msgstr "Información" -#: ../src\wxUI\commonMessageDialogs.py:73 +#: ../src\wxUI\commonMessageDialogs.py:74 msgid "" "TWBlue has detected that you're running windows 10 and has changed the " "default keymap to the Windows 10 keymap. It means that some keyboard " @@ -2225,11 +2320,11 @@ msgstr "" "el editor de combinaciones de teclado y ver todas las combinaciones " "disponibles en este mapa de teclado." -#: ../src\wxUI\commonMessageDialogs.py:76 +#: ../src\wxUI\commonMessageDialogs.py:77 msgid "You have been blocked from viewing this content" msgstr "Te han bloqueado y no puedes ver este contenido" -#: ../src\wxUI\commonMessageDialogs.py:79 +#: ../src\wxUI\commonMessageDialogs.py:80 msgid "" "You have been blocked from viewing someone's content. In order to avoid " "conflicts with the full session, TWBlue will remove the affected timeline." @@ -2237,7 +2332,7 @@ msgstr "" "Alguien te ha bloqueado y no puedes ver su contenido. Para evitar conflictos " "en la sesión entera, TWBlue quitará el hilo temporal afectado." -#: ../src\wxUI\commonMessageDialogs.py:82 +#: ../src\wxUI\commonMessageDialogs.py:83 msgid "" "TWBlue cannot load this timeline because the user has been suspended from " "Twitter." @@ -2245,15 +2340,15 @@ msgstr "" "TWBlue no puede cargar este hilo temporal porque el usuario ha sido " "suspendido por Twitter." -#: ../src\wxUI\commonMessageDialogs.py:85 +#: ../src\wxUI\commonMessageDialogs.py:86 msgid "Do you really want to delete this filter?" msgstr "¿Realmente deseas eliminar este filtro?" -#: ../src\wxUI\commonMessageDialogs.py:88 +#: ../src\wxUI\commonMessageDialogs.py:89 msgid "This filter already exists. Please use a different title" msgstr "Este filtro ya existe, por favor utiliza un título diferente" -#: ../src\wxUI\commonMessageDialogs.py:94 +#: ../src\wxUI\commonMessageDialogs.py:95 msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." @@ -2261,146 +2356,146 @@ msgstr "" "{0} se cerró de forma inesperada la última vez que se usó. Si el problema " "persiste, por favor informa de él a los desarrolladores de {0}." -#: ../src\wxUI\dialogs\attach.py:9 +#: ../src\wxUI\dialogs\attach.py:10 msgid "Add an attachment" msgstr "Adjuntar un archivo" -#: ../src\wxUI\dialogs\attach.py:12 +#: ../src\wxUI\dialogs\attach.py:13 msgid "Attachments" msgstr "Adjuntos" -#: ../src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Title" msgstr "Título" -#: ../src\wxUI\dialogs\attach.py:13 +#: ../src\wxUI\dialogs\attach.py:14 msgid "Type" msgstr "Tipo" -#: ../src\wxUI\dialogs\attach.py:18 +#: ../src\wxUI\dialogs\attach.py:19 msgid "Add attachments" msgstr "Añadir adjuntos" -#: ../src\wxUI\dialogs\attach.py:19 +#: ../src\wxUI\dialogs\attach.py:20 msgid "&Photo" msgstr "&Foto" -#: ../src\wxUI\dialogs\attach.py:20 +#: ../src\wxUI\dialogs\attach.py:21 msgid "Remove attachment" msgstr "Remover archivo" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 #: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" msgstr "Archivos de imagen (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -#: ../src\wxUI\dialogs\attach.py:36 ../src\wxUI\dialogs\message.py:116 +#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 #: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:81 +#: ../src\wxUI\dialogs\update_profile.py:82 msgid "Select the picture to be uploaded" msgstr "Selecciona una foto para subir" -#: ../src\wxUI\dialogs\attach.py:43 +#: ../src\wxUI\dialogs\attach.py:44 msgid "please provide a description" msgstr "por favor proporciona una descripción" -#: ../src\wxUI\dialogs\attach.py:43 ../src\wxUI\dialogs\lists.py:13 -#: ../src\wxUI\dialogs\lists.py:69 +#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 +#: ../src\wxUI\dialogs\lists.py:70 msgid "Description" msgstr "Descripción" -#: ../src\wxUI\dialogs\configuration.py:16 +#: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "Idioma" -#: ../src\wxUI\dialogs\configuration.py:23 +#: ../src\wxUI\dialogs\configuration.py:22 msgid "Run {0} at Windows startup" msgstr "Ejecutar {0} al iniciar Windows" -#: ../src\wxUI\dialogs\configuration.py:24 +#: ../src\wxUI\dialogs\configuration.py:23 msgid "ask before exiting {0}" msgstr "preguntar antes de salir de {0}" -#: ../src\wxUI\dialogs\configuration.py:27 +#: ../src\wxUI\dialogs\configuration.py:26 msgid "Disable Streaming functions" msgstr "Desactivar funciones en tiempo real" -#: ../src\wxUI\dialogs\configuration.py:30 +#: ../src\wxUI\dialogs\configuration.py:29 msgid "Buffer update interval, in minutes" msgstr "Intervalo de actualización de los buffers, en minutos" -#: ../src\wxUI\dialogs\configuration.py:36 +#: ../src\wxUI\dialogs\configuration.py:35 msgid "Play a sound when {0} launches" msgstr "Reproducir un sonido cuando inicia {0}" -#: ../src\wxUI\dialogs\configuration.py:38 +#: ../src\wxUI\dialogs\configuration.py:37 msgid "Speak a message when {0} launches" msgstr "Hablar un mensaje cuando {0} inicie" -#: ../src\wxUI\dialogs\configuration.py:40 +#: ../src\wxUI\dialogs\configuration.py:39 msgid "Use invisible interface's keyboard shortcuts while GUI is visible" msgstr "" "Usar los atajos de teclado de la interfaz invisible en la ventana gráfica" -#: ../src\wxUI\dialogs\configuration.py:42 +#: ../src\wxUI\dialogs\configuration.py:41 msgid "Activate Sapi5 when any other screen reader is not being run" msgstr "Activar Sapi5 cuando no hay ningún lector de pantalla ejecutándose" -#: ../src\wxUI\dialogs\configuration.py:44 +#: ../src\wxUI\dialogs\configuration.py:43 msgid "Hide GUI on launch" msgstr "Esconder interfaz gráfica al iniciar" -#: ../src\wxUI\dialogs\configuration.py:46 +#: ../src\wxUI\dialogs\configuration.py:45 msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" msgstr "" "Lectura completa de Tuits largos (puede disminuir el rendimiento del cliente)" -#: ../src\wxUI\dialogs\configuration.py:48 +#: ../src\wxUI\dialogs\configuration.py:47 msgid "Remember state for mention all and long tweet" msgstr "Recordar estado para casillas de mencionar a todos y tweet largos" -#: ../src\wxUI\dialogs\configuration.py:51 +#: ../src\wxUI\dialogs\configuration.py:50 msgid "Keymap" msgstr "Mapa de teclado" -#: ../src\wxUI\dialogs\configuration.py:56 +#: ../src\wxUI\dialogs\configuration.py:55 msgid "Check for updates when {0} launches" msgstr "Comprobar actualizaciones cuando {0} inicie" -#: ../src\wxUI\dialogs\configuration.py:66 +#: ../src\wxUI\dialogs\configuration.py:65 msgid "Proxy type: " msgstr "Tipo de proxy: " -#: ../src\wxUI\dialogs\configuration.py:73 +#: ../src\wxUI\dialogs\configuration.py:72 msgid "Proxy server: " msgstr "Servidor proxy: " -#: ../src\wxUI\dialogs\configuration.py:79 +#: ../src\wxUI\dialogs\configuration.py:78 msgid "Port: " msgstr "Puerto: " -#: ../src\wxUI\dialogs\configuration.py:85 +#: ../src\wxUI\dialogs\configuration.py:84 msgid "User: " msgstr "Usuario: " -#: ../src\wxUI\dialogs\configuration.py:91 +#: ../src\wxUI\dialogs\configuration.py:90 msgid "Password: " msgstr "Contraseña: " -#: ../src\wxUI\dialogs\configuration.py:103 +#: ../src\wxUI\dialogs\configuration.py:102 msgid "Autocompletion settings..." msgstr "Opciones de autocompletado de usuarios..." -#: ../src\wxUI\dialogs\configuration.py:105 +#: ../src\wxUI\dialogs\configuration.py:104 msgid "Relative timestamps" msgstr "Tiempos relativos" -#: ../src\wxUI\dialogs\configuration.py:108 +#: ../src\wxUI\dialogs\configuration.py:107 msgid "Items on each API call" msgstr "Elementos por cada llamada a la API" -#: ../src\wxUI\dialogs\configuration.py:114 +#: ../src\wxUI\dialogs\configuration.py:113 msgid "" "Inverted buffers: The newest tweets will be shown at the beginning while the " "oldest at the end" @@ -2408,15 +2503,15 @@ msgstr "" "Buffers invertidos: los nuevos tweets se mostrarán al principio de las " "listas y los viejos al final" -#: ../src\wxUI\dialogs\configuration.py:116 +#: ../src\wxUI\dialogs\configuration.py:115 msgid "Retweet mode" msgstr "Modo de retuit" -#: ../src\wxUI\dialogs\configuration.py:122 +#: ../src\wxUI\dialogs\configuration.py:121 msgid "Show screen names instead of full names" msgstr "Mostrar nombres de pantalla en lugar de nombres completos" -#: ../src\wxUI\dialogs\configuration.py:124 +#: ../src\wxUI\dialogs\configuration.py:123 msgid "" "Number of items per buffer to cache in database (0 to disable caching, blank " "for unlimited)" @@ -2425,6 +2520,14 @@ msgstr "" "blanco para guardarlos de forma ilimitada, 0 para desactivar la base de " "datos)" +#: ../src\wxUI\dialogs\configuration.py:127 +msgid "" +"Load cache for tweets in memory (much faster in big datasets but requires " +"more RAM)" +msgstr "" +"Cargar cache para Tweets en RAM (es más rápido para listas muy grandes de " +"elementos, pero requiere más memoria)" + #: ../src\wxUI\dialogs\configuration.py:134 msgid "Enable automatic speech feedback" msgstr "Activar mensajes automáticos hablados" @@ -2438,7 +2541,7 @@ msgid "Status" msgstr "Estado" #: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Buffer" msgstr "Buffer" @@ -2563,175 +2666,175 @@ msgstr "Extras" msgid "Save" msgstr "Guardar" -#: ../src\wxUI\dialogs\filterDialogs.py:15 +#: ../src\wxUI\dialogs\filterDialogs.py:16 msgid "Create a filter for this buffer" msgstr "Crear filtro para este buffer" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:17 msgid "Filter title" msgstr "Nombre del filtro" -#: ../src\wxUI\dialogs\filterDialogs.py:25 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by word" msgstr "Filtrar por palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:26 +#: ../src\wxUI\dialogs\filterDialogs.py:27 msgid "Ignore tweets wich contain the following word" msgstr "Ignorar tuits que contengan la siguiente palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:28 msgid "Ignore tweets without the following word" msgstr "Ignorar tuits que no contengan la siguiente palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:32 +#: ../src\wxUI\dialogs\filterDialogs.py:33 msgid "word" msgstr "palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:37 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow retweets" msgstr "Permitir retuits" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:39 msgid "Allow quoted tweets" msgstr "Permitir tweets citados" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:40 msgid "Allow replies" msgstr "Permitir respuestas" -#: ../src\wxUI\dialogs\filterDialogs.py:47 +#: ../src\wxUI\dialogs\filterDialogs.py:48 msgid "Use this term as a regular expression" msgstr "Usar término como expresión regular" -#: ../src\wxUI\dialogs\filterDialogs.py:49 -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter by language" msgstr "Filtrar por idioma" -#: ../src\wxUI\dialogs\filterDialogs.py:50 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Load tweets in the following languages" msgstr "Cargar tuits en los siguientes idiomas" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:52 msgid "Ignore tweets in the following languages" msgstr "Ignorar tuits en los siguientes idiomas" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:53 msgid "Don't filter by language" msgstr "No filtrar por idioma" -#: ../src\wxUI\dialogs\filterDialogs.py:63 +#: ../src\wxUI\dialogs\filterDialogs.py:64 msgid "Supported languages" msgstr "Idiomas soportados" -#: ../src\wxUI\dialogs\filterDialogs.py:68 +#: ../src\wxUI\dialogs\filterDialogs.py:69 msgid "Add selected language to filter" msgstr "Añadir idioma seleccionado al filtro" -#: ../src\wxUI\dialogs\filterDialogs.py:72 +#: ../src\wxUI\dialogs\filterDialogs.py:73 msgid "Selected languages" msgstr "Idiomas seleccionados" -#: ../src\wxUI\dialogs\filterDialogs.py:74 -#: ../src\wxUI\dialogs\filterDialogs.py:132 ../src\wxUI\dialogs\lists.py:20 -#: ../src\wxUI\dialogs\lists.py:131 +#: ../src\wxUI\dialogs\filterDialogs.py:75 +#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "Borrar" -#: ../src\wxUI\dialogs\filterDialogs.py:122 +#: ../src\wxUI\dialogs\filterDialogs.py:123 msgid "Manage filters" msgstr "Gestionar filtros" -#: ../src\wxUI\dialogs\filterDialogs.py:124 +#: ../src\wxUI\dialogs\filterDialogs.py:125 msgid "Filters" msgstr "Filtros" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:126 msgid "Filter" msgstr "Filtro" -#: ../src\wxUI\dialogs\find.py:12 +#: ../src\wxUI\dialogs\find.py:13 msgid "Find in current buffer" msgstr "Buscar en el buffer actual" -#: ../src\wxUI\dialogs\find.py:13 +#: ../src\wxUI\dialogs\find.py:14 msgid "String" msgstr "Término" -#: ../src\wxUI\dialogs\lists.py:10 +#: ../src\wxUI\dialogs\lists.py:11 msgid "Lists manager" msgstr "Gestor de listas" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "List" msgstr "Lista" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Members" msgstr "Miembros" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "Owner" msgstr "Propietario" -#: ../src\wxUI\dialogs\lists.py:13 +#: ../src\wxUI\dialogs\lists.py:14 msgid "mode" msgstr "modo" -#: ../src\wxUI\dialogs\lists.py:18 ../src\wxUI\dialogs\lists.py:61 +#: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "Crear nueva lista" -#: ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\lists.py:22 msgid "Open in buffer" msgstr "Abrir en buffer" -#: ../src\wxUI\dialogs\lists.py:51 +#: ../src\wxUI\dialogs\lists.py:52 msgid "Viewing lists for %s" msgstr "Viendo las listas de %s" -#: ../src\wxUI\dialogs\lists.py:52 +#: ../src\wxUI\dialogs\lists.py:53 msgid "Subscribe" msgstr "Darte de alta" -#: ../src\wxUI\dialogs\lists.py:53 +#: ../src\wxUI\dialogs\lists.py:54 msgid "Unsubscribe" msgstr "Darse de baja" -#: ../src\wxUI\dialogs\lists.py:64 +#: ../src\wxUI\dialogs\lists.py:65 msgid "Name (20 characters maximun)" msgstr "Nombre (máximo 20 caracteres)" -#: ../src\wxUI\dialogs\lists.py:74 +#: ../src\wxUI\dialogs\lists.py:75 msgid "Mode" msgstr "Modo" -#: ../src\wxUI\dialogs\lists.py:75 +#: ../src\wxUI\dialogs\lists.py:76 msgid "Public" msgstr "Público" -#: ../src\wxUI\dialogs\lists.py:76 +#: ../src\wxUI\dialogs\lists.py:77 msgid "Private" msgstr "Privado" -#: ../src\wxUI\dialogs\lists.py:96 +#: ../src\wxUI\dialogs\lists.py:97 msgid "Editing the list %s" msgstr "Editando la lista %s" -#: ../src\wxUI\dialogs\lists.py:107 +#: ../src\wxUI\dialogs\lists.py:108 msgid "Select a list to add the user" msgstr "Selecciona una lista para añadir al usuario" -#: ../src\wxUI\dialogs\lists.py:108 +#: ../src\wxUI\dialogs\lists.py:109 msgid "Add" msgstr "Añadir" -#: ../src\wxUI\dialogs\lists.py:130 +#: ../src\wxUI\dialogs\lists.py:131 msgid "Select a list to remove the user" msgstr "Selecciona una lista para quitar al usuario" -#: ../src\wxUI\dialogs\lists.py:148 +#: ../src\wxUI\dialogs\lists.py:149 msgid "Do you really want to delete this list?" msgstr "¿Realmente deseas eliminar esta lista?" @@ -2746,7 +2849,7 @@ msgstr "&Subir imagen..." #: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 #: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:430 +#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 msgid "Check &spelling..." msgstr "Revisar &ortografía..." @@ -2762,13 +2865,13 @@ msgstr "Acortar &URL" #: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 #: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:358 ../src\wxUI\dialogs\message.py:431 +#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 msgid "&Expand URL" msgstr "&Expandir URL" #: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 #: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:433 +#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 msgid "&Translate..." msgstr "&Traducir..." @@ -2784,7 +2887,7 @@ msgstr "En&viar" #: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 #: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:361 ../src\wxUI\dialogs\message.py:434 +#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 msgid "C&lose" msgstr "Ce&rrar" @@ -2816,23 +2919,27 @@ msgstr "Me gusta: " msgid "Source: " msgstr "Desde: " -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:420 +#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 msgid "Date: " msgstr "Fecha: " -#: ../src\wxUI\dialogs\message.py:405 +#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 +msgid "Copy link to clipboard" +msgstr "Copiar enlace al portapapeles" + +#: ../src\wxUI\dialogs\message.py:408 msgid "View" msgstr "Ver" -#: ../src\wxUI\dialogs\message.py:407 +#: ../src\wxUI\dialogs\message.py:410 msgid "Item" msgstr "Elemento" -#: ../src\wxUI\dialogs\search.py:13 +#: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "Buscar en Twitter" -#: ../src\wxUI\dialogs\search.py:14 ../src\wxUI\view.py:19 +#: ../src\wxUI\dialogs\search.py:13 ../src\wxUI\view.py:21 msgid "&Search" msgstr "&Buscar" @@ -2840,7 +2947,7 @@ msgstr "&Buscar" msgid "Tweets" msgstr "Tuits" -#: ../src\wxUI\dialogs\search.py:22 +#: ../src\wxUI\dialogs\search.py:22 ../src\wxUI\dialogs\userAliasDialogs.py:43 msgid "Users" msgstr "Usuarios" @@ -2868,414 +2975,478 @@ msgstr "Recientes" msgid "Popular" msgstr "Populares" -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:28 -#: ../src\wxUI\dialogs\userActions.py:40 -#: ../src\wxUI\dialogs\userSelection.py:32 +#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:25 +#: ../src\wxUI\dialogs\userActions.py:41 +#: ../src\wxUI\dialogs\userSelection.py:33 msgid "&OK" msgstr "&Aceptar" -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:18 -#: ../src\wxUI\dialogs\trends.py:30 ../src\wxUI\dialogs\update_profile.py:36 -#: ../src\wxUI\dialogs\userActions.py:42 -#: ../src\wxUI\dialogs\userSelection.py:34 +#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:19 +#: ../src\wxUI\dialogs\trends.py:27 ../src\wxUI\dialogs\update_profile.py:37 +#: ../src\wxUI\dialogs\userActions.py:43 +#: ../src\wxUI\dialogs\userSelection.py:35 msgid "&Close" msgstr "Ce&rrar" -#: ../src\wxUI\dialogs\show_user.py:11 +#: ../src\wxUI\dialogs\show_user.py:12 msgid "Details" msgstr "Detalles" -#: ../src\wxUI\dialogs\show_user.py:16 +#: ../src\wxUI\dialogs\show_user.py:17 msgid "&Go to URL" msgstr "&Ir a URL" -#: ../src\wxUI\dialogs\trends.py:12 +#: ../src\wxUI\dialogs\trends.py:10 msgid "View trending topics" msgstr "Ver tendencias" -#: ../src\wxUI\dialogs\trends.py:13 +#: ../src\wxUI\dialogs\trends.py:11 msgid "Trending topics by" msgstr "Tendencias por" -#: ../src\wxUI\dialogs\trends.py:15 +#: ../src\wxUI\dialogs\trends.py:12 msgid "Country" msgstr "País" -#: ../src\wxUI\dialogs\trends.py:16 +#: ../src\wxUI\dialogs\trends.py:13 msgid "City" msgstr "Ciudad" -#: ../src\wxUI\dialogs\trends.py:22 ../src\wxUI\dialogs\update_profile.py:17 +#: ../src\wxUI\dialogs\trends.py:19 ../src\wxUI\dialogs\update_profile.py:18 msgid "&Location" msgstr "&Ubicación" -#: ../src\wxUI\dialogs\update_profile.py:9 +#: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "Actualizar tu perfil" -#: ../src\wxUI\dialogs\update_profile.py:11 +#: ../src\wxUI\dialogs\update_profile.py:12 msgid "&Name (50 characters maximum)" msgstr "&Nombre (máximo 50 caracteres)" -#: ../src\wxUI\dialogs\update_profile.py:22 +#: ../src\wxUI\dialogs\update_profile.py:23 msgid "&Website" msgstr "Sitio &web" -#: ../src\wxUI\dialogs\update_profile.py:27 +#: ../src\wxUI\dialogs\update_profile.py:28 msgid "&Bio (160 characters maximum)" msgstr "&Descripción (máximo 160 caracteres)" -#: ../src\wxUI\dialogs\update_profile.py:33 +#: ../src\wxUI\dialogs\update_profile.py:34 msgid "Upload a &picture" msgstr "Subir una &foto" -#: ../src\wxUI\dialogs\update_profile.py:34 ../src\wxUI\view.py:17 +#: ../src\wxUI\dialogs\update_profile.py:35 ../src\wxUI\view.py:19 msgid "&Update profile" msgstr "Actuali&zar perfil" -#: ../src\wxUI\dialogs\update_profile.py:76 +#: ../src\wxUI\dialogs\update_profile.py:77 msgid "Upload a picture" msgstr "Subir una foto" -#: ../src\wxUI\dialogs\update_profile.py:78 +#: ../src\wxUI\dialogs\update_profile.py:79 msgid "Discard image" msgstr "Descartar foto" -#: ../src\wxUI\dialogs\urlList.py:5 +#: ../src\wxUI\dialogs\urlList.py:6 msgid "Select URL" msgstr "Selecciona la URL" -#: ../src\wxUI\dialogs\userActions.py:10 ../src\wxUI\view.py:83 +#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:87 msgid "&User" msgstr "&Usuario" -#: ../src\wxUI\dialogs\userActions.py:13 -#: ../src\wxUI\dialogs\userSelection.py:13 ../src\wxUI\dialogs\utils.py:30 +#: ../src\wxUI\dialogs\userActions.py:14 +#: ../src\wxUI\dialogs\userAliasDialogs.py:13 +#: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 msgid "&Autocomplete users" msgstr "&Autocompletar usuarios" -#: ../src\wxUI\dialogs\userActions.py:19 +#: ../src\wxUI\dialogs\userActions.py:20 msgid "&Follow" msgstr "&Seguir" -#: ../src\wxUI\dialogs\userActions.py:20 +#: ../src\wxUI\dialogs\userActions.py:21 msgid "U&nfollow" msgstr "&Dejar de seguir" -#: ../src\wxUI\dialogs\userActions.py:21 ../src\wxUI\view.py:59 +#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:63 msgid "&Mute" msgstr "S&ilenciar" -#: ../src\wxUI\dialogs\userActions.py:22 +#: ../src\wxUI\dialogs\userActions.py:23 msgid "Unmu&te" msgstr "D&esactivar silencio" -#: ../src\wxUI\dialogs\userActions.py:23 +#: ../src\wxUI\dialogs\userActions.py:24 msgid "&Block" msgstr "&Bloquear" -#: ../src\wxUI\dialogs\userActions.py:24 +#: ../src\wxUI\dialogs\userActions.py:25 msgid "Unbl&ock" msgstr "Desb&loquear" -#: ../src\wxUI\dialogs\userActions.py:25 +#: ../src\wxUI\dialogs\userActions.py:26 msgid "&Report as spam" msgstr "&Reportar como spam" -#: ../src\wxUI\dialogs\userActions.py:26 +#: ../src\wxUI\dialogs\userActions.py:27 msgid "&Ignore tweets from this client" msgstr "&Ignorar tuits de este cliente" -#: ../src\wxUI\dialogs\userSelection.py:9 +#: ../src\wxUI\dialogs\userAliasDialogs.py:18 +msgid "Alias" +msgstr "Alias" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:41 +msgid "Edit user aliases" +msgstr "Editar alias de usuarios" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:48 +msgid "Actions" +msgstr "Acciones" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:50 +msgid "Add alias" +msgstr "Añadir alias" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:51 +msgid "Adds a new user alias" +msgstr "Añadir un nuevo alias" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:54 +msgid "Edit the currently focused user Alias." +msgstr "Editar alias del usuario seleccionado" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:58 +msgid "Remove the currently focused user alias." +msgstr "Eliminar alias del usuario seleccionado." + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Are you sure you want to delete this user alias?" +msgstr "¿Estás seguro que deseas eliminar este alias de usuario?" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +msgid "Remove user alias" +msgstr "Eliminar alias de usuario" + +#: ../src\wxUI\dialogs\userAliasDialogs.py:93 +msgid "User alias" +msgstr "Alias de usuario" + +#: ../src\wxUI\dialogs\userSelection.py:10 msgid "Timeline for %s" msgstr "Línea temporal de %s" -#: ../src\wxUI\dialogs\userSelection.py:18 +#: ../src\wxUI\dialogs\userSelection.py:19 msgid "Buffer type" msgstr "Tipo de buffer" -#: ../src\wxUI\dialogs\userSelection.py:19 +#: ../src\wxUI\dialogs\userSelection.py:20 msgid "&Tweets" msgstr "&Tuits" -#: ../src\wxUI\dialogs\userSelection.py:20 +#: ../src\wxUI\dialogs\userSelection.py:21 msgid "&Likes" msgstr "Tuits marcados como &me gusta" -#: ../src\wxUI\dialogs\userSelection.py:21 +#: ../src\wxUI\dialogs\userSelection.py:22 msgid "&Followers" msgstr "&Seguidores" -#: ../src\wxUI\dialogs\userSelection.py:22 +#: ../src\wxUI\dialogs\userSelection.py:23 msgid "F&riends" msgstr "&Amigos" -#: ../src\wxUI\menus.py:7 ../src\wxUI\view.py:30 +#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:33 msgid "&Retweet" msgstr "&Retuit" -#: ../src\wxUI\menus.py:9 ../src\wxUI\menus.py:33 ../src\wxUI\view.py:29 +#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:32 msgid "Re&ply" msgstr "Res&ponder" -#: ../src\wxUI\menus.py:11 ../src\wxUI\view.py:31 +#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:34 msgid "&Like" msgstr "Me &gusta" -#: ../src\wxUI\menus.py:13 ../src\wxUI\view.py:32 +#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:35 msgid "&Unlike" msgstr "&Ya no me gusta" -#: ../src\wxUI\menus.py:15 ../src\wxUI\menus.py:35 ../src\wxUI\menus.py:51 +#: ../src\wxUI\menus.py:16 ../src\wxUI\menus.py:36 ../src\wxUI\menus.py:52 msgid "&Open URL" msgstr "&Abrir URL" -#: ../src\wxUI\menus.py:17 ../src\wxUI\menus.py:53 ../src\wxUI\menus.py:86 +#: ../src\wxUI\menus.py:18 ../src\wxUI\menus.py:54 ../src\wxUI\menus.py:87 msgid "&Open in Twitter" msgstr "&Abrir en Twitter" -#: ../src\wxUI\menus.py:19 ../src\wxUI\menus.py:37 ../src\wxUI\menus.py:55 +#: ../src\wxUI\menus.py:20 ../src\wxUI\menus.py:38 ../src\wxUI\menus.py:56 msgid "&Play audio" msgstr "&Reproducir audio" -#: ../src\wxUI\menus.py:21 ../src\wxUI\menus.py:57 ../src\wxUI\view.py:33 +#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:36 msgid "&Show tweet" msgstr "&Ver tuit" -#: ../src\wxUI\menus.py:23 ../src\wxUI\menus.py:41 ../src\wxUI\menus.py:59 -#: ../src\wxUI\menus.py:69 ../src\wxUI\menus.py:88 ../src\wxUI\menus.py:102 +#: ../src\wxUI\menus.py:24 ../src\wxUI\menus.py:42 ../src\wxUI\menus.py:60 +#: ../src\wxUI\menus.py:70 ../src\wxUI\menus.py:89 ../src\wxUI\menus.py:103 msgid "&Copy to clipboard" msgstr "&Copiar al portapapeles" -#: ../src\wxUI\menus.py:25 ../src\wxUI\menus.py:43 ../src\wxUI\menus.py:61 -#: ../src\wxUI\menus.py:71 ../src\wxUI\view.py:37 +#: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 +#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:40 msgid "&Delete" msgstr "&Eliminar" -#: ../src\wxUI\menus.py:27 ../src\wxUI\menus.py:45 ../src\wxUI\menus.py:90 +#: ../src\wxUI\menus.py:28 ../src\wxUI\menus.py:46 ../src\wxUI\menus.py:91 msgid "&User actions..." msgstr "&Acciones de usuario..." -#: ../src\wxUI\menus.py:39 +#: ../src\wxUI\menus.py:40 msgid "&Show direct message" msgstr "&Mostrar mensaje directo" -#: ../src\wxUI\menus.py:67 +#: ../src\wxUI\menus.py:68 msgid "&Show event" msgstr "&Mostrar evento" -#: ../src\wxUI\menus.py:77 +#: ../src\wxUI\menus.py:78 msgid "Direct &message" msgstr "Mensaje &directo" -#: ../src\wxUI\menus.py:79 ../src\wxUI\view.py:46 +#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:50 msgid "&View lists" msgstr "&Ver listas" -#: ../src\wxUI\menus.py:82 ../src\wxUI\view.py:47 +#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:51 msgid "Show user &profile" msgstr "Ve&r perfil del usuario" -#: ../src\wxUI\menus.py:84 +#: ../src\wxUI\menus.py:85 msgid "&Show user" msgstr "&Mostrar usuario" -#: ../src\wxUI\menus.py:98 +#: ../src\wxUI\menus.py:99 msgid "&Tweet about this trend" msgstr "&Tuitear sobre esta tendencia" -#: ../src\wxUI\menus.py:100 +#: ../src\wxUI\menus.py:101 msgid "&Show item" msgstr "&Ver tuit" -#: ../src\wxUI\sysTrayIcon.py:35 ../src\wxUI\view.py:23 +#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:26 msgid "&Global settings" msgstr "Opciones &globales" -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:22 +#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:25 msgid "Account se&ttings" msgstr "Opciones de &cuenta" -#: ../src\wxUI\sysTrayIcon.py:37 +#: ../src\wxUI\sysTrayIcon.py:38 msgid "Update &profile" msgstr "Actualizar &perfil" -#: ../src\wxUI\sysTrayIcon.py:38 +#: ../src\wxUI\sysTrayIcon.py:39 msgid "&Show / hide" msgstr "&Mostrar / esconder" -#: ../src\wxUI\sysTrayIcon.py:39 ../src\wxUI\view.py:71 +#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:75 msgid "&Documentation" msgstr "&Documentación" -#: ../src\wxUI\sysTrayIcon.py:40 +#: ../src\wxUI\sysTrayIcon.py:41 msgid "Check for &updates" msgstr "Comprobar &actualizaciones" -#: ../src\wxUI\sysTrayIcon.py:41 +#: ../src\wxUI\sysTrayIcon.py:42 msgid "&Exit" msgstr "&Salir" -#: ../src\wxUI\view.py:16 +#: ../src\wxUI\view.py:18 msgid "&Manage accounts" msgstr "Gestionar &cuentas" -#: ../src\wxUI\view.py:18 +#: ../src\wxUI\view.py:20 msgid "&Hide window" msgstr "Esconder &ventana" -#: ../src\wxUI\view.py:20 +#: ../src\wxUI\view.py:22 msgid "&Lists manager" msgstr "Gestor de &listas" -#: ../src\wxUI\view.py:21 +#: ../src\wxUI\view.py:23 +msgid "Manage user aliases" +msgstr "Gestionar alias de usuario" + +#: ../src\wxUI\view.py:24 msgid "&Edit keystrokes" msgstr "Editar combinaciones de &teclas" -#: ../src\wxUI\view.py:24 +#: ../src\wxUI\view.py:27 msgid "E&xit" msgstr "S&alir" -#: ../src\wxUI\view.py:28 ../src\wxUI\view.py:82 +#: ../src\wxUI\view.py:31 ../src\wxUI\view.py:86 msgid "&Tweet" msgstr "&Tuit" -#: ../src\wxUI\view.py:34 +#: ../src\wxUI\view.py:37 msgid "View &address" msgstr "Ver &dirección" -#: ../src\wxUI\view.py:35 +#: ../src\wxUI\view.py:38 msgid "View conversa&tion" msgstr "Ver conversa&ción" -#: ../src\wxUI\view.py:36 +#: ../src\wxUI\view.py:39 msgid "Read text in picture" msgstr "Leer texto en imágenes" -#: ../src\wxUI\view.py:41 +#: ../src\wxUI\view.py:44 msgid "&Actions..." msgstr "&Acciones..." -#: ../src\wxUI\view.py:42 +#: ../src\wxUI\view.py:45 msgid "&View timeline..." msgstr "&Ver línea temporal..." -#: ../src\wxUI\view.py:43 +#: ../src\wxUI\view.py:46 msgid "Direct me&ssage" msgstr "&Mensaje directo" -#: ../src\wxUI\view.py:44 +#: ../src\wxUI\view.py:47 +msgid "Add a&lias" +msgstr "Añadir alias" + +#: ../src\wxUI\view.py:48 msgid "&Add to list" msgstr "&Añadir a lista" -#: ../src\wxUI\view.py:45 +#: ../src\wxUI\view.py:49 msgid "R&emove from list" msgstr "&Quitar de lista" -#: ../src\wxUI\view.py:48 +#: ../src\wxUI\view.py:52 msgid "V&iew likes" msgstr "&Ver tuits marcados con me gusta" -#: ../src\wxUI\view.py:52 +#: ../src\wxUI\view.py:56 msgid "&Update buffer" msgstr "&actualizar buffer" -#: ../src\wxUI\view.py:53 +#: ../src\wxUI\view.py:57 msgid "New &trending topics buffer..." msgstr "Nuevo buffer de &tendencias..." -#: ../src\wxUI\view.py:54 +#: ../src\wxUI\view.py:58 msgid "Create a &filter" msgstr "Crear &filtro" -#: ../src\wxUI\view.py:55 +#: ../src\wxUI\view.py:59 msgid "&Manage filters" msgstr "Gestionar &filtros" -#: ../src\wxUI\view.py:56 +#: ../src\wxUI\view.py:60 msgid "Find a string in the currently focused buffer..." msgstr "Buscar término en el buffer actual..." -#: ../src\wxUI\view.py:57 +#: ../src\wxUI\view.py:61 msgid "&Load previous items" msgstr "&Cargar elementos anteriores" -#: ../src\wxUI\view.py:60 +#: ../src\wxUI\view.py:64 msgid "&Autoread" msgstr "&lectura automática" -#: ../src\wxUI\view.py:61 +#: ../src\wxUI\view.py:65 msgid "&Clear buffer" msgstr "&Vaciar buffer" -#: ../src\wxUI\view.py:62 +#: ../src\wxUI\view.py:66 msgid "&Destroy" msgstr "&Eliminar" -#: ../src\wxUI\view.py:66 +#: ../src\wxUI\view.py:70 msgid "&Seek back 5 seconds" msgstr "&Retroceder 5 segundos" -#: ../src\wxUI\view.py:67 +#: ../src\wxUI\view.py:71 msgid "&Seek forward 5 seconds" msgstr "A&vanzar 5 segundos" -#: ../src\wxUI\view.py:72 +#: ../src\wxUI\view.py:76 msgid "Sounds &tutorial" msgstr "Tutorial de &sonidos" -#: ../src\wxUI\view.py:73 +#: ../src\wxUI\view.py:77 msgid "&What's new in this version?" msgstr "¿&Qué hay de nuevo en esta versión?" -#: ../src\wxUI\view.py:74 +#: ../src\wxUI\view.py:78 msgid "&Check for updates" msgstr "&Comprobar actualizaciones" -#: ../src\wxUI\view.py:75 +#: ../src\wxUI\view.py:79 msgid "&Report an error" msgstr "&Reportar un error" -#: ../src\wxUI\view.py:76 +#: ../src\wxUI\view.py:80 msgid "{0}'s &website" msgstr "Sitio &web de {0}" -#: ../src\wxUI\view.py:77 +#: ../src\wxUI\view.py:81 msgid "Get soundpacks for TWBlue" msgstr "Obtener paquetes de sonidos para TWBlue" -#: ../src\wxUI\view.py:78 +#: ../src\wxUI\view.py:82 msgid "About &{0}" msgstr "Sobre &{0}" -#: ../src\wxUI\view.py:81 +#: ../src\wxUI\view.py:85 msgid "&Application" msgstr "&Aplicación" -#: ../src\wxUI\view.py:84 +#: ../src\wxUI\view.py:88 msgid "&Buffer" msgstr "&Buffer" -#: ../src\wxUI\view.py:85 +#: ../src\wxUI\view.py:89 msgid "&Audio" msgstr "&Audio" -#: ../src\wxUI\view.py:86 +#: ../src\wxUI\view.py:90 msgid "&Help" msgstr "Ay&uda" -#: ../src\wxUI\view.py:172 +#: ../src\wxUI\view.py:176 msgid "Address" msgstr "Dirección" -#: ../src\wxUI\view.py:203 +#: ../src\wxUI\view.py:207 msgid "Update" msgstr "Actualización" -#: ../src\wxUI\view.py:203 +#: ../src\wxUI\view.py:207 msgid "Your {0} version is up to date" msgstr "Tu versión de {0} está actualizada" +#~ msgid "Friends' Timelines" +#~ msgstr "Líneas temporales de amigos" + +#~ msgid "Events" +#~ msgstr "Eventos" + +#~ msgid "This tweet doesn't contain images" +#~ msgstr "El tuit no contiene imágenes" + +#~ msgid "Direct connection" +#~ msgstr "Conexión directa" + +#~ msgid "There are no more items to retrieve in this buffer." +#~ msgstr "No hay más elementos que recuperar en este buffer." + #~ msgid "Empty" #~ msgstr "Vacío" @@ -3451,9 +3622,6 @@ msgstr "Tu versión de {0} está actualizada" #~ msgid "Update profile" #~ msgstr "Actualizar perfil" -#~ msgid "Follow" -#~ msgstr "Seguir" - #~ msgid "Mute" #~ msgstr "Silenciar" @@ -3505,9 +3673,6 @@ msgstr "Tu versión de {0} está actualizada" #~ msgid "Opening media..." #~ msgstr "Abriendo medio..." -#~ msgid "Add a new ignored client" -#~ msgstr "Añadir un nuevo clienteClientes ignorados" - #~ msgid "Do you really want to delete this timeline?" #~ msgstr "¿Realmente deseas eliminar esta línea temporal?" @@ -3785,9 +3950,6 @@ msgstr "Tu versión de {0} está actualizada" #~ msgid "See the users list" #~ msgstr "Ver lista de usuarios" -#~ msgid "Do you really want to delete this message?" -#~ msgstr "¿Realmente quieres eliminar este mensaje?" - #~ msgid "Unable to play audio." #~ msgstr "Imposible reproducir audio" From 8a8f1998ac6c426822f4553b594e0583ef8e8e42 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 09:58:57 -0600 Subject: [PATCH 189/245] Added usable appkeys for sources --- src/appkeys.cp37-win32.pyd | Bin 0 -> 15360 bytes src/appkeys.cp37-win_amd64.pyd | Bin 0 -> 19456 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/appkeys.cp37-win32.pyd create mode 100644 src/appkeys.cp37-win_amd64.pyd diff --git a/src/appkeys.cp37-win32.pyd b/src/appkeys.cp37-win32.pyd new file mode 100644 index 0000000000000000000000000000000000000000..46ae5afe93b5aab543f270ae85eebcfb2ef6bbc2 GIT binary patch literal 15360 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

  • JVVJPJq#CQXgRY2{3vyydN-pc`jd=OYeyfUj?HVqvx)I(F@v>fQ<=?x%3jY z7O;u3BuQW0!U;REL&$WRhvlS2Plq?Cp+A&C#BTD@ z-^yGyiOuyC&czmFm_KiBuw<_1Zp3i7peCs(j9uMN4kcTcYh4K5-Qo|*&w@=nLb(#$ z7)y>O*CC%3n*7B4e2vc?)VSLyb?C;Q^my?HJ^UQ=dI~iwy#>h~5p>fzrNLhT(Takh zPCDy=!-Ao8^1`vv+<_*a3!$3h!p1IFr(5vJa&@{X*2%D@4es^ySlbb3S>J*uG8b*o z#B*+2hueb?2AF(Dv*{@~DgT6gLDPiLu->cjAbDtlFq#65K!2x{Fa-WgNz>tPqg81* zEf4-yN$3E~OE=ztoONhAy#e~uCW^s@NiP4dwF;JtC82DayfOuSWJ2lvHE?_Yj%X}D zFMV_JB;K=?cD1)9cYr-#SE$X`c>TyFke}M~SJhS&nDaG30jHz84H~!ScYA~Rr3*5r z+T6jQw|yP#0s{V^JwFuimjsdiw7Y`^?JZ4#j$lW#P=I|_;tsYKKCH{f2J*Kw^a4Mv02;4myVxC|YJM-4j+KQO#x_?h9j;bX%r<6L90aglMEvDWy2vDw&W{FU*s z;vW>BE}mx6naWJ{rnROfQ;Vs?6f*rE(=O9Lnf94}WIAj*VJbE+Hm^5tHdk1hEuEH# z~*u_gT+a&s#sS z{-;%G`--i=R%W};=Csw>9<;5q`D}ihVB2ilX8Swaw{17t=h)}j3+)EG*B-JD*x$FG zxBuS$2fJy(!UYd55Es0(AiCh~1w#wcN~e})m8wf;msXdqEbSCz8NF z%Ft=(GHf?IVR*{$jN$u+eTGBEqsEVnSBz=JMa8D#(qd2X#^No-Un|~M{8I7T#UB>` zq4>XwrDs`q(sNl1%C54D*fV z*=B>;ZeC!vSkhIpt>n8Uhf7YByj$|`C4(gwOJ-Q} ztoK?=tsbjj?Y8c+J_)P6Xgz9u(<;Gg8MgVh#kLi;04(*Gt>5-T+mCIp*#6D-uI;?- zq784M?KA8*+n=!a+xOa^x9_+A8aAWAH4mFyqpQ+6buZ|mI!}?WsI%x?(Q0FtvB&td z@fqW5#;B3r6B&S4uC3Av+HKk%?K9eEwfnUPv`4kau`AALhqafqN}WoVtDB{p4+{eM Hul)MIJCEJO literal 0 HcmV?d00001 diff --git a/src/appkeys.cp37-win_amd64.pyd b/src/appkeys.cp37-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..c19fc7d7baad946002aa57921d15beb6c3b794cb GIT binary patch literal 19456 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 literal 0 HcmV?d00001 From 60a67947e60d35de3f0945620e9e6ca4a617fca1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 10:03:51 -0600 Subject: [PATCH 190/245] Updated Pygettext to Python 3.7.9 --- tools/pygettext.py | 240 +++++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 139 deletions(-) diff --git a/tools/pygettext.py b/tools/pygettext.py index bb0dd35d..b46dd339 100644 --- a/tools/pygettext.py +++ b/tools/pygettext.py @@ -1,6 +1,6 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 # -*- coding: iso-8859-1 -*- -# Originally written by Barry Warsaw +# Originally written by Barry Warsaw # # Minimally patched to make it even more xgettext compatible # by Peter Funk @@ -156,14 +156,14 @@ If `inputfile' is -, standard input is read. """) import os -import imp +import importlib.machinery +import importlib.util import sys import glob import time import getopt import token import tokenize -import operator __version__ = '1.5' @@ -189,50 +189,51 @@ msgstr "" "Last-Translator: FULL NAME \\n" "Language-Team: LANGUAGE \\n" "MIME-Version: 1.0\\n" -"Content-Type: text/plain; charset=CHARSET\\n" -"Content-Transfer-Encoding: ENCODING\\n" +"Content-Type: text/plain; charset=%(charset)s\\n" +"Content-Transfer-Encoding: %(encoding)s\\n" "Generated-By: pygettext.py %(version)s\\n" ''') def usage(code, msg=''): - print >> sys.stderr, __doc__ % globals() + print(__doc__ % globals(), file=sys.stderr) if msg: - print >> sys.stderr, msg + print(msg, file=sys.stderr) sys.exit(code) -escapes = [] - -def make_escapes(pass_iso8859): - global escapes - if pass_iso8859: - # Allow iso-8859 characters to pass through so that e.g. 'msgid +def make_escapes(pass_nonascii): + global escapes, escape + if pass_nonascii: + # Allow non-ascii characters to pass through so that e.g. 'msgid # "Hhe"' would result not result in 'msgid "H\366he"'. Otherwise we # escape any character outside the 32..126 range. mod = 128 + escape = escape_ascii else: mod = 256 - for i in range(256): - if 32 <= (i % mod) <= 126: - escapes.append(chr(i)) - else: - escapes.append("\\%03o" % i) - escapes[ord('\\')] = '\\\\' - escapes[ord('\t')] = '\\t' - escapes[ord('\r')] = '\\r' - escapes[ord('\n')] = '\\n' - escapes[ord('\"')] = '\\"' + escape = escape_nonascii + escapes = [r"\%03o" % i for i in range(mod)] + for i in range(32, 127): + escapes[i] = chr(i) + escapes[ord('\\')] = r'\\' + escapes[ord('\t')] = r'\t' + escapes[ord('\r')] = r'\r' + escapes[ord('\n')] = r'\n' + escapes[ord('\"')] = r'\"' -def escape(s): - global escapes - s = list(s) - for i in range(len(s)): - s[i] = escapes[ord(s[i])] - return EMPTYSTRING.join(s) +def escape_ascii(s, encoding): + return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s) + +def escape_nonascii(s, encoding): + return ''.join(escapes[b] for b in s.encode(encoding)) + + +def is_literal_string(s): + return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"') def safe_eval(s): @@ -240,18 +241,18 @@ def safe_eval(s): return eval(s, {'__builtins__':{}}, {}) -def normalize(s): +def normalize(s, encoding): # This converts the various Python string types into a format that is # appropriate for .po files, namely much closer to C style. lines = s.split('\n') if len(lines) == 1: - s = '"' + escape(s) + '"' + s = '"' + escape(s, encoding) + '"' else: if not lines[-1]: del lines[-1] lines[-1] = lines[-1] + '\n' for i in range(len(lines)): - lines[i] = escape(lines[i]) + lines[i] = escape(lines[i], encoding) lineterm = '\\n"\n"' s = '""\n"' + lineterm.join(lines) + '"' return s @@ -262,64 +263,6 @@ def containsAny(str, set): return 1 in [c in str for c in set] -def _visit_pyfiles(list, dirname, names): - """Helper for getFilesForName().""" - # get extension for python source files - if not globals().has_key('_py_ext'): - global _py_ext - _py_ext = [triple[0] for triple in imp.get_suffixes() - if triple[2] == imp.PY_SOURCE][0] - - # don't recurse into CVS directories - if 'CVS' in names: - names.remove('CVS') - - # add all *.py files to list - list.extend( - [os.path.join(dirname, file) for file in names - if os.path.splitext(file)[1] == _py_ext] - ) - - -def _get_modpkg_path(dotted_name, pathlist=None): - """Get the filesystem path for a module or a package. - - Return the file system path to a file for a module, and to a directory for - a package. Return None if the name is not found, or is a builtin or - extension module. - """ - # split off top-most name - parts = dotted_name.split('.', 1) - - if len(parts) > 1: - # we have a dotted path, import top-level package - try: - file, pathname, description = imp.find_module(parts[0], pathlist) - if file: file.close() - except ImportError: - return None - - # check if it's indeed a package - if description[2] == imp.PKG_DIRECTORY: - # recursively handle the remaining name parts - pathname = _get_modpkg_path(parts[1], [pathname]) - else: - pathname = None - else: - # plain name - try: - file, pathname, description = imp.find_module( - dotted_name, pathlist) - if file: - file.close() - if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]: - pathname = None - except ImportError: - pathname = None - - return pathname - - def getFilesForName(name): """Get a list of module files for a filename, a module or package name, or a directory. @@ -334,14 +277,28 @@ def getFilesForName(name): return list # try to find module or package - name = _get_modpkg_path(name) + try: + spec = importlib.util.find_spec(name) + name = spec.origin + except ImportError: + name = None if not name: return [] if os.path.isdir(name): # find all python files in directory list = [] - os.path.walk(name, _visit_pyfiles, list) + # get extension for python source files + _py_ext = importlib.machinery.SOURCE_SUFFIXES[0] + for root, dirs, files in os.walk(name): + # don't recurse into CVS directories + if 'CVS' in dirs: + dirs.remove('CVS') + # add all *.py files to list + list.extend( + [os.path.join(root, file) for file in files + if os.path.splitext(file)[1] == _py_ext] + ) return list elif os.path.exists(name): # a single file @@ -359,12 +316,13 @@ class TokenEater: self.__lineno = -1 self.__freshmodule = 1 self.__curfile = None + self.__enclosurecount = 0 def __call__(self, ttype, tstring, stup, etup, line): # dispatch ## import token -## print >> sys.stderr, 'ttype:', token.tok_name[ttype], \ -## 'tstring:', tstring +## print('ttype:', token.tok_name[ttype], 'tstring:', tstring, +## file=sys.stderr) self.__state(ttype, tstring, stup[0]) def __waiting(self, ttype, tstring, lineno): @@ -373,13 +331,13 @@ class TokenEater: if opts.docstrings and not opts.nodocstrings.get(self.__curfile): # module docstring? if self.__freshmodule: - if ttype == tokenize.STRING: + if ttype == tokenize.STRING and is_literal_string(tstring): self.__addentry(safe_eval(tstring), lineno, isdocstring=1) self.__freshmodule = 0 elif ttype not in (tokenize.COMMENT, tokenize.NL): self.__freshmodule = 0 return - # class docstring? + # class or func/method docstring? if ttype == tokenize.NAME and tstring in ('class', 'def'): self.__state = self.__suiteseen return @@ -387,13 +345,19 @@ class TokenEater: self.__state = self.__keywordseen def __suiteseen(self, ttype, tstring, lineno): - # ignore anything until we see the colon - if ttype == tokenize.OP and tstring == ':': - self.__state = self.__suitedocstring + # skip over any enclosure pairs until we see the colon + if ttype == tokenize.OP: + if tstring == ':' and self.__enclosurecount == 0: + # we see a colon and we're not in an enclosure: end of def + self.__state = self.__suitedocstring + elif tstring in '([{': + self.__enclosurecount += 1 + elif tstring in ')]}': + self.__enclosurecount -= 1 def __suitedocstring(self, ttype, tstring, lineno): # ignore any intervening noise - if ttype == tokenize.STRING: + if ttype == tokenize.STRING and is_literal_string(tstring): self.__addentry(safe_eval(tstring), lineno, isdocstring=1) self.__state = self.__waiting elif ttype not in (tokenize.NEWLINE, tokenize.INDENT, @@ -418,18 +382,18 @@ class TokenEater: if self.__data: self.__addentry(EMPTYSTRING.join(self.__data)) self.__state = self.__waiting - elif ttype == tokenize.STRING: + elif ttype == tokenize.STRING and is_literal_string(tstring): self.__data.append(safe_eval(tstring)) elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT, token.NEWLINE, tokenize.NL]: # warn if we see anything else than STRING or whitespace - print >> sys.stderr, _( + print(_( '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' ) % { 'token': tstring, 'file': self.__curfile, 'lineno': self.__lineno - } + }, file=sys.stderr) self.__state = self.__waiting def __addentry(self, msg, lineno=None, isdocstring=0): @@ -445,45 +409,41 @@ class TokenEater: def write(self, fp): options = self.__options - timestamp = time.strftime('%Y-%m-%d %H:%M+%Z') - # The time stamp in the header doesn't have the same format as that - # generated by xgettext... - print >> fp, pot_header % {'time': timestamp, 'version': __version__} + timestamp = time.strftime('%Y-%m-%d %H:%M%z') + encoding = fp.encoding if fp.encoding else 'UTF-8' + print(pot_header % {'time': timestamp, 'version': __version__, + 'charset': encoding, + 'encoding': '8bit'}, file=fp) # Sort the entries. First sort each particular entry's keys, then # sort all the entries by their first item. reverse = {} for k, v in self.__messages.items(): - keys = v.keys() - keys.sort() + keys = sorted(v.keys()) reverse.setdefault(tuple(keys), []).append((k, v)) - rkeys = reverse.keys() - rkeys.sort() + rkeys = sorted(reverse.keys()) for rkey in rkeys: rentries = reverse[rkey] rentries.sort() for k, v in rentries: - isdocstring = 0 # If the entry was gleaned out of a docstring, then add a # comment stating so. This is to aid translators who may wish # to skip translating some unimportant docstrings. - if reduce(operator.__add__, v.values()): - isdocstring = 1 + isdocstring = any(v.values()) # k is the message string, v is a dictionary-set of (filename, # lineno) tuples. We want to sort the entries in v first by # file name and then by line number. - v = v.keys() - v.sort() + v = sorted(v.keys()) if not options.writelocations: pass # location comments are different b/w Solaris and GNU: elif options.locationstyle == options.SOLARIS: for filename, lineno in v: d = {'filename': filename, 'lineno': lineno} - print >>fp, _( - '# File: %(filename)s, line: %(lineno)d') % d + print(_( + '# File: %(filename)s, line: %(lineno)d') % d, file=fp) elif options.locationstyle == options.GNU: # fit as many locations on one line, as long as the - # resulting line length doesn't exceeds 'options.width' + # resulting line length doesn't exceed 'options.width' locline = '#:' for filename, lineno in v: d = {'filename': filename, 'lineno': lineno} @@ -491,14 +451,14 @@ class TokenEater: if len(locline) + len(s) <= options.width: locline = locline + s else: - print >> fp, locline + print(locline, file=fp) locline = "#:" + s if len(locline) > 2: - print >> fp, locline + print(locline, file=fp) if isdocstring: - print >> fp, '#, docstring' - print >> fp, 'msgid', normalize(k) - print >> fp, 'msgstr ""\n' + print('#, docstring', file=fp) + print('msgid', normalize(k, encoding), file=fp) + print('msgstr ""\n', file=fp) @@ -514,7 +474,7 @@ def main(): 'style=', 'verbose', 'version', 'width=', 'exclude-file=', 'docstrings', 'no-docstrings', ]) - except getopt.error, msg: + except getopt.error as msg: usage(1, msg) # for holding option values @@ -572,7 +532,7 @@ def main(): elif opt in ('-v', '--verbose'): options.verbose = 1 elif opt in ('-V', '--version'): - print _('pygettext.py (xgettext for Python) %s') % __version__ + print(_('pygettext.py (xgettext for Python) %s') % __version__) sys.exit(0) elif opt in ('-w', '--width'): try: @@ -593,7 +553,7 @@ def main(): fp.close() # calculate escapes - make_escapes(options.escape) + make_escapes(not options.escape) # calculate all keywords options.keywords.extend(default_keywords) @@ -605,8 +565,8 @@ def main(): options.toexclude = fp.readlines() fp.close() except IOError: - print >> sys.stderr, _( - "Can't read --exclude-file: %s") % options.excludefilename + print(_( + "Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr) sys.exit(1) else: options.toexclude = [] @@ -625,21 +585,24 @@ def main(): for filename in args: if filename == '-': if options.verbose: - print _('Reading standard input') - fp = sys.stdin + print(_('Reading standard input')) + fp = sys.stdin.buffer closep = 0 else: if options.verbose: - print _('Working on %s') % filename - fp = open(filename) + print(_('Working on %s') % filename) + fp = open(filename, 'rb') closep = 1 try: eater.set_filename(filename) try: - tokenize.tokenize(fp.readline, eater) - except tokenize.TokenError, e: - print >> sys.stderr, '%s: %s, line %d, column %d' % ( - e[0], filename, e[1][0], e[1][1]) + tokens = tokenize.tokenize(fp.readline) + for _token in tokens: + eater(*_token) + except tokenize.TokenError as e: + print('%s: %s, line %d, column %d' % ( + e.args[0], filename, e.args[1][0], e.args[1][1]), + file=sys.stderr) finally: if closep: fp.close() @@ -663,7 +626,6 @@ def main(): if __name__ == '__main__': main() # some more test strings - _(u'a unicode string') # this one creates a warning _('*** Seen unexpected token "%(token)s"') % {'token': 'test'} _('more' 'than' 'one' 'string') From ed8055827355a89759015a6e279dc250905964e8 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 17:04:03 -0600 Subject: [PATCH 191/245] Remove BOM from changelog --- doc/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.md b/doc/changelog.md index e5086795..aafc305d 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -1,4 +1,4 @@ -TWBlue Changelog +TWBlue Changelog ## changes in this version From ab44ce6fcb9ba1f2776b214adc660dcdf39b7d06 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 1 Nov 2021 17:18:49 -0600 Subject: [PATCH 192/245] Rebuilt documentation generators --- doc/documentation_importer.py | 39 ++++++----- doc/generator.py | 120 ++++++++++++++++++++-------------- 2 files changed, 89 insertions(+), 70 deletions(-) diff --git a/doc/documentation_importer.py b/doc/documentation_importer.py index 9210a28a..f9b42c6f 100644 --- a/doc/documentation_importer.py +++ b/doc/documentation_importer.py @@ -1,28 +1,27 @@ # -*- coding: utf-8 -*- -from codecs import open """ This script converts the hold documentation (saved in markdown files) in a python file with a list of strings to translate it using gettext.""" def prepare_documentation_in_file(fileSource, fileDest): - """ This takes documentation written in a markdown file and put all the contents in a python file, to create a translatable documentation. - @fileSource str: A markdown(.md) file. - @fileDest str: A file where this will put the new strings""" + """ This takes documentation written in a markdown file and put all the contents in a python file, to create a translatable documentation. + @fileSource str: A markdown(.md) file. + @fileDest str: A file where this will put the new strings""" - f1 = open(fileSource, "r", encoding="utf-8") - f2 = open(fileDest, "w", encoding="utf-8") - lns = f1.readlines() - f2.write("# -*- coding: utf-8 -*-\n") - f2.write("documentation = [\n") - for i in lns: - if "\n" == i: - newvar = "\"\"," - elif "\n" == i[-1]: - newvar = "\"\"\"%s\"\"\",\n" % (i[:-1]) - else: - newvar = "\"\"\"%s\"\"\",\n" % (i) - f2.write(newvar) - f1.close() - f2.write("]") - f2.close() + f1 = open(fileSource, "r", encoding="utf-8") + f2 = open(fileDest, "w", encoding="utf-8") + lns = f1.readlines() + f2.write("# -*- coding: utf-8 -*-\n") + f2.write("documentation = [\n") + for i in lns: + if "\n" == i: + newvar = "\"\",\n" + elif "\n" == i[-1]: + newvar = "_(\"\"\"%s\"\"\"),\n" % (i[:-1]) + else: + newvar = "_(\"\"\"%s\"\"\"),\n" % (i) + f2.write(newvar) + f1.close() + f2.write("]") + f2.close() prepare_documentation_in_file("manual.md", "strings.py") diff --git a/doc/generator.py b/doc/generator.py index b48374ad..01b03432 100644 --- a/doc/generator.py +++ b/doc/generator.py @@ -5,63 +5,83 @@ import locale import paths import markdown import shutil -from codecs import open as _open from importlib import reload -def get_translation_function(name, language): - if language == "en": - return gettext.NullTranslations() - translation_function = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[language]) - return translation_function +# Languages already translated or translating the documentation. +documentation_languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da", "sr"] -# the list of supported language codes of TW Blue -languages = ["en", "es", "fr", "de", "it", "gl", "ja", "ru", "ro", "eu", "ca", "da", "sr"] -def generate_document(language, document_type="documentation"): - if document_type == "documentation": - translation_file = "twblue-documentation" - translation_function = get_translation_function(translation_file, language) - markdown_file = markdown.markdown("\n".join([translation_function.gettext(s[:-1]) if s != "\n" else s for s in strings.documentation[1:]]), extensions=["markdown.extensions.toc"]) - title = translation_function.gettext(strings.documentation[0][:-1]) - filename = "manual.html" - elif document_type == "changelog": - translation_file = "twblue-changelog" - translation_function = get_translation_function(translation_file, language) - markdown_file = markdown.markdown("\n".join([translation_function.gettext(s[:-1]) if s != "\n" else s for s in changelog.documentation[1:]]), extensions=["markdown.extensions.toc"]) - title = translation_function.gettext(changelog.documentation[0][:-1]) - filename = "changelog.html" - first_html_block = """ - - - %s - - - -

    %s

    - """ % (language, title, title) - first_html_block = first_html_block+ markdown_file - first_html_block = first_html_block + "\n\n" - if not os.path.exists(os.path.join("documentation", language)): - os.mkdir(os.path.join("documentation", language)) - mdfile = _open(os.path.join("documentation", language, filename), "w", encoding="utf-8") - mdfile.write(first_html_block) - mdfile.close() +# Changelog translated languages. +changelog_languages = ["en", "ca", "de", "es", "eu", "fr", "gl", "ja", "ro", "ru", "sr"] + +# this function will help us to have both strings.py and changelog.py without issues by installing a global dummy translation function. +def install_null_translation(name): + _ = gettext.NullTranslations() + _.install() + return + +def get_translations(name): + """ Create translation instances for every language of the translated document. """ + translations = {} + if "documentation" in name: + langs = documentation_languages + else: + langs = changelog_languages + for l in langs: + if l != "en": + _ = gettext.translation(name, os.path.join(paths.app_path(), "locales"), languages=[l]) + translations[l] = _ + else: + _ = gettext.NullTranslations() + translations[l] = _ + return translations + +def generate_document(lang, lang_name, document_type="documentation"): + """ Generates a document by using the provided lang object, which should be a translation, and lang_name, which should be the two letter code representing the language. """ + if document_type == "documentation": + translation_file = "twblue-documentation" + markdown_file = markdown.markdown("\n".join([lang.gettext(s) if s != "" else s for s in strings.documentation[1:]]), extensions=["markdown.extensions.toc"]) + title = lang.gettext(strings.documentation[0]) + filename = "manual.html" + elif document_type == "changelog": + translation_file = "twblue-changelog" + markdown_file = markdown.markdown("\n".join([lang.gettext(s) if s != "" else s for s in changelog.documentation[1:]]), extensions=["markdown.extensions.toc"]) + title = lang.gettext(changelog.documentation[0]) + filename = "changelog.html" + first_html_block = """ + + + %s + + + +

    %s

    + """ % (lang_name, title, title) + first_html_block = first_html_block+ markdown_file + first_html_block = first_html_block + "\n\n" + if not os.path.exists(os.path.join("documentation", lang_name)): + os.mkdir(os.path.join("documentation", lang_name)) + mdfile = open(os.path.join("documentation", lang_name, filename), "w", encoding="utf-8") + mdfile.write(first_html_block) + mdfile.close() def create_documentation(): - print("Creating documentation in the supported languages...\n") - if not os.path.exists("documentation"): - os.mkdir("documentation") - if os.path.exists(os.path.join("documentation", "license.txt")) == False: - shutil.copy(os.path.join("..", "license.txt"), os.path.join("documentation", "license.txt")) - for i in languages: - print("Creating documentation for: %s" % (i,)) - try: - generate_document(i) - generate_document(i, "changelog") - except: - continue - print("Done") + changelog_translations = get_translations("twblue-changelog") + documentation_translations = get_translations("twblue-documentation") + print("Creating documentation in the supported languages...\n") + if not os.path.exists("documentation"): + os.mkdir("documentation") + if os.path.exists(os.path.join("documentation", "license.txt")) == False: + shutil.copy(os.path.join("..", "license.txt"), os.path.join("documentation", "license.txt")) + for i in documentation_languages: + print("Creating documentation for: %s" % (i,)) + generate_document(lang_name=i, lang=documentation_translations.get(i)) + for i in changelog_languages: + print("Creating changelog for: %s" % (i,)) + generate_document(lang_name=i, lang=changelog_translations.get(i), document_type="changelog") + print("Done") +install_null_translation("twblue-documentation") import strings import changelog create_documentation() \ No newline at end of file From 9f7892ff03a48ad1d299a9cafcc845671c9539ba Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 2 Nov 2021 10:11:24 -0600 Subject: [PATCH 193/245] Updated spanish translation for changelog --- .../es/LC_MESSAGES/twblue-changelog.mo | Bin 47934 -> 68867 bytes .../es/LC_MESSAGES/twblue-changelog.po | 843 ++++++++++++++---- 2 files changed, 661 insertions(+), 182 deletions(-) diff --git a/doc/locales/es/LC_MESSAGES/twblue-changelog.mo b/doc/locales/es/LC_MESSAGES/twblue-changelog.mo index f9b5957d68f4f7009f8ae5786784570a61aed01d..493b7e29ca259f964c33871b720b7def3c8e85c1 100644 GIT binary patch delta 21247 zcma)@37A|}nfGsJA%G$RA(#Y`O9CXFG?iYm6EOi2K*AycB4!Y7SKaQuNi9t+3C)rM z5flYSEEaWK2#XpeMksXzWwYI3+)!r(R|ZE$LB)L>k?;3^&$-pr3C#1=laqhly7!*t z-QV||e(=u|u73Zd`cDp?baTMxXSBoBrUXG>2ly&3_&jrP5d4Gd{|0XZpP3p2*Yf*y z(}G|L`0B%g;C0|S@Lcd(a54BJFa{5LO%T+>$X4lfodlkCj{uUd{EwIYBT2?goosC!M~N z`|kxsiKC7Vf>q!(C;E}@@s?OH4HQW zih}jygWx%?Uj&(3@Z9PkfC#~nYiQtlPzx=B2X+L(XF*NqD<|-F%nu7s41y2w!;L2e z!3V(ZwL#Di{u@}<^|~Oq0lWi@z#e-07T5sq1+$RhGH}|dPzihw_-6XO@by7(J=YJO z76fkuPg~Dqz&kxYU+2qt{BZo~XaO(W3|`0e*Ukuno#5GLI#T`}Jb~*~X9Yn9tbzW}q~hu`2kn8V* z1@N^fHEa$(0g7Zl18)Y`GV4RZCqW72^B{8!7H&ks!OOsT;65z-yI=;af*t3(iEagV zhfyEZX1DDfb88`r=1Cu{GV>7Y+o$8gK)sfo=vH;PaqX zehuW=49*-1f?tEzf`0?c2?7chxcLciC%BA(&)tFsaD77_!2_QHw}J12yh|BBI0$QT z5qJuCF}M?)4bChD!Kc9Ezz}>EoCY2+?C>b?Fx>}Xd$0k7JHcJxBnJLp@J_BJ!4mGf zz+ZwVRj?^w7yPJeM!Wg)W^ka!>cB69zXwm-8U+6W9?x_i0iOWH+Yi8xyTN%QPDZ{5 zib5w`ihlrq04@g~y3Fo+a17W5z8c&BUIj^W;F%MG;J>cLoN~PsUA>k2M%q4K(>CtQoif zTmU`*&SApOfLX3zaf>rFCGbUle*x4AUwE&h%$@HGg12+M>iw8o?tdASg}t8ts?z^X z7=9-=J_H^Pp7>#B*)F=x@$y!1DKGp5Tmfcw1i@->2o$Mzg0M4~aJvgEt_9J=;MO~w z@94PGdBwZI2VvcsySUFd!N+88;Q!{Gtd{G)gKNPjK8|$qK!_5r^+!U?%#c{)29CgQHbEyCccC5gF`+I z-@vbcSAlOs5O_D(@3T%F?+4MmVD-NS!56{LfzN@Lea^Yv zBA7EDa~AA&u*nO51;4=kyT9p7XY#EeIGyY8+wS=ycr4eCfUCgYf`0epxt{iYRu4W1Y6X7=MS)NMz{$cg$f6Fe z01@=yY49*z|3?tK9=sXE2nIg`uLU>#(DnBe_$=2mo^X_$Qh(A(>svuIF8B?I7zA(m zk(=?d9|u7VO8fvsV1xBPbshc*%=7!@KXV=Z_s-8U8vI_rivN+XVCa|5ea?Qy+4e!Oli#P(t4Mx4I0#-3BJjZ#6FlmVE`eDMX1Trqd?WY>xSWA!AQ)fgdc&V__23bI zk*vV~2l(<a0mw-1<9U&HmiGzqKNdjaj!G_evT3J#)4vp!2h%Pp7{d!?1> z=hb}K&tIJCaVe-ZuJ+e4_!`>Pv=8{-?w1^D!6(r!^grI|@nP^Qv=7p@(|$&iU{`4e z&@Q5VfhLg=bze(MKjNZ3CE5boL%Q&v2f!<6QYJIM?*Syx?Vnj(h^6hHcXKg7JC62a z+Gg4y?Ta*hUPXH+t*i?^KcEfKK1{oe_D{4kXcgMgH2X*nPo}+>wup8MZ6U2e`zcMI zGim*_+iBZqlWEt{zE4YN@1pIX&8DTFKL6z&kGsK-(tb#rE|1KiTuUB;MZw)`)k2k+7#L@+P7%>Tui%*R-?U+b_wk!+S_Qx|5pH4 z((a?Zk9I!oTG}^h^JxE03u*fND{U3+{j?12&9pmcU#98P=^*$wP^{JGtF%XGZ>KG$ zeS|iF_6eFj)T1x{GYWnwy#Q~dP4w3{gBxhC^w)yV(|T#^X^+y<&vd@Lf%XpC4BAZE z;j|lQAE!M=JBwC7hySM1K1b8%D%$t#+t`0A`T7LyP}(%wVYKw~WcmfXhV~)aGFp>% zFioFN(H^ILj8>o(X+db8dKfMUPaOzHO0}?7%nrrbEn#&isf3ldT1|?BUEw(!PsrEe za9fhkhvhiRaht25Qa%oIQ8nt1DsebaE)~LDQrVIT&(X_zKN&1014%Y2R`VlaC12VW zm%GCLTGifBRKsE^j4!E{qp%Pc zO68F*{ZNRi)wmoEm9~Zb$)M{Y4y)VZxLUDEvY1SG0@IGlaTnc}YJ)?5F9Ejt*pEZk(i(!<_#+3>b3FCZRh>P?*f1p%mGErd|TG&IPj~;PDcZQMH z60_=ofw)`=2g}T`HtdOH6t45Ms8t&rj4RbR7pl)}sW4n)MHMJe9SWhHUv0=uJ-`Z} z`fyy*$i)(rf|@pPDclmr!(k*=OtUVa$ODKJkttSr`>ZQkv~evU*r3ZMB&XmBp2mYY7zh zbnA3tgFKYui)%?auJBGdPN(E&WF&t%O2hDcu1f+EZSTdibLEgFipBCN<{b|@)IZ{T2D zw6&!o>lDl;6*4MM50*-~P(zi9#$ePDF+jC4&A+~CQpXu*NN_5W2owt4jLO*|CkgZ~ z*{@{FF;ZHL3Xlg0K^ceh(TM*+lZCOVzBd1O;M|V-#u$R;YFQSen_gWi$)yM^8jFmG zFQpiwJ>8kU?#2~|%xD~W$nP3g9dhV|6-yciOkEw$of~Em zLu`VkjLeREr*~O%{nYPuWVXa3g=iS^3`hMK0_d`>RNjIe&mj>TlVYy4trGV1WWxEI z=Ju^VB9W9%~FS>;j{rD94> z=rP-7=7vj{V82xKref2=l7*+@FVN1`Z8?x!%>;M|!|sL*tL1t$fKM`E@hb?O;UA27 zA*tYOif&*!K=I>>Gd^A>oDN5jK;Jgiv_ zTv9Fl-M;rnk6YBCNj?PK&jlzuNdaIZ5D{4 zu~qu$R9^;Op2gO&xUuFFy%QIA_cR}wvAd)0WhabkxdcxDEw(1PxKu%SoDXt319_@Y z0;RR*P!#u=lNjjih$|^gpFvU!a7A58WMmIz>G~s!T;vxK+l8>4iI(HRT0Sy|3Jp=@ zl0EB2!(>Y@mN$NW{KEY``4@L~Ha8u8nG~QmCP|IhxK;KNvyq*NFynY>G=?$ zdr%gkuGEHyOJ%Pgu!T@a_EEx;cQK!rei_ICoO4c&j;~QI?}WH-`HBnX4^^wfjknF3 zyT;4J3TG<^o%rfC$hu-AC*eza8;_jdGr4a` zZ)a!Y58>M9r+gtjV~lwy`kguta%AdWwgv9SQj$&yJ-F^&lc zkhX1QRMTY4dVrA%w#C#EQGYom1U7?Qoh!+-u%T?qBK8t?Ct2yLoAT1e!{_%-?pwN) z8E20C^C_rqIVx82&ekD2Ta&C$J4R6K_>xR|-`wEIrP3e{@f`n7$@jWsi6_Jo)O_Zg zzfC$N8@VXM+jmxhs@00AJ7wYo;#!=SV+Ht%!cy4nyA)Ar{_U749d9o1SejYz zwnB7#$2R20*%A#F1dv6U(N-tW;Dc8)6RJMValgV?u*9r}qLHl_)vUn;2T+*M03(dT*>*eCR>h647Ip=+RBF z+c>j-U-y#EaMRr0WhSu`h4;?CzHS+W=4;WAX0VOWRxv267Ofon%&JNzu}K5r(#0e{ zWNDQV@~Q$XV=-f5hRNFI1Egi1X4{k`SUBz@4E$16Dp~i^;hpxWMVt<9hB1;#rG{%T z!{vh~1po<@g`s01UKegB);r#-DhnCGEyMV7j8H={p7+Ddk1xr_!={25_)2HU`V~r~ z)6x3VNNsEgbuf@zVw%;8gN(_k0jiQ0ZYve%VReY6&{{^dCCL)>_F*uJ)gk8;7xygf za)z+7a?zs3W9J|93VtFH+cbA^kFjc^u($JDbrYsGmOy_^#R3Dxux0GCIKmj-`Ds3y zfRb8l1I9!5T$Q03ZBeQ~2R^n45&tZqOM6!$2XeGQp74lVDNA*r=&gQh2t0ew3aMr9 zek)c;ruvxgRkOM$gQ(35om*O5H6=6)X2HH3sEcbHUz6fi9I6awd)ZNl)Vti-x8CL0xBdl(PpG5e#yh=ZR2%O_T6*gJwHW|8lCc0v` zM$H>J(%_L~qb=jMB9m5@%}-9?c&1tHx@l6KADlf(0}0}tQ}+sTv!&q?XUM2;IfAEA zY|EOF+*gPsl#-A%TK1_LM77F~nj1`mRLYWFZLJTv_aQW1U>s97*MkguYa0v9%w-^iGFZ<$49+1P;8zkLw zO6|8VOz5%uxOaCfQ5;?yHd#mt1QK53tpw-n7r6?*j%7Z*i@VJ)f##RIysO02uUZC) zS=lsaY@MRSSr|?j(ihHeRUn*fS4sm_75HFTVl@g?Uec#C%R4jpzP2%NKQY;8uKC!i zbsZZ-tZbg_0Rcp!&Rc(?WeP~Ba}%Tt)e?0^sfK)ql>}X~0&i5GV8M7BT&DAA7$3~d z>^`iIoUR|Z6)A2~8Z} z*hLP05o1b>ns`ZqRoQre;sOqR4};T6QDu0dd`zT=B(?msVk1{UH2UMD%Ox}sBI6|+ zjXAT=VyOrr)Q$54ZA|pjAmh@yTLA^^Fpah#;NlvE1Sn-Wr;more-RDg2gVrF>a1E$ z7}vky3ft8og?-E&8{01YCgN23R5ZkmCl)mlnV`-t$Mxi{C?j;8g!3&j>>sHcBkT^6 zHB_QX)XEE74%1ptTl!Ltof5%h@o|qni7i!U#x(kLsgue9j5Y#0@qiX?QhlL~tvHIF zFpc9fF`h|nFdid~2^xf*6BhS0Cm;XG33Y7;n77_AlnhiCuIuUc!30d!+#rC=)bB}kuE(md5(K3rbeTz$%> z^f+r^a@D)cB^Mx0a`pPBJL-PIZg?VTij^nFMCz8Or#XzD)EOnpYnYdU>8iQ9Gl?)% zc#Es2N9-9;tdm#5&iIn1k<$s9<~CRot?15IP0FX!BU43n%ux6NktW9=pCi$C#m1Cr zY8BWq=CTS+jcI3TLXZM4M|c5$EAHLl|cqshyBnnBFqE#T;HfRV*H8*(+Zz zmiat;&FP4XHg=#sUPOW0^6oSgZCp3&$h1<^-MO+Ep7Gg<^~iNeWlI}LX)qx1v%->T zrp_E|J&|G&?%b_|3dojmwYPe;uZD8w+pQFKQ)KabB?l z;_TLdiYM9Dc1>*Cp8Xd0xZGCwa zZ|!}oIe+t{#wRa0X2aRBszt}1UKvbs$DU9dtQ>nzX{B`==U1!uIL{iY@uit!T;2by zGmkx+xL$RcV^4yxD=ob{wx{RV?w+t`*~)IdEN%3@`BxMBGTn_MFYK|MwFTjZge;&^ zV8aHzleS^@D}1L~gP3GXnQ$$}k#5Ge zSCw8^{u35PcU0KbB6%X+jLUT*^9Wau9&D!UKqqa3s|(T$e1j=Pt&nI6Ofg}{hQHA5HcXIODDj0^qss65C_szh@9%hogzd)ym@ zVX_=1RTz#hrAI0qsLR+A2ox+ol51Dd4ca+N!?*d&B8)flYMudjP!#lrg*{hho=b93 z-3HT}Y0(h64iTjgS&C9_0r)mZO4{SAsgd!9$q+>iCfZS=W&qEKtso4ZUST)&D(a&x z3Q<(nGZ6&M=i#!;BkFwfBxcu=?Iy-$msUGZO24H0Ri>%To~>=Dg9&#ug)BaT;f5y6 zz!kSO<~D0jgtXA?r6q>-!S_O3$MV6xDhf{-W}GC5)Y?Rk2}Zo|!2aPRm#&1w)Db?5 zirMU26tVbkFY)Hi{W!qj{8>7a{ z@XyPe6SrL4k2dX!!de{*%f2l_#qR6aIAV#|U;;p80mlw?WW?P*Zx#jTrkKLpIqry{ zbfCRTr;(mJl5|I2%cr#*7ADThnAMJFqe;fLrAchANYYv}6c;22{isIEDmYQ9CYk2x z7oO0uioh_^d)nHvjj#S%CCi%dVVWL0d^WdYsn9RcgjNJ7Dq7KDW6^cfX7Gz9U#rxx z-+bZPM|RC?FFLQIehSVOt5HJq=*v7Y<#)8X8Wp0^drEr2GgSOc1yTc7Mw{3H-OO?X z!u9Ry6kdr$YP`4xpbUZ}nUs4Q=EzWoQ!hCv6HsVl#2?c%)3dA$l;eiZBS2C_tZno7 z#G26sY4KE&^zUg^nR9k%bZ6bGuGh2Fif~kbz?g1v0$ZtyDA<9tkk}ZCM3_Y$-2vf@ zM0=PI5e+#on+N+$BZtNP(R%8$oGW}d{8DTK${jx5>b(iXmBBuFg zI+vmuYQwCoSTYx}@r;3Qyrch!=JU~_361A+`|m$iFl-)}ThY;YG5ad*Ij@MH|fY@)P^h?w7qX<3Yp8*!pRLP?)))RsWBTS9bnx(`fjhtwoF7r6+uwV%CD@#G10 zw?91+ZXMmFZEVfa+fn3kJj>w)UVadN?>DtuFL`-!d)lnRN_d2Gt;j}1(nh%Cb-0v+ z_wq#W1-Zy3WyzMD3#+0gW>#(}Vv_^Y+PG)EnX`KgQWb-SKQ3JOK=f%2!c4*U0a_vbWUXn1uemw(qhs&eQODG2-l9z@T z*QHhbPPmA8`2O?@u{Ku3nLNU|5v@*9Zgq60)@$3`kc)F67H2tjI~8#be5^YHRqb^f zCp7~fY_sh>dQV+a;^bkDX5B7uem078Atx(v+R7mcB0H@rE{@*s36=KgY)5K*cvJ3( zhh4N!A8q5Si#q2Q%TV(ry!9St2AZ_UD~4BU{v}PN<>B4z;vA@1Q7+V9{Kln%SErS zcUaLiGRY{^=$!$UZ|1B*o=62^ufttz8PQo)W0UCQUNNl`vn3g;oM`ZT+a!?*j5y&M z%%Q;IsAWz&YPUltH#+ZJcD%i)TCn0>dWEI^(PlHyL5;ibIJx=c z#akvGaK4LwMV@gR^t*0)eVw}G1|=(stojqJ4pEA$i54VrROJ9Ni5e=h`LG=~P?n3+ ztXjFgkqiPNz?En-S5`WJFKZNAO3c~Shw!dLb86v2*n+pz>0RUX=>0@O7Gi2duPTnS zZ5#E?8)|Rrc%us_Tk|%uYqy?LK$QC#NAwT-++gIzqWzQm0`omtzj8I{EdqZ{ zKjB2}j}vHENq~URc2P%nQ8t1n%(|_JDe>T!)IR%l*q%QpD0E2Rq06V$O~n1gvLziP z(;-pBM5YpFs%?Mh=|dMC_%(S!HJ!jX&r=w^-)-z;HAZ)_g@BQ9f|N!W?zE!Ji*4}x zaIktf)eYW}jTsx%P4(sX{&#MFd)>%S{lL?MU_6iQ!D89|Bop^V35af~nh0Jl5db+S zFDcQHFipimPg_0oOMT(V(As$w>|SIxQ!8;~(hA{_E)GhzP7 zfxI`QWITVSW$(Ar*mxOXn)!LiR?16Y@QrEWsu{^=%2F5E{?#^gM9FTg9Y8Rq`;>(B zq`{lx)7Z+!0)Daqg_b&*2MH8{qn%@Bt3MHsns zdCN5X6-6~u=d8^obcVK={JwmlCg#a_t%252$`!H5ia=f zfdsVIK?TyVN=8+}#zW`#z0}EsW>jag?JigG`*i`KIc*93{(4iWwly7CN5uKMIrK2Q5+A^+Q^(1^8A%Qif5dYV?h3+e_ zP0uZOGo$&c7-as~71=b9Kdm6*lBJrz6x&J|OdZ}NH%*gd+@_sTXzu~B!e&~!E{3@W za#SK%MZN9Kttx||adwhHrw2?@#?CJIa)5GKXxEDPN)#&;Rq&skLgFAe0jJB&Bm(Av zp|Ers-5D=^OIZ^-qZ*I*+4y0s4{Mb25a(E*S*k#&pEs}LPB47x%Iy>8I_gHr{nGH9ps^tjo5^#zmb{F+OAwZY6->T_Bt;aC>Q2?e=3ULjX0a;DA< zh3Akr=HiCE3PW35X~oSd?(lklscLC?KAL9%md-w?=T^6LLJ(EO&kpl$g)b#&V-;`}D@}mHRfHyy?JYs9z2H45UVPtwhu39Wsf`KdtYM@8f94p43Ll ziqlOA2h0Y8t3_ZNnh(6QI(gb!LcWq_80$beCnF+-JdH;#n|h#6FudGknwc9PpNOeL z;;H#bj+|f^8Ph(*G_$TUu4W)*BEq4>i3oK$5zgigVU*2qMuyZ4b+k9M-NbnbTeesC zR-C8dnv-wd+3{Le7O&J4$0Z1tsztWOmKDN!^AP6LtjkzN{<7yOu+mJ-_Dw-~Ku!vJ z?T%U}B*OV^MLKe65zil}K$2MmQBG~dd83y*RiUu6@v$9;HotyLrsE~ZAUJAXy9rnW~f^R*~POt!eKTQkPMx@kb22_S(NJyMpPNyCA*}et~v0=L;2UN zPfLczK_dZw$sw)k6&3hl4!UK`YOW}4ZM^==zET1QtgUqvKfYhC}BtM%H zR_#6aOkX;FLN;9M*apM#f-_H93OZ?sywq}lDgNLFy_juw>Zg){)3Pz2>V3T#XpVck zV!TVV-AfS0+fh~VAU!f~8$JHJ7OiL>cdCQfxbrTwNYyG-kDGNf2yN;JvXaL5c-<+Bwh;c0rboptCL$IoL7ofQPest>Yc?i3%_oH?e|3 z%1o0)?d((Ig2wAs=T`cq&3v)jHL2~Rxh z+>AR0!VEjxkAFP1^OFQr z9c9>|2)<c5eeGSxgwG@a>f9>@o3mB?|+&sJ4gIALlce z5bngCPf>E(MV)>{77tPE#Y(sN6T z77ZrVM*YmWlkGqY^_Ur|Uv2QEByFBrN!D*P^*s4-JWx`G`gZ~Ho)A*DC delta 4350 zcmZA433!ax9>?+jOcHA^VoB^m?L;zJgor)%Jz_0o#7H9|Bs5~lgp{h-+Ls`zwrWFc z$+5e|rLEgmAGep5UP~>-y)9LHTh#rYIg{sc?|J<4Ip>{s<~`f{&dAC4J@VM@zFgUN zrBI4VZL-}@ecZ|gBiXt6xA4cF~bYY81B5r&aH=)13NEq(HFYy*e zV{v7Xns^6a)o&?NMWhx7TB3fTr`H6pS;&d9#@qhH>v^vayjG}c&TEFcL;X;HuEL9W z8k2B)HIW<)2oTBCUCyU6nFCb=MRIMti24I6)?gNJI{I_G7@N@klwRuBZ(~!8<0>t2 z7V35Zw#9F7AeLuZ<8TzNz+E^8W9x_{>M1);)tT|H)lc43g2x`%k1 zc1V45ymkYTnY3Nlg!8XpN7`i?imbw(I3BOyHtg1jS;Sv)3NC8Q{AW>lN<|--$?(3w zpHX*gFT)AP$Yyj7laOo63e+9lhx!74;s=<(N$;b*g~&Kuk7>Hi^f+-kp2l-nj2{Pc znORguwh}po-{I?wWOInfaN2fGK7V4?2-^PsmASTkjfGOCOh32!R z2=z?d#Ff}5TBI6YMGnamT!fBxW)J-p|4I8tHa724Xi)A}-i=Yd$aWKQv zJwA(zv34hRJ2S8qzoGqgXOVTdp5Ze%Y0oHfF&&%W3*;1O5^Fv`2`$?0"gkLV^c z5%1#9II_FQAK0C%7Gh_1ViXs=gYmQ*^=AEXCT5_ckD2PNIF|MmtcRUhzuoA>AgtVv zTMxsHZs|=WP@jN5gM;ztOJ1LOt>rS0;Aqt64aN5`3!9_=1m?d1BZ-+{ z?#nTBSNHS;>XA)+Lu4V^lSDq}yj;`|n7Cw-X?PbuVfx z6Z)r`8H&Rk+J&iZ^Q90n#XKU{;0j)doys>Eevg+hIgQ6B_F^GZxZpDEPWw5%(0e9! zI-}$GQp})z<4yCeIhsZm$A85B98X}K^(HOGS=iq_(>w~l#A6(o!_m3eVYb=T$54M@ z_c`Wya0KVk-p&STk0A^o8dER=3ve)ALjH*(+k71t;W^sze7JspOaAcD;@(At&y<#W zKIrK-yiB$5E%RVnG+*Qs{rUoSJ+J?S`Z=+XbxFYo$ekw6cg$_O2Nma)TV!t2Be{GP z^ZN9~=DZUaOgmtS=iAjSu~Z&$U@oR$#!~Y^H}C`6?UtF5{tGA2uD;wnDc$%n?GV-} z3eTbLXhn9I9^u!hmu#SA-j|1~X+Ot6%wwH<>p9v4%q*jV~?N(pL=N$K>&=Xi_C3@~Gkgp8Jf1+VEx8|= z=Rs4Zi#t;iu?e0+cL9}$RGQ*C8jbODtc7>5HkRFLZqLT3A25rMzR7jeOP8~ahZANN znx**@`_SIWFxfux2kP^)cks=LL5z+*$+MlzKX;03-o?F&HFulMcNlxp&M)GL$H=bZ zNZL<|%?HLQ^MmC)#&WzD>!W9IDRM|I;!s?^*Zfqwh5VC#tV06&>}Nw_;(oVz^j_kC zzTmI}X392TL)z^RnkUvc)FXU^nK+Yq_rZs#r}8(fgF%NqHxV`S<)k}ZQuK`I4PJ$G zA$ku~<@%l<3gEf#waH`#X-c?@{-^lTvdF8X6VZhmLn@L=#GjNRV@MFGOU4ns4BSwj zeKiyH^4246-Fsd1=yX|4SUykb%imdqeJN8(I%!GtOqCQp?Rw;_pr^1>p3;%O!%04= zPLfC#(S_|MZxp7O5O!KgP=4p~702-`ek-h%VUV$zWGB4bHw;vgHyBoa^FCuIrux#v*{o*(uJm`H|_{$wSY zMsmprGO=WV{b)2G6UatVK(>-FqRTs^42jSUZ^=d{Sx35(wxl;HDVwRRC$A9~2`44x zFWyRsex6OHF`6_dnIw+PCK==vGK8pw0lqeMEwGkN71VrTvpUo%Z=I?At97|fjA~c+ zj7>#0*x{?rHrZ@b$<2q@RE-dak7b4Ru#Sh{QlXLee62-kV<*iXMMb_IL=30+C zov^;>lBn`x1MDig$0A=fsBflS#ShrztLnu2`>3p8i*4%qh&Y?|%c#<7>X>}H`e9sN zX;n1wsgJ6gdWD{(75k`u8CPxULgrFGbtij*ug~4XN3Fs08^1nqKzwl5G?#N)QtIU3 zSm!iXbWm8Rqit|#c(5ZX$PpeL9?_y_YML|1l|F6qcxPHrT55`Oa)PVezyZN=t~Zm? z|NniF!C_%Rj<(T`h!&w?)~WeF`GvI#YZY!CT;NcRa@*U~xyAi#*0;;6sfgtvb}QJb zs8+pK!)BefT3a#sF12jMHJf^|x<@IMu%WYE?cKc8rY3Do_Oa^h=&gG09A;CYyYKs1 zXZGE)y6g|ItOMt*GKX_its{1u)$3S}ia9>RuBLo8#!t=qD%?jUpPuTcs(&b3%zXW{?&VS)$_)nGV0=;mA=aFL7-jLds675Iy|dpS7l$smfBxb+7{(k gmx=0|ls?TFG~N}I;7l2pl$x%q@x!`In(mVS0)>h5@c;k- diff --git a/doc/locales/es/LC_MESSAGES/twblue-changelog.po b/doc/locales/es/LC_MESSAGES/twblue-changelog.po index 06defef6..f6103073 100644 --- a/doc/locales/es/LC_MESSAGES/twblue-changelog.po +++ b/doc/locales/es/LC_MESSAGES/twblue-changelog.po @@ -5,8 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2019-05-22 19:14+0200\n" +"Report-Msgid-Bugs-To: manuel@manuelcortez.net\n" +"POT-Creation-Date: 2021-11-01 16:17-0600\n" +"PO-Revision-Date: 2021-11-01 17:01-0600\n" "Last-Translator: José Manuel Delicado \n" "Language-Team: \n" "Language: es\n" @@ -14,18 +15,496 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.2.3\n" +"X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../doc/changelog.py:3 -msgid "TWBlue Changelog" -msgstr "Lista de cambios de TWBlue" +#: changelog.py:3 +msgid "TWBlue Changelog" +msgstr "Lista de cambios de TWBlue" -#: ../doc/changelog.py:4 +#: changelog.py:5 changelog.py:7 msgid "## changes in this version" msgstr "## Cambios en esta versión" -#: ../doc/changelog.py:5 +#: changelog.py:9 +msgid "" +"* TWBlue should retrieve tweets from threads and conversations in a more " +"reliable way. Tweets in the same thread (made by the same author) will be " +"sorted correctly, although replies to the thread (made by different people) " +"may not be ordered in the same way they are displayed in Twitter apps. " +"([#417](https://github.com/manuelcortez/TWBlue/issues/417))" +msgstr "" +"* TWBlue debería mostrar los hilos y conversaciones de manera más eficiente. " +"Los hilos se mostrarán en el orden en el que fueron creados, mientras que " +"las respuestas a alguno de los tweets que componen el hilo se podrían " +"mostrar en un orden diferente al que se muestra en las aplicaciones de " +"Twitter. ([#417](https://github.com/manuelcortez/TWBlue/issues/417))" + +#: changelog.py:10 +msgid "" +"* fixed a bug when clearing the direct messages buffer. ([#418](https://" +"github.com/manuelcortez/TWBlue/issues/418))" +msgstr "" +"* Corregido un error que impedía vaciar el buffer de mensajes directos. " +"([#418](https://github.com/manuelcortez/TWBlue/issues/418))* solucionado un " +"problema en el Streaming API que causaba que TWBlue desconectara el " +"Streaming. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" + +#: changelog.py:11 +msgid "" +"* fixed an issue that was making TWBlue to show incorrectly titles for " +"trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/" +"TWBlue/issues/421))" +msgstr "" +"* Se ha corregido un problema que hacía que TWBlue mostrara de forma " +"incorrecta los títulos de los buffers de trending topics al iniciarse. " +"([#421](https://github.com/manuelcortez/TWBlue/issues/421))" + +#: changelog.py:13 +msgid "## Changes in Version 2021.10.30" +msgstr "## Cambios en la versión 2021.10.30" + +#: changelog.py:15 +msgid "" +"* Fixed many errors in the way we compile TWBlue, so users of 64 bits " +"systems and particularly windows 7 users would be able to install TWBlue " +"again. In case of issues with versions prior to 2021.10.30, please remove " +"everything related to TWBlue (except configs) and reinstall the version " +"2021.10.30 to fix any possible error. This step won't be needed again in 23 " +"months. ([#416,](https://github.com/manuelcortez/TWBlue/issues/416), [#415,]" +"(https://github.com/manuelcortez/TWBlue/issues/415))" +msgstr "" +"* Se han corregido algunos errores importantes en el proceso que utilizamos " +"para compilar las versiones de TWBlue. Gracias a estas correcciones, los " +"usuarios de sistemas de 64 bits, y en particular, los usuarios de Windows 7, " +"podrán volver a utilizar TWBlue con normalidad. En caso de presentar " +"problemas con versiones 2021.10.30 o anteriores, por favor elimina todo lo " +"relacionado con la aplicación (esta vez, sin incluir la configuración) e " +"intenta instalar desde cero. Esto no volverá a ser necesario por los " +"próximos 23 meses.([#416,](https://github.com/manuelcortez/TWBlue/" +"issues/416), [#415,](https://github.com/manuelcortez/TWBlue/issues/415))" + +#: changelog.py:16 +msgid "" +"* fixed an issue that was making impossible to manually add an user to the " +"autocomplete users database." +msgstr "" +"* Corregido un error que causaba que fuera imposible añadir manualmente un " +"usuario a la base de datos de autocompletado." + +#: changelog.py:17 +msgid "" +"* Started to improve support to conversations by searching for " +"conversation_id." +msgstr "" +"* Se ha comenzado a mejorar el soporte a las conversaciones e hilos buscando " +"por el parámetro conversation_id en Twitter." + +#: changelog.py:19 +msgid "## changes in version 2021.10.27" +msgstr "## Cambios en la versión 2021.10.27" + +#: changelog.py:21 +msgid "" +"* Added an user alias manager, located in the application menu in the menu " +"bar. From this dialog, it is possible to review, add, edit or remove user " +"aliases for the current account. ([#401](https://github.com/manuelcortez/" +"TWBlue/issues/401))" +msgstr "" +"* Agregado un administrador de alias de usuario, ubicado en la barra de " +"menú, dentro del menú de aplicación. Desde este apartado, es posible añadir, " +"editar y eliminar el alias para los usuarios de la cuenta seleccionada. " +"([#401](https://github.com/manuelcortez/TWBlue/issues/401))" + +#: changelog.py:22 +msgid "" +"* TWBlue now closes the VLC player window automatically when a video reaches " +"its end. ([#399](https://github.com/manuelcortez/TWBlue/issues/399))" +msgstr "" +"* TWBlue ahora cierra la ventana de reproducción de VLC al terminar la " +"reproducción de un video. ([#399](https://github.com/manuelcortez/TWBlue/" +"issues/399))" + +#: changelog.py:23 +msgid "" +"* After a lot of time, TWBlue now uses a new default Soundpack, called " +"FreakyBlue. This soundpack will be set by default in all new sessions " +"created in the application. Thanks to [Andre Louis](https://twitter.com/" +"FreakyFwoof) for the pack. ([#247](https://github.com/manuelcortez/TWBlue/" +"issues/247))" +msgstr "" +"* Después de mucho tiempo, TWBlue tiene un paquete de sonidos nuevo, llamado " +"FreakyBlue. Este paquete será el seleccionado por defecto al iniciar sesión " +"en la aplicación. Gracias a [Andre Louis](https://twitter.com/FreakyFwoof) " +"por tomarse el trabajo de diseñar el paquete de sonidos para TWBlue. ([#247]" +"(https://github.com/manuelcortez/TWBlue/issues/247))" + +#: changelog.py:24 +msgid "" +"* When reading a tweet, if the tweet contains more than 2 consecutive " +"mentions, TWBlue will announce how many more users the tweet includes, as " +"opposed to read every user in the conversation. You still can display the " +"tweet to read all users." +msgstr "" +"* Cuando se lea un tweet, si el elemento contiene muchos usuarios " +"mencionados, TWBlue indicará los primeros dos usuarios e indicará el número " +"de usuarios adicionales que tiene el tweet, en lugar de leer todos y cada " +"uno de los usuarios que han sido mencionados. Todavía puede verse el " +"conjunto de usuarios mencionados en el tweet utilizando el diálogo de ver " +"tweets." + +#: changelog.py:25 +msgid "" +"* In the tweet displayer, It is possible to copy a link to the current tweet " +"or person by pressing a button called \"copy link to clipboard\"." +msgstr "" +"* En el diálogo para mostrar tweets, es posible copiar el vínculo de acceso " +"directo al tweet o usuario seleccionando el botón llamado \"copiar vínculo " +"al portapapeles\"." + +#: changelog.py:26 +msgid "" +"* Added a keymap capable to work under Windows 11. ([#391](https://github." +"com/manuelcortez/TWBlue/pull/391))" +msgstr "" +"* Se ha añadido un mapa de teclado capaz de funcionar correctamente en " +"Windows 11. ([#391](https://github.com/manuelcortez/TWBlue/pull/391))" + +#: changelog.py:27 +msgid "" +"* Added user aliases to TWBlue. This feature allows you to rename user's " +"display names on Twitter, so the next time you'll read an user it will be " +"announced as you configured. For adding an alias to an user, select the " +"\"add alias\" option in the user menu, located in the menu bar. This feature " +"works only if you have set display screen names unchecked. Users are " +"displayed with their display name in people buffers only. This action is " +"supported in all keymaps, although it is undefined by default. ([#389]" +"(https://github.com/manuelcortez/TWBlue/pull/389))" +msgstr "" +"* Se han añadido alias de usuario a TWBlue. Esta función permite renombrar " +"los usuarios que se muestran en Twitter, de modo que la próxima vez que se " +"lea un usuario se anunciará tal y como esté configurado. Para añadir un " +"alias a un usuario, selecciona la opción \"añadir alias\" en el menú de " +"usuario, situado en la barra de menú. Esta opción sólo funciona si has " +"desmarcado la opción de mostrar nombres de pantalla. Los usuarios se " +"muestran con su nombre de pantalla sólo en los buffers de personas. Esta " +"acción es compatible con todos los mapas de teclado, aunque no está asignada " +"a ninguna combinación de teclado por defecto. ([#389](https://github.com/" +"manuelcortez/TWBlue/pull/389))" + +#: changelog.py:28 +msgid "* There are some changes to the autocomplete users feature:" +msgstr "* Hemos introducido algunos cambios al autocompletado de usuarios:" + +#: changelog.py:29 +msgid "" +" * Now users can search for twitter screen names or display names in the " +"database." +msgstr "" +" * Ahora, es posible buscar utilizando los nombres de pantalla o nombres " +"para mostrar de los usuarios de Twitter." + +#: changelog.py:30 +msgid "" +"* It is possible to undefine keystrokes in the current keymap in TWBlue. " +"This allows you, for example, to redefine keystrokes completely." +msgstr "" +"* Es posible desasignar combinaciones de teclado en el mapa de teclado en " +"uso en TWBlue. Esto permite, por ejemplo, desasignar combinaciones de " +"teclado para utilizarlas en otras funciones." + +#: changelog.py:31 +msgid "" +"* We have changed our Geocoding service to the Nominatim API from " +"OpenStreetMap. Addresses present in tweets are going to be determined by " +"this service, as the Google Maps API now requires an API key. ([#390]" +"(https://github.com/manuelcortez/TWBlue/issues/390))" +msgstr "" +"* Hemos cambiado nuestro proveedor de servicio de geocodificación a la API " +"Nominatim de OpenStreetMap. Las direcciones presentes en los tweets van a " +"ser determinadas por este servicio, ya que la API de Google Maps requiere " +"ahora una clave API de pago. ([#390](https://github.com/manuelcortez/TWBlue/" +"issues/390))" + +#: changelog.py:32 +msgid "" +"* Added a limited version of the Twitter's Streaming API: The Streaming API " +"will work only for tweets, and will receive tweets only by people you " +"follow. Protected users are not possible to be streamed. It is possible that " +"during high tweet traffic, the Stream might get disconnected at times, but " +"TWBlue should be capable of detecting this problem and reconnecting the " +"stream again. ([#385](https://github.com/manuelcortez/TWBlue/pull/385))" +msgstr "" +"* Se ha añadido una versión limitada de la Streaming API de Twitter: La " +"Streaming API funcionará sólo para los tweets, y recibirá los tweets sólo de " +"las personas que sigues. Los usuarios protegidos no serán incluidos en los " +"tweets que se reciben en la streaming API. Es posible que durante un alto " +"tráfico de tweets, el Stream pueda desconectarse a veces, pero TWBlue " +"debería ser capaz de detectar este problema y reconectar el stream de nuevo. " +"([#385](https://github.com/manuelcortez/TWBlue/pull/385))" + +#: changelog.py:33 +msgid "" +"* Fixed an issue that made TWBlue to not show a dialog when attempting to " +"show a profile for a suspended user. ([#387](https://github.com/manuelcortez/" +"TWBlue/issues/387))" +msgstr "" +"* Se ha corregido un problema que causaba que TWBlue fuera incapaz de " +"mostrar nada al intentar ver el perfil de un usuario suspendido. ([#387]" +"(https://github.com/manuelcortez/TWBlue/issues/387))" + +#: changelog.py:34 +msgid "" +"* Added support for Twitter audio and videos: Tweets which contains audio or " +"videos will be detected as audio items, and you can playback those with the " +"regular command to play audios. ([#384,](https://github.com/manuelcortez/" +"TWBlue/pull/384))" +msgstr "" +"* Se ha añadido soporte para audio y vídeos de Twitter: Los tweets que " +"contengan audio o vídeos serán detectados como elementos de audio, y podrás " +"reproducirlos con el comando habitual para reproducir audios. ([#384,]" +"(https://github.com/manuelcortez/TWBlue/pull/384))" + +#: changelog.py:35 +msgid "" +"* We just implemented some changes in the way TWBlue handles tweets in order " +"to reduce its RAM memory usage [#380](https://github.com/manuelcortez/TWBlue/" +"pull/380):" +msgstr "" +"* Hemos implementado una serie de cambios en la forma en que TWBlue almacena " +"los tweets, con el objetivo de mejorar el consumo de memoria y CPU. [#380]" +"(https://github.com/manuelcortez/TWBlue/pull/380):" + +#: changelog.py:36 +msgid "" +" * We reduced the tweets size by storing only the tweet fields we " +"currently use. This should reduce tweet's size in memory for every object up " +"to 75%." +msgstr "" +" * Hemos logrado reducir el tamaño de los tweets almacenando sólo los " +"campos de información que usamos actualmente. Esto debería reducir el tamaño " +"del tweet en la memoria para cada objeto hasta un 75%." + +#: changelog.py:37 +msgid "" +" * When using the cache database to store your tweets, there is a new " +"setting present in the account settings dialog, in the general tab. This " +"setting allows you to control whether TWBlue will load the whole database " +"into memory (which is the current behaviour) or not." +msgstr "" +" * Cuando se utiliza la base de datos de caché para almacenar tweets, hay " +"un nuevo ajuste presente en el diálogo de configuración de la cuenta, en la " +"pestaña general. Este ajuste te permite controlar si TWBlue cargará toda la " +"base de datos en la memoria RAM (Opción predeterminada) o no." + +#: changelog.py:38 +msgid "" +" * Loading the whole database into memory has the advantage of being " +"extremely fast to access any element (for example when moving through tweets " +"in a buffer), but it requires more memory as the tweet buffers grow up. This " +"should, however, use less memory than before thanks to the optimizations " +"performed in tweet objects. If you have a machine with enough memory, this " +"should be a good option for your case." +msgstr "" +" * Cargar toda la base de datos en la memoria tiene la ventaja de ser " +"extremadamente rápido para acceder a cualquier elemento (por ejemplo, al " +"desplazarse por los tweets en un buffer), pero requiere más memoria a medida " +"que los buffers de tweets se hacen más grandes. Sin embargo, debería " +"utilizar menos memoria que antes gracias a las optimizaciones realizadas en " +"los objetos de tweets. Si tienes una máquina con suficiente memoria, esta " +"debería ser una buena opción para ti." + +#: changelog.py:39 +msgid "" +" * If you uncheck this setting, TWBlue will read the whole database " +"from disk. This is significantly slower, but the advantage of this setting " +"is that it will consume almost no extra memory, no matter how big is the " +"tweets dataset. Be ware, though, that TWBlue might start to feel slower when " +"accessing elements (for example when reading tweets) as the buffers grow up. " +"This setting is suggested for computers with low memory or for those people " +"not wanting to keep a really big amount of tweets stored." +msgstr "" +" * Si desmarcas esta opción, TWBlue leerá toda la base de datos desde " +"el disco. Esto es significativamente más lento, pero la ventaja de esta " +"opción es que no consumirá casi nada de memoria extra, sin importar lo " +"grande que sea el buffer. Sin embargo, ten en cuenta que TWBlue puede " +"empezar a ser más lento al acceder a los elementos (por ejemplo, al leer " +"tweets) a medida que los buffers se hacen más grandes. Esta configuración se " +"sugiere para ordenadores con poca memoria o para aquellas personas que no " +"quieran mantener una cantidad realmente grande de tweets almacenados." + +#: changelog.py:40 +msgid "" +"* Changed the label in the direct message's text control so it will indicate " +"that the user needs to write the text there, without referring to any " +"username in particular. ([#366,](https://github.com/manuelcortez/TWBlue/" +"issues/366))" +msgstr "" +"* Se ha cambiado la etiqueta del campo de texto para escribir el recipiente " +"de un mensaje directo. Ahora en dicho campo no se especifica ningún nombre " +"de usuario. ([#366,](https://github.com/manuelcortez/TWBlue/issues/366))" + +#: changelog.py:41 +msgid "" +"* TWBlue will take Shift+F10 again as the contextual menu key in the list of " +"items in a buffer. This stopped working after we have migrated to WX 4.1. " +"([#353,](https://github.com/manuelcortez/TWBlue/issues/353))" +msgstr "" +"* TWBlue puede volver a usar la combinación de teclado Shift+F10 como la " +"tecla de menú contextual." + +#: changelog.py:42 +msgid "" +"* TWBlue should render correctly retweets of quoted tweets. ([#365,](https://" +"github.com/manuelcortez/TWBlue/issues/365))" +msgstr "" +"* TWBlue debería mostrar apropiadamente los retweets de un tweet citado. " +"([#365,](https://github.com/manuelcortez/TWBlue/issues/365))" + +#: changelog.py:43 +msgid "" +"* Fixed an error that was causing TWBlue to be unable to output to screen " +"readers at times. ([#369,](https://github.com/manuelcortez/TWBlue/" +"issues/369))" +msgstr "" +"* Corregido un error que causaba que en ocasiones, TWBlue fuera incapaz de " +"enviar texto a los lectores de pantalla. ([#369,](https://github.com/" +"manuelcortez/TWBlue/issues/369))" + +#: changelog.py:44 +msgid "" +"* Fixed autocomplete users feature. ([#367,](https://github.com/manuelcortez/" +"TWBlue/issues/367))" +msgstr "" +"* Corregida la característica de autocompletado de usuarios. ([#367,]" +"(https://github.com/manuelcortez/TWBlue/issues/367))" + +#: changelog.py:45 +msgid "" +"* Fixed error when displaying an URL at the end of a line, when the tweet or " +"direct message contained multiple lines. Now the URL should be displayed " +"correctly. ([#305,](https://github.com/manuelcortez/TWBlue/issues/305) " +"[#272,](https://github.com/manuelcortez/TWBlue/issues/272))" +msgstr "" +"* Corregido un error al intentar colocar direcciones URL en tweets o " +"mensajes directos con múltiples líneas. Ahora deberían verse correctamente " +"todas las direcciones. ([#305,](https://github.com/manuelcortez/TWBlue/" +"issues/305) [#272,](https://github.com/manuelcortez/TWBlue/issues/272))" + +#: changelog.py:46 +msgid "" +"* TWBlue has been migrated completely to Python 3 (currently, the software " +"builds with Python 3.8)." +msgstr "" +"* TWBlue ha sido migrado completamente a Python 3 (actualmente, el software " +"se construye con Python 3.8)." + +#: changelog.py:47 +msgid "" +"* TWBlue should be restarted gracefully. Before, the application was " +"alerting users of not being closed properly every time the application " +"restarted by itself." +msgstr "" +"* TWBlue debería reiniciarse apropiadamente. Antes, la aplicación alertaba a " +"los usuarios de que no se cerraba correctamente cada vez que debía efectuar " +"un reinicio." + +#: changelog.py:48 +msgid "" +"* If TWBlue attemps to load an account with invalid tokens (this happens " +"when reactivating a previously deactivated account, or when access to the ap " +"is revoqued), TWBlue will inform the user about this error and will skip the " +"account. Before, the app was unable to start due to a critical error. " +"([#328,](https://github.com/manuelcortez/TWBlue/issues/328))" +msgstr "" +"* Si TWBlue intenta cargar una cuenta con tokens no válidos (esto ocurre " +"cuando se reactiva una cuenta previamente desactivada, o cuando se revoca el " +"acceso a la ap), TWBlue informará al usuario sobre este error y omitirá la " +"sesión. Antes, la aplicación no podía iniciarse debido a un error crítico. " +"([#328,](https://github.com/manuelcortez/TWBlue/issues/328))" + +#: changelog.py:49 +msgid "" +"* When sending a direct message, the title of the window will change " +"appropiately when the recipient is edited. ([#276,](https://github.com/" +"manuelcortez/TWBlue/issues/276))" +msgstr "" +"* Al enviar un mensaje directo, el título de la ventana cambiará " +"apropiadamente cada vez que el recipiente es editado. ([#276,](https://" +"github.com/manuelcortez/TWBlue/issues/276))" + +#: changelog.py:50 +msgid "" +"* URL'S in user profiles are expanded automatically. ([#275,](https://github." +"com/manuelcortez/TWBlue/issues/275))" +msgstr "" +"* Las direcciones URL de los perfiles de usuario estarán expandidas " +"automáticamente. ([#275,](https://github.com/manuelcortez/TWBlue/issues/275))" + +#: changelog.py:51 +msgid "" +"* TWBlue now uses [Tweepy,](https://github.com/tweepy/tweepy) to connect " +"with Twitter. We have adopted this change in order to support Twitter'S API " +"V 2 in the very near future. ([#333,](https://github.com/manuelcortez/TWBlue/" +"issues/337) [#347](https://github.com/manuelcortez/TWBlue/pull/347))" +msgstr "" +"* TWBlue ahora utiliza la librería [Tweepy](https://github.com/tweepy/" +"tweepy) para conectar con Twitter. Hemos decidido adoptar este cambio para " +"así poder utilizar las características presentes en la versión 2 de la API " +"de Twitter en un futuro cercano. ([#333,](https://github.com/manuelcortez/" +"TWBlue/issues/337) [#347](https://github.com/manuelcortez/TWBlue/pull/347))" + +#: changelog.py:52 +msgid "" +"* TWBlue can upload images in Tweets and replies again. ([#240,](https://" +"github.com/manuelcortez/TWBlue/issues/240))" +msgstr "" +"* TWBlue puede subir imágenes en tweets y respuestas de nuevo. ([#240,]" +"(https://github.com/manuelcortez/TWBlue/issues/240))" + +#: changelog.py:53 +msgid "" +"* Fixed the way we use to count characters in Twitter. The new methods in " +"TWBlue take into account special characters and URLS as documented in " +"Twitter. ([#199,](https://github.com/manuelcortez/TWBlue/issues/199) [#315]" +"(https://github.com/manuelcortez/TWBlue/issues/315))" +msgstr "" +"* Hemos corregido la manera en la que TWBlue cuenta los caracteres en los " +"tweets y al escribir. Ahora los caracteres serán contados de acuerdo con las " +"especificaciones de Twitter. ([#199,](https://github.com/manuelcortez/TWBlue/" +"issues/199) [#315](https://github.com/manuelcortez/TWBlue/issues/315))" + +#: changelog.py:54 +msgid "* Proxy support now works as expected." +msgstr "* El soporte Proxy ahora debería funcionar como es debido." + +#: changelog.py:55 +msgid "" +"* Changed translation service from yandex.translate to Google Translator. " +"([#355,](https://github.com/manuelcortez/TWBlue/issues/355))" +msgstr "" +"* Hemos cambiado el servicio de traducción de yandex.translate a Google " +"Translate. ([#355,](https://github.com/manuelcortez/TWBlue/issues/355))" + +#: changelog.py:56 +msgid "" +"* Improved method to load direct messages in the buffers. Now it should be " +"faster due to less calls to Twitter API performed from the client." +msgstr "" +"* Se ha mejorado el método para cargar los mensajes directos en los buffers. " +"Ahora debería ser más rápido debido a que se realizan menos llamadas a la " +"API de Twitter desde el cliente." + +#: changelog.py:57 +msgid "" +"* And more. ([#352,](https://github.com/manuelcortez/TWBlue/issues/352))" +msgstr "* Y más ([#352,](https://github.com/manuelcortez/TWBlue/issues/352))" + +#: changelog.py:59 +msgid "## Changes in version 0.95" +msgstr "## Cambios en la versión 0.95" + +#: changelog.py:61 msgid "" "* TWBlue can open a Tweet or user directly in Twitter. There is a new option " "in the context menu for people and tweet buffers, and also, the shortcut " @@ -36,12 +515,12 @@ msgstr "" "también el atajo control+win+alt+enter para abrir en Twitter el elemento con " "el foco." -#: ../doc/changelog.py:6 +#: changelog.py:62 msgid "* Some keystrokes were remapped in the Windows 10 Keymap:" msgstr "" "* Cambiados algunos atajos de teclado en el mapa de teclado de Windows 10:" -#: ../doc/changelog.py:7 +#: changelog.py:63 msgid "" " * Read location of a tweet: Ctrl+Win+G. ([#177](https://github.com/" "manuelcortez/TWBlue/pull/177))" @@ -49,17 +528,17 @@ msgstr "" " * Leer ubicación de un tuit: CTRL+Win+G. ([#177](https://github.com/" "manuelcortez/TWBlue/pull/177))" -#: ../doc/changelog.py:8 +#: changelog.py:64 msgid " * Open global settings dialogue: Ctrl+Win+Alt+O." msgstr " * Abrir diálogo de configuración global: Ctrl+Win+Alt+O." -#: ../doc/changelog.py:9 +#: changelog.py:65 msgid " * Mute/unmute current session: Control + Windows + Alt + M." msgstr "" " * Silenciar / desactivar silencio en la sesión actual: Control + Windows " "+ Alt + M." -#: ../doc/changelog.py:10 +#: changelog.py:66 msgid "" "* Fixed an error that was preventing TWBlue to load the direct messages " "buffer if an user who sent a message has been deleted." @@ -67,7 +546,7 @@ msgstr "" "* Corregido un error que impedía a TWBlue cargar el buffer de mensajes " "directos si se ha eliminado un usuario que envió un mensaje." -#: ../doc/changelog.py:11 +#: changelog.py:67 msgid "" "* Added support for playing audios posted in [AnyAudio.net](http://anyaudio." "net) directly from TWBlue. Thanks to [Sam Tupy](http://www.samtupy.com/)" @@ -76,7 +555,7 @@ msgstr "" "(http://anyaudio.net) directamente desde TWBlue. Gracias a [Sam Tupy](http://" "www.samtupy.com/)" -#: ../doc/changelog.py:12 +#: changelog.py:68 msgid "" "* Custom buffer ordering will not be reset every time the application " "restarts after an account setting has been modified." @@ -84,7 +563,7 @@ msgstr "" "* El orden personalizado de buffers no se restablecerá cada vez que la " "aplicación se reinicie tras modificar un ajuste de la cuenta." -#: ../doc/changelog.py:13 +#: changelog.py:69 msgid "" "* When adding or removing an user from a list, it is possible to press enter " "in the focused list instead of having to search for the \"add\" or \"delete" @@ -94,7 +573,7 @@ msgstr "" "la lista con el foco en vez de tener que buscar los botones \"Añadir\" o " "\"Eliminar\"." -#: ../doc/changelog.py:14 +#: changelog.py:70 msgid "" "* Quoted and long tweets are displayed properly in the sent tweets buffer " "after being send. ([#253](https://github.com/manuelcortez/TWBlue/issues/253))" @@ -103,7 +582,7 @@ msgstr "" "enviados después de enviarse. ([#253](https://github.com/manuelcortez/TWBlue/" "issues/253))" -#: ../doc/changelog.py:15 +#: changelog.py:71 msgid "" "* Fixed an issue that was making the list manager keystroke unable to be " "shown in the keystroke editor. Now the keystroke is listed properly. ([#260]" @@ -114,7 +593,7 @@ msgstr "" "se lista adecuadamente. ([#260](https://github.com/manuelcortez/TWBlue/" "issues/260))" -#: ../doc/changelog.py:16 +#: changelog.py:72 msgid "" "* The volume slider, located in the account settings of TWBlue, now should " "decrease and increase value properly when up and down arrows are pressed. " @@ -126,7 +605,7 @@ msgstr "" "arriba y abajo. Antes lo hacía en orden inverso. ([#261](https://github.com/" "manuelcortez/TWBlue/issues/261))" -#: ../doc/changelog.py:17 +#: changelog.py:73 msgid "" "* autoreading has been redesigned to work in a similar way for almost all " "buffers. Needs testing. ([#221](https://github.com/manuelcortez/TWBlue/" @@ -136,7 +615,7 @@ msgstr "" "casi todos los buffers. Necesita pruebas. ([#221](https://github.com/" "manuelcortez/TWBlue/issues/221))" -#: ../doc/changelog.py:18 +#: changelog.py:74 msgid "" "* When displaying tweets or direct messages, a new field has been added to " "show the date when the item has been posted to Twitter." @@ -144,7 +623,7 @@ msgstr "" "* Al mostrar tuits o mensajes directos, ahora hay un nuevo campo que muestra " "la fecha en la que se publicó ese elemento en Twitter." -#: ../doc/changelog.py:19 +#: changelog.py:75 msgid "" "* Added support for deleting direct messages by using the new Twitter API " "methods." @@ -152,14 +631,14 @@ msgstr "" "* Se ha añadido soporte para eliminar mensajes directos usando los nuevos " "métodos de la API de Twitter." -#: ../doc/changelog.py:20 +#: changelog.py:76 msgid "" "* When quoting a retweet, the quote will be made to the original tweet " "instead of the retweet." msgstr "" "* Al citar un retuit, la cita apuntará al tuit original en vez del retuit." -#: ../doc/changelog.py:21 +#: changelog.py:77 msgid "" "* If the sent direct messages buffer is hidden, TWBlue should keep loading " "everything as expected. ([#246](https://github.com/manuelcortez/TWBlue/" @@ -169,7 +648,7 @@ msgstr "" "cargar todo como se espera. ([#246](https://github.com/manuelcortez/TWBlue/" "issues/246))" -#: ../doc/changelog.py:22 +#: changelog.py:78 msgid "" "* There is a new soundpack, called FreakyBlue (Thanks to [Andre Louis]" "(https://twitter.com/FreakyFwoof)) as a new option in TWBlue. This pack can " @@ -183,7 +662,7 @@ msgstr "" "que los usuarios deberían echar un vistazo y dar su opinión en las " "snapshots. ([#247](https://github.com/manuelcortez/TWBlue/issues/247))" -#: ../doc/changelog.py:23 +#: changelog.py:79 msgid "" "* There is a new option in the help menu that allows you to visit the " "soundpacks section in the TWBlue website. ([#247](https://github.com/" @@ -193,7 +672,7 @@ msgstr "" "paquetes de sonidos en el sitio web de TWBlue. ([#247](https://github.com/" "manuelcortez/TWBlue/issues/247))" -#: ../doc/changelog.py:24 +#: changelog.py:80 msgid "" "* When reading location of a geotagged tweet, it will be translated for " "users of other languages. ([#251](https://github.com/manuelcortez/TWBlue/" @@ -203,7 +682,7 @@ msgstr "" "usuarios de otros idiomas. ([#251](https://github.com/manuelcortez/TWBlue/" "pull/251))" -#: ../doc/changelog.py:25 +#: changelog.py:81 msgid "" "* When there are no more items to retrieve in direct messages and people " "buffers, a message will announce it." @@ -211,7 +690,7 @@ msgstr "" "* Cuando no haya más elementos que recuperar en los buffers de mensajes " "directos y personas, un mensaje lo indicará." -#: ../doc/changelog.py:26 +#: changelog.py:82 msgid "" "* Fixed an issue reported by some users that was making them unable to load " "more items in their direct messages." @@ -219,14 +698,14 @@ msgstr "" "* Corregido un problema reportado por algunos usuarios que les impedía " "cargar más elementos en sus mensajes directos." -#: ../doc/changelog.py:27 +#: changelog.py:83 msgid "" "* It is possible to add a tweet to the likes buffer from the menu bar again." msgstr "" "* Es posible añadir tuits al buffer de me gusta desde la barra de menú otra " "vez." -#: ../doc/changelog.py:28 +#: changelog.py:84 msgid "" "* Tweets, replies and retweets will be added to sent tweets right after " "being posted in Twitter." @@ -234,16 +713,16 @@ msgstr "" "* Los tuits, respuestas y retuits se añadirán a los tuits enviados justo al " "publicarse en Twitter." -#: ../doc/changelog.py:29 +#: changelog.py:85 msgid "* Extended Tweets should be displayed properly in list buffers." msgstr "" "* Los tuits largos deberían mostrarse correctamente en los buffers de listas." -#: ../doc/changelog.py:30 +#: changelog.py:87 msgid "## Changes in version 0.94" msgstr "## Cambios en la versión 0.94" -#: ../doc/changelog.py:31 +#: changelog.py:89 msgid "" "* Added an option in the global settings dialog to disable the Streaming " "features of TWBlue. TWBlue will remove all Streaming features after August " @@ -257,7 +736,7 @@ msgstr "" "permite saber cómo se comportará la aplicación al llegar ese día. ([#219]" "(https://github.com/manuelcortez/TWBlue/issues/219))" -#: ../doc/changelog.py:32 +#: changelog.py:90 msgid "" "* Due to Twitter API changes, Switched authorisation method to Pin-code " "based authorisation. When you add new accounts to TWBlue, you will be " @@ -270,7 +749,7 @@ msgstr "" "autorizar recibirás un número que deberás pegar en la ventana de TWBlue para " "poder continuar. ([#216](https://github.com/manuelcortez/TWBlue/issues/216))" -#: ../doc/changelog.py:33 +#: changelog.py:91 msgid "" "* In order to comply with latest Twitter changes, TWBlue has switched to the " "new method used to send and receive direct messages, according to issue " @@ -281,7 +760,7 @@ msgstr "" "directos, de acuerdo con lo dispuesto en el issue [#215.](https://github.com/" "manuelcortez/twblue/issues/215)" -#: ../doc/changelog.py:34 +#: changelog.py:92 msgid "" " * The new method does not allow direct messages to be processed in real " "time. Direct messages will be updated periodically." @@ -290,7 +769,7 @@ msgstr "" "tiempo real. Los mensajes directos se actualizarán periódicamente, pero no " "en tiempo real." -#: ../doc/changelog.py:35 +#: changelog.py:93 msgid "" "* After august 16 or when streaming is disabled, the events buffer will no " "longer be created in TWBlue." @@ -298,7 +777,7 @@ msgstr "" "* Luego del 16 de agosto o si las características en tiempo real han sido " "desactivadas, el buffer de eventos dejará de ser utilizado en TWBlue." -#: ../doc/changelog.py:36 +#: changelog.py:94 msgid "" "* You can configure frequency for buffer updates in TWBlue. By default, " "TWBlue will update all buffers every 2 minutes, but you can change this " @@ -310,7 +789,7 @@ msgstr "" "esto puede cambiarse desde el diálogo de opciones globales. ([#223](https://" "github.com/manuelcortez/TWBlue/issues/223))" -#: ../doc/changelog.py:37 +#: changelog.py:95 msgid "" "* Added a new tab called feedback, in the account settings dialog. This tab " "allows you to control whether automatic speech or Braille feedbak in certain " @@ -327,7 +806,7 @@ msgstr "" "salida automática. ([#203](https://github.com/manuelcortez/TWBlue/" "issues/203))" -#: ../doc/changelog.py:38 +#: changelog.py:96 msgid "" "* The spell checking dialog now has access keys defined for the most " "important actions. ([#211](https://github.com/manuelcortez/TWBlue/" @@ -337,7 +816,7 @@ msgstr "" "para las acciones más importantes. ([#211](https://github.com/manuelcortez/" "TWBlue/issues/211))" -#: ../doc/changelog.py:39 +#: changelog.py:97 msgid "" "* TWBlue now Uses WXPython 4.0.1. This will allow us to migrate all " "important components to Python 3 in the future. ([#207](https://github.com/" @@ -347,7 +826,7 @@ msgstr "" "componentes importantes a Python 3 en el futuro. ([#207](https://github.com/" "manuelcortez/TWBlue/issues/207))" -#: ../doc/changelog.py:40 +#: changelog.py:98 msgid "" "* When you quote a Tweet, if the original tweet was posted with Twishort, " "TWBlue should display properly the quoted tweet. Before it was displaying " @@ -358,7 +837,7 @@ msgstr "" "debería mostrar correctamente el tuit citado. Antes sólo mostraba el tuit " "original. ([#206](https://github.com/manuelcortez/TWBlue/issues/206))" -#: ../doc/changelog.py:41 +#: changelog.py:99 msgid "" "* It is possible to filter by retweets, quotes and replies when creating a " "new filter." @@ -366,7 +845,7 @@ msgstr "" "* Es posible filtrar por retuits, tuits citados y respuestas al crear nuevos " "filtros." -#: ../doc/changelog.py:42 +#: changelog.py:100 msgid "" "* Added support for playing youtube Links directly from the client. ([#94]" "(https://github.com/manuelcortez/TWBlue/issues/94))" @@ -374,11 +853,11 @@ msgstr "" "* Se ha añadido soporte para reproducir enlaces de Youtube directamente " "desde el cliente. ([#94](https://github.com/manuelcortez/TWBlue/issues/94))" -#: ../doc/changelog.py:43 +#: changelog.py:101 msgid "* Replaced Bass with libVLC for playing URL streams." msgstr "* Se ha reemplazado bass por LibVlc para reproducir audio desde URLS." -#: ../doc/changelog.py:44 +#: changelog.py:102 msgid "" "* the checkbox for indicating whether TWBlue will include everyone in a " "reply or not, will be unchecked by default." @@ -386,7 +865,7 @@ msgstr "" "* La casilla que indica si TWBlue debe incluir a todos los participantes en " "una respuesta estará desmarcada por defecto." -#: ../doc/changelog.py:45 +#: changelog.py:103 msgid "" "* You can request TWBlue to save the state for two checkboxes: Long tweet " "and mention all, from the global settings dialogue." @@ -394,7 +873,7 @@ msgstr "" "* Puedes pedir a TWBlue que guarde el estado de dos casillas: tuit largo y " "mencionar a todos, desde el diálogo de opciones globales." -#: ../doc/changelog.py:46 +#: changelog.py:104 msgid "" "* For windows 10 users, some keystrokes in the invisible user interface have " "been changed or merged:" @@ -402,7 +881,7 @@ msgstr "" "* Para usuarios de Windows 10, algunas combinaciones de teclado en el modo " "invisible han sufrido cambios o han sido combinadas:" -#: ../doc/changelog.py:47 +#: changelog.py:105 msgid "" " * control+Windows+alt+F will be used for toggling between adding and " "removing a tweet to user's likes. This function will execute the needed " @@ -412,22 +891,22 @@ msgstr "" "un tuit a los tuits que le gustan a un usuario. Esta función ejecutará la " "acción necesaria basándose en el estado actual del tuit con el foco." -#: ../doc/changelog.py:48 +#: changelog.py:106 msgid "* TWBlue will show an error if something goes wrong in an audio upload." msgstr "" "* TWBlue mostrará un error si algo sale mal durante la carga de un archivo " "de audio." -#: ../doc/changelog.py:49 +#: changelog.py:107 msgid "" "* And more. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " msgstr "* Y más. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " -#: ../doc/changelog.py:50 +#: changelog.py:109 msgid "## Changes in version 0.93" msgstr "## Cambios en la versión 0.93" -#: ../doc/changelog.py:51 +#: changelog.py:111 msgid "" "* A new soundpack has been added to TWBlue. Thanks to [@ValeriaK305](https://" "twitter.com/ValeriaK305)" @@ -435,7 +914,7 @@ msgstr "" "* Se ha añadido un nuevo paquete de sonidos a la instalación predeterminada " "de TWBlue, gracias a [@ValeriaK305](https://twitter.com/ValeriaK305)" -#: ../doc/changelog.py:52 +#: changelog.py:112 msgid "" "* In the Windows 10 keymap, we have changed some default keystrokes as " "windows now uses some previously assigned shortcuts:" @@ -444,16 +923,16 @@ msgstr "" "de teclado, ya que Windows ahora utiliza algunos de los atajos que utilizaba " "TWBlue:" -#: ../doc/changelog.py:53 +#: changelog.py:113 msgid " * For liking a tweet, press Control+Windows+alt+f" msgstr "" " * Para marcar como me gusta un tweet, presiona control+windows+alt+f" -#: ../doc/changelog.py:54 +#: changelog.py:114 msgid " * for opening a trends buffer, press control+Windows+T" msgstr " * Para abrir un buffer de tendencias, presiona Control+Windows+T" -#: ../doc/changelog.py:55 +#: changelog.py:115 msgid "" "* TWBlue has received improvements in some functions for handling extended " "tweets, long tweets and quoted retweets. It should render some tweets in a " @@ -463,7 +942,7 @@ msgstr "" "extendidos y retuits citados. Debería ser capaz de mostrar mejor algunos " "tuits." -#: ../doc/changelog.py:56 +#: changelog.py:116 msgid "" "* In the spell checker module, there is a new button that will allow you to " "add your own words to your personal dictionary so the module won't mark them " @@ -473,7 +952,7 @@ msgstr "" "la palabra a tu diccionario. De esta forma,en un futuro esa palabra no " "aparecerá marcada como mal escrita." -#: ../doc/changelog.py:57 +#: changelog.py:117 msgid "" "* Added filtering capabilities to TWBlue. ([#102](https://github.com/" "manuelcortez/TWBlue/issues/102))" @@ -481,7 +960,7 @@ msgstr "" "* Se han añadido filtros a TWBlue. ([#102](https://github.com/manuelcortez/" "TWBlue/issues/102))" -#: ../doc/changelog.py:58 +#: changelog.py:118 msgid "" " * You can create a filter for the current buffer from the buffer menu in " "the menu bar. At this moment, invisible interface does not have any shorcut " @@ -491,11 +970,11 @@ msgstr "" "ubicado en la barra de menú. Por el momento, la interfaz invisible no cuenta " "con un atajo para esta acción." -#: ../doc/changelog.py:59 +#: changelog.py:119 msgid " * You can create filters by word or languages." msgstr " * Puedes crear filtros de palabras o de idiomas en el tuit." -#: ../doc/changelog.py:60 +#: changelog.py:120 msgid "" " * For deleting already created filters, you can go to the filter manager " "in the buffer menu and delete the filters you won't need." @@ -503,7 +982,7 @@ msgstr "" " * Para eliminar filtros previamente creados, puedes acceder al gestor de " "filtros en el menú buffer, y eliminar desde ahí los que ya no necesites." -#: ../doc/changelog.py:61 +#: changelog.py:121 msgid "" "* Links should be opened properly in quoted tweets ([#167,](https://github." "com/manuelcortez/TWBlue/issues/167) [#184](https://github.com/manuelcortez/" @@ -513,14 +992,14 @@ msgstr "" "(https://github.com/manuelcortez/TWBlue/issues/167) [#184](https://github." "com/manuelcortez/TWBlue/issues/184))" -#: ../doc/changelog.py:62 +#: changelog.py:122 msgid "" "* Increased display name limit up to 50 characters in update profile dialog." msgstr "" "* Se ha aumentado el número de caracteres permitidos en los nombres para " "mostrar en Twitter a 50 caracteres." -#: ../doc/changelog.py:63 +#: changelog.py:123 msgid "" "* When authorising an account, you will see a dialogue with a cancel button, " "in case you want to abort the process. Also, NVDA will not be blocked when " @@ -532,7 +1011,7 @@ msgstr "" "autorización para la cuenta. ([#101](https://github.com/manuelcortez/TWBlue/" "issues/101))" -#: ../doc/changelog.py:64 +#: changelog.py:124 msgid "" "* In the translator module, the list of available languages is fetched " "automatically from the provider. That means all of these languages will work " @@ -547,7 +1026,7 @@ msgstr "" "determina de forma automática por el API de Yandex. ([#153](https://github." "com/manuelcortez/TWBlue/issues/153))" -#: ../doc/changelog.py:65 +#: changelog.py:125 msgid "" "* Trending topics, searches and conversation buffers will use mute settings " "set for the session in wich they were opened. ([#157](https://github.com/" @@ -557,7 +1036,7 @@ msgstr "" "opciones de silencio en la sesión de TWBlue donde fueron creados. ([#157]" "(https://github.com/manuelcortez/TWBlue/issues/157))" -#: ../doc/changelog.py:66 +#: changelog.py:126 msgid "" "* The Tweet limit is now 280 characters lenght instead 140. It means you can " "tweet longer tweets. ([#172](https://github.com/manuelcortez/TWBlue/" @@ -567,7 +1046,7 @@ msgstr "" "significa que se pueden escribir tuits más largos. [#172](https://github.com/" "manuelcortez/TWBlue/issues/172))" -#: ../doc/changelog.py:67 +#: changelog.py:127 msgid "" "* Per popular request, Status for mention to all and long tweet checkboxes " "will not be saved in settings. ([#170](https://github.com/manuelcortez/" @@ -577,7 +1056,7 @@ msgstr "" "escribir un tuit largo y responder a todos. ([#170](https://github.com/" "manuelcortez/TWBlue/issues/170))" -#: ../doc/changelog.py:68 +#: changelog.py:128 msgid "" "* Fixed a problem that was making TWBlue unable to start if it was being ran " "in Windows with Serbian language. ([#175](https://github.com/manuelcortez/" @@ -587,11 +1066,11 @@ msgstr "" "el equipo se detectaba el idioma serbio. ([#175](https://github.com/" "manuelcortez/TWBlue/issues/175))" -#: ../doc/changelog.py:69 +#: changelog.py:129 msgid "* Added Danish translation." msgstr "* Se ha añadido la traducción al Danés." -#: ../doc/changelog.py:70 +#: changelog.py:130 msgid "" "* And more. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) " "[#163,](https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://" @@ -606,11 +1085,11 @@ msgstr "" "TWBlue/issues/173) [#174,](https://github.com/manuelcortez/TWBlue/" "issues/174) [#176,](https://github.com/manuelcortez/TWBlue/issues/176))" -#: ../doc/changelog.py:71 +#: changelog.py:132 msgid "## changes in version 0.91 and 0.92" msgstr "## Cambios en las versiones 0.91 y 0.92" -#: ../doc/changelog.py:72 +#: changelog.py:134 msgid "" "* Fixed incorrect unicode handling when copying tweet to clipboard. ([#150]" "(https://github.com/manuelcortez/TWBlue/issues/150))" @@ -618,7 +1097,7 @@ msgstr "" "* Se ha corregido un error de Unicode al copiar tuits al portapapeles. " "([#150](https://github.com/manuelcortez/TWBlue/issues/150))" -#: ../doc/changelog.py:73 +#: changelog.py:135 msgid "" "* TWBlue will show an error when trying to open a timeline for a suspended " "user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))" @@ -627,7 +1106,7 @@ msgstr "" "usuario suspendido. ([#128](https://github.com/manuelcortez/TWBlue/" "issues/128))" -#: ../doc/changelog.py:74 +#: changelog.py:136 msgid "" "* Removed TwUp as service as it no longer exists. ([#112](https://github.com/" "manuelcortez/TWBlue/issues/112))" @@ -635,7 +1114,7 @@ msgstr "" "* Se ha removido el servicio de audio TWUp, debido a que ya no existe. " "([#112](https://github.com/manuelcortez/TWBlue/issues/112))" -#: ../doc/changelog.py:75 +#: changelog.py:137 msgid "" "* Release audio files after uploading them. ([#130](https://github.com/" "manuelcortez/TWBlue/issues/130))" @@ -644,7 +1123,7 @@ msgstr "" "luego de haber sido subidos a algún servicio de audio. ([#130](https://" "github.com/manuelcortez/TWBlue/issues/130))" -#: ../doc/changelog.py:76 +#: changelog.py:138 msgid "" "* Now TWBlue will use Yandex's translation services instead microsoft " "translator. ([#132](https://github.com/manuelcortez/TWBlue/issues/132))" @@ -653,7 +1132,7 @@ msgstr "" "Microsoft Translator. ([#132](https://github.com/manuelcortez/TWBlue/" "issues/132))" -#: ../doc/changelog.py:77 +#: changelog.py:139 msgid "" "* SndUp users will be able to upload audio in their account by using their " "API Key again. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" @@ -661,7 +1140,7 @@ msgstr "" "* Los usuarios con cuenta de SNDUp podrán subir audios utilizando su clave " "de API de nuevo. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" -#: ../doc/changelog.py:78 +#: changelog.py:140 msgid "" "* old tweets shouldn't be added as new items in buffers. ([#116,](https://" "github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" @@ -671,7 +1150,7 @@ msgstr "" "github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" "manuelcortez/TWBlue/issues/133))" -#: ../doc/changelog.py:79 +#: changelog.py:141 msgid "" "* All mentionned users should be displayed correctly in Twishort's long " "tweets. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#135]" @@ -681,7 +1160,7 @@ msgstr "" "hechos mediante Twishort. ([#116,](https://github.com/manuelcortez/TWBlue/" "issues/116)) ([#135](https://github.com/manuelcortez/TWBlue/issues/135))" -#: ../doc/changelog.py:80 +#: changelog.py:142 msgid "" "* It is possible to select a language for OCR service from the extras panel, " "in the account settings dialogue. You can, however, set this to detect " @@ -696,7 +1175,7 @@ msgstr "" "especiales o símbolos que no forman parte del alfabeto inglés. ([#107]" "(https://github.com/manuelcortez/TWBlue/issues/107))" -#: ../doc/changelog.py:81 +#: changelog.py:143 msgid "" "* Fixed a problem with JAWS for Windows and TWBlue. Now JAWS will work " "normally in this update. [#100](https://github.com/manuelcortez/twblue/" @@ -706,15 +1185,15 @@ msgstr "" "funcionar de forma correcta con este lector de pantalla. [#100](https://" "github.com/manuelcortez/twblue/issues/100)" -#: ../doc/changelog.py:82 +#: changelog.py:144 msgid "* And more ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" msgstr "* Y más ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" -#: ../doc/changelog.py:83 +#: changelog.py:146 msgid "## Changes in version 0.90" msgstr "## Cambios en la versión 0.90" -#: ../doc/changelog.py:84 +#: changelog.py:148 msgid "" "* Fixed a bug in long tweet parsing that was making TWBlue to disconnect the " "streaming API. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" @@ -723,7 +1202,7 @@ msgstr "" "desconectara el Streaming. ([#103](https://github.com/manuelcortez/TWBlue/" "issues/103))" -#: ../doc/changelog.py:85 +#: changelog.py:149 msgid "" "* Now OCR will work in images from retweets. It fixes a bug where TWBlue was " "detecting images but couldn't apply OCR on them. ([#105](https://github.com/" @@ -734,7 +1213,7 @@ msgstr "" "pudiera aplicar OCR en ellas. ([#105](https://github.com/manuelcortez/TWBlue/" "issues/105))" -#: ../doc/changelog.py:86 +#: changelog.py:150 msgid "" "* TWBlue won't try to load tweets already deleted, made with Twishort. " "Before, if someone posted a long tweet but deleted it in the Twishort's " @@ -747,7 +1226,7 @@ msgstr "" "problemas en todo el cliente. ([#113](https://github.com/manuelcortez/TWBlue/" "issues/113))" -#: ../doc/changelog.py:87 +#: changelog.py:151 msgid "" "* TWBlue shows an error message when you try to view the profile of an user " "that does not exist or has been suspended. ([#114,](https://github.com/" @@ -759,7 +1238,7 @@ msgstr "" "manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" "TWBlue/issues/115))" -#: ../doc/changelog.py:88 +#: changelog.py:152 msgid "" "* The spellchecker module should select the right language when is set to " "\"user default\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" @@ -768,7 +1247,7 @@ msgstr "" "apropiado cuando el idioma del cliente se establece en \"Idioma " "predeterminado\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" -#: ../doc/changelog.py:89 +#: changelog.py:153 msgid "" "* Image description will be displayed in retweets too. ([#119](https://" "github.com/manuelcortez/TWBlue/issues/119))" @@ -776,7 +1255,7 @@ msgstr "" "* La descripción de imágenes se mostrará en retuits también. ([#119](https://" "github.com/manuelcortez/TWBlue/issues/119))" -#: ../doc/changelog.py:90 +#: changelog.py:154 msgid "" "* When reading a long tweet, you shouldn't read strange entities anymore. " "([#118](https://github.com/manuelcortez/twblue/issues/118))" @@ -784,7 +1263,7 @@ msgstr "" "* cuando se lea un tuit largo, no deberían aparecer símbolos extraños. " "([#118](https://github.com/manuelcortez/twblue/issues/118))" -#: ../doc/changelog.py:91 +#: changelog.py:155 msgid "" "* TWBlue will not try to load timelines if the user is blocking you. ([#125]" "(https://github.com/manuelcortez/twblue/issues/125))" @@ -793,28 +1272,28 @@ msgstr "" "a la cuenta actual. ([#125](https://github.com/manuelcortez/twblue/" "issues/125))" -#: ../doc/changelog.py:92 +#: changelog.py:157 msgid "## Changes in version 0.88 and 0.89" msgstr "## Cambios en las versiones 0.88 y 0.89" -#: ../doc/changelog.py:93 +#: changelog.py:159 msgid "* Fixed more issues with streams and reconnections." msgstr "* Corregidos más problemas con los streams y la reconexión." -#: ../doc/changelog.py:94 +#: changelog.py:160 msgid "* newer updates will indicate the release date in the updater." msgstr "" "* Las actualizaciones más nuevas indicarán la fecha de lanzamiento en el " "módulo de actualización." -#: ../doc/changelog.py:95 +#: changelog.py:161 msgid "" "* Changes to keystrokes are reflected in keystroke editor automatically." msgstr "" "* Los cambios en las combinaciones de teclado se reflejarán automáticamente " "en el editor de combinaciones de teclado." -#: ../doc/changelog.py:96 +#: changelog.py:162 msgid "" "* In replies with multiple users, if the mention to all checkbox is " "unchecked, you will see a checkbox per user so you will be able to control " @@ -824,7 +1303,7 @@ msgstr "" "todos no está marcada, verás una casilla para cada usuario, lo que te " "permitirá seleccionar a los usuarios que serán mencionados en la respuesta." -#: ../doc/changelog.py:97 +#: changelog.py:163 msgid "" "* Fixed a bug that caused duplicated user mentions in replies when the tweet " "was made with Twishort." @@ -832,7 +1311,7 @@ msgstr "" "* Corregido un error que causaba que TWBlue mostrara menciones duplicadas si " "el tuit había sido enviado mediante Twishort." -#: ../doc/changelog.py:98 +#: changelog.py:164 msgid "" "* Retweets should be displayed normally again when the originating tweet is " "a Twishort's long tweet." @@ -840,7 +1319,7 @@ msgstr "" "* Los Retuits deben mostrarse correctamente si el tuit original había sido " "enviado mediante Twishort." -#: ../doc/changelog.py:99 +#: changelog.py:165 msgid "" "* Changed the way TWBlue saves user timelines in configuration. Now it uses " "user IDS instead usernames. With user IDS, if an user changes the username, " @@ -853,7 +1332,7 @@ msgstr "" "cambia su nombre de usuario TWBlue todavía será capaz de crear la línea " "temporal. Esto no era posible anteriormente." -#: ../doc/changelog.py:100 +#: changelog.py:166 msgid "" "* Added a new setting in the account settings dialogue that makes TWBlue to " "show twitter usernames instead the full name." @@ -861,7 +1340,7 @@ msgstr "" "* Añadida una opción en el diálogo de opciones de cuenta que hace que TWBlue " "muestre el nombre de pantalla del usuario en lugar del nombre completo." -#: ../doc/changelog.py:101 +#: changelog.py:167 msgid "" "* Added OCR in twitter pictures. There is a new item in the tweet menu that " "allows you to extract and display text in images. Also the keystroke alt+Win" @@ -872,18 +1351,18 @@ msgstr "" "imagen del tuit seleccionado. También se ha añadido la combinación Alt + " "Windows +O para el mismo propósito en la interfaz invisible." -#: ../doc/changelog.py:102 +#: changelog.py:168 msgid "* Now TWBlue will play a sound when the focused tweet contains images." msgstr "" "* Ahora TWBlue reproducirá un sonido cuando el tuit seleccionado contenga " "imágenes." -#: ../doc/changelog.py:103 +#: changelog.py:169 msgid "" "* Your own quoted tweets will not appear in the mentions buffer anymore." msgstr "* Tus tuits citados dejarán de mostrarse en el buffer de menciones." -#: ../doc/changelog.py:104 +#: changelog.py:170 msgid "" "* The config file is saved in a different way, it should fix the bug where " "TWBlue needs to be restarted after the config folder is deleted." @@ -892,13 +1371,13 @@ msgstr "" "solucionar el error que requería borrar el directorio de configuraciones y " "reiniciar TWBlue." -#: ../doc/changelog.py:105 +#: changelog.py:171 msgid "* Mentioning people from friends or followers buffers works again." msgstr "" "* Es posible de nuevo mencionar usuarios desde los buffers de seguidores y " "amigos." -#: ../doc/changelog.py:106 +#: changelog.py:172 msgid "" "* Support for proxy servers has been improved. Now TWBlue supports http, " "https, socks4 and socks5 proxies, with and without autentication." @@ -906,15 +1385,15 @@ msgstr "" "* Se ha mejorado el soporte para servidores proxy. Ahora TWBlue soporta " "proxys http, https, socks4 y socks5, con o sin autenticación." -#: ../doc/changelog.py:107 +#: changelog.py:174 msgid "## Changes in version 0.87" msgstr "## Cambios en la versión 0.87" -#: ../doc/changelog.py:108 +#: changelog.py:176 msgid "* Fixed stream connection errors." msgstr "* Arreglados errores en la conexión de los streams." -#: ../doc/changelog.py:109 +#: changelog.py:177 msgid "" "* Now TWBlue can handle properly a reply to the sender without including all " "other mentioned users." @@ -922,11 +1401,11 @@ msgstr "" "* Ahora TWBlue puede manejar correctamente las respuestas sin incluir a " "todos los usuarios del tuit original." -#: ../doc/changelog.py:110 +#: changelog.py:178 msgid "* Updated translations." msgstr "* Traducciones actualizadas." -#: ../doc/changelog.py:111 +#: changelog.py:179 msgid "" "* The status of the mention to all checkbox will be remembered the next time " "you reply to multiple users." @@ -934,11 +1413,11 @@ msgstr "" "* El estado de la casilla para mencionar a todos se recordará la próxima vez " "que escribas una respuesta." -#: ../doc/changelog.py:112 +#: changelog.py:181 msgid "## Changes in version 0.86" msgstr "## Cambios en la versión 0.86" -#: ../doc/changelog.py:113 +#: changelog.py:183 msgid "" "* Fixed a very important security issue. Now TWBlue will send tweets to " "twishort without using any other server." @@ -946,7 +1425,7 @@ msgstr "" "* Arreglado un error de seguridad muy importante. Ahora TWBlue enviará tuits " "hacia Twishort sin utilizar un servidor intermedio." -#: ../doc/changelog.py:114 +#: changelog.py:184 msgid "" "* When you add a comment to a tweet, it will be sent as a quoted tweet, even " "if your reply plus the original tweet is not exceeding 140 characters." @@ -955,7 +1434,7 @@ msgstr "" "citado, incluso si el comentario más el tuit original no supera los 140 " "caracteres." -#: ../doc/changelog.py:115 +#: changelog.py:185 msgid "" "* Updated windows 10 keymap for reflecting changes made in the last windows " "10 build." @@ -963,11 +1442,11 @@ msgstr "" "* Actualizado el mapa de teclado de Windows 10 debido a los cambios de la " "última build." -#: ../doc/changelog.py:116 +#: changelog.py:186 msgid "* Added last changes in the twitter API." msgstr "* Añadidos los últimos cambios en el API de Twitter." -#: ../doc/changelog.py:117 +#: changelog.py:187 msgid "" "* When replying, it will not show the twitter username in the text box. When " "you send the tweet, the username will be added automatically." @@ -976,7 +1455,7 @@ msgstr "" "campo de texto. El nombre de usuario será añadido de forma automática al " "enviar el tuit." -#: ../doc/changelog.py:118 +#: changelog.py:188 msgid "" "* When replying to multiple users, you'll have a checkbox instead a button " "for mentioning all people. If this is checked, twitter usernames will be " @@ -986,44 +1465,44 @@ msgstr "" "lugar de un botón para mencionar a todos. Si es marcada, los nombres de " "usuario de Twitter se añadirán automáticamente al enviar el tuit." -#: ../doc/changelog.py:119 +#: changelog.py:190 msgid "## Changes in version 0.85" msgstr "## Cambios en la versión 0.85" -#: ../doc/changelog.py:120 +#: changelog.py:192 msgid "* Long and quoted tweets should be displayed properly In lists." msgstr "" "* Los tuits largos y citados deberían mostrarse correctamente en las listas." -#: ../doc/changelog.py:121 +#: changelog.py:193 msgid "* The connection should be more stable." msgstr "* La conexión debería ser más estable." -#: ../doc/changelog.py:122 +#: changelog.py:194 msgid "* Added an autostart option in the global settings dialogue." msgstr "" "* Se ha añadido la opción para iniciar después de iniciar sesión en Windows " "en el diálogo de opciones globales." -#: ../doc/changelog.py:123 +#: changelog.py:195 msgid "* Updated translation." msgstr "* Se han actualizado las traducciones." -#: ../doc/changelog.py:124 +#: changelog.py:196 msgid "* Updated russian documentation." msgstr "* Actualizada la documentación en ruso." -#: ../doc/changelog.py:125 +#: changelog.py:197 msgid "* Tweets in cached database should be loaded properly." msgstr "* Se deben cargar correctamente los tuits en la base de datos." -#: ../doc/changelog.py:126 +#: changelog.py:198 msgid "* Added some missed dictionaries for spelling correction." msgstr "" "* Se han añadido algunos nuevos diccionarios en el módulo de corrección " "ortográfica." -#: ../doc/changelog.py:127 +#: changelog.py:199 msgid "" "* Timelines, lists and other buffer should be created in the right order at " "startup." @@ -1031,15 +1510,15 @@ msgstr "" "* Líneas temporales, listas y otros buffers deberían ser creados en el orden " "correcto al iniciar TWBlue." -#: ../doc/changelog.py:128 +#: changelog.py:201 msgid "## Changes in version 0.84 " msgstr "## Cambios en la versión 0.84 " -#: ../doc/changelog.py:129 +#: changelog.py:203 msgid "* More improvements in quoted and long tweets." msgstr "* Más mejoras en los tuits largos y citados." -#: ../doc/changelog.py:130 +#: changelog.py:204 msgid "" "* Updated translations: Russian, Italian, French, Romanian, Galician and " "Finnish." @@ -1047,7 +1526,7 @@ msgstr "" "* Actualizadas las siguientes traducciones: Ruso, italiano, francés, rumano, " "gallego y finlandés." -#: ../doc/changelog.py:131 +#: changelog.py:205 msgid "" "* Improvements in the audio uploader module: Now it can handle audio with " "non-english characters." @@ -1055,7 +1534,7 @@ msgstr "" "* Mejoras en el módulo de carga de archivos de audio: Ahora es capaz de " "manejar archivos de audio con caracteres especiales." -#: ../doc/changelog.py:132 +#: changelog.py:206 msgid "" "* the title of the window should be updated properly when spellcheck, " "translate or shorten/unshorten URL buttons are pressed." @@ -1063,7 +1542,7 @@ msgstr "" "* El título de la ventana debe actualizarse correctamente cuando se utilizan " "funciones como corrección ortográfica, traducción o acortar / expandir URL." -#: ../doc/changelog.py:133 +#: changelog.py:207 msgid "" "* the bug that changes the selected tweet in the home timeline shouldn't be " "happening so often." @@ -1071,11 +1550,11 @@ msgstr "" "* El error que hacía que el tuit seleccionado cambiara en la interfaz " "visible debería estar parcialmente corregido." -#: ../doc/changelog.py:134 +#: changelog.py:209 msgid "## Changes in version 0.82 and 0.83" msgstr "## Cambios en las versiones 0.82 y 0.83" -#: ../doc/changelog.py:135 +#: changelog.py:211 msgid "" "* If the tweet source (client) is an application with unicode characters " "(example: российская газета) it will not break the tweet displayer." @@ -1084,7 +1563,7 @@ msgstr "" "caracteres Unicode en su nombre (por ejemplo: российская газета), el " "visualizador de tuits lo podrá mostrar adecuadamente." -#: ../doc/changelog.py:136 +#: changelog.py:212 msgid "" "* Added a new field for image description in tweet displayer. When " "available, it will show description for images posted in tweets." @@ -1093,7 +1572,7 @@ msgstr "" "tuits. Cuando estén disponibles, se mostrarán descripciones para las " "imágenes en el tuit." -#: ../doc/changelog.py:137 +#: changelog.py:213 msgid "" "* users can add image descriptions to their photos. When uploading an image, " "a dialog will show for asking a description." @@ -1101,15 +1580,15 @@ msgstr "" "* Los usuarios ahora pueden añadir descripción a sus fotos. Al subir la " "imagen, aparecerá un diálogo para que se proporcione una descripción." -#: ../doc/changelog.py:138 +#: changelog.py:214 msgid "* Redesigned upload image dialog." msgstr "* El diálogo para subir imágenes ha sido rediseñado." -#: ../doc/changelog.py:139 +#: changelog.py:215 msgid "* Fixed photo uploads when posting tweets." msgstr "* Se ha corregido la carga de imágenes al publicar tuits." -#: ../doc/changelog.py:140 +#: changelog.py:216 msgid "" "* When getting tweets for a conversation, ignores deleted tweets or some " "errors, now TWBlue will try to get as much tweets as possible, even if some " @@ -1119,23 +1598,23 @@ msgstr "" "los tuits eliminados y algunos errores comunes. TWBlue cargará la mayor " "cantidad de tuits posible." -#: ../doc/changelog.py:141 +#: changelog.py:217 msgid "* Added audio playback from soundcloud." msgstr "* Añadida la reproducción de audio desde Soundcloud." -#: ../doc/changelog.py:142 +#: changelog.py:218 msgid "* Now the session mute option don't makes the screen reader speaks." msgstr "" "* Al silenciar una sesión, el lector de pantalla ya no anunciará ningún " "contenido automáticamente." -#: ../doc/changelog.py:143 +#: changelog.py:219 msgid "* Fixed the direct message dialog. Now it should be displayed properly." msgstr "" "* Corregido el diálogo de mensaje directo. Ahora debería mostrarse " "correctamente." -#: ../doc/changelog.py:144 +#: changelog.py:220 msgid "" "* when a tweet is deleted in twitter, TWBlue should reflect this change and " "delete that tweet in every buffer it is displayed." @@ -1143,7 +1622,7 @@ msgstr "" "* Cuando se elimina un tuit, TWBlue debería reflejar el cambio y eliminar el " "tuit de todos los buffers donde se muestra." -#: ../doc/changelog.py:145 +#: changelog.py:221 msgid "" "* If your session is broken, TWBlue will be able to remove it automatically " "instead just crashing." @@ -1151,12 +1630,12 @@ msgstr "" "* Si la configuración de una sesión ha sido dañada, TWBlue debería ser capaz " "de eliminarla y continuar en lugar de no abrirse." -#: ../doc/changelog.py:146 +#: changelog.py:222 msgid "* audio uploader should display the current progress." msgstr "" "* El diálogo de carga de archivos de audio ahora muestra el progreso actual." -#: ../doc/changelog.py:147 +#: changelog.py:223 msgid "" "* users can disable the check for updates feature at startup from the " "general tab, in the global settings dialogue." @@ -1164,7 +1643,7 @@ msgstr "" "* Es posible desactivar la comprobación automática de actualizaciones en el " "diálogo de opciones globales, en la pestaña General." -#: ../doc/changelog.py:148 +#: changelog.py:224 msgid "" "* The invisible interface and the window should be synchronized when the " "client reconnects." @@ -1172,12 +1651,12 @@ msgstr "" "* La interfaz invisible y la ventana gráfica deben estar sincronizadas " "cuando el cliente se reconecta." -#: ../doc/changelog.py:149 +#: changelog.py:225 msgid "* The documentation option in the systray icon should be enabled." msgstr "" "* La opción de documentación en la bandeja del sistema se encuentra activa." -#: ../doc/changelog.py:150 +#: changelog.py:226 msgid "" "* In trending buffers, you can press enter for posting a tweet about the " "focused trend." @@ -1185,7 +1664,7 @@ msgstr "" "* En buffers de tendencias, puedes pulsar enter sobre cada tendencia para " "publicar un tuit acerca de ella." -#: ../doc/changelog.py:151 +#: changelog.py:227 msgid "" "* Updated russian documentation and main program interface (thanks to " "Natalia Hedlund (Наталья Хедлунд), [@lifestar_n](https://twitter.com/" @@ -1194,19 +1673,19 @@ msgstr "" "* Actualizada la documentación e interfaz en ruso (gracias a Natalia Hedlund " "(Наталья Хедлунд), [@lifestar_n](https://twitter.com/lifestar_n) en twitter)" -#: ../doc/changelog.py:152 +#: changelog.py:228 msgid "* updated translations." msgstr "* Actualizadas algunas traducciones." -#: ../doc/changelog.py:153 +#: changelog.py:230 msgid "## Changes in Version 0.81" msgstr "## Cambios en la versión 0.81" -#: ../doc/changelog.py:154 +#: changelog.py:232 msgid "* Updated translations" msgstr "* Traducciones actualizadas" -#: ../doc/changelog.py:155 +#: changelog.py:233 msgid "" "* The updater module has received some improvements. Now it includes a " "Mirror URL for checking updates if the main URL is not available at the " @@ -1217,24 +1696,24 @@ msgstr "" "una URL con información de actualizaciones de respaldo por si la dirección " "principal no funciona." -#: ../doc/changelog.py:156 +#: changelog.py:234 msgid "* some GUI elements now use keyboard shortcuts for common actions." msgstr "" "* Algunos elementos de la interfaz gráfica ahora utilizan atajos de teclado " "para acciones comunes." -#: ../doc/changelog.py:157 +#: changelog.py:235 msgid "* fixed a bug in the geolocation dialog." msgstr "" "* Corregido un error en el diálogo para mostrar la información geográfica en " "Tuits." -#: ../doc/changelog.py:158 +#: changelog.py:236 msgid "* the chicken nugget keymap should work properly." msgstr "" "* El mapa de teclado de chicken Nugget debería funcionar correctamente." -#: ../doc/changelog.py:159 +#: changelog.py:237 msgid "" "* Added a new soundpack to the default installation of TWBlue, thanks to " "[@Deng90](https://twitter.com/deng90)" @@ -1242,11 +1721,11 @@ msgstr "" "* Se ha añadido un nuevo paquete de sonidos a la instalación predeterminada " "de TWBlue, gracias a [@Deng90](https://twitter.com/deng90)" -#: ../doc/changelog.py:160 +#: changelog.py:238 msgid "* Now the changelog is written in an html File." msgstr "* La lista de cambios ahora está escrita en un archivo HTML." -#: ../doc/changelog.py:161 +#: changelog.py:239 msgid "" "* Added some missed dictionaries in last version for the spell checking " "feature." @@ -1254,7 +1733,7 @@ msgstr "" "* Se han añadido algunos diccionarios al módulo de corrección ortográfica " "que no habían sido añadidos en la última versión." -#: ../doc/changelog.py:162 +#: changelog.py:240 msgid "" "* Trimmed the beginnings of the sounds in the default soundpack. Thanks to " "[@masonasons](https://github.com/masonasons)" @@ -1263,7 +1742,7 @@ msgstr "" "de sonidos predeterminado. Gracias a [@masonasons](https://github.com/" "masonasons)" -#: ../doc/changelog.py:163 +#: changelog.py:241 msgid "" "* Added Opus support for sound playback in TWBlue. Thanks to [@masonasons]" "(https://github.com/masonasons)" @@ -1271,7 +1750,7 @@ msgstr "" "* Añadido soporte al códec Opus en TWBlue. Gracias a [@masonasons](https://" "github.com/masonasons)" -#: ../doc/changelog.py:164 +#: changelog.py:242 msgid "" "* Added a source field in view tweet dialogue. Thanks to [@masonasons]" "(https://github.com/masonasons)" @@ -1280,14 +1759,14 @@ msgstr "" "el visualizador de tuits. Gracias a [@masonasons](https://github.com/" "masonasons)" -#: ../doc/changelog.py:165 +#: changelog.py:243 msgid "" "* You can load previous items in followers and friend buffers for others." msgstr "" "* Se pueden cargar más elementos en los buffers de seguidores y amigos de " "otros usuarios." -#: ../doc/changelog.py:166 +#: changelog.py:244 msgid "" "* The Spell Checker dialogue should not display an error message when you " "have set \"default language\" in the global settings dialogue if your " @@ -1298,20 +1777,20 @@ msgstr "" "tu idioma se encuentra soportado. [#168](http://twblue.es/bugs/view.php?" "id=168)" -#: ../doc/changelog.py:167 +#: changelog.py:245 msgid "* Updated romanian translation." msgstr "* Actualizada la traducción al rumano." -#: ../doc/changelog.py:168 +#: changelog.py:246 msgid "* Some code cleanups." msgstr "* Limpieza del código." -#: ../doc/changelog.py:169 +#: changelog.py:247 msgid "* The bug reports feature is fully operational again." msgstr "" "* El sistema de reporte de errores es completamente operativo de nuevo." -#: ../doc/changelog.py:170 +#: changelog.py:248 msgid "" "* TWBlue should work again for users that contains special characters in " "windows usernames." @@ -1319,24 +1798,24 @@ msgstr "" "* TWBlue debería funcionar de nuevo para usuarios que contienen caracteres " "especiales en sus nombres de usuario de Windows." -#: ../doc/changelog.py:171 +#: changelog.py:249 msgid "* Added more options for the tweet searches." msgstr "* Añadidas más opciones para las búsquedas en Twitter." -#: ../doc/changelog.py:172 +#: changelog.py:250 msgid "* Added play_audio to the keymap editor." msgstr "* Añadida la función play_audio al editor de mapas de teclado." -#: ../doc/changelog.py:173 +#: changelog.py:251 msgid "* Windows key is no longer required in the keymap editor" msgstr "" "* La tecla Windows ya no es obligatoria en el editor de mapas de teclado" -#: ../doc/changelog.py:174 +#: changelog.py:252 msgid "* Switched to the Microsoft translator." msgstr "* hemos pasado a usar el servicio Microsoft translator." -#: ../doc/changelog.py:175 +#: changelog.py:253 msgid "" "* You can update the current buffer by pressing ctrl+win+shift+u in the " "default keymap or in the buffer menu." @@ -1344,20 +1823,20 @@ msgstr "" "* Puedes actualizar el buffer actual pulsando ctrl+win+shift+u en la " "interfaz invisible o desde el menú buffer." -#: ../doc/changelog.py:176 +#: changelog.py:254 msgid "* Changed some keystrokes in the windows 10 default keymap" msgstr "" "* Cambiados algunos atajos de teclado en el mapa de teclado de Windows 10" -#: ../doc/changelog.py:177 +#: changelog.py:255 msgid "* New followers and friends buffer for user timelines." msgstr "* Nuevos buffers de amigos y seguidores para otros usuarios." -#: ../doc/changelog.py:178 +#: changelog.py:257 msgid "---" msgstr "---" -#: ../doc/changelog.py:179 +#: changelog.py:258 msgid "Copyright © 2014-2017, Manuel Cortez." msgstr "Copyright © 2014-2017, Manuel Cortéz." From c3261a4e2ccb0cfd76d5682b0c69fbd92f79183e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 2 Nov 2021 10:59:03 -0600 Subject: [PATCH 194/245] Updated sintax for doc and changelog locales --- .../ar/lc_messages/twblue-changelog.mo | Bin 436 -> 429 bytes .../ar/lc_messages/twblue-changelog.po | 2 +- .../ar/lc_messages/twblue-documentation.mo | Bin 1612 -> 1493 bytes .../ar/lc_messages/twblue-documentation.po | 2 +- .../ca/lc_messages/twblue-changelog.mo | Bin 27577 -> 26342 bytes .../ca/lc_messages/twblue-changelog.po | 2 +- .../ca/lc_messages/twblue-documentation.mo | Bin 52304 -> 48526 bytes .../ca/lc_messages/twblue-documentation.po | 2 +- .../da/LC_MESSAGES/twblue-documentation.mo | Bin 71814 -> 70406 bytes .../da/LC_MESSAGES/twblue-documentation.po | 2 +- .../de/lc_messages/twblue-changelog.mo | Bin 45384 -> 44417 bytes .../de/lc_messages/twblue-changelog.po | 2 +- .../de/lc_messages/twblue-documentation.mo | Bin 71449 -> 70038 bytes .../de/lc_messages/twblue-documentation.po | 2 +- .../es/LC_MESSAGES/twblue-changelog.mo | Bin 68867 -> 67651 bytes .../es/LC_MESSAGES/twblue-documentation.mo | Bin 75252 -> 73822 bytes .../es/LC_MESSAGES/twblue-documentation.po | 2 +- .../eu/lc_messages/twblue-changelog.mo | Bin 19676 -> 19173 bytes .../eu/lc_messages/twblue-changelog.po | 2 +- .../lc_messages/twblue-changelog.temp.temp.po | 635 -------- .../eu/lc_messages/twblue-documentation.mo | Bin 3535 -> 2467 bytes .../eu/lc_messages/twblue-documentation.po | 2 +- .../fi/lc_messages/twblue-changelog.mo | Bin 0 -> 429 bytes .../fi/lc_messages/twblue-changelog.po | 2 +- .../fi/lc_messages/twblue-documentation.mo | Bin 0 -> 7278 bytes .../fi/lc_messages/twblue-documentation.po | 2 +- .../fr/lc_messages/twblue-changelog.mo | Bin 48316 -> 46978 bytes .../fr/lc_messages/twblue-changelog.po | 2 +- .../fr/lc_messages/twblue-documentation.mo | Bin 79337 -> 77895 bytes .../fr/lc_messages/twblue-documentation.po | 2 +- ... Kinnunen's conflicted copy 2019-03-25).po | 1343 ----------------- .../gl/lc_messages/twblue-changelog.mo | Bin 41777 -> 40873 bytes .../gl/lc_messages/twblue-changelog.po | 2 +- .../gl/lc_messages/twblue-documentation.mo | Bin 73544 -> 72102 bytes .../gl/lc_messages/twblue-documentation.po | 2 +- .../hu/lc_messages/twblue-changelog.mo | Bin 397 -> 390 bytes .../hu/lc_messages/twblue-changelog.po | 2 +- .../hu/lc_messages/twblue-documentation.mo | Bin 522 -> 455 bytes .../hu/lc_messages/twblue-documentation.po | 2 +- .../it/lc_messages/twblue-changelog.mo | Bin 397 -> 390 bytes .../it/lc_messages/twblue-changelog.po | 2 +- .../it/lc_messages/twblue-documentation.mo | Bin 72675 -> 71234 bytes .../it/lc_messages/twblue-documentation.po | 2 +- .../ja/lc_messages/twblue-changelog.mo | Bin 12582 -> 10410 bytes .../ja/lc_messages/twblue-changelog.po | 2 +- .../ja/lc_messages/twblue-documentation.mo | Bin 82197 -> 80787 bytes .../ja/lc_messages/twblue-documentation.po | 2 +- .../pl/lc_messages/twblue-changelog.mo | Bin 2355 -> 2316 bytes .../pl/lc_messages/twblue-changelog.po | 2 +- .../pl/lc_messages/twblue-documentation.mo | Bin 4787 -> 4524 bytes .../pl/lc_messages/twblue-documentation.po | 2 +- .../pt/lc_messages/twblue-changelog.mo | Bin 397 -> 390 bytes .../pt/lc_messages/twblue-changelog.po | 2 +- .../pt/lc_messages/twblue-documentation.mo | Bin 552 -> 457 bytes .../pt/lc_messages/twblue-documentation.po | 2 +- doc/locales/pt/manual.md | 285 ---- .../ro/LC_MESSAGES/twblue-changelog.mo | Bin 34847 -> 33512 bytes .../ro/LC_MESSAGES/twblue-changelog.po | 2 +- .../ro/LC_MESSAGES/twblue-documentation.mo | Bin 71441 -> 70000 bytes .../ro/LC_MESSAGES/twblue-documentation.po | 2 +- .../ru/lc_messages/twblue-changelog.mo | Bin 47434 -> 45656 bytes .../ru/lc_messages/twblue-changelog.po | 2 +- .../ru/lc_messages/twblue-documentation.mo | Bin 96821 -> 95380 bytes .../ru/lc_messages/twblue-documentation.po | 2 +- .../sr/lc_messages/twblue-changelog.mo | Bin 44869 -> 43899 bytes .../sr/lc_messages/twblue-changelog.po | 2 +- .../sr/lc_messages/twblue-documentation.mo | Bin 71568 -> 70166 bytes .../sr/lc_messages/twblue-documentation.po | 2 +- .../tr/lc_messages/twblue-changelog.mo | Bin 7348 -> 7140 bytes .../tr/lc_messages/twblue-changelog.po | 2 +- .../tr/lc_messages/twblue-documentation.mo | Bin 7535 -> 7366 bytes .../tr/lc_messages/twblue-documentation.po | 2 +- 72 files changed, 34 insertions(+), 2297 deletions(-) delete mode 100644 doc/locales/eu/lc_messages/twblue-changelog.temp.temp.po create mode 100644 doc/locales/fi/lc_messages/twblue-changelog.mo create mode 100644 doc/locales/fi/lc_messages/twblue-documentation.mo delete mode 100644 doc/locales/gl/lc_messages/twblue-changelog (Jani Kinnunen's conflicted copy 2019-03-25).po delete mode 100644 doc/locales/pt/manual.md diff --git a/doc/locales/ar/lc_messages/twblue-changelog.mo b/doc/locales/ar/lc_messages/twblue-changelog.mo index e505c5df3b7e5c3ca3bd3985d34e2f69b056f137..a6c44b3db419d44dbe387087d405bb9cdd2ba067 100644 GIT binary patch delta 162 zcmdnOyq0-_NDu=O&;hdR85tOKL1F<#`B|ySCAyv|x?!nB#hLkeRtgGSL8%4#MJ2kv z#p#(Tx=y9(#kwK+Rtm1Zj-EaajxH`iuED_*eZ>VVbq$Pl4b2q{jjfDLv<(aV~8y=2|ICZfDe*_{EgDv?Oh^4x=HjQ({tTj)IY%rJf-d0{~W> BDjEO) delta 164 zcmZ3>yoGs!h%++-1A`6_gMbAPS1~d$SORGvg#ZCX`B|ySCAyv|x?!nB#hLkeRtj7J z{vo=~MX8A;6K5z)oRBG^8 diff --git a/doc/locales/ar/lc_messages/twblue-changelog.po b/doc/locales/ar/lc_messages/twblue-changelog.po index 0084cb4a..5532b127 100644 --- a/doc/locales/ar/lc_messages/twblue-changelog.po +++ b/doc/locales/ar/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-08-07 13:48-0500\n" "Last-Translator: Manuel Cortez \n" "Language-Team: \n" diff --git a/doc/locales/ar/lc_messages/twblue-documentation.mo b/doc/locales/ar/lc_messages/twblue-documentation.mo index 768a5caa7d0d0465f4a1c630a10bfb6206152d26..e832dc6c9fe09750275df6029d87e5d4e60547ba 100644 GIT binary patch delta 273 zcmX@ZbCtXPo)F7a1|VPuVi_O~0dbH(50K3b#JxbQ4a75n*cgb90K-!FfftTSPkg*>qAj-*iM9a{OpayBX0cL8ESkKZ$!78#=DNx3%%;qx cC25oGnGLy}5|dJM6pZvN^$a&#vj{Q)07SqvQ~&?~ delta 376 zcmXAjze~eF7>2(j^#@6pIygC86;UaT#M&w?odgwB8qk7*%aNY7Sd((SLJLAyhi-?P zAdZeAxH{B9(ZxaB`~&TWD~S6y zkO5yH2P_<>;Wc;`K7!BT3)nY_eqbyrC5TdR89sq4a7eU6kJv1um>(l5z*YDO9>DR% zI1>P4|BoDx3&a|UFh=+fk$pd?82ZRw{#w80xs3dQ)#l7KO zw-H23dci!?H)bxm%foty*F}+WseLPNRS!1xrR8N>y}D3Jbd}rcG0)B0huJL=3dvO@ si_DKit)b8tT+h=VW\n" "Language-Team: Mohammed Al Shara \n" diff --git a/doc/locales/ca/lc_messages/twblue-changelog.mo b/doc/locales/ca/lc_messages/twblue-changelog.mo index f1f2e0719b9150a0c91a3c80281972086a2058fc..9ed6631f3be517b3a999a892fb56b529f5973901 100644 GIT binary patch delta 2039 zcmYM#eN5DK9Ki7po}0nt17K#v!v!Lu{P2zg;f_#`2bF|)&IcsDgM+w?BRD24?Pxut z`Ol5Y4O-@0HcSn|B5jqFW05YloNXCxnY3k^4?S!yt@n4|+q!Z0`h9*6-{0r^`93gu zK4SVzL~tr*W}om0@Qvqt(xjsQKU-#rKXvg?_M3!PDK7dc7YJUJdcnLdj-2xG}D(MLhhA`n?ZpLqLBbF`Xiw7}_ z#BSg!;#BHZh+fRZL%0IZ<0#Id{*5?}>ctt1>#G<*E6zv|DMC92Rfan_Xu*B>1V$w4 z9{RD5_**1t@g<4$Vh^UF*+Tizj`esBub_=adoU?kWDmZDDRjVKf=m)uEz)x;C6)T` z=ESB{-QXp35zk(%8>~Q;z##h2#al1qVXVbB7}yAV#C(Sj$D;>r(U|3Hc> zX2z!qQNx1)#4k93$8mU>$P4IW27Qj#uos66Rsa@I_dJ}$QjA)zD_4tZuAIUg zG*fSK6Bn*TAHI+8q8h^bpiN{e2X7*Oa)+N?XwA}@9ziwxPh%&pW`;e3AD{{C*<7Qv zxu_bv!&_fO7v)gxjiXBB7BW4=nkz!}Wj(4m*vc**XY@)l&CrQK` z=tMsntf^OU00%J5srQmEu}j^TuM<0lw}@||s@zr9E=3ATT7lkBHefjydQp}1JM6$@ z>h=}(VKHu7MXBlWL98NJCA@ON&~76 z_Tf3ah>!Dr8D){L##FBE#AZ|(UPL!0J}koUN)MjG5$wk93SFV=_%?Am76#nuvdD4qc7>ba>2M zno(BmZTEKsjPlNw)+VE{tEJPZ^*b#k<*w4Q)vn^=>XMq8sLG03qo~8{4z&8)jAD1d z>$GH9Z4Sd~H*C2Uo84*8US{PJs>t)rbXpqSp<{VPp^zgz^lx5{sVmSN%5~Vxg>H{` UyCo~rk!cHk;y5$hpPyj;4=uVc)&Kwi delta 3265 zcmZYAdvH|M9l-Hl2#P!dhyfJIL4|~ntl7Zwh@gaMLXDJQ5~Kpbo86o2rMr9AyLV$E zl=a;s)nzrTAowvK1= z+s`?7Z_YjEch0%{;Yitu_sR;tn>qdop$ri7h_}i`et^3t@Im=_qDTzSVF9ZriMaS9 z{2|VsEYgTCVH19gm*bKtB3EN8UV%GNuRm1sU}!;pK}BzTuk^*IB`c?je8BZ6Iyh~b z$o)8oL--kHaG*lO#y{a|Y@aSNqfBHNt7$(qL!<^zVjZ3-wdc$fS*25IrqaO|yYSce z7PjFNmoig28bzJihRa0$io>`b^OYj|@t2su&9g@PI5+IS z4SO}Ek5lpRJX&azrx);b+=X|Ozb*I=yahM1PK^xg`*;KGx33gghZXZhB6uq<$9wSv zzKC)3s=^1K#z$$-H!Nubm7h>)!BNx^F5sgdTQH4>P-i&zDzbumkR-?~*6m@eMNRcl zJcy&X6${shoW&ZygJ*E_5|J)k#{%Dl`%yDcQ7^(|r4+Wr%-3UEh77Ai?0j&FMN**eai^4-=uuC2+Jk&QQIvz4|_`OT_yLS-gmgvK8;tYDI9q0`(;JB#{Wxqv=?_Xe`7uav24!;#*P7x>~e)KtFGEJD`h0+L0kWjY&hJ8Fs# zp@*N~o0x17xe=H0ktPF!xQX_MH}S5(m93l%jJ1jE!(r^z^IydRJ~G5k6{!Zg<6zi>CMVj4QYV`$+yWcx^GCvQ0%#zAcF3N!R7 zK0|v&cX+DaN1ed9&E%i#$-PwK_$um*YHlNKcmOq34{qUQgY&+|cg)}f{+;$8NCyW& zPH&|ToUko?z+U8E56!j=hsBd)<};(CJZ zB{K-k?EjZ~8q7Z|Iy)_sLV_O_tu7#Rb5#(!rdrrPGApQ+euAmHrS`QYuPT|vN`eXV za~uAU=~8Q%tk0i9Wh#*-$X4*W1R19vlx;*UaVZfamJ+%b*h9e^l9iM3#0FwMaR<>z za43Rf%hCs@2tF?@)O2HBsq?QXUDoxUL$FDMHDxJ-!toDE9iKkIp8CA-(hOcYx<_=w zj+M)(=)Tf7;shc^aO{Jk`)3ESSzDTaJpo!QVo6X7Kh^+8S6Yd6#3h85HiCU86A6!K zC$#8>8Y_#b=+T@>loKn6MTC~wM4q^aAj`$uC%jzfO4=r8XMB@zJUi~2w4KXY{dUgu z=KK0=&m=9Xww*DaopuN8M8q_wQeV3HE{BV~w#lZfxScRg#<&@KtP3}j8j2V(lv;CJ zlD>Fg!pZa-%M`x&*g7-h=1tIB(zZNq$hr9p9rhWYftCjMzd;2f&w6gw_EJN2JkSsB z`(meIe;L=;5n71^1N7bCzTW(_V3JNIZ6_Sdw~tg@(plHiv9YVZ#j`EnaWnNda=FPg zHbhs}H}JQ@M3**2S1noZdX`DpX2ABWjBDbg(6dseW`jNG#NEZk=a%g(E{ruzxy8!# z=SgUjiCe|tSggFetF`#6ShO}f)NlK~J?KZWLna!DP1;i5W@qTlcfBUl;W8lKG)AJ4 zXt5_&TXtRXv)IVo&g!IP?9|EQDJSh@ET6h&+4hRxzNxZc?92eO$gxJARmUX#95>`l z+F?z7UDPl!RC3ix$E4jHgZ556o#8)CUjLkU*k43yH{~r>s#^PW^vkhc#yY7p+7I(~ z=s|Dj&7C^J(kGm_#eTXo&&CRd8w|?CT~9ZdmDbJ1dYw8#2dOXhYDlJ)wLIGy\n" "Language-Team: Fran Torres Gallego. \n" diff --git a/doc/locales/ca/lc_messages/twblue-documentation.mo b/doc/locales/ca/lc_messages/twblue-documentation.mo index c1be3f5d47f6109bd275d8a88483565deb4a1f4d..451a06537c8621a731cefd91c581d4534d2e7508 100644 GIT binary patch delta 2952 zcmYM$3slZ$9Ki8kryG#aye79 zXtr>S(Z=RDPA(g3$DCtkZEk0FY{R~fr*qb+KL6kI|3A0i^F06ey;@?m;U7y=bEh`j zgr92udhu7-Rz?5+w7ew}O!zzYvk)=ZisTZ`|DAipL#$N#PrTtg3hfL+jzT0PMXtuYwsTcWWK#-nO52UUY6bVW1v!xOFL zcd#4rV^sCpJLm!RM_2lnVO*$&5|KemYO6V@GV&o(SN5Q4sJ1o!8X2p6k4g9|&c>Kd z44O>Upi1pEMwfu;%t}q*EH1`xF`xb=jOkb4ml%jM>170#;Sjum1JS0t$Z+&UZ(M*w zu^ivUCJaJ%M}0pTRePH-0x#pA49vkv#EZB+={5b!g&!A_(8zSNun0r&Z)6fOqPNHl zDvrZKzTv?RqOKHS zEgr;CIMq#LBbMV}^m1o#I30Un0vktVCacvWs8W0% zL6PimDs03a+<%D|h#g0Z@GH&yTZRK-L>jOXOL#76jL1IPc@ZnJo$_*aB2~qAJXyn~ zsFvz3F0)|$2Tl-~PsOS@{U+!hvYUc6b_{@GDgHo6!f`uwJTTe^l>{DC~iWsGiHk&bSk;@#q51zk2W_1!`oM zTOYXH>LctzxmAWp2XsU=AP=NZ2|y+x`!R}4bRW99iP&s5a*uEXLcY zmM}ew{Bt6te|GDu7uoPqhF*9B)lyhd+ZV^60Zqt;mumFK-*7Ox=IZyx1RO=2kGmMy zSyc6BF5xAFW=zFM(+B!E9Km1;JoEHY%)>$|79b~1+OgGDgJHN4*Wftp##>}KrlMN= z-RO_cQBA}vUuP&CsUl6N_T2ate6XSEDi=Muh^O=*F2qoDT&dr9iRexI0-JC^fsS9| zSYoeL3<~qmj{%=XHM6I*UW!u+_50*0hHyV&wTLB_tf3DzmYqdk`v302?t9Um=f3#K+XdD>w;D*Xd8yN0>;5>sfe`EDzS}3?^?7nV@p< zgbQ_y!pQ3}Ovh?;+Qh!VMl8TbI3E{n)=Sll>Kr?7(XZU`W)b?9&Demww(8G@Td3CF zVVlS_jKJ5p7voJduy?zD@jTz5&-;oJ%6MQm`CEyhWjZtGP&H(|Q?GFlvYe8IarhXc zF|3>~BUp?padCxS`@hhcIC~f0j_7v_n)11b-ou9C#zlH%ze(&qkv}MJM78Gim81~Y zRdIIlKHkJt2lOj9@gRfc`Dcf@N4fbEy<|&|=(RtCYH8g_YaPzTGM?{UL;lq+Jb6@i z5JdjZ5%0h(OswUdfZyTISjyRXipyzbG7V%N*WVj1p3omI1L|2G?$=-y_gy|?LY7SI zB&jA2Y0&kzozidIwWsT9?8X`Djs;h^)%}z*(Z($!jv+QXZElKTRBl?fAwDzE zB_cL-^w^Nl@bI{Zi4)DnjP9L=8+?2X#-T1o-#}l#K|cJLvoccK1iH*lHebnzGS_Dg tG`nW{Tjl1=F;C4j+Kx(|l{(*Li1%=BW8JIFLhrhieV%>ljOY8<{0G}g-B$nr delta 6541 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 ONrz\n" "Language-Team: Francisco Torres Gallego \n" diff --git a/doc/locales/da/LC_MESSAGES/twblue-documentation.mo b/doc/locales/da/LC_MESSAGES/twblue-documentation.mo index 106a512b6821c8ee2b0233a141d87c0160db58bd..b93f7796e45b5f5b026e5fedd90f9ae50b3a5b90 100644 GIT binary patch delta 4356 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 Mb=Y3KFlXj}0Et;?4*&oF diff --git a/doc/locales/da/LC_MESSAGES/twblue-documentation.po b/doc/locales/da/LC_MESSAGES/twblue-documentation.po index a302adee..143d3f96 100644 --- a/doc/locales/da/LC_MESSAGES/twblue-documentation.po +++ b/doc/locales/da/LC_MESSAGES/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-11-17 10:25+0100\n" "Last-Translator: Nicolai Svendsen \n" "Language-Team: \n" diff --git a/doc/locales/de/lc_messages/twblue-changelog.mo b/doc/locales/de/lc_messages/twblue-changelog.mo index 3e4fa9d94a1603bf24ae8e591d4272d59b42fdf6..fd58e5ca565111a2c78178a7cd2a0cc16239e2c3 100644 GIT binary patch delta 2995 zcmYk;dsNPM9Ki8U>U2zo%8JhC7L@CLV!<@dAe7OB{ruZAHwOh3Xe?;vSs*rpN$%j+fBC9na!3?2f_hMLaPE zd*FOj{Uz-gMm4H!9p`KhHrisl4*Eein?r2Ip&Bp))q*yn8u%~#30<5;((y5_z{HLs zOYmpR#HlVK>+D48UD$>iAilH6a6Ey|eDDl?h+B8np9i5Y@n-CYXKZmZh7fml6`6qJ zF%GM+9RI+4Eb1nbijM5I0W)zl4zaN8EGATrp`*o3r*3FZk!Ip-RQ<`lM3!O=`tZD$ zyFQv2gUA;8OE3k!dW-DGwYUujd5~_riXUJYX;blO{01%kz4TeWz=3ou@fPvJT4W6Q z0o6)hqMBe-ACU^I#+?{Nnr2}WE>tmTGT{llhCTX<9L9&3hZPKd8N2(7B-wHP_i0R} zBPxIb!AhIWm_Qs7NO9STlwl3=`Tlz689^+DxEA?H9^+f+9?ayJfU~i~0KI`6Tu=N3 z@~Dhux8bUc^Jwg&;|!`)nkjX)^M5cE-MI=GxCYfN_!Cto{FrSMmSSi09-?bu7#0)f zB1sV$D)Jrp;%ZGL80Qby1n| zKC#0)B8AwDYT_&kBMJM&G6}B29q2Sp#_z9;YCzMxHv&%CZ57<>@kJx zVJWKd&!XCS*i`)@nu6-N>lPXx(1@HSVviS)nD~+n6gCr(%*vAqjXy!@(HG)+KBT) z{cV|#$A}FSKq2$X_cYevv>biCe!=4^&eiwT`F)XL#MS75P3Vb^i>Mp)L;lNre$?Ru z+>4cqby0_tZx{7?(_U&@@g9xdwHq~z(Z$re0HoV|<(*@*adE-UYnO=x;>zynmrSiabtBhiOT zu4*9->+w8p#dWLotJ#ZmkyVL8we!zWopDf+KFWODNqi4gl^3qnM^}ZcO`6aP&Bg3M zonKf*h0U@dXZ1D;|Beuat3!1dzR_}&tfBSc$prj_eT9~T8>BP zZ@@mdj9o_IUgUJ;Hwz6bjbwgQ<5Nt*o#lE0yG{C?Ux|C@U$B{7vfxfz^j|oUq~#j@ z2Qd{b+jOnmN3~PW?fS*F4-XSxMIS8K!O^MbYiOu@f6?YWR0BDXKNHSFvM*P$4HHjd z+w+NMR_NmV7FA8msnmaPT*TKKsuHqc(@m|s>e)7})?|k7!nwKBzESjiT?qKEAc=8 delta 3969 zcmY+{3s6+o9mnxMYAwM;MMknmT=a|9dVSddA;=&bfQpd(Z3c zTGun+%I5=i`?>Ck$c!PpQ2sGgqyc}x7_1#8@-%kiRQx+SF?6_y3-{o0^!65s!Z-0l z{1W4^%SU7+euERx(^q5^PDVYR;>*WqCC@rggL>ktR{I^xTb2(jhx(cGf>Cd10qO@| zz~AF_EX2+cA}`|OkBd~{ek?{mf03OYyys6h^aF-H!6;w_dh5h=i5;uQ=TD>4@!xTutH!T50u2M0QAX6XKg zcWFlinB$|zi)^CpL_6pAqE3zHM3KFig8A5sXK+p+qlkaSQrs~~qy`_Nwl~qc-=gad z6`jkU)17FH3Fhvw5V^Lrpx$XW>IMFdhcSgrDMb9$flFgh&<#21JUaVUA@RE~Wh)M$zN6D3NyBF78r$9z0cKHWnhEC7t*r z_TVM-VFl;mN2nc`!kdj)iBoWJtVp7EJ(kKT4s1pp%7AI6=a;a6b`KU|A`{JL%X!q1 z_%pWR{5X*j_($ZBe2+UYGTyAAxA9}zU*IvkID>V8%V*MA9r{O}VvC>?Yw;Pnr+54b z?!wWtSnZ5JJKmsuEkWcE9-;emPG%;unsGha@ju8ZVo%}%ScuK|0qPAepChss@1g4s zmF#4Ze_}FM?Z5<9Vk{T@1~X{~rZWGy2{&Tod^6PTxRQ1+j>81z?;JYNhCU0}dKhh) zivIdOW?QNx3LSEMLEF5?&Bvo4=*oe{Hv*WFEfAGgmhZ|g)x|%WrlhS2GJh5T!dMY zL_Cl6sEcrFw#W+Hi0kntM&f+NUq8PZwdW793Vn0Ud5tbAH5~AGR%9U7B3o3pqAzw} z6I1an7SLYARi@)br1SEv)lOU~vYK`^ZpANfKNdR7gKf|%kw4H*z?m43Co%?IE2xA~ zsm8I`VfmruSC*dnW^vh3&s$_!Y}tr5j(4IRuOa{BJ6^Oy*-kUHb*Ljy$lV^+N6(+A z)Nr7l?lEfOv4#~&k8|;P+TDdbK5;xt_8u0X?)PQ9xegmphx!5Plm&87=Q;;bh2n$_$aS%5WTFN}qp7Mg3>n%8#niY z7H?t{@C;7CYseOsZ;_9X*v)3QoW&EgS8p+k+N;_Oc_r!%-^WielVNx5pc2YmyolZS zCdSorB0af>I%FC3%s2i5SD+^+>+v->n)9xs-tgV6d==wK_NbnJA9X5bH<(4Y8GC47 zLheyoUt;`qA9`;S`5ETmEc^>*W5jm$DDJ?0xR|>Qz&pt3%VRrD&t0f<{5`UaBx#rV za_U4~VI?K3zLC%;UObuKerHs4-ZO=fPcqJB`_ZnNmV!cN-1+he{|8o1j- zw7*9Ez-`SeF!X9MpK}|dY3DG17qAH@VInIp8P{S3o_A5S@05IFQsPGL#GK!U=FD`b^NW$KYNktQ+^kiXG)<(ZFjd~b)z2C9E>JY1<*BD7+toA9aC%cGiA}_kFR+1-4Bsogf zkxX)sJVMxg?*AKt`*(gG7LcW6A!#M$WG7ip))Fm0BIC(wa*VW*b`nJ>F4@kjCz+~E ztJI={93qKiI!Psc^Gb6R7gRV3oN=~%XR}XE%)lj? z$<3)bks+m31`A&DT}kEmpJna%WYBNQQ?uzx3fb$ L;x9DhJk0nnG_pI| diff --git a/doc/locales/de/lc_messages/twblue-changelog.po b/doc/locales/de/lc_messages/twblue-changelog.po index 38ccfbfe..e681dee5 100644 --- a/doc/locales/de/lc_messages/twblue-changelog.po +++ b/doc/locales/de/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2019-03-17 16:39+0100\n" "Last-Translator: Steffen Schultz \n" "Language-Team: \n" diff --git a/doc/locales/de/lc_messages/twblue-documentation.mo b/doc/locales/de/lc_messages/twblue-documentation.mo index 022ae8629c697ef87ccef16af3b8b2ddf5094eb2..9d6b39611781b894c774d56143121cb5f198c656 100644 GIT binary patch delta 4360 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 BWx@ae diff --git a/doc/locales/de/lc_messages/twblue-documentation.po b/doc/locales/de/lc_messages/twblue-documentation.po index 08a7fe42..fb754089 100644 --- a/doc/locales/de/lc_messages/twblue-documentation.po +++ b/doc/locales/de/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: TWBlue Documentation\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-08-08 11:01+0200\n" "Last-Translator: Steffen Schultz \n" "Language-Team: Steffen Schultz \n" diff --git a/doc/locales/es/LC_MESSAGES/twblue-changelog.mo b/doc/locales/es/LC_MESSAGES/twblue-changelog.mo index 493b7e29ca259f964c33871b720b7def3c8e85c1..5ec37f0df226da8ceb9fac1b713bf929238b459a 100644 GIT binary patch delta 3717 zcmYk;)QCu*k3E|@o*FXkCFa*&eFOzY}QAh1& zn51b5qBdeuI#@E9TR3X&H1Cw zS9eKT|fluR)*c*F3srLh2j(3@krk>pu zf9SH#3+6@V@gH~#v+yLn%En>btYst>xRf}xFQdRl z%)yyYi7e;-aWw5sv5Gu{b@&+9f5uzHkMU`Pu2dKZTVz1oyb&MjTH3h_A@= zI0kQH8NPta`-{Ad-{NbyU;xi|;3YVi7d|ymB$Mk2gG9c<-8dFs9n4_4e-OtJ+lK~d zp$N@X9L6S;K#^v+j%E#<57K%wf|-Bf3iP8PYlyCiaZGF(*Wbi+v8Jr}e z4;G^t=?CaWy&Gsc)D}a^iBn@mHWD9xR^&a?V)_V?*<7%U6v@MMT!{^6!;CnQukk4E z#BT6 zDm+UZK9l{;b6sbNoF)!P71@9fFdR3ev2*Y&nhvMh$p1(Rr8a$0Jvxc|vmn-DEzZS6 z^8Ewu!#1oWJ<+&1gVPQ#VI(hJHb;cP$^p{42R(ns;f5#BOksSMF6ttDnfQ{Of;WXk z-m(jG(TdiWco;{zoPr#Nl8elSlp%#6k1Jz?v!I*9=*pN3v_Nz;YY;NnNYJvx)f-J7UFf{ZVNdb@iv-vhA`am z=*>KugDDHmb4|#Cm*mAd6&sPMVgFO`=SJQuoMKpxThZ-RJ;C;3EU|Zy$j3Mf&F*lg zb*5F4&^%XzA?UY6Upy5}#u|`U$W1i$vY2v;q+X<>+5a<&b$g_tJ2y&kB`IBpi5<8{ z{%#O2d_%X7&7mW?i&Ll{SE{SM9Ak;y-_(vLVkPljJdLxKF;LnGX3Km^JaswSo%f5| z3RW~G;%E$7$@z`>=!;JD!#|@pUUA)*KWaU1m$7K-&2+^jF1NTm=<+J|rk-UL`8N;r zrC?qZk8j~z9EA6 zFpm@i=;da7R7iq57 zlWN;Bk%`1T#P2} zb;_JGGiYH$2H*GNd?~Ib`pQCAL;3akf zR-$=sHS<6!CFrs)x)Mw$_PN4Z;5i3=Pki8?n%SzW`t?k0B>yZ}*-Bv`PQIooUxJy$ z$B~6AVc+TJwGrnM@1-?!yK8&Edu8(A1Cqft8Mx_#Wmo>q*(Y zh5VbICbVcus?m>l)Q_5hm(ZWsG6}EbT{x*;x%{q9^lwE z{ozuF%z~u;tlx&%Uql|Kol=~}_40e#{(o^kanXG}>Rap-CUPP40lNT;F$KfeW8O5d z9L-2}SS;;dv4Rek_WwBCMAMPvj+XWebmvDv0dX!a#_w<(raok8Pk9yk630Jm(IXyB zCZ4`W!94JKXA7T0evG1-0_kFD|1X(;7fVf3&oz0@!jjO=lLJQOW!Una)g_)?Bcehg z1A-%hgPoNnIUZ5gj0N4Ev*lzK*fKK$CTG~@MOmG-jzLa;M|j7A{5j4vM@aWL+w6>N PYiQu`z>u124sXY==O(1R delta 4970 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 bo9H;?2zHB3n~;%h3keDf3f`7eJZIS-x%%DE delta 5754 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 diff --git a/doc/locales/es/LC_MESSAGES/twblue-documentation.po b/doc/locales/es/LC_MESSAGES/twblue-documentation.po index 792235a2..a511716a 100644 --- a/doc/locales/es/LC_MESSAGES/twblue-documentation.po +++ b/doc/locales/es/LC_MESSAGES/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: twblue-documentation 0.84\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2019-05-06 23:06+0200\n" "Last-Translator: José Manuel Delicado \n" "Language-Team: Spanish \n" diff --git a/doc/locales/eu/lc_messages/twblue-changelog.mo b/doc/locales/eu/lc_messages/twblue-changelog.mo index 9f6f990966b5fc140b07ceb74a0f0544c8804c98..6f7e6c0ef3592e29f8e3d9679eee04c46387c582 100644 GIT binary patch delta 1604 zcmYk+Uu=_A7{~G7(%@v{pK<(gIOsNq?Pf>2QgL+^+HMYz#ciEvAe$EH>SSzVTfw1N zF2Kc34TlX#@WPI%rz>1Em6?vz4!1II8}X0Ma|gh7;vU(qb+ zU1q=d06tB;bh*@lFW_#xfM$mYx5Q96Bv&1A%p*DKYiz@7_z1?zr33f|TDYu2x=)<{ zB!l%#Tt-uY5FKUC@EtT6UqRCw6?aJw;6pfpIW(njsFDJhMf2hb9KzG+!pI6fqY_bM z^U6~`zN+uBjQ7jM>ZZ%fks>JKxCPCFBToD_ngu?>efSM_;byPxH0~i@Qf+s;g%1VeQBGd;0k#ldCr$HUj03+PEj06I@f?<| zmiFTx_$Ur>pa=0YWJz_^+t=+N4idY#tG&1jO_Tl*-q8u1B#u95H|yWnMjUFkcRq>~PuI~L zZB2BY{R_6+aT4=69Z(JK~Y;12zB&;^i;sy0Sf6y0L?G6OP!BsVWzx9l#w31gw_l AqyPW_ delta 2105 zcmZwHeN0t#7{Kx8h6G+;uc879UgYK46|P(agDZ%N2_nTymn0c(mpr?{;w8Lf=;~r7 zF0_rjvBqC*&aqloSCSj8xmHuMmo0L=&C%9MvQ4aiY9rTH-{+juKds;PoX_t$T+aEO z=l7g5JL;GjbBv@!qayNoA_vCxB$0Id1herLuEpeJ>wJ!FrR@RK-}T%1nC-hb!}%|; z1LF%t25_}gq#H-jz`vamm2xJ=B9V=F4)gIdJD@g3deBMa*F3_i1ttzn@F86sbjdoo2z@J~FAo7Y>{iN4Qd zCntVFyuOQDPUtuH8VKZ*0QBLBk z7{l}&ky2s*FEZK7iQA|Z@aI~4_&Vx}e?jey%seiF)%Xq$;Vvwt9DY28dgBXt7_VUh zmhsO=9U>J-QDpJ~5pE@4V+Qw^drYXBqJNMEd=&Kp6F7*|cn}*mS-y=& z$(Q9@-9C)<R{1qN-0P#%A^hR>7W}pjJ4RdS!5r+f!cJx+qs9wo#Omq zd>R8qRz>1?iu~XfE{s1TrzEG?+QR+VLmtNlT*oS+H<@%XF|dY>E$2oT@nP~i4_ZGg zW23f_52K!+!f8w?6L}G5aX)qjM9$(z$i1bRf9l1Tun+IyQ`p5juT6ThocgCS3A5Z0 z97Nq~7aRQ?2JjV}w5_caIZr-=UKVJ5JWyjb z>s@Rl&!@xn$)87xD|b-0c0-hnrdrZ%`zC%!ehZs%oL}*9@)u^~_Bs}W?U;byA%*zg z!LFEZR{DSbx`6x43 zgl?Dasg9*YCDA}s5G#pA1TTR3kpi>N9@V|2XUwM1c|O7GZ;m{U+P$lY73LW}F1Bg5 zSu*iy;%T?j*-#%WsOmF9kyt#>9Xp@bkx~#eLR|s3vo6#f?hl2HfZOPg?eml*Gza&@ zPI&y@-hr?Yi5SmDe7ys1zpupEQc!Jl8-1ZjPhY^@&|@6xh`5V\n" "Language-Team: \n" diff --git a/doc/locales/eu/lc_messages/twblue-changelog.temp.temp.po b/doc/locales/eu/lc_messages/twblue-changelog.temp.temp.po deleted file mode 100644 index 51f9b73d..00000000 --- a/doc/locales/eu/lc_messages/twblue-changelog.temp.temp.po +++ /dev/null @@ -1,635 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"POT-Creation-Date: 2017-07-08 16:25+Hora de verano central (Mxico)\n" -"PO-Revision-Date: 2017-07-15 19:44+0200\n" -"Last-Translator: Sukil Etxenike \n" -"Language-Team: \n" -"Language: eu\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 2.0.1\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../doc/changelog.py:3 -msgid "TWBlue Changelog" -msgstr "TwBlueren aldaketak" - -#: ../doc/changelog.py:4 -msgid "## changes in this version" -msgstr "## Aldaketak bertsio honetan" - -#: ../doc/changelog.py:5 -msgid "" -"* TWBlue will show an error when trying to open a timeline for a suspended " -"user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))" -msgstr "" -"* TWBluek errore bat erakutsiko du ezabatutako erabiltzaile batn denbora " -"lerro bat irekitzen saiatzean . ([#128](https://github.com/manuelcortez/" -"TWBlue/issues/128))" - -#: ../doc/changelog.py:6 -msgid "" -"* Removed TwUp as service as it no longer exists. ([#112](https://github.com/" -"manuelcortez/TWBlue/issues/112))" -msgstr "" -"* TwUp zerbitzua kendu da, jada ez delako existitzen. ([#112](https://github." -"com/manuelcortez/TWBlue/issues/112)) " - -#: ../doc/changelog.py:7 -msgid "" -"* Release audio files after uploading them. ([#130](https://github.com/" -"manuelcortez/TWBlue/issues/130))" -msgstr "" -"* Orain audio fitxategiak askatzen dira igo ondoren. ([#130](https://github." -"com/manuelcortez/TWBlue/issues/130))" - -#: ../doc/changelog.py:8 -msgid "" -"* Now TWBlue will use Yandex's translation services instead microsoft " -"translator. ([#132](https://github.com/manuelcortez/TWBlue/issues/132))" -msgstr "" -"* Orain TWBluek Yandexen itzultzailea erabiltzen du Microsoften " -"itzultzailearen ordez. ([#132](https://github.com/manuelcortez/TWBlue/" -"issues/132))" - -#: ../doc/changelog.py:9 -msgid "" -"* SndUp users will be able to upload audio in their account by using their " -"API Key again. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" -msgstr "" -"* SndUp-en erabiltzaileek orain audioak igo ditzakete haien API kodea " -"erabilita. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" - -#: ../doc/changelog.py:10 -msgid "" -"* old tweets shouldn't be added as new items in buffers. ([#116,](https://" -"github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" -"manuelcortez/TWBlue/issues/133))" -msgstr "" -"* Txio zaharrak ez lirateke buferretan elementu berri gisa agertu behar. " -"([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://" -"github.com/manuelcortez/TWBlue/issues/133))" - -#: ../doc/changelog.py:11 -msgid "" -"* All mentionned users should be displayed correctly in Twishort's long " -"tweets. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#135]" -"(https://github.com/manuelcortez/TWBlue/issues/135))" -msgstr "" -"* Aipatutako erabiltzaile guztiak ondo agertu beharko lirateke Tuishort-en " -"txio luzeetan. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) " -"([#135](https://github.com/manuelcortez/TWBlue/issues/135))" - -#: ../doc/changelog.py:12 -msgid "" -"* It is possible to select a language for OCR service from the extras panel, " -"in the account settings dialogue. You can, however, set this to detect " -"automatically. OCR should work better in languages with special characters " -"or non-english symbols. ([#107](https://github.com/manuelcortez/TWBlue/" -"issues/107))" -msgstr "" - -#: ../doc/changelog.py:13 -msgid "" -"* Fixed a problem with JAWS for Windows and TWBlue. Now JAWS will work " -"normally in this update. [#100](https://github.com/manuelcortez/twblue/" -"issues/100)" -msgstr "" - -#: ../doc/changelog.py:14 -msgid "* And more ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" -msgstr "" - -#: ../doc/changelog.py:15 -msgid "## Changes in version 0.90" -msgstr "" - -#: ../doc/changelog.py:16 -msgid "" -"* Fixed a bug in long tweet parsing that was making TWBlue to disconnect the " -"streaming API. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" -msgstr "" - -#: ../doc/changelog.py:17 -msgid "" -"* Now OCR will work in images from retweets. It fixes a bug where TWBlue was " -"detecting images but couldn't apply OCR on them. ([#105](https://github.com/" -"manuelcortez/TWBlue/issues/105))" -msgstr "" - -#: ../doc/changelog.py:18 -msgid "" -"* TWBlue won't try to load tweets already deleted, made with Twishort. " -"Before, if someone posted a long tweet but deleted it in the Twishort's " -"site, TWBlue was trying to load the tweet and it was causing problems in all " -"the client. ([#113](https://github.com/manuelcortez/TWBlue/issues/113))" -msgstr "" - -#: ../doc/changelog.py:19 -msgid "" -"* TWBlue shows an error message when you try to view the profile of an user " -"that does not exist or has been suspended. ([#114,](https://github.com/" -"manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" -"TWBlue/issues/115))" -msgstr "" - -#: ../doc/changelog.py:20 -msgid "" -"* The spellchecker module should select the right language when is set to " -"\"user default\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" -msgstr "" - -#: ../doc/changelog.py:21 -msgid "" -"* Image description will be displayed in retweets too. ([#119](https://" -"github.com/manuelcortez/TWBlue/issues/119))" -msgstr "" - -#: ../doc/changelog.py:22 -msgid "" -"* When reading a long tweet, you shouldn't read strange entities anymore. " -"([#118](https://github.com/manuelcortez/twblue/issues/118))" -msgstr "" - -#: ../doc/changelog.py:23 -msgid "" -"* TWBlue will not try to load timelines if the user is blocking you. ([#125]" -"(https://github.com/manuelcortez/twblue/issues/125))" -msgstr "" - -#: ../doc/changelog.py:24 -msgid "## Changes in version 0.88 and 0.89" -msgstr "" - -#: ../doc/changelog.py:25 -msgid "* Fixed more issues with streams and reconnections." -msgstr "" - -#: ../doc/changelog.py:26 -msgid "* newer updates will indicate the release date in the updater." -msgstr "" - -#: ../doc/changelog.py:27 -msgid "" -"* Changes to keystrokes are reflected in keystroke editor automatically." -msgstr "" - -#: ../doc/changelog.py:28 -msgid "" -"* In replies with multiple users, if the mention to all checkbox is " -"unchecked, you will see a checkbox per user so you will be able to control " -"who will be mentioned in the reply." -msgstr "" - -#: ../doc/changelog.py:29 -msgid "" -"* Fixed a bug that caused duplicated user mentions in replies when the tweet " -"was made with Twishort." -msgstr "" - -#: ../doc/changelog.py:30 -msgid "" -"* Retweets should be displayed normally again when the originating tweet is " -"a Twishort's long tweet." -msgstr "" - -#: ../doc/changelog.py:31 -msgid "" -"* Changed the way TWBlue saves user timelines in configuration. Now it uses " -"user IDS instead usernames. With user IDS, if an user changes the username, " -"TWBlue still will create his/her timeline. This was not possible by using " -"usernames." -msgstr "" - -#: ../doc/changelog.py:32 -msgid "" -"* Added a new setting in the account settings dialogue that makes TWBlue to " -"show twitter usernames instead the full name." -msgstr "" - -#: ../doc/changelog.py:33 -msgid "" -"* Added OCR in twitter pictures. There is a new item in the tweet menu that " -"allows you to extract and display text in images. Also the keystroke alt+Win" -"+o has been added for the same purpose from the invisible interface." -msgstr "" - -#: ../doc/changelog.py:34 -msgid "* Now TWBlue will play a sound when the focused tweet contains images." -msgstr "" - -#: ../doc/changelog.py:35 -msgid "" -"* Your own quoted tweets will not appear in the mentions buffer anymore." -msgstr "" - -#: ../doc/changelog.py:36 -msgid "" -"* The config file is saved in a different way, it should fix the bug where " -"TWBlue needs to be restarted after the config folder is deleted." -msgstr "" - -#: ../doc/changelog.py:37 -msgid "* Mentioning people from friends or followers buffers works again." -msgstr "" - -#: ../doc/changelog.py:38 -msgid "" -"* Support for proxy servers has been improved. Now TWBlue supports http, " -"https, socks4 and socks5 proxies, with and without autentication." -msgstr "" - -#: ../doc/changelog.py:39 -msgid "## Changes in version 0.87" -msgstr "" - -#: ../doc/changelog.py:40 -msgid "* Fixed stream connection errors." -msgstr "" - -#: ../doc/changelog.py:41 -msgid "" -"* Now TWBlue can handle properly a reply to the sender without including all " -"other mentioned users." -msgstr "" - -#: ../doc/changelog.py:42 -msgid "* Updated translations." -msgstr "" - -#: ../doc/changelog.py:43 -msgid "" -"* The status of the mention to all checkbox will be remembered the next time " -"you reply to multiple users." -msgstr "" - -#: ../doc/changelog.py:44 -msgid "## Changes in version 0.86" -msgstr "" - -#: ../doc/changelog.py:45 -msgid "" -"* Fixed a very important security issue. Now TWBlue will send tweets to " -"twishort without using any other server." -msgstr "" - -#: ../doc/changelog.py:46 -msgid "" -"* When you add a comment to a tweet, it will be sent as a quoted tweet, even " -"if your reply plus the original tweet is not exceeding 140 characters." -msgstr "" - -#: ../doc/changelog.py:47 -msgid "" -"* Updated windows 10 keymap for reflecting changes made in the last windows " -"10 build." -msgstr "" - -#: ../doc/changelog.py:48 -msgid "* Added last changes in the twitter API." -msgstr "" - -#: ../doc/changelog.py:49 -msgid "" -"* When replying, it will not show the twitter username in the text box. When " -"you send the tweet, the username will be added automatically." -msgstr "" - -#: ../doc/changelog.py:50 -msgid "" -"* When replying to multiple users, you'll have a checkbox instead a button " -"for mentioning all people. If this is checked, twitter usernames will be " -"added automatically when you send your reply." -msgstr "" - -#: ../doc/changelog.py:51 -msgid "## Changes in version 0.85" -msgstr "" - -#: ../doc/changelog.py:52 -msgid "* Long and quoted tweets should be displayed properly In lists." -msgstr "" - -#: ../doc/changelog.py:53 -msgid "* The connection should be more stable." -msgstr "" - -#: ../doc/changelog.py:54 -msgid "* Added an autostart option in the global settings dialogue." -msgstr "" - -#: ../doc/changelog.py:55 -msgid "* Updated translation." -msgstr "" - -#: ../doc/changelog.py:56 -msgid "* Updated russian documentation." -msgstr "" - -#: ../doc/changelog.py:57 -msgid "* Tweets in cached database should be loaded properly." -msgstr "" - -#: ../doc/changelog.py:58 -msgid "* Added some missed dictionaries for spelling correction." -msgstr "" - -#: ../doc/changelog.py:59 -msgid "" -"* Timelines, lists and other buffer should be created in the right order at " -"startup." -msgstr "" - -#: ../doc/changelog.py:60 -msgid "## Changes in version 0.84 " -msgstr "" - -#: ../doc/changelog.py:61 -msgid "* More improvements in quoted and long tweets." -msgstr "" - -#: ../doc/changelog.py:62 -msgid "" -"* Updated translations: Russian, Italian, French, Romanian, Galician and " -"Finnish." -msgstr "" - -#: ../doc/changelog.py:63 -msgid "" -"* Improvements in the audio uploader module: Now it can handle audio with " -"non-english characters." -msgstr "" - -#: ../doc/changelog.py:64 -msgid "" -"* the title of the window should be updated properly when spellcheck, " -"translate or shorten/unshorten URL buttons are pressed." -msgstr "" - -#: ../doc/changelog.py:65 -msgid "" -"* the bug that changes the selected tweet in the home timeline shouldn't be " -"happening so often." -msgstr "" - -#: ../doc/changelog.py:66 -msgid "## Changes in version 0.82 and 0.83" -msgstr "" - -#: ../doc/changelog.py:67 -msgid "" -"* If the tweet source (client) is an application with unicode characters " -"(example: российская газета) it will not break the tweet displayer." -msgstr "" - -#: ../doc/changelog.py:68 -msgid "" -"* Added a new field for image description in tweet displayer. When " -"available, it will show description for images posted in tweets." -msgstr "" - -#: ../doc/changelog.py:69 -msgid "" -"* users can add image descriptions to their photos. When uploading an image, " -"a dialog will show for asking a description." -msgstr "" - -#: ../doc/changelog.py:70 -msgid "* Redesigned upload image dialog." -msgstr "" - -#: ../doc/changelog.py:71 -msgid "* Fixed photo uploads when posting tweets." -msgstr "" - -#: ../doc/changelog.py:72 -msgid "" -"* When getting tweets for a conversation, ignores deleted tweets or some " -"errors, now TWBlue will try to get as much tweets as possible, even if some " -"of these are no longer available." -msgstr "" - -#: ../doc/changelog.py:73 -msgid "* Added audio playback from soundcloud." -msgstr "" - -#: ../doc/changelog.py:74 -msgid "* Now the session mute option don't makes the screen reader speaks." -msgstr "" - -#: ../doc/changelog.py:75 -msgid "* Fixed the direct message dialog. Now it should be displayed properly." -msgstr "" - -#: ../doc/changelog.py:76 -msgid "" -"* when a tweet is deleted in twitter, TWBlue should reflect this change and " -"delete that tweet in every buffer it is displayed." -msgstr "" - -#: ../doc/changelog.py:77 -msgid "" -"* If your session is broken, TWBlue will be able to remove it automatically " -"instead just crashing." -msgstr "" - -#: ../doc/changelog.py:78 -msgid "* audio uploader should display the current progress." -msgstr "" - -#: ../doc/changelog.py:79 -msgid "" -"* users can disable the check for updates feature at startup from the " -"general tab, in the global settings dialogue." -msgstr "" - -#: ../doc/changelog.py:80 -msgid "" -"* The invisible interface and the window should be synchronized when the " -"client reconnects." -msgstr "" - -#: ../doc/changelog.py:81 -msgid "* The documentation option in the systray icon should be enabled." -msgstr "" -"* Sistemaren ikonoetako dokumentazioa ikusteko aukera erabilgarria egon " -"beharko litzateke." - -#: ../doc/changelog.py:82 -msgid "" -"* In trending buffers, you can press enter for posting a tweet about the " -"focused trend." -msgstr "" -"* Tendentzien buferretan, enter saka dezakezu enfokatutako tendentziari " -"buruz txio bat argitaratzeko." - -#: ../doc/changelog.py:83 -msgid "" -"* Updated russian documentation and main program interface (thanks to " -"Natalia Hedlund (Наталья Хедлунд), [@lifestar_n](https://twitter.com/" -"lifestar_n) in twitter)" -msgstr "" - -#: ../doc/changelog.py:84 -msgid "* updated translations." -msgstr "* Itzulpenak eguneratuak izan dira." - -#: ../doc/changelog.py:85 -msgid "## Changes in Version 0.81" -msgstr "## 0.81bertsioaren aldaketak" - -#: ../doc/changelog.py:86 -msgid "* Updated translations" -msgstr "* Itzulpenak eguneratuak izan dira" - -#: ../doc/changelog.py:87 -msgid "" -"* The updater module has received some improvements. Now it includes a " -"Mirror URL for checking updates if the main URL is not available at the " -"moment. If something is wrong and both locations don't work, the program " -"will start anyway." -msgstr "" - -#: ../doc/changelog.py:88 -msgid "* some GUI elements now use keyboard shortcuts for common actions." -msgstr "" -"* Interfaze grafikoko elementu batzuek lasterbide teklak dituzte ohiko " -"ekintzetarako." - -#: ../doc/changelog.py:89 -msgid "* fixed a bug in the geolocation dialog." -msgstr "* Errore bat konpondu da geottxioen elkarrizketa-koadroan." - -#: ../doc/changelog.py:90 -msgid "* the chicken nugget keymap should work properly." -msgstr "* Chicken Nuggetaren teklatu-mapak ondo funtzionatu beharko luke." - -#: ../doc/changelog.py:91 -msgid "" -"* Added a new soundpack to the default installation of TWBlue, thanks to " -"[@Deng90](https://twitter.com/deng90)" -msgstr "" -"* Soinu pakete berri bat gehitu zaio TWBlueren lehenetsitako instalazioari, " -"eskerrak [@Deng90](https://twitter.com/deng90)" - -#: ../doc/changelog.py:92 -msgid "* Now the changelog is written in an html File." -msgstr "* Orain aldaketen fitxategia html fitxategi bat da." - -#: ../doc/changelog.py:93 -msgid "" -"* Added some missed dictionaries in last version for the spell checking " -"feature." -msgstr "" -"* Aurreko bertsioan falta ziren hiztegi batzuk gehitu dira, zuzentzaleak " -"erabiltzen dituenak." - -#: ../doc/changelog.py:94 -msgid "" -"* Trimmed the beginnings of the sounds in the default soundpack. Thanks to " -"[@masonasons](https://github.com/masonasons)" -msgstr "" -"* ehenetsitako soiinu paketearen soinuen hasierak moztu dira. Eskerrak " -"[@masonasons-i.](https://github.com/masonasons)" - -#: ../doc/changelog.py:95 -msgid "" -"* Added Opus support for sound playback in TWBlue. Thanks to [@masonasons]" -"(https://github.com/masonasons)" -msgstr "" -"* Opus formatua erreproduzi daiteke, eskerrak [@masonasons-i.](https://" -"github.com/masonasons)." - -#: ../doc/changelog.py:96 -msgid "" -"* Added a source field in view tweet dialogue. Thanks to [@masonasons]" -"(https://github.com/masonasons)" -msgstr "" -"* \"Iturria\" gehitu zaio txioa erakusteko elkarrizketa koadroari. Eskerrak " -"[@masonasons-i.](https://github.com/masonasons)" - -#: ../doc/changelog.py:97 -msgid "" -"* You can load previous items in followers and friend buffers for others." -msgstr "" -"* Aurreko elementuak karga ditzakezu besteen jarraitzaile eta lagunen " -"buferretan." - -#: ../doc/changelog.py:98 -msgid "" -"* The Spell Checker dialogue should not display an error message when you " -"have set \"default language\" in the global settings dialogue if your " -"language is supported [#168](http://twblue.es/bugs/view.php?id=168)" -msgstr "" -"* Zuzentzailearen elkarrizketa-koadroak ez luke errorerik erakutsi behar " -"aukera globaletan \"Lehenetsitako hizkuntza\" aukeratua dagoenean eta zure " -"hizkuntza erabilgarria denean [#168](http://twblue.es/bugs/view.php?id=168)" - -#: ../doc/changelog.py:99 -msgid "* Updated romanian translation." -msgstr "* Errumaniera itzulpena eguneratua izan da." - -#: ../doc/changelog.py:100 -msgid "* Some code cleanups." -msgstr "* Kode garbiketa batzuk." - -#: ../doc/changelog.py:101 -msgid "* The bug reports feature is fully operational again." -msgstr "* Arazoez informatzeko ezaugarriak berriz funtzionaten du" - -#: ../doc/changelog.py:102 -msgid "" -"* TWBlue should work again for users that contains special characters in " -"windows usernames." -msgstr "" -"* TWBluek berriz funtzionatu beharko luke haien Windows erabiltzaile-" -"izenetan karaktere bereziak dituzten erabiltzaileentzat." - -#: ../doc/changelog.py:103 -msgid "* Added more options for the tweet searches." -msgstr "* Txioen bilaketarako aukera gehiago gehitu dira." - -#: ../doc/changelog.py:104 -msgid "* Added play_audio to the keymap editor." -msgstr "* play_audio teklatu-mapen editorera gehitua izan da." - -#: ../doc/changelog.py:105 -msgid "* Windows key is no longer required in the keymap editor" -msgstr "* Windows tekla ez da jada bearrezkoa teklatu-mapen editorean." - -#: ../doc/changelog.py:106 -msgid "* Switched to the Microsoft translator." -msgstr "* Microsoften itzultzailera aldatu gara." - -#: ../doc/changelog.py:107 -msgid "" -"* You can update the current buffer by pressing ctrl+win+shift+u in the " -"default keymap or in the buffer menu." -msgstr "" -"* Enfokatutako uferra ktrl+shift+win+u sakatuta (lehenetsitako teklatu-" -"mapak) edo menuan eguneratu daitezke." - -#: ../doc/changelog.py:108 -msgid "* Changed some keystrokes in the windows 10 default keymap" -msgstr "" -"* Lasterbide-tekla batzuk aldatuak izan dira Windows 10erako teklatu-mapan." - -#: ../doc/changelog.py:109 -msgid "* New followers and friends buffer for user timelines." -msgstr "" -"* Jarraitzaileen eta lagunen bufer berria erabiltzaileen denbora-lerroentzat." - -#: ../doc/changelog.py:110 -msgid "---" -msgstr "---" - -#: ../doc/changelog.py:111 -msgid "Copyright © 2014-2017, Manuel Cortez." -msgstr "Copyright © 2014-2017, Manuel Cortez." diff --git a/doc/locales/eu/lc_messages/twblue-documentation.mo b/doc/locales/eu/lc_messages/twblue-documentation.mo index 57c9414ef8194661c91a59d43520ad941f2a7398..3abe64b6467095336ddd36b20b61a18c1f133615 100644 GIT binary patch delta 407 zcmX>vy;!*Zo)F7a1|Z-AVi_Rr0dbJPA0V3_i2nky2oUo!GB9ueX(b@d4WzZ9v^kL0 z2J)SOv@wv*2hxf_dNGhz0@6o;v@Vc-0i<(*v=|cu!!!nldWIGtqY)@5&CI~C7f8=# zVPN0_Du`x-I4TWD^8)#$K$;UsH$%mHfwT^gKL<#IEIbLMHGuSAAgv0d)z~58K0q2| zVFQpZ0n+b)v^~(CWRNeEH*aB-VBGwkiIs748|y|!pPl2j`NBLhQAT?1oXLvsZ~V=H45 zZ37^fT+N=%Vx^E;I{7ZU>Ez8Env>-?Oqokd(k6#-7;-x$CZ*;m80lH+8E*c|q0Ttj MmFw~5ejW!#04jY&NdN!< delta 1486 zcmY+CPly~v6vk_^JDYV9O^i`A8hMEcS+mo_j%GzxLGfQaC|Q_cTG>(-Bpw7 zs?2r=8N7H^8T2RwPl5;I96jz$1U-5Z1U-s5co7u+YGz#6VrqU>uV2;s-mCY;13x@E z{`ti6rvl>y=3|&&VV=f(zJWiCufedqgTG_o6g&y;fvez8;1Teb1%C(EvHuHv8a#hU zh%?|0cow_`M&Re*k`QC@Jr<9{@FQ4&e}JEX*YWieT=FOQ0r+7PYjE}OT+ly=-h$u1 z;C*209wF`p9|7?b7w{MCU9b(l2nIm~xCY(^&m+G0Zt>wRh*;trZVi=K1B0MfK?hF3 zJ_M{G-50=*j?RVP)BXsRfLR>J4Alu$y&n@f9T>PuAP*rn7v`WG3GR<&te{7%V1}}X z5yXXzMC;Dqry6IYC=#!j*cVbecFJh#8%x_)U&_6th;D7XKYj4fN@Kh|QqDUM@!Qza`X*5vrfH=?1sHDnxSSdEe(3FzOfw7KCMD->4 zVZu(9WctC)630&6R8GO9G<7eHHz*#kg;`p7S;}QucIber5mz(ueXFES$~N`6PYZWsr8mt2o2GR^ITa7Znh} zsf3Un?o1Bx+!fHj{Tn;BD+CI9VyMSjFpY^+06^h$gEAh3a9(*bJw1i z4jNBZM#~_b;}}7Mw4yUTwe(G6a(DTmNvC<_iKi~DziuoO6ztvB30sPx(c+!f-rW0g zSH@@2eIDcu&~#^~9WnC`4xXi(^~?NKlE z)VmwkBP%r}CYv{1tqf1bhkxB~v63yi!_=Y0WMa@*nKdm6okhc(9iu}FrXHip+(vV3 zP=?mX&>Au`vm>c@yNXkTZ6RyV8L>^3gO{r%6Aw7=sYGG}A$UqgD~%T&KI<9<4QT8( z<(zsQmLwfxr!$qg6e9ECADFm!L^o~b%3sLWJ2`>n$ zVH_`FX{wdYeD3j\n" "Language-Team: Sukil Echenique \n" diff --git a/doc/locales/fi/lc_messages/twblue-changelog.mo b/doc/locales/fi/lc_messages/twblue-changelog.mo new file mode 100644 index 0000000000000000000000000000000000000000..51402baa962d56476f6569a37ca661a778cc6096 GIT binary patch literal 429 zcmYjNO;5ux3>^}u9yxOe5(f~tv>g*$M$x_snzV{(tGH*KSBko%N>aqQ@GJOx{1)6! zVpy@_=R8|4@8{(ByG3zCc}jU+gMV>N^%p%t-J5ImhN*?=8eUMFTuIKDv%pem3$e-a zHH@mvK%zK{;^A~Q7)~aOXt{Le&k2k*3QIFE5f(WMJiiBC8~i)ww|V>a%A+76Ebu+A zcOQ6N@aQzWP5@qqcr#%vBw9#Q2&*(_v5*xOY)n${lihC{IM`ol({v@;2O5-FB{CAQ z$^QT(D7KtA^P)>p5d3ElLu#D`~mK z4|`J\n" "Language-Team: \n" diff --git a/doc/locales/fi/lc_messages/twblue-documentation.mo b/doc/locales/fi/lc_messages/twblue-documentation.mo new file mode 100644 index 0000000000000000000000000000000000000000..f38123e33820ffbfac2905b4876e168c6c6e8960 GIT binary patch literal 7278 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 S0\n" "Language-Team: \n" diff --git a/doc/locales/fr/lc_messages/twblue-changelog.mo b/doc/locales/fr/lc_messages/twblue-changelog.mo index 6435cb92ac3d114a5687bac1da15e20e349f1385..83695c7f341e6f42b172abb2dd10cff939873cc4 100644 GIT binary patch delta 2961 zcmYM$3slZ$9Ki8k$#F&(nMIf)w@R&CmP+WRB`@8E)@2pCSfd-l*6T85EXrGpkjuh~ zGE$AvM&}Tku`^?aZHHqY7P|DONld7j^M`TtM+Yq|PwOXICR zRu#hU5PyUCEAOtN|9{rKM2ZM)a6FddWIT`Ku&1@ie4LC%+>3i~xQ)mdY{&EX0{!re zt;hhhuoH1nw+!N7AO%xUok%dd)a+*DLa8^$m(6yX?a^D`Hx$)%0jL_3g6g?v@dn<; zO#IGXWDUCY5m~01+`z#?3P!!IZ>+?L#IMlaf>!qx8A&|-4ShZzM-gAg(b&yF$6n}5 z9EXu;!f3pM<>=E-bez_o?5LC-;UElGIEpNy!Zv(|cr49VDf2Lk(A@x*oMdOInKqS zUb+MQy+ulhlfCIKW%7uEV00S8492;rQu!KbP(9y`YRua3Lv&~AtJ%Mme<~9fu>!}A z7hzh+IrPQfa6LNG8agjE_#<}UZro|~(MvCIf=E0CUHA|U+`SV0nE+vU0zX45e`Yxu zD8tLdP0Z9CSRA02=kQ5nkvJYzg@0lo+D+Eak3ti1JyxJGaEizR4zA(@4C3nN=t({g zpet$dp~5Q|OKcM=(u}FN6dkAPRF`2gaXUJpE3LNTzHoFVp25s@z(r<@u%DW4J2;5q zL=(P?J;G@IMC_Z$rh}tMqYLJt(Vc@z4p_p{Wzm=LNV5tu@G9p(^Q)4dWb#5l^W=@z3TX`HOZR$Px6xy&nk zg2!D#2(}V|@(kF@l-p zKtujT`Xaqohwj!1Zzgpi@(gJvuN@e?S&wmVlYWm^<95os(4PlvENAKA`3imimCqRl&R0~5 ze2stL2&~$oUuvh2c`O6Anp2Oh)GxtR`isPJ8+!o{EW&YknA++%e|HD#mbk21Z?QLa z>M;!1r8g9Z-6AnuSBk6f4!UF79^KQ;IGVWO3;m_^D>@QCMdJVtde`W!*B!~0tU|S3 z?e^-ol+8Z9g&x8j%D3#-TWilR^{lQ&YYSFFt$x3!(Q1+>j*N#Il7sx~!Z`=^1~#o; zzs4);$$u6n&Nt}g;B!bXkDF+qJnJj{1#}$MocISL@#JB>)!H86n}B#BCgb!*{ozrM z5yZ|%^~Y!ys*c(<>DA(fR4Lb*ob^kjxLI$(E-gA$BhiBkVp|%2wvC_Ec*$_W)+Ks= z_M+T;4?|vh<~)y}#p!t-v5WkiLk)r9)29T6ghYqN#F#cD47c*)XF8KmVCCnWmTMZH t7-Divay6|@9N%qmewyiIqIa*Ll+^iI&SN}%J-r))lfohzBkFSc{0DU>?uGyW delta 4317 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 diff --git a/doc/locales/fr/lc_messages/twblue-changelog.po b/doc/locales/fr/lc_messages/twblue-changelog.po index 6bcd6cf0..b63e5c4a 100644 --- a/doc/locales/fr/lc_messages/twblue-changelog.po +++ b/doc/locales/fr/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: twblue-changelog 0.93\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2019-07-22 16:16+0200\n" "Last-Translator: Corentin BACQUÉ-CAZENAVE \n" "Language-Team: Corentin BACQUÉ-CAZENAVE \n" diff --git a/doc/locales/fr/lc_messages/twblue-documentation.mo b/doc/locales/fr/lc_messages/twblue-documentation.mo index 8b3416dbded3c6d76e303d7a2bd802860745939c..3065b0af4eeefb43d73fe5fd70936b0b4d4fcb9c 100644 GIT binary patch delta 4360 zcmYk=dt8rM9>DSMBihu8q;e}iBBg%nSL0G6T~uO zu`$?nnRu!;niGyPwnf{W0|F{d~`Jp7WgZJ?A{n!-Idf zJpWzG4IOOqvpCDOu6 z#1%aq`XN;$2-{*b@*}BUVv}AROef-6`7L(A3Ut8}=!R#p8(u-x@Q``uk8dbkY%j zgCt4rq8ed?qr6o|9ed+6$^+1Xt8qFWw{hT4s(m|&lu;1ZnKTpE;W*;<+%*()P-UVV z7vOGOioU)~6K=&QjPw(E8?Bf@JBKiw*x4k_nU2JM#8Z(|Vk_gIc`lJQr4Ie^8Ft5x z{8C2oOQmcQ_QfTr8rqL)M0XtLJ!wp}7r`$z1!FN7m!i6EFAl_SF^v0*2Y2gFK|HF8 zi_wgg7=yJq6g_*=Yn+I~@g%AnIJ1D1W(>k~Ou=Osf|pROk(a2}NC=e&<4o+!{iTuv z?jhGvUHB4{F|oI9@IzE7J%+01&u{>m19ijMs5-g@N8;a+kx3A}QRNdb9?Ma6@HW2& z;V=5o0q!pe9H_Y~#9?><8JxVtX!Ip5>cWYbh^z24UPA6A>lkK(A#xPei1(A{Cj1sN z@UJYO0t}{Cu~>oZWT{vApTdPdaZpdeC{~JE0~Ye79DyoTxu_c6hpM4E9FD`^(itg3 zHS)`j*pG#wGByq~(T+vffD18~`Bvq3`;-4}93+y@!5&Mu|wM*V$Iu?<}&3F;#Viu#Ciq{5{|A#bei4nO$LDx9_ zpm>4ph~4N7S(dJ-<~|uKa5<6$F%1!!jp?Y)pTeQ|0@quWG+lS(2EAm5%XoUzP3?ah z2VpHlw&PD!ygExio6j<_`NX|*^rG3ED>8=*o%2|H)VE>{@p@L&`xg#VUBRxv#^2~gJAV~}XK-?pgO4$ZVJxRY zJ?`a(nQQ1AvD*iF6-TcVX+^z`B|M}k_rpx$uRmm7i9^@x4hC&xoe&>JE|s$%=?B$F zJ3EQ;MW`}RR!aWcaS&3bU%S!hMx2b^n2v2R7rn3;yWvJu=MSSFUO;!e@9;TxA#TN8 zT(LX)U4g5+7o$-cycN@OV`9XWKYXBP@2D_yASKZJ3W$$W9XfEu;;XVl^pzj*p3tY~}Ne zxN;lwOPo`o-xal}Zu}aH&||yEd$<}?sPFPSy$x*{JM^=9177CDSC~r0t-EwX4={$< zla=L1 zQ*#gpW4%MaJ^INt8G|UVKnq^Lq1cFN82_n$Uf3~_*k!Ls9~^<|y2Ti+_Wv#phEZ?_ z)kuT)>DO*9ss{IBEIz?F4BxLuYDKl}$}tOHqFOT(d3+ASwHS-%QMK#xNBy!&M)d?- zfwQ>3RCAz4+UtPGJD7o^a0jZCKSk9MpM!d;reZ(ht*AzN4SQgZL;78jh>^rwa0u37 zZ>HAguwL~spRvALum#Z;Mumu@q?rmcFq^o;pBNSX8e`Gx7<(SaVhb+JM_1|>oY0@w zOHbQ&i?a`zg&Xd}<*cf@=g$LSO2$bS$O z+Mm}S41+G{*KZZpQX%K2Mn!E|~p{PGHXlow@_Kmh-PrEvl6-^n4G zg0`>pOUj0RTz>~cD3|}LwZQzFIe5y61*m$O^O_e4ai=$I6JmqE0a$@1tii`j!97&( z^*Se``O|Hlvmu+f?gv~&y_Kv;nitpBhU8FhEj}l1a5Ll}KKi90(^Z9SZ4CJW#odth zG;kV^b3tueLv|6DP}mMF9gOBFiDyF7sa}UOFvQzv{+iv0&#CtWotVP!I~u|kmq%TU z=I@2=ynB1LF|nRLlzOAF&jb>Br4Qs{$7X+BQW(b#pmTu&yCU)nlepAh1pg0 zUN@GcjLx2yUtl$-7S5VI!yI2UtI(XDA7x5RjT@E{8<&tUI&sVx*R+x8<{<^ynbz6) zbIl2v*6b)#c$g*992Q}=3@}+Dq9Wc34&#r#>7%TcQKp#%_6&QNJ)ktuzR}*#smMCh a{-xdG7N41woo5Q~8`;-VHK%mRj{gHUS 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\n" "Language-Team: Rémy Ruiz \n" diff --git a/doc/locales/gl/lc_messages/twblue-changelog (Jani Kinnunen's conflicted copy 2019-03-25).po b/doc/locales/gl/lc_messages/twblue-changelog (Jani Kinnunen's conflicted copy 2019-03-25).po deleted file mode 100644 index 503e12c8..00000000 --- a/doc/locales/gl/lc_messages/twblue-changelog (Jani Kinnunen's conflicted copy 2019-03-25).po +++ /dev/null @@ -1,1343 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" -"PO-Revision-Date: 2018-08-08 11:46+0100\n" -"Last-Translator: \n" -"Language-Team: \n" -"Language: gl\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 1.6.11\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../doc/changelog.py:3 -msgid "TWBlue Changelog" -msgstr "TWBlue Changelog" - -#: ../doc/changelog.py:4 -msgid "## changes in this version" -msgstr "## cambios nesta versión" - -#: ../doc/changelog.py:5 -msgid "" -"* TWBlue can open a Tweet or user directly in Twitter. There is a new option " -"in the context menu for people and tweet buffers, and also, the shortcut " -"control+win+alt+Enter will open the focused item in Twitter." -msgstr "" - -#: ../doc/changelog.py:6 -#, fuzzy -msgid "* Some keystrokes were remapped in the Windows 10 Keymap:" -msgstr "" -"* Cambiados algúns atallos de teclado no mapa de teclado do Windows 10." - -#: ../doc/changelog.py:7 -#, fuzzy -msgid "" -" * Read location of a tweet: Ctrl+Win+G. ([#177](https://github.com/" -"manuelcortez/TWBlue/pull/177))" -msgstr "" -"* Arranxado un erro que facía que os arquivos de audio non se liberaran " -"despois de se subir a algún servizo de audio. ([#130](https://github.com/" -"manuelcortez/TWBlue/issues/130))" - -#: ../doc/changelog.py:8 -msgid " * Open global settings dialogue: Ctrl+Win+Alt+O." -msgstr "" - -#: ../doc/changelog.py:9 -#, fuzzy -msgid " * Mute/unmute current session: Control + Windows + Alt + M." -msgstr " * Para marcar como góstame un chío, preme Control+Windows+alt+f" - -#: ../doc/changelog.py:10 -msgid "" -"* Fixed an error that was preventing TWBlue to load the direct messages " -"buffer if an user who sent a message has been deleted." -msgstr "" - -#: ../doc/changelog.py:11 -msgid "" -"* Added support for playing audios posted in [AnyAudio.net](http://anyaudio." -"net) directly from TWBlue. Thanks to [Sam Tupy](http://www.samtupy.com/)" -msgstr "" - -#: ../doc/changelog.py:12 -msgid "" -"* Custom buffer ordering will not be reset every time the application " -"restarts after an account setting has been modified." -msgstr "" - -#: ../doc/changelog.py:13 -msgid "" -"* When adding or removing an user from a list, it is possible to press enter " -"in the focused list instead of having to search for the \"add\" or \"delete" -"\" button." -msgstr "" - -#: ../doc/changelog.py:14 -#, fuzzy -msgid "" -"* Quoted and long tweets are displayed properly in the sent tweets buffer " -"after being send. ([#253](https://github.com/manuelcortez/TWBlue/issues/253))" -msgstr "" -"* A descripción de imaxes amosarase tamén en rechíos. ([#119](https://github." -"com/manuelcortez/TWBlue/issues/119))" - -#: ../doc/changelog.py:15 -#, fuzzy -msgid "" -"* Fixed an issue that was making the list manager keystroke unable to be " -"shown in the keystroke editor. Now the keystroke is listed properly. ([#260]" -"(https://github.com/manuelcortez/TWBlue/issues/260))" -msgstr "" -"* Arranxado un problema que facía que o TWBlue non poidese comezar se se " -"estaba a executar en Windows coa lingua Servia. ([#175](https://github.com/" -"manuelcortez/TWBlue/issues/175))" - -#: ../doc/changelog.py:16 -#, fuzzy -msgid "" -"* The volume slider, located in the account settings of TWBlue, now should " -"decrease and increase value properly when up and down arrows are pressed. " -"Before it was doing it in inverted order. ([#261](https://github.com/" -"manuelcortez/TWBlue/issues/261))" -msgstr "" -"* Cando cites un chío, se o chío orixinal se publicou con Twishort, o TWBlue " -"amosará correctamente o chío citado. Antes só amosaba o chío orixinal. " -"([#206](https://github.com/manuelcortez/TWBlue/issues/206))" - -#: ../doc/changelog.py:17 -#, fuzzy -msgid "" -"* autoreading has been redesigned to work in a similar way for almost all " -"buffers. Needs testing. ([#221](https://github.com/manuelcortez/TWBlue/" -"issues/221))" -msgstr "" -"* O TWBlue amosará un erro se se intenta abrir una liña temporal para un " -"usuario suspendido. ([#128](https://github.com/manuelcortez/TWBlue/" -"issues/128))" - -#: ../doc/changelog.py:18 -msgid "" -"* When displaying tweets or direct messages, a new field has been added to " -"show the date when the item has been posted to Twitter." -msgstr "" - -#: ../doc/changelog.py:19 -msgid "" -"* Added support for deleting direct messages by using the new Twitter API " -"methods." -msgstr "" - -#: ../doc/changelog.py:20 -msgid "" -"* When quoting a retweet, the quote will be made to the original tweet " -"instead of the retweet." -msgstr "" - -#: ../doc/changelog.py:21 -#, fuzzy -msgid "" -"* If the sent direct messages buffer is hidden, TWBlue should keep loading " -"everything as expected. ([#246](https://github.com/manuelcortez/TWBlue/" -"issues/246))" -msgstr "" -"* Arranxado un erro que facía que os arquivos de audio non se liberaran " -"despois de se subir a algún servizo de audio. ([#130](https://github.com/" -"manuelcortez/TWBlue/issues/130))" - -#: ../doc/changelog.py:22 -msgid "" -"* There is a new soundpack, called FreakyBlue (Thanks to [Andre Louis]" -"(https://twitter.com/FreakyFwoof)) as a new option in TWBlue. This pack can " -"be the default in the next stable, so users can take a look and share their " -"opinion in snapshot versions. ([#247](https://github.com/manuelcortez/TWBlue/" -"issues/247))" -msgstr "" - -#: ../doc/changelog.py:23 -#, fuzzy -msgid "" -"* There is a new option in the help menu that allows you to visit the " -"soundpacks section in the TWBlue website. ([#247](https://github.com/" -"manuelcortez/TWBlue/issues/247))" -msgstr "" -"* O TWBlue agora Usa WXPython 4.0.1. Esto permitiranos migrar todos os " -"compoñentes importantes a Python 3 no futuro. ([#207](https://github.com/" -"manuelcortez/TWBlue/issues/207))" - -#: ../doc/changelog.py:24 -#, fuzzy -msgid "" -"* When reading location of a geotagged tweet, it will be translated for " -"users of other languages. ([#251](https://github.com/manuelcortez/TWBlue/" -"pull/251))" -msgstr "" -"* cando se lea un chío longo, non deberían aparecer símbolos extranos. " -"([#118](https://github.com/manuelcortez/twblue/issues/118))" - -#: ../doc/changelog.py:25 -msgid "" -"* When there are no more items to retrieve in direct messages and people " -"buffers, a message will announce it." -msgstr "" - -#: ../doc/changelog.py:26 -msgid "" -"* Fixed an issue reported by some users that was making them unable to load " -"more items in their direct messages." -msgstr "" - -#: ../doc/changelog.py:27 -msgid "" -"* It is possible to add a tweet to the likes buffer from the menu bar again." -msgstr "" - -#: ../doc/changelog.py:28 -msgid "" -"* Tweets, replies and retweets will be added to sent tweets right after " -"being posted in Twitter." -msgstr "" - -#: ../doc/changelog.py:29 -#, fuzzy -msgid "* Extended Tweets should be displayed properly in list buffers." -msgstr "" -"* Os chíos longos e citados deberían amosarse correctamente nas listas." - -#: ../doc/changelog.py:30 -#, fuzzy -msgid "## Changes in version 0.94" -msgstr "## Cambios na versión 0.93" - -#: ../doc/changelog.py:31 -msgid "" -"* Added an option in the global settings dialog to disable the Streaming " -"features of TWBlue. TWBlue will remove all Streaming features after August " -"16, so this option will give people an idea about how it will be. ([#219]" -"(https://github.com/manuelcortez/TWBlue/issues/219))" -msgstr "" -"* Engadida una opción no diálogo opción globais para deshabilitar as " -"características de Streaming do TWBlue. TWBlue eliminará todas as " -"características de Streaming despois do 16 de agosto, así esta opción dará " -"una idea á xente de como será. ([#219](https://github.com/manuelcortez/" -"TWBlue/issues/219))" - -#: ../doc/changelog.py:32 -msgid "" -"* Due to Twitter API changes, Switched authorisation method to Pin-code " -"based authorisation. When you add new accounts to TWBlue, you will be " -"required to paste a code displayed in the Twitter website in order to grant " -"access to TWBlue. ([#216](https://github.com/manuelcortez/TWBlue/issues/216))" -msgstr "" -"* Debido aos cambios na API de Twitter, cambiou o método de autorización a " -"una autorización baseada nun código Pin. Cando engadas contas novas ao " -"TWBlue, pediráseche pegar un código amosado no sitio web do Twitter para " -"garantizar o aceso ao TWBlue. ([#216](https://github.com/manuelcortez/TWBlue/" -"issues/216))" - -#: ../doc/changelog.py:33 -msgid "" -"* In order to comply with latest Twitter changes, TWBlue has switched to the " -"new method used to send and receive direct messages, according to issue " -"[#215.](https://github.com/manuelcortez/twblue/issues/215)" -msgstr "" -"* Para poder cumprir cos últimos cambios en Twitter, o TWBlue cambiou ao " -"novo método usado para enviar e recibir as mensaxes directas, de acordo co " -"arranxo [#215.](https://github.com/manuelcortez/twblue/issues/215)" - -#: ../doc/changelog.py:34 -msgid "" -" * The new method does not allow direct messages to be processed in real " -"time. Direct messages will be updated periodically." -msgstr "" -" * O novo método non permite procesar as mensaxes directas en tempo real. " -"As mensaxes directas actualizaranse periódicamente." - -#: ../doc/changelog.py:35 -msgid "" -"* After august 16 or when streaming is disabled, the events buffer will no " -"longer be created in TWBlue." -msgstr "" -"* Despois do 16 de agosto ou cando se deshabilite o streaming, o búfer " -"eventos xa non se creará no TWBlue." - -#: ../doc/changelog.py:36 -msgid "" -"* You can configure frequency for buffer updates in TWBlue. By default, " -"TWBlue will update all buffers every 2 minutes, but you can change this " -"setting in the global settings dialog. ([#223](https://github.com/" -"manuelcortez/TWBlue/issues/223))" -msgstr "" -"* Podes configurar a frecuencia para as actualizacións do búfer no TWBlue. " -"De xeito predeterminado, o TWBlue actualizará todos os búferes cada 2 " -"minutos, pero podes cambiar esta opción no diálogo opcións globais. ([#223]" -"(https://github.com/manuelcortez/TWBlue/issues/223))" - -#: ../doc/changelog.py:37 -#, fuzzy -msgid "" -"* Added a new tab called feedback, in the account settings dialog. This tab " -"allows you to control whether automatic speech or Braille feedbak in certain " -"events (mentions and direct messages received) is enabled. Take into account " -"that this option will take preference over automatic reading of buffers and " -"any kind of automatic output. ([#203](https://github.com/manuelcortez/TWBlue/" -"issues/203))" -msgstr "" -"* Engadida una nova pestana chamada retroalimentación, no diálogo opcións da " -"conta. Esta pestana permíteche controlar a retroalimentación automática da " -"fala ou do braille en certos eventos (mencións e mensaxes directas " -"recibidas) está habilitado. Ten en conta que esta opción terá preferencia " -"sobre a lectura automática dos búferes e de calquer tipo de saída " -"automática. ([#203](https://github.com/manuelcortez/TWBlue/issues/203))" - -#: ../doc/changelog.py:38 -msgid "" -"* The spell checking dialog now has access keys defined for the most " -"important actions. ([#211](https://github.com/manuelcortez/TWBlue/" -"issues/211))" -msgstr "" -"* O diálogo de correción de ortografía agora ten teclas de aceso definidas " -"para as acións máis importantes. ([#211](https://github.com/manuelcortez/" -"TWBlue/issues/211))" - -#: ../doc/changelog.py:39 -msgid "" -"* TWBlue now Uses WXPython 4.0.1. This will allow us to migrate all " -"important components to Python 3 in the future. ([#207](https://github.com/" -"manuelcortez/TWBlue/issues/207))" -msgstr "" -"* O TWBlue agora Usa WXPython 4.0.1. Esto permitiranos migrar todos os " -"compoñentes importantes a Python 3 no futuro. ([#207](https://github.com/" -"manuelcortez/TWBlue/issues/207))" - -#: ../doc/changelog.py:40 -msgid "" -"* When you quote a Tweet, if the original tweet was posted with Twishort, " -"TWBlue should display properly the quoted tweet. Before it was displaying " -"the original tweet only. ([#206](https://github.com/manuelcortez/TWBlue/" -"issues/206))" -msgstr "" -"* Cando cites un chío, se o chío orixinal se publicou con Twishort, o TWBlue " -"amosará correctamente o chío citado. Antes só amosaba o chío orixinal. " -"([#206](https://github.com/manuelcortez/TWBlue/issues/206))" - -#: ../doc/changelog.py:41 -msgid "" -"* It is possible to filter by retweets, quotes and replies when creating a " -"new filter." -msgstr "" -"* É posible filtrar por rechíos, citados e respostas cando se cree un filtro " -"novo." - -#: ../doc/changelog.py:42 -msgid "" -"* Added support for playing youtube Links directly from the client. ([#94]" -"(https://github.com/manuelcortez/TWBlue/issues/94))" -msgstr "" -"* Engadido o soporte para reproducir ligas de youtube directamente dende o " -"cliente. ([#94](https://github.com/manuelcortez/TWBlue/issues/94))" - -#: ../doc/changelog.py:43 -msgid "* Replaced Bass with libVLC for playing URL streams." -msgstr "* Remplazado Bass con libVLC para reproducir URL streams." - -#: ../doc/changelog.py:44 -#, fuzzy -msgid "" -"* the checkbox for indicating whether TWBlue will include everyone in a " -"reply or not, will be unchecked by default." -msgstr "" -"* A caixa de verificación para indicar se o TWBlue incluirá a calquera nunha " -"resposta ou non, estará desmarcada por omisión." - -#: ../doc/changelog.py:45 -msgid "" -"* You can request TWBlue to save the state for two checkboxes: Long tweet " -"and mention all, from the global settings dialogue." -msgstr "" -"* Podes pedir ao TWBlue que garde o estado para dúas caixas de verificación: " -"Chío longo e mencionar a todos, dende a Caixa de diálogo opcións globais." - -#: ../doc/changelog.py:46 -msgid "" -"* For windows 10 users, some keystrokes in the invisible user interface have " -"been changed or merged:" -msgstr "" -"* Para os usuarios do windows 10, cambiáronse ou fusionáronse algúns atallos " -"de teclado na interfaz invisible de usuario:" - -#: ../doc/changelog.py:47 -msgid "" -" * control+Windows+alt+F will be used for toggling between adding and " -"removing a tweet to user's likes. This function will execute the needed " -"action based in the current status for the focused tweet." -msgstr "" -" * control+Windows+alt+F usarase para conmutar entre engadir ou borrar un " -"chío aos gústame do usuario. Esta función executará a acción necesaria " -"baseada no estado actual para o chío enfocado." - -#: ../doc/changelog.py:48 -msgid "* TWBlue will show an error if something goes wrong in an audio upload." -msgstr "* O TWBlue amosará un erro se algo vai mal nunha subida dun audio." - -#: ../doc/changelog.py:49 -msgid "" -"* And more. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " -msgstr "* E máis. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " - -#: ../doc/changelog.py:50 -msgid "## Changes in version 0.93" -msgstr "## Cambios na versión 0.93" - -#: ../doc/changelog.py:51 -msgid "" -"* A new soundpack has been added to TWBlue. Thanks to [@ValeriaK305](https://" -"twitter.com/ValeriaK305)" -msgstr "" -"* Engadido un novo pack de sons ao TWBlue. Grazas a [@ValeriaK305](https://" -"twitter.com/ValeriaK305)" - -#: ../doc/changelog.py:52 -msgid "" -"* In the Windows 10 keymap, we have changed some default keystrokes as " -"windows now uses some previously assigned shortcuts:" -msgstr "" -"* No mapa de teclado para o Windows 10, cambiamos algún atallos de teclado " -"predeterminados xa que windows agora usa algúns atallos de teclado asignados " -"anteriormente:" - -#: ../doc/changelog.py:53 -msgid " * For liking a tweet, press Control+Windows+alt+f" -msgstr " * Para marcar como góstame un chío, preme Control+Windows+alt+f" - -#: ../doc/changelog.py:54 -msgid " * for opening a trends buffer, press control+Windows+T" -msgstr " * para abrir un búfer de tendencias, press control+Windows+T" - -#: ../doc/changelog.py:55 -msgid "" -"* TWBlue has received improvements in some functions for handling extended " -"tweets, long tweets and quoted retweets. It should render some tweets in a " -"better way." -msgstr "" -"* TWBlue recibíu algunhas melloras no manexo de chíos longos, extendidos e " -"rechíos citados. Debería ser capaz de amosar mellor algúns chíos." - -#: ../doc/changelog.py:56 -msgid "" -"* In the spell checker module, there is a new button that will allow you to " -"add your own words to your personal dictionary so the module won't mark them " -"as mispelled the next time you will check spelling." -msgstr "" -"* No módulo de revisión de ortografía, hai unha función que che permite " -"engadir a palabra ao teu diccionario. Deste xeito, nun futuro esa palabra " -"non aparecerá marcada como mal escrita." - -#: ../doc/changelog.py:57 -msgid "" -"* Added filtering capabilities to TWBlue. ([#102](https://github.com/" -"manuelcortez/TWBlue/issues/102))" -msgstr "" -"* Engadidas capacidades de filtrar ao TWBlue. ([#102](https://github.com/" -"manuelcortez/TWBlue/issues/102))" - -#: ../doc/changelog.py:58 -msgid "" -" * You can create a filter for the current buffer from the buffer menu in " -"the menu bar. At this moment, invisible interface does not have any shorcut " -"for this." -msgstr "" -"* Podes crear filtros para o búfer actual dende o menú búfer, atopado na " -"barra de menú. Polo de agora, a interfaz invisible non conta cun atallo para " -"esta ación." - -#: ../doc/changelog.py:59 -msgid " * You can create filters by word or languages." -msgstr " * Podes crear filtros de palabras ou de linguas no chío." - -#: ../doc/changelog.py:60 -msgid "" -" * For deleting already created filters, you can go to the filter manager " -"in the buffer menu and delete the filters you won't need." -msgstr "" -"* Para borrar os filtros, podes aceder ao xestor de filtros no menú búfer, e " -"borrar dende ahí os que xa non necesites." - -#: ../doc/changelog.py:61 -msgid "" -"* Links should be opened properly in quoted tweets ([#167,](https://github." -"com/manuelcortez/TWBlue/issues/167) [#184](https://github.com/manuelcortez/" -"TWBlue/issues/184))" -msgstr "" -"* As ligas deberíanse abrir apropriadamente en chíos cidatos ([#167,]" -"(https://github.com/manuelcortez/TWBlue/issues/167) [#184](https://github." -"com/manuelcortez/TWBlue/issues/184))" - -#: ../doc/changelog.py:62 -msgid "" -"* Increased display name limit up to 50 characters in update profile dialog." -msgstr "" -"* Incrementouse o número de caracteres permitidos nos nomes para amosar en " -"Twitter a 50 caracteres." - -#: ../doc/changelog.py:63 -msgid "" -"* When authorising an account, you will see a dialogue with a cancel button, " -"in case you want to abort the process. Also, NVDA will not be blocked when " -"the process starts. ([#101](https://github.com/manuelcortez/TWBlue/" -"issues/101))" -msgstr "" -"* Ao autorizar unha conta nova, verás un botón para cancelar a acción, se " -"queres deter o proceso. Ademáis, o NVDA non se bloqueará ao se iniciar a " -"autorización para a conta. ([#101](https://github.com/manuelcortez/TWBlue/" -"issues/101))" - -#: ../doc/changelog.py:64 -msgid "" -"* In the translator module, the list of available languages is fetched " -"automatically from the provider. That means all of these languages will work " -"and there will not be inconsistencies. Also we've removed the first combo " -"box, because the language is detected automatically by Yandex'S API. ([#153]" -"(https://github.com/manuelcortez/TWBlue/issues/153))" -msgstr "" -"* no módulo de tradución, a listaxe de linguas soportadas obtense " -"automáticamente dende a web do proveedor. Esto significa que todos as " -"linguas funcionarán correctamente e non haberá problemas ao se traducir. " -"Tamén borramos a primeira Caixa combinada, xa que a lingua de orixen " -"determínase de xeito automático pola API de Yandex. ([#153](https://github." -"com/manuelcortez/TWBlue/issues/153))" - -#: ../doc/changelog.py:65 -msgid "" -"* Trending topics, searches and conversation buffers will use mute settings " -"set for the session in wich they were opened. ([#157](https://github.com/" -"manuelcortez/TWBlue/issues/157))" -msgstr "" -"* As tendencias, as procuras e os búferes de conversa usarán as opcións de " -"silenciado configuradas para a sesión na que fosen abertos. ([#157](https://" -"github.com/manuelcortez/TWBlue/issues/157))" - -#: ../doc/changelog.py:66 -msgid "" -"* The Tweet limit is now 280 characters lenght instead 140. It means you can " -"tweet longer tweets. ([#172](https://github.com/manuelcortez/TWBlue/" -"issues/172))" -msgstr "" -"* O límite para o chío agora e´de 280 caracteres de longo en lugar de 140. " -"Significa podes facer chíos máis longos. ([#172](https://github.com/" -"manuelcortez/TWBlue/issues/172))" - -#: ../doc/changelog.py:67 -msgid "" -"* Per popular request, Status for mention to all and long tweet checkboxes " -"will not be saved in settings. ([#170](https://github.com/manuelcortez/" -"TWBlue/issues/170))" -msgstr "" -"* Por petición popular, as caixas de verificación Estado para mencionar a " -"todos e chíos longos non se gardarán nas opcións. ([#170](https://github.com/" -"manuelcortez/TWBlue/issues/170))" - -#: ../doc/changelog.py:68 -msgid "" -"* Fixed a problem that was making TWBlue unable to start if it was being ran " -"in Windows with Serbian language. ([#175](https://github.com/manuelcortez/" -"TWBlue/issues/175))" -msgstr "" -"* Arranxado un problema que facía que o TWBlue non poidese comezar se se " -"estaba a executar en Windows coa lingua Servia. ([#175](https://github.com/" -"manuelcortez/TWBlue/issues/175))" - -#: ../doc/changelog.py:69 -msgid "* Added Danish translation." -msgstr "* Engadida a tradución ao danés." - -#: ../doc/changelog.py:70 -msgid "" -"* And more. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) " -"[#163,](https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://" -"github.com/manuelcortez/TWBlue/issues/159) [#173,](https://github.com/" -"manuelcortez/TWBlue/issues/173) [#174,](https://github.com/manuelcortez/" -"TWBlue/issues/174) [#176,](https://github.com/manuelcortez/TWBlue/" -"issues/176))" -msgstr "" -"* E máis. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) [#163,]" -"(https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://github." -"com/manuelcortez/TWBlue/issues/159) [#173,](https://github.com/manuelcortez/" -"TWBlue/issues/173) [#174,]* And more. ([#156,](https://github.com/" -"manuelcortez/TWBlue/issues/156) [#163,](https://github.com/manuelcortez/" -"TWBlue/issues/163) [#159,](https://github.com/manuelcortez/TWBlue/" -"issues/159) [#173,](https://github.com/manuelcortez/TWBlue/issues/173) " -"[#174,](https://github.com/manuelcortez/TWBlue/issues/174) [#176,](https://" -"github.com/manuelcortez/TWBlue/issues/176))" - -#: ../doc/changelog.py:71 -msgid "## changes in version 0.91 and 0.92" -msgstr "## Cambios na versión 0.91 e 0.92" - -#: ../doc/changelog.py:72 -msgid "" -"* Fixed incorrect unicode handling when copying tweet to clipboard. ([#150]" -"(https://github.com/manuelcortez/TWBlue/issues/150))" -msgstr "" -"* Arranxado o manexo incorrecto do unicode ao se copiar chíos ao " -"portapapeis. ([#150](https://github.com/manuelcortez/TWBlue/issues/150))" - -#: ../doc/changelog.py:73 -msgid "" -"* TWBlue will show an error when trying to open a timeline for a suspended " -"user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))" -msgstr "" -"* O TWBlue amosará un erro se se intenta abrir una liña temporal para un " -"usuario suspendido. ([#128](https://github.com/manuelcortez/TWBlue/" -"issues/128))" - -#: ../doc/changelog.py:74 -msgid "" -"* Removed TwUp as service as it no longer exists. ([#112](https://github.com/" -"manuelcortez/TWBlue/issues/112))" -msgstr "" -"* Eliminouse o servicio de audio TWUp, debido a que xa non existe. ([#112]" -"(https://github.com/manuelcortez/TWBlue/issues/112))" - -#: ../doc/changelog.py:75 -msgid "" -"* Release audio files after uploading them. ([#130](https://github.com/" -"manuelcortez/TWBlue/issues/130))" -msgstr "" -"* Arranxado un erro que facía que os arquivos de audio non se liberaran " -"despois de se subir a algún servizo de audio. ([#130](https://github.com/" -"manuelcortez/TWBlue/issues/130))" - -#: ../doc/changelog.py:76 -msgid "" -"* Now TWBlue will use Yandex's translation services instead microsoft " -"translator. ([#132](https://github.com/manuelcortez/TWBlue/issues/132))" -msgstr "" -"* Agora o TWBlue usará os servizos de traducción de Yandex en lugar de " -"Microsoft Translator. ([#132](https://github.com/manuelcortez/TWBlue/" -"issues/132))" - -#: ../doc/changelog.py:77 -msgid "" -"* SndUp users will be able to upload audio in their account by using their " -"API Key again. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" -msgstr "" -"* Os usuarios con conta de SNDUp poderán subir audios usando a súa clave de " -"API de novo. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" - -#: ../doc/changelog.py:78 -msgid "" -"* old tweets shouldn't be added as new items in buffers. ([#116,](https://" -"github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" -"manuelcortez/TWBlue/issues/133))" -msgstr "" -"* Xa non se engadirán tuits vellos coma se foran recentes. ([#116,](https://" -"github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" -"manuelcortez/TWBlue/issues/133))" - -#: ../doc/changelog.py:79 -msgid "" -"* All mentionned users should be displayed correctly in Twishort's long " -"tweets. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#135]" -"(https://github.com/manuelcortez/TWBlue/issues/135))" -msgstr "" -"* Todos os usuarios mencionados deberán amosarse correctamente en tuits " -"feitos mediante Twishort. ([#116,](https://github.com/manuelcortez/TWBlue/" -"issues/116)) ([#135](https://github.com/manuelcortez/TWBlue/issues/135))" - -#: ../doc/changelog.py:80 -msgid "" -"* It is possible to select a language for OCR service from the extras panel, " -"in the account settings dialogue. You can, however, set this to detect " -"automatically. OCR should work better in languages with special characters " -"or non-english symbols. ([#107](https://github.com/manuelcortez/TWBlue/" -"issues/107))" -msgstr "" -"* É posible selecionar unha lingua para a función de OCR en imaxes, dende a " -"pestana extras, no diálogo de opcións da conta. Tamén podes, nembargantes, " -"estabrecer a opción en detectar automáticamente. A característica de OCR en " -"imaxes funcionará mellor en linguas que usen caracteres especiais ou " -"símbolos que non forman parte do alfabeto inglés. ([#107](https://github.com/" -"manuelcortez/TWBlue/issues/107))" - -#: ../doc/changelog.py:81 -msgid "" -"* Fixed a problem with JAWS for Windows and TWBlue. Now JAWS will work " -"normally in this update. [#100](https://github.com/manuelcortez/twblue/" -"issues/100)" -msgstr "" -"* Arranxado un problema entre JAWS for Windows e o TWBlue. Agora o TWBlue " -"debería funcionar de xeito correcto con este lector de pantalla. [#100]" -"(https://github.com/manuelcortez/twblue/issues/100)" - -#: ../doc/changelog.py:82 -msgid "* And more ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" -msgstr "* E máis ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" - -#: ../doc/changelog.py:83 -msgid "## Changes in version 0.90" -msgstr "## Cambios na versión 0.90" - -#: ../doc/changelog.py:84 -msgid "" -"* Fixed a bug in long tweet parsing that was making TWBlue to disconnect the " -"streaming API. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" -msgstr "" -"* Arranxado un problema na Streaming API que causaba que o TWBlue " -"desconectara o Streaming. ([#103](https://github.com/manuelcortez/TWBlue/" -"issues/103))" - -#: ../doc/changelog.py:85 -msgid "" -"* Now OCR will work in images from retweets. It fixes a bug where TWBlue was " -"detecting images but couldn't apply OCR on them. ([#105](https://github.com/" -"manuelcortez/TWBlue/issues/105))" -msgstr "" -"* Agora o OCR en imaxes funcionará nos Rechíos tamén. Esto soluciona un erro " -"que causaba que as imaxes se detectaran nos rechíos, pero non se poidera " -"aplicar o OCR nelas. ([#105](https://github.com/manuelcortez/TWBlue/" -"issues/105))" - -#: ../doc/changelog.py:86 -msgid "" -"* TWBlue won't try to load tweets already deleted, made with Twishort. " -"Before, if someone posted a long tweet but deleted it in the Twishort's " -"site, TWBlue was trying to load the tweet and it was causing problems in all " -"the client. ([#113](https://github.com/manuelcortez/TWBlue/issues/113))" -msgstr "" -"* Agora o TWBlue xa non intentará cargar chíos feitos co Twishort que xa " -"foron borrados. Antes, se alguén creaba un chío para despois borralo, dende " -"Twishort, o TWBlue de todos modos tentaba cargar o chío, causando problemas " -"en todo o cliente. ([#113](https://github.com/manuelcortez/TWBlue/" -"issues/113))" - -#: ../doc/changelog.py:87 -msgid "" -"* TWBlue shows an error message when you try to view the profile of an user " -"that does not exist or has been suspended. ([#114,](https://github.com/" -"manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" -"TWBlue/issues/115))" -msgstr "" -"* O TWBlue amosa unha mensaxe de erro se se tenta ver o perfil dunha conta " -"que non existe ou que foi suspendida. ([#114,](https://github.com/" -"manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" -"TWBlue/issues/115))" - -#: ../doc/changelog.py:88 -msgid "" -"* The spellchecker module should select the right language when is set to " -"\"user default\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" -msgstr "" -"* O módulo de correción ortográfica debería selecionar a lingua apropriada " -"cando a lingua do cliente se establece en \"Lingua predeterminada\". ([#117]" -"(https://github.com/manuelcortez/TWBlue/issues/117))" - -#: ../doc/changelog.py:89 -msgid "" -"* Image description will be displayed in retweets too. ([#119](https://" -"github.com/manuelcortez/TWBlue/issues/119))" -msgstr "" -"* A descripción de imaxes amosarase tamén en rechíos. ([#119](https://github." -"com/manuelcortez/TWBlue/issues/119))" - -#: ../doc/changelog.py:90 -msgid "" -"* When reading a long tweet, you shouldn't read strange entities anymore. " -"([#118](https://github.com/manuelcortez/twblue/issues/118))" -msgstr "" -"* cando se lea un chío longo, non deberían aparecer símbolos extranos. " -"([#118](https://github.com/manuelcortez/twblue/issues/118))" - -#: ../doc/changelog.py:91 -msgid "" -"* TWBlue will not try to load timelines if the user is blocking you. ([#125]" -"(https://github.com/manuelcortez/twblue/issues/125))" -msgstr "" -"* O TWBlue non tentará cargar liñas temporais de usuarios que bloquearon á " -"conta actual. ([#125](https://github.com/manuelcortez/twblue/issues/125))" - -#: ../doc/changelog.py:92 -msgid "## Changes in version 0.88 and 0.89" -msgstr "## Cambios na versión 0.88 e 0.89" - -#: ../doc/changelog.py:93 -msgid "* Fixed more issues with streams and reconnections." -msgstr "* Correxidos máis problemas cos streams e ca reconexión." - -#: ../doc/changelog.py:94 -msgid "* newer updates will indicate the release date in the updater." -msgstr "" -"* As actualizacións máis novas indicarán a data do lanzamento no módulo de " -"actualización." - -#: ../doc/changelog.py:95 -msgid "" -"* Changes to keystrokes are reflected in keystroke editor automatically." -msgstr "" -"* Os cambios nas combinacións de teclado refrictiranse automáticamente no " -"editor de combinacións de teclado." - -#: ../doc/changelog.py:96 -msgid "" -"* In replies with multiple users, if the mention to all checkbox is " -"unchecked, you will see a checkbox per user so you will be able to control " -"who will be mentioned in the reply." -msgstr "" -"* nas respostas onde hai varios usuarios, se a Caixa mencionar a todos non " -"está marcada, verás unha caixa para cada usuario, o que che permitirá " -"selecionar aos usuarios que serán mencionados na resposta." - -#: ../doc/changelog.py:97 -msgid "" -"* Fixed a bug that caused duplicated user mentions in replies when the tweet " -"was made with Twishort." -msgstr "" -"* Correxido un erro que causaba que o TWBlue amosara mencións duplicadas se " -"o chío se enviara mediante Twishort." - -#: ../doc/changelog.py:98 -msgid "" -"* Retweets should be displayed normally again when the originating tweet is " -"a Twishort's long tweet." -msgstr "" -"* Os Rechíos deben amosarse correctamente se o chío orixinal fhabía se " -"enviara mediante Twishort." - -#: ../doc/changelog.py:99 -msgid "" -"* Changed the way TWBlue saves user timelines in configuration. Now it uses " -"user IDS instead usernames. With user IDS, if an user changes the username, " -"TWBlue still will create his/her timeline. This was not possible by using " -"usernames." -msgstr "" -"* Cambiada a maneira na que TWBlue garda as liñas temporais na " -"configuración. Agora úsanse identificadores de usuario en lugar de nomes de " -"usuario. Usando os identificadores para cada usuario, se alguén cambia o seu " -"nome de usuario TWBlue aínda será capaz de crear a liña temporal. Esto non " -"era posible anteriormente." - -#: ../doc/changelog.py:100 -msgid "" -"* Added a new setting in the account settings dialogue that makes TWBlue to " -"show twitter usernames instead the full name." -msgstr "" -"* engadida unha opción no diálogo de opcións de conta que fai que o TWBlue " -"amose o nome de pantalla do usuario en lugar do nome completo." - -#: ../doc/changelog.py:101 -msgid "" -"* Added OCR in twitter pictures. There is a new item in the tweet menu that " -"allows you to extract and display text in images. Also the keystroke alt+Win" -"+o has been added for the same purpose from the invisible interface." -msgstr "" -"* Engadido o OCR nas imaxes de Twitter. Hai unha nova opción no menú chío " -"que permite extraer o texto á imaxen do tuit selecionado. Tamén se engadiu a " -"combinación Alt+Windows+O para o mesmo propósito na interfaz invisible." - -#: ../doc/changelog.py:102 -msgid "* Now TWBlue will play a sound when the focused tweet contains images." -msgstr "" -"* Agora o TWBlue reproducirá un son cando o chío selecionado conteña imaxes" - -#: ../doc/changelog.py:103 -msgid "" -"* Your own quoted tweets will not appear in the mentions buffer anymore." -msgstr "* Os teus chíos citados deixarán de amosarse no búfer de mencións." - -#: ../doc/changelog.py:104 -msgid "" -"* The config file is saved in a different way, it should fix the bug where " -"TWBlue needs to be restarted after the config folder is deleted." -msgstr "" -"* O ficheiro de configuración gárdase de un xeito diferente. Esto debería " -"solucionar o erro que requería borrar o directorio de configuracións e " -"reiniciar o TWBlue." - -#: ../doc/changelog.py:105 -msgid "* Mentioning people from friends or followers buffers works again." -msgstr "" -"* funciona de novo mencionar usuarios dende os búferes de seguidores e " -"amigos." - -#: ../doc/changelog.py:106 -msgid "" -"* Support for proxy servers has been improved. Now TWBlue supports http, " -"https, socks4 and socks5 proxies, with and without autentication." -msgstr "" -"* Mellorouse o soporte para servidores proxy. Agora o TWBlue soporta proxys " -"http, https, socks4 e socks5, con ou sen autenticación." - -#: ../doc/changelog.py:107 -msgid "## Changes in version 0.87" -msgstr "## Cambios na versión 0.87" - -#: ../doc/changelog.py:108 -msgid "* Fixed stream connection errors." -msgstr "* Correxidos erros na conexión dos streams." - -#: ../doc/changelog.py:109 -msgid "" -"* Now TWBlue can handle properly a reply to the sender without including all " -"other mentioned users." -msgstr "" -"* Agora o TWBlue pode manexar correctamente as respostas sen incluir a todos " -"os usuarios do chío orixinal." - -#: ../doc/changelog.py:110 -msgid "* Updated translations." -msgstr "* Actualizáronse as traduccións." - -#: ../doc/changelog.py:111 -msgid "" -"* The status of the mention to all checkbox will be remembered the next time " -"you reply to multiple users." -msgstr "" -"* O estado da caixa para mencionar a todos lembrarase a seguinte vez que " -"escrebas unha resposta." - -#: ../doc/changelog.py:112 -msgid "## Changes in version 0.86" -msgstr "## Cambios na versión 0.86" - -#: ../doc/changelog.py:113 -msgid "" -"* Fixed a very important security issue. Now TWBlue will send tweets to " -"twishort without using any other server." -msgstr "" -"* Correxido un erro de seguridade moi importante. Agora o TWBlue enviará " -"chíos cara Twishort sen usar un servidor intermedio." - -#: ../doc/changelog.py:114 -msgid "" -"* When you add a comment to a tweet, it will be sent as a quoted tweet, even " -"if your reply plus the original tweet is not exceeding 140 characters." -msgstr "" -"* Cando se engada un comentario a un chío, este enviarase coma un chío " -"citado, incluso se o comentario máis o chío orixinal non supera os 140 " -"caracteres." - -#: ../doc/changelog.py:115 -msgid "" -"* Updated windows 10 keymap for reflecting changes made in the last windows " -"10 build." -msgstr "" -"* Actualizado o mapa de teclado de Windows 10 debido aos cambios da última " -"build." - -#: ../doc/changelog.py:116 -msgid "* Added last changes in the twitter API." -msgstr "* Engadidos os últimos cambios na API do Twitter." - -#: ../doc/changelog.py:117 -msgid "" -"* When replying, it will not show the twitter username in the text box. When " -"you send the tweet, the username will be added automatically." -msgstr "" -"* Cando se resposte a un chío, non se amosará o nome do usuario no campo de " -"texto. O nome de usuario será engadido de forma automática ao enviar o chío." - -#: ../doc/changelog.py:118 -msgid "" -"* When replying to multiple users, you'll have a checkbox instead a button " -"for mentioning all people. If this is checked, twitter usernames will be " -"added automatically when you send your reply." -msgstr "" -"* Cando se resposte a un chío con varios usuarios, verás unha caixa en lugar " -"dun botón para mencionar a todos. Se é marcada, os nomes de usuario do " -"Twitter engadiranse automáticamente ao enviar o chío." - -#: ../doc/changelog.py:119 -msgid "## Changes in version 0.85" -msgstr "## Cambios na versión 0.85" - -#: ../doc/changelog.py:120 -msgid "* Long and quoted tweets should be displayed properly In lists." -msgstr "" -"* Os chíos longos e citados deberían amosarse correctamente nas listas." - -#: ../doc/changelog.py:121 -msgid "* The connection should be more stable." -msgstr "* A conexión debería ser máis estable." - -#: ../doc/changelog.py:122 -msgid "* Added an autostart option in the global settings dialogue." -msgstr "" -"* Engadiuse a opción para comezar despois de iniciar sesión en Windows no " -"diálogo de opcións globais." - -#: ../doc/changelog.py:123 -msgid "* Updated translation." -msgstr "* Actualizadas as traduccións." - -#: ../doc/changelog.py:124 -msgid "* Updated russian documentation." -msgstr "* Actualizada a documentación en ruso." - -#: ../doc/changelog.py:125 -msgid "* Tweets in cached database should be loaded properly." -msgstr "* Deberíanse cargar correctamente os chíos na base de datos." - -#: ../doc/changelog.py:126 -msgid "* Added some missed dictionaries for spelling correction." -msgstr "" -"* Engadíronse algúns diccionarios novos no módulo de corrección ortográfica." - -#: ../doc/changelog.py:127 -msgid "" -"* Timelines, lists and other buffer should be created in the right order at " -"startup." -msgstr "" -"* As liñas temporais, as listas e outros búferes deberíanse crear na orden " -"correcta ao iniciar o TWBlue." - -#: ../doc/changelog.py:128 -msgid "## Changes in version 0.84 " -msgstr "## Cambios na versión 0.84 " - -#: ../doc/changelog.py:129 -msgid "* More improvements in quoted and long tweets." -msgstr "* Máis melloras nos chíos longos e citados." - -#: ../doc/changelog.py:130 -msgid "" -"* Updated translations: Russian, Italian, French, Romanian, Galician and " -"Finnish." -msgstr "" -"* Actualizadas as traducións: Ruso, italiano, francés, rumano, galego e " -"finlandés." - -#: ../doc/changelog.py:131 -msgid "" -"* Improvements in the audio uploader module: Now it can handle audio with " -"non-english characters." -msgstr "" -"* Melloras no módulo de carga de ficheiros de audio: Agora é capaz de " -"manexar ficheiros de audio con caracteres especiais." - -#: ../doc/changelog.py:132 -msgid "" -"* the title of the window should be updated properly when spellcheck, " -"translate or shorten/unshorten URL buttons are pressed." -msgstr "" -"* O título da ventá debería actualizarse correctamente cando se utilizan " -"funcións coma corrección ortográfica, traducción ou acurtar / expandir URL." - -#: ../doc/changelog.py:133 -msgid "" -"* the bug that changes the selected tweet in the home timeline shouldn't be " -"happening so often." -msgstr "" -"* O erro que facía que o chío selecionado cambiara na interfaz visible " -"debería estar parcialmente correxido." - -#: ../doc/changelog.py:134 -msgid "## Changes in version 0.82 and 0.83" -msgstr "## Cambios na versión 0.82 e 0.83" - -#: ../doc/changelog.py:135 -msgid "" -"* If the tweet source (client) is an application with unicode characters " -"(example: российская газета) it will not break the tweet displayer." -msgstr "" -"* Se a fonte do chío (cliente) é una aplicación con caracteres unicode " -"(exempro: " -"\\321\\200\\320\\276\\321\\201\\321\\201\\320\\270\\320\\271\\321\\201\\320\\272\\320\\260\\321\\217 " -"\\320\\263\\320\\260\\320\\267\\320\\265\\321\\202\\320\\260) non se romperá " -"o visualizador do chío." - -#: ../doc/changelog.py:136 -msgid "" -"* Added a new field for image description in tweet displayer. When " -"available, it will show description for images posted in tweets." -msgstr "" -"* Engadido un campo para descripción de imaxes no visualizador de chíos, " -"Cando estean dispoñibles, amosaránse descripcións para as imaxes no chío." - -#: ../doc/changelog.py:137 -msgid "" -"* users can add image descriptions to their photos. When uploading an image, " -"a dialog will show for asking a description." -msgstr "" -"* Os usuarios agora poden engadir descripción ás súas fotos. Ao subir a " -"imaxen, aparecerá un diálogo para que se proporcione unha descripción." - -#: ../doc/changelog.py:138 -msgid "* Redesigned upload image dialog." -msgstr "* Rediseñouse o diálogo para subir imaxes." - -#: ../doc/changelog.py:139 -msgid "* Fixed photo uploads when posting tweets." -msgstr "* Correxiuse a carga das imaxes ao se publicar chíos." - -#: ../doc/changelog.py:140 -msgid "" -"* When getting tweets for a conversation, ignores deleted tweets or some " -"errors, now TWBlue will try to get as much tweets as possible, even if some " -"of these are no longer available." -msgstr "" -"* cando se obteñen chíos para amosar unha conversa, agora ignóranse os chíos " -"borrados e algúns erros comúns. TWBlue cargará a maior cantidade de chíos " -"posible." - -#: ../doc/changelog.py:141 -msgid "* Added audio playback from soundcloud." -msgstr "* Engadida a reprodución de audio dende Soundcloud." - -#: ../doc/changelog.py:142 -msgid "* Now the session mute option don't makes the screen reader speaks." -msgstr "" -"* Ao se silenciar unha sesión, agora o lector de pantalla xa non anunciará " -"ningún contido automáticamente." - -#: ../doc/changelog.py:143 -msgid "* Fixed the direct message dialog. Now it should be displayed properly." -msgstr "" -"* Correxido o diálogo de mensaxe directa. Agora debería amosarse " -"correctamente." - -#: ../doc/changelog.py:144 -msgid "" -"* when a tweet is deleted in twitter, TWBlue should reflect this change and " -"delete that tweet in every buffer it is displayed." -msgstr "" -"* Cando se borra un chío, o TWBlue debería amosar o cambio e borrar o chío " -"de todos os búferes onde se amosa." - -#: ../doc/changelog.py:145 -msgid "" -"* If your session is broken, TWBlue will be able to remove it automatically " -"instead just crashing." -msgstr "" -"* Se a configuración dunha sesión foi dañada, o TWBlue debería ser capaz de " -"borrala e de continuar en lugar de non se abrir." - -#: ../doc/changelog.py:146 -msgid "* audio uploader should display the current progress." -msgstr "" -"* O diálogo de carga de ficheiros de audio agora amosa o progreso actual." - -#: ../doc/changelog.py:147 -msgid "" -"* users can disable the check for updates feature at startup from the " -"general tab, in the global settings dialogue." -msgstr "" -"* Os usuarios poden desactivar a comprobación automática de actualizacións " -"no diálogo de opcións globais, na pestana Xeral." - -#: ../doc/changelog.py:148 -msgid "" -"* The invisible interface and the window should be synchronized when the " -"client reconnects." -msgstr "" -"* A interfaz invisible e a ventá gráfica deben estar sincronizadas cando o " -"cliente se reconecta." - -#: ../doc/changelog.py:149 -msgid "* The documentation option in the systray icon should be enabled." -msgstr "* A opción de documentación na bandexa do sistema atópase activa." - -#: ../doc/changelog.py:150 -msgid "" -"* In trending buffers, you can press enter for posting a tweet about the " -"focused trend." -msgstr "" -"* Nos búferes de tendencias, podes premer intro sobre cada tendencia para " -"publicar un chío acerca dela." - -#: ../doc/changelog.py:151 -msgid "" -"* Updated russian documentation and main program interface (thanks to " -"Natalia Hedlund (Наталья Хедлунд), [@lifestar_n](https://twitter.com/" -"lifestar_n) in twitter)" -msgstr "" -"* Actualizada a documentación e a interfaz principal do programa ao ruso " -"(Grazas a Natalia Hedlund " -"(\\320\\235\\320\\260\\321\\202\\320\\260\\320\\273\\321\\214\\321\\217 " -"\\320\\245\\320\\265\\320\\264\\320\\273\\321\\203\\320\\275\\320\\264), " -"[@lifestar_n](https://twitter.com/lifestar_n) in twitter)" - -#: ../doc/changelog.py:152 -msgid "* updated translations." -msgstr "* Actualizadas as traduccións." - -#: ../doc/changelog.py:153 -msgid "## Changes in Version 0.81" -msgstr "## Cambios na Versión 0.81" - -#: ../doc/changelog.py:154 -msgid "* Updated translations" -msgstr "* Actualizadas as traducións." - -#: ../doc/changelog.py:155 -msgid "" -"* The updater module has received some improvements. Now it includes a " -"Mirror URL for checking updates if the main URL is not available at the " -"moment. If something is wrong and both locations don't work, the program " -"will start anyway." -msgstr "" -"* O módulo de actualizacións recibiu algunhas melloras. Agora inclúe unha " -"URL con información de actualizacións de copia de seguridade por se o " -"enderezo principal non funciona." - -#: ../doc/changelog.py:156 -msgid "* some GUI elements now use keyboard shortcuts for common actions." -msgstr "" -"* Algúns elementos da interfaz gráfica agora usan atallos de teclado para " -"accións comúns." - -#: ../doc/changelog.py:157 -msgid "* fixed a bug in the geolocation dialog." -msgstr "" -"* Correxido un erro no diálogo para amosar a información xeográfica en chíos." - -#: ../doc/changelog.py:158 -msgid "* the chicken nugget keymap should work properly." -msgstr "* O mapa de teclado de chicken Nugget debería funcionar correctamente." - -#: ../doc/changelog.py:159 -msgid "" -"* Added a new soundpack to the default installation of TWBlue, thanks to " -"[@Deng90](https://twitter.com/deng90)" -msgstr "" -"* Engadiuse un novo paquete de sons á instalación predeterminada do TWBlue, " -"gracias a [@Deng90](https://twitter.com/deng90)" - -#: ../doc/changelog.py:160 -msgid "* Now the changelog is written in an html File." -msgstr "* Agora o changelog escrébese nun Ficheiro html." - -#: ../doc/changelog.py:161 -msgid "" -"* Added some missed dictionaries in last version for the spell checking " -"feature." -msgstr "" -"* Engadíronse algúns dicionarios ao módulo de corrección ortográfica que non " -"foran engadidos na última versión. " - -#: ../doc/changelog.py:162 -msgid "" -"* Trimmed the beginnings of the sounds in the default soundpack. Thanks to " -"[@masonasons](https://github.com/masonasons)" -msgstr "" -"* Borráronse os silenzos ao comezo dos sons no paquete de sons " -"predeterminado. Gracias a [@masonasons](https://github.com/masonasons)" - -#: ../doc/changelog.py:163 -msgid "" -"* Added Opus support for sound playback in TWBlue. Thanks to [@masonasons]" -"(https://github.com/masonasons)" -msgstr "" -"* Engadido o soporte ao códec Opus no TWBlue. Gracias a [@masonasons]" -"(https://github.com/masonasons)" - -#: ../doc/changelog.py:164 -msgid "" -"* Added a source field in view tweet dialogue. Thanks to [@masonasons]" -"(https://github.com/masonasons)" -msgstr "" -"* Engadido un campo para amosar o cliente dende o que se fai un chío no " -"visualizador de chíos. Gracias a [@masonasons](https://github.com/masonasons)" - -#: ../doc/changelog.py:165 -msgid "" -"* You can load previous items in followers and friend buffers for others." -msgstr "" -"* Podes cargar máis elementos nos búferes de seguedores e amigos de outros " -"usuarios." - -#: ../doc/changelog.py:166 -msgid "" -"* The Spell Checker dialogue should not display an error message when you " -"have set \"default language\" in the global settings dialogue if your " -"language is supported [#168](http://twblue.es/bugs/view.php?id=168)" -msgstr "" -"* O módulo de corrección ortográfica non amosará unha mensaxe de erro ao se " -"establecer \"Lingua predeterminada\" no diálogo de opcións globais se a túa " -"língua se atopa soportada. [#168](http://twblue.es/bugs/view.php?id=168)" - -#: ../doc/changelog.py:167 -msgid "* Updated romanian translation." -msgstr "* Actualizada a tradución ao romanés." - -#: ../doc/changelog.py:168 -msgid "* Some code cleanups." -msgstr "* Limpeza do código." - -#: ../doc/changelog.py:169 -msgid "* The bug reports feature is fully operational again." -msgstr "" -"* O sistema de información de erros está completamente operativo de novo." - -#: ../doc/changelog.py:170 -msgid "" -"* TWBlue should work again for users that contains special characters in " -"windows usernames." -msgstr "" -"* O TWBlue debería funcionar de novo para usuarios que conteñan caracteres " -"especiais nos seus nomes de usuario do Windows." - -#: ../doc/changelog.py:171 -msgid "* Added more options for the tweet searches." -msgstr "* Engadidas máis opcións para as procuras no Twitter." - -#: ../doc/changelog.py:172 -msgid "* Added play_audio to the keymap editor." -msgstr "* Engadida a función play_audio ao editor de mapas de teclado." - -#: ../doc/changelog.py:173 -msgid "* Windows key is no longer required in the keymap editor" -msgstr "* A tecla Windows xa non é obrigatoria no editor de mapas de teclado." - -#: ../doc/changelog.py:174 -msgid "* Switched to the Microsoft translator." -msgstr "* Cambiamos a usar o servicio Microsoft translator." - -#: ../doc/changelog.py:175 -msgid "" -"* You can update the current buffer by pressing ctrl+win+shift+u in the " -"default keymap or in the buffer menu." -msgstr "" -"* Podes actualizar o búfer actual premendo ctrl+win+shift+u na interfaz " -"invisible ou dende o menú búfer." - -#: ../doc/changelog.py:176 -msgid "* Changed some keystrokes in the windows 10 default keymap" -msgstr "" -"* Cambiados algúns atallos de teclado no mapa de teclado do Windows 10." - -#: ../doc/changelog.py:177 -msgid "* New followers and friends buffer for user timelines." -msgstr "* Novos búferes de amigos e seguedores para outros usuarios." - -#: ../doc/changelog.py:178 -msgid "---" -msgstr "---" - -#: ../doc/changelog.py:179 -msgid "Copyright © 2014-2017, Manuel Cortez." -msgstr "Copyright 2014-2017, Manuel Cortez." - -#~ msgid "" -#~ " * The sent direct messages buffer has been removed. All direct " -#~ "messages will be placed in one buffer only. " -#~ msgstr "" -#~ " * Eliminouse o búfer de mensaxes directas enviadas. Todas as mensaxes " -#~ "directas colócanse nun único búfer. " - -#~ msgid "" -#~ " * When sending a direct message, you will hear a sound if the message " -#~ "has been sent properly, but the direct message will not be added to the " -#~ "buffer inmediately." -#~ msgstr "" -#~ " * Cando se envíe una mensaxe directa, escoitarás un son se a mensaxe " -#~ "se enviou apropriadamente, pero a mensaxe directa non se engadirá ao " -#~ "búfer inmediatamente." diff --git a/doc/locales/gl/lc_messages/twblue-changelog.mo b/doc/locales/gl/lc_messages/twblue-changelog.mo index c68704b2b89f5c7213dceb28c8224711a9b2f017..57a0258aa709db161ed5dcf42d0f2b81d93cf4aa 100644 GIT binary patch delta 2705 zcmYk;eN5F=7{KudaM@5IUKAA6D~1S)$rUv~NEB2Q-|j^e3KH~s!xvr@L_oWQyhKV0 zS0qXloh7=OA|=x?8EZIvX-rpH>83XEHK*1JSC)N`=l&7@e9m)zZ|6McIfvVN*7-=M z^Db|j{O`}-Riu)51Wv(27>+-qy3u`*$U)qRMl=o_I0VkvVuCbNHaAugF~DvSB(?7w}i&mu%!qUHBb~aXQlr;(>N-AinM|vI+}FkVd?Q zjaW5OBo{}I5_u2nP%V*%fx%%dhF~|2#>c1ze%+JdB^=17r?T%iFBjhU?MqbzQvGsAhZy z>v0S(Vb$ameyDQROM}5nYM97nEW-o1)F^Tc`|&M2OkN+NOSniWK0!6W4O1vkJdIDziFoZaktU3OL+_@mxSiM|LVvFbW7V2<(@-B67)e@jC90A3;~K1qVwU(6r}2SX zlyVZWe~idU%)>$)M}Ac%n{gCg!Q z#hT62yP+D%rd&qqM_!)KOE3&uF&9-41tf~RgBE1fq#M=y`cX}+V1YglYH%a*z=e9Z zl%NaoUkhy_6tMhDhZhDeqMDu9^H@Y&w^)Qp$zal>Qfoq$iE8{@^_y5+k^%qkkalqOOm|l^ExUTdG=&!s^ud&cHN@U@uET?P72R1M%0M1qwlnWup?A%J%oj^-lY2DcNV$<|<#1ymo3#n= zU=;loOiPWtYqdV0Qmi6h6JNw`EPGd&|OJ`WCkM?EA>Pb0n zQTzV~8qeu4Gwf0&m6(s;;TBBD7Wom+VlVDzlr5N(%b|k4dCZ)FUO|;w3zf#$r59N} z3Fl?aT(3qo@Q_Wq`fuPOzAqu_auMQCmg!U^&``(D37~aty=CcoJ{neXPS?M%jv)r8*3n$?<^( zSCb_-XG4DIf{oU!RiQHrtQ$joz1hnBMsJd zu8A4h)`ASHB{a#Bu|CpZe`pS|r6y&eA*P6oy&CJNOtTPxVMobKA^GzDI=syX= Bwt)Zu delta 3616 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 b$j(f$$4p4hoMz98@TJAz@a<;{j^_Oj9RYJV diff --git a/doc/locales/gl/lc_messages/twblue-documentation.po b/doc/locales/gl/lc_messages/twblue-documentation.po index 9712fbee..bfe34947 100644 --- a/doc/locales/gl/lc_messages/twblue-documentation.po +++ b/doc/locales/gl/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: tw blue documentation 0.46\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-08-08 11:34+0100\n" "Last-Translator: Juan C. Buño \n" "Language-Team: Alba Quinteiro \n" diff --git a/doc/locales/hu/lc_messages/twblue-changelog.mo b/doc/locales/hu/lc_messages/twblue-changelog.mo index f53cb685a2ebc6811c8a3695bb07922189ca2995..f9d414336628c8935455d2c17d8f8b3489289c45 100644 GIT binary patch delta 162 zcmeBWZeyMx62yQ6bb#y#Mg|65kXS%bepYI7iLPggZdhtjab|v=m4X6SP-;PbQHic^ zae8Kou2X4xv2IAdm4d6Uqozl$ey7qhO?Gsb|Q=0095p BDH8wy delta 163 zcmZo;?q!}J;>^szz@P)fAYcK+!Hf(HmOvUvAwWP;epYI7iLPggZdhtjab|v=l>%3Q ze~7MgQEFnz#2E?`Cpd}dhNLFu0>yn2^U_Nb(^IV!GD;^4Fq$%lhPX}kU^LV!s7y~S xDM_s;(JQD_Fw`^UiqLgW%}XsxEXgmjQV7UTP01`#Fw!&7Gn)8Ji`kls0RRdfDG2}o diff --git a/doc/locales/hu/lc_messages/twblue-changelog.po b/doc/locales/hu/lc_messages/twblue-changelog.po index cc86518d..63843755 100644 --- a/doc/locales/hu/lc_messages/twblue-changelog.po +++ b/doc/locales/hu/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2017-12-11 11:07-0600\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/doc/locales/hu/lc_messages/twblue-documentation.mo b/doc/locales/hu/lc_messages/twblue-documentation.mo index a2b23b1e14407af867fa2dcf1d0734fdaa024e15..065ee2c672972d6f039f9bafafb5ba68b38c7b91 100644 GIT binary patch delta 162 zcmeBTInF#mM3eyu=m6O>85tOKCz=}j1f>?_7nSJx7N=*X=sK0A7wd-PTPe8uI(qsz zIJ&q5xdsPw1^9>PIv1rTmSpDV>AEDAq*^H$85mmX8W`&unkyI@TN#^Z8vwz?HQ6Fo z3K^wbK8bnhrHSdOx*@5FxmF63_cLlu)@C$iE-gu$oXlv*>y((3nxkN(XQ^k%#Q*@8 CDJmfV delta 203 zcmX@k+{H3MM3I?+fk6j|LBIltFEBDNSORGv1pyN^jVCsUP29(=Y-FPCkzbUkkXl@F zcwt^jVv#~}YFw=2|Im`6TA0mnNpCS}A0dP7Y)= zWeyE-o7~B0s9jK*o?23pT2Z1`P^n<3XUY|!>z\n" "Language-Team: \n" diff --git a/doc/locales/it/lc_messages/twblue-changelog.mo b/doc/locales/it/lc_messages/twblue-changelog.mo index d8e985e39df1402cd1a176285a1aa09671cdc9bd..ebf9145a1fa60aaf7d9bf28cdcee8d589e848778 100644 GIT binary patch delta 162 zcmeBWZeyMx62yQ6bb#y#Mg|65kXS%bepYI7iLPggZdhtjab|v=m4X6SP-;PbQHic^ zae8Kou2X4xv2IAdm4d6Uqozl$ey7qhO?Gsb|Q=0095q BDH8wy delta 163 zcmZo;?q!}J;>^szz@P)fAYcK+!Hf(HmOvUvAwWP;epYI7iLPggZdhtjab|v=l>%3Q ze~7MgQEFnz#2E?`Cpd}dhNLFu0>yn2^U_Nb(^IV!GD{{4Fq$%lhPX}kU^LV!s7y~S xDM_s;(JQD_Fw`^UiqLgW%}XsxEXgmjQV7UTP01`#Fw!&7Gn)8Ji`kls0RRdgDG2}o diff --git a/doc/locales/it/lc_messages/twblue-changelog.po b/doc/locales/it/lc_messages/twblue-changelog.po index 739b2c2f..d288faf9 100644 --- a/doc/locales/it/lc_messages/twblue-changelog.po +++ b/doc/locales/it/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2017-12-11 11:07-0600\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/doc/locales/it/lc_messages/twblue-documentation.mo b/doc/locales/it/lc_messages/twblue-documentation.mo index 5b98fffd0712edcc7e7db15ff2face6896a0b363..3da1c1b0440ffc3c2368320432a0089bfc603dc6 100644 GIT binary patch delta 4372 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 L&t9IiDSyQ;RM+7K delta 5783 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 fD#QEc\n" "Language-Team: \n" diff --git a/doc/locales/ja/lc_messages/twblue-changelog.mo b/doc/locales/ja/lc_messages/twblue-changelog.mo index e3a5bd5b60484b42d8a5a75e24242e26e7671969..96e197b7ffe3b7898b18b6397662d12afb45240d 100644 GIT binary patch delta 828 zcmYMyT}V@59LMqhoRZFWn{L^QXXSEKNA_ZvBO>P{3pLYaUL{9dYn85aBMQqdG7FMH z2fd97yyzmqY2Ed95fVXklU+nNUDSmMC3F#3eNSi51BcJ~J?GiO|M@?g9e8+b{8L5l zv@q&;w(vwOM*2T)=ZK6Gr|>lvTScnz1Ma{z+>DM~b3Tx@GiyBSb^OS>yLbu5@+5h#%L{ZM4=~Wq#<*I+pc58m(SJFB^Ww%VfJ#%mkK?Z45W3k<+bQyrJXvQJaKs~}|5|s) zW43O_qd&IZ${f#I$;rGam@Cp(tM+s%w(jWp#7I)@7>&gT)le!nszwq)rM08^aQngL zaJaj*r^nWHG@`bQM73l*F|3BQWHhMwy}l;Z8&G|XiZ2ihH0<^=^plPjdr&!}+1jznF*`l$1H=3VuIHIr5>WqOIv F`4>0ag?j)1 delta 2622 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 Ag8%>k diff --git a/doc/locales/ja/lc_messages/twblue-documentation.po b/doc/locales/ja/lc_messages/twblue-documentation.po index 74a1b294..46d4399a 100644 --- a/doc/locales/ja/lc_messages/twblue-documentation.po +++ b/doc/locales/ja/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-08-08 19:09+0900\n" "Last-Translator: Masamitsu Misono \n" "Language-Team: NVDA Help Desk \n" diff --git a/doc/locales/pl/lc_messages/twblue-changelog.mo b/doc/locales/pl/lc_messages/twblue-changelog.mo index 23e79664ee3f504fa73dc6beb3ad11e56b9ab633..035db01e7c840f123c55d3ea557f1e037cd7def2 100644 GIT binary patch delta 263 zcmdli)FU)Oq@Do@%mK2cfOswt_X6<_AWjEjH%11ATp+y;NKXaQGE58%JwSRBklqNS z?U@-ET7YsNfwUNqU&hM705Yo=NEZTWEjFMSke&miR|08ab_RwiKzc7b13SY`AR~xl zq&u^gJ6&t*#rOqr+cuN{ diff --git a/doc/locales/pl/lc_messages/twblue-changelog.po b/doc/locales/pl/lc_messages/twblue-changelog.po index b4f375f6..ae4e991c 100644 --- a/doc/locales/pl/lc_messages/twblue-changelog.po +++ b/doc/locales/pl/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2017-12-11 11:08-0600\n" "Last-Translator: zvonimir stanecic \n" "Language-Team: \n" diff --git a/doc/locales/pl/lc_messages/twblue-documentation.mo b/doc/locales/pl/lc_messages/twblue-documentation.mo index c551c01715ef154b325c6ddce7221443a1c7b0c2..179c4bff5e509a561f3cef1aeda96efde59d2ff6 100644 GIT binary patch delta 779 zcmYk(Pe_w-9LMqRT26b`AJgfmv>ufrn$L7DDW8O#Y%oD%xzV8rS~!QKbN-p9V0aEg zdY~@pF$luTK*U1_J#>tM5q0R#t>_YTiD1?H%br6I56|oOeV*TseZQYo&c5hb50vG< z>*)cJX6g-W#VtIBd)S6=F@Rt36xOf_Pk2TA*o|i}j9qvQ&tVZwe1h$`gZewKy;2r~ z#b;g|#qZdGzugVNgY^UFQ4d^2Z7Ai|ciegbwSiUa#Wg&MyBNYMUPe!YNEB_<1`7?$ z-_2s37Zz49iC<7Vzu>D+bRFlY7w|ED!c~vRN}~u{GUHb*fM1GN3F;uGZM9<7eoDAPRv*g*k*Co7|#~+rEETDWpdd$+jMUEr<_;DptrO< Y?ff+&{?Y8++^jhe9tuY)AN^I|KMLewg#Z8m delta 1045 zcmXxjOK1~89LMoV8dI~{`exM+z8q!|0MvD)u*rFG~C0S~)P2zS7?LmTi z@FF5cd+>3R3W9==_NI99A|fahJ&AV_JSm8%-~aA9F!}7v?#|BqX7V&%@4D4m?N>@Y z2=ha!G$^$eFJTK_#WgsO8}Ko<;tSk@?{Ou5!&UeLJ1`tkY6tGbZajn5z2 zh^i`si$yw`@fB{xcfkW+QC|2Rv|CpA6Y4}6pf70WP$n>rd(gtocoTc^31)B^_hEC? zpWwl0m08kJpu@!LID$*qjek&9)YYie6y|Uq>v$!k)KQktnCfjzsU}kVfRfl3W+MrH zN4ivGwVz-!%Kc81h4odrkeMGtdGHKMv=&O#mvI~34%*LgJ?+;h5r0B??-$BKB2E5# zJ*a691?_Vvi8+DS0;_kpXy?WPGKPAIL-+6gN?2EBsQw7p_HXr($ip_nWD-na=1`Cfm2ScckoC+Maex12X)3%${jA&-+AC2Yc EKih|QhyVZp diff --git a/doc/locales/pl/lc_messages/twblue-documentation.po b/doc/locales/pl/lc_messages/twblue-documentation.po index c20e8c96..7c281a31 100644 --- a/doc/locales/pl/lc_messages/twblue-documentation.po +++ b/doc/locales/pl/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue documentation 0.46\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2017-01-22 21:42+0100\n" "Last-Translator: Zvonimir Stanečić \n" "Language-Team: \n" diff --git a/doc/locales/pt/lc_messages/twblue-changelog.mo b/doc/locales/pt/lc_messages/twblue-changelog.mo index 112641aa3b99cd6f47a636fb5917c6564dc0ed0a..f78ff5813861e6c0af8ccd6af2be0430748e1c0c 100644 GIT binary patch delta 162 zcmeBWZeyMx62yQ6bb#y#Mg|65kXS%bepYI7iLPggZdhtjab|v=m4X6SP-;PbQHic^ zae8Kou2X4xv2IAdm4d6Uqozl$ey7qhO?Gsb|Q=0003t BDH;F( delta 163 zcmZo;?q!}J;>^szz@P)fAYcK+!Hf(HmOvUvAwWP;epYI7iLPggZdhtjab|v=l>%3Q ze~7MgQEFnz#2E?`Cpd}dhNLFu0>yn2^U_Nb(^IV!3Q8smFq$%lhPX}kU^LV!s7y~S xDM_s;(JQD_Fw`^UiqLgW%}XsxEXgmjQV7UTP01`#Fw!&7Gn)8Ji`kls0RRi%DG&ev diff --git a/doc/locales/pt/lc_messages/twblue-changelog.po b/doc/locales/pt/lc_messages/twblue-changelog.po index 44f69c6f..d8bab64b 100644 --- a/doc/locales/pt/lc_messages/twblue-changelog.po +++ b/doc/locales/pt/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2017-12-11 11:08-0600\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/doc/locales/pt/lc_messages/twblue-documentation.mo b/doc/locales/pt/lc_messages/twblue-documentation.mo index 53f3ddc702f99efcb7f1479a60271230d18ef0b4..526e4126faa16af289b88db8764d37aa5876fdc9 100644 GIT binary patch delta 167 zcmZ3%a*|o+o)F7a1|VPrVi_P-0dbIk4v;+?D5(piCk7cP2c;I|7nSJx7N=*X=sK0A z7wd-PTPe8uI(qszIJ&q5xdsPMY!nx=)HN{HH8fW+G`2D}(KY~riN~_VtrQAM;+=xH yd=m50OB2&mbwg4UbFCC6-(l38?7?WtTw0Pgxq;D;*C{b6HAlfn&r;8jiva)wekURT delta 255 zcmX@fyn-d@o)F7a1|VPpVi_RT0b*7lwgF-g2moS6APxlLOF%|2l&=QV01^iQkX|_8 zny6ziu|aI&K5k_r6K#+DqC|z%;*!G)^HLIv6p~Z(N{SM56f}GfudK*S&exo{B3oQH zBsDSDN`cEKF)zI|F+J5vp`aw*DQI#qqbYM}h}-0DMnmm_%JkHdlGKV4y@E;wLp@Wj z2wnHoywsw^lKdhog@F9jl*|&KxS5`z;bbjFO=WAK0*I(?aDHh~a;kGiVo`BwiIoD- LL|qFm1}+8wr\n" "Language-Team: \n" diff --git a/doc/locales/pt/manual.md b/doc/locales/pt/manual.md deleted file mode 100644 index a3703c37..00000000 --- a/doc/locales/pt/manual.md +++ /dev/null @@ -1,285 +0,0 @@ -% Documentação do TW Blue 0.42 - -# Versão 0.42 (alpha) - -# ¡Perigro! - -Você está lendo um documento gerado para uma aplicação em fase de desenvolvimento. A intenção deste manual é esclarecer alguns detalhes sobre o funcionamento do programa. Note-se que sendo desenvolvido ativamente, o software pode mudar um pouco em relação a esta documentação num futuro próximo. Por isso é aconselhável dar uma olhada de vez em quando para não se perder muito. - -Si quieres ver lo que ha cambiado con respecto a la versión anterior, [lee la lista de novedades aquí.](changes.html) - -# TW Blue - -TW Blue é um aplicativo para utilizar o Twitter de forma simples e rápida, além de evitar tanto quanto possível consumir demasiados recursos do computador. Com ele é possível realizar ações do Twitter, tais como: - -* Crear, responder, reenviar y eliminar Tuits, -* Marcar como favorito, eliminar de tus favoritos un tuit, -* Enviar y eliminar mensajes directos, -* Ver tus amigos y seguidores, -* Seguir, dejar de seguir, reportar como spam y bloquear a un usuario, -* Abrir una línea temporal para un usuario, lo que permite obtener todos los Tuits de ese usuario únicamente, -* Abrir direcciones URL cuando vayan en un tuit o mensaje directo, -* Reproducir varios tipos de archivos o direcciones que contengan audio. -* Y más. - -# Tabla de contenidos - -Para poder utilizar una aplicación como TW Blue que te permita gestionar una cuenta de Twitter, primero tienes que estar registrado en esta red social. Esta documentación no tiene como objetivo explicar el procedimiento para hacerlo. Partiremos desde el punto que tienes una cuenta con su respectivo nombre de usuario y contraseña. La documentación cubrirá estas secciones. - -* [Autorizar la aplicación](#autorizar) -* [La interfaz del programa](#interfaz) -* [Controles](#controles) - * [La interfaz gráfica (GUI)](#gui) - * [Botones de la aplicación](#botones) - * [Menús](#menus) - * [Menú aplicación](#app) - * [Menú Tuit](#tuit) - * [Menú Usuario](#usuario) - * [Menú buffer](#buffer) - * [Menú ayuda](#ayuda) - * [La interfaz No Visible](#interfaz_no_visible) - * [Atajos de Teclado para la Interfaz Gráfica](#atajos) - * [Atajos de Teclado para la Interfaz no Visible](#atajos_invisibles) -* [Listas](#listas) -* [Reportando Errores desde la web](#reportar) -* [Contacto](#contacto) - -## Autorizando la aplicación {#autorizar} - -Antes de nada, lo primero que se necesita es autorizar al programa para que este pueda acceder a tu cuenta de Twitter, y desde ella realizar lo que le pidas. El proceso de autorización es bastante sencillo, y en ningún momento el programa podrá tener acceso a tus datos como usuario y contraseña. Para autorizar la aplicación, solo tienes que abrir el archivo principal del programa, llamado TW Blue.exe (en algunos PC, solo se muestra como TW Blue). - -Al hacerlo, si no has configurado ninguna vez el programa, se mostrará un cuadro de diálogo donde te informa que serás llevado a Twitter para autorizar la aplicación una vez pulses sobre "aceptar". Para empezar con el proceso de autorización presiona sobre el único botón de ese diálogo. - -A continuación, tu navegador predeterminado se abrirá con la página de Twitter solicitándote autorizar la aplicación. Escribe, si no estás autenticado ya, tu nombre de usuario y contraseña, luego busca el botón autorizar, y presiónalo. - -De la página a la que serás redirigido (si el proceso ha tenido éxito), busca las instrucciones que te proporciona Twitter. En resumen, te dará un código numérico de varios dígitos que deberás pegar en un cuadro de texto que la aplicación ha abierto en otra ventana. - -Pega el código de verificación, y pulsa la tecla Intro. - -Si todo ha salido bien, la aplicación empezará a reproducir un grupo de sonidos en señal que se están actualizando tus datos. - -Cuando termine, el programa reproducirá otro sonido, y el lector de pantalla dirá "listo". - -## La interfaz del programa {#interfaz} - -La forma más simple de describir la interfaz gráfica de la aplicación es la de una ventana con una barra de menú con cinco menús (aplicación, tuit, usuario, buffer y ayuda); una lista de varios elementos y en la mayoría de los casos tres botones. Tuit, retuit y responder. Las acciones para cada uno de estos elementos serán descritas más adelante. - -Los elementos que hay en las listas pueden ser Tuits, mensajes directos o usuarios. TW Blue crea diferentes pestañas para cada lista, pues estos elementos pueden ser Tuits enviados, Tuits recividos en la línea principal, favoritos, o mensajes directos, y cada pestaña tiene un solo tipo de Tuit. Estas pestañas se llaman listas o buffers. - -Para cambiar entre las listas se hace presionando Control+Tab si se desea avanzar, y Control+Shift+Tab para retroceder. En todo momento los lectores de pantalla anunciarán la lista hacia la que se cambie el foco de la aplicación. Aquí están las listas básicas de TW Blue, que aparecen si se usa la configuración por defecto. - -* Principal: Aquí van todos los Tuits que se muestran en la línea principal. Estos son los Tuits de los usuarios a los que sigues. -* Menciones: Si un usuario (lo sigas o no) te menciona en Twitter, lo verás en esta lista. -* Mensajes directos: Aquí están los mensajes directos (privados) que intercambias con los usuarios que sigues y te siguen. Esta lista solo muestra los mensajes recividos. -* Enviados: En esta lista se muestran todos los Tuits y mensajes directos que se han enviado desde tu cuenta. -* Favoritos: Aquí verás los Tuits que has marcado como favoritos. -* Seguidores: Cuando los usuarios sigan tu cuenta, podrás verlos en esta lista, junto con un poco de información de la cuenta. -* Amigos: Igual que la lista anterior, pero estos usuarios son a los que tú sigues. -* Eventos: Un evento en TW Blue es "algo" que pase en Twitter. En la línea de eventos, podrás ver registrados los eventos más comunes (p. Ej. Te han comenzado a seguir, han marcado o removido un tweet tuyo de los favoritos, te has suscrito a una lista). Son como pequeñas notificaciones que envía Twitter y TW Blue organiza para que no te pierdas lo que ha pasado con tu cuenta. -* Línea temporal de un usuario: Estas son listas que tú deberás crear. Es una lista que contiene únicamente los Tuits de un usuario. Se usan si algún día necesitas o quieres ver los Tuits que ha realizado solo una persona y no deseas buscar por todo tu timeline. Puedes crear tantas como usuarios necesites. -* Lista: Una lista es parecida a una línea temporal, pero compuesta por los tweets de cada usuario que forme parte de ella. De momento las listas son una característica experimental de TW Blue. Si experimentas problemas con ellas, por favor escríbenos para contárnoslo. -* Búsqueda: Un buffer de búsqueda contiene los resultados de una búsqueda hecha en TW Blue. Las búsquedas pueden ser por tuits, en cuyo caso buscas un término en los tuits relevantes de Twitter, o por usuarios, donde los resultados son nombres de usuario de Twitter. -* Favoritos de un usuario: Es posible pedirle a TW Blue que te muestre los tuits que un usuario ha marcado como favoritos. - -Nota: Únicamente para esta versión de TW Blue, los amigos y seguidores actualizarán hasta 400, o cerca a los 400. En la próxima versión proporcionaremos un método para ver los amigos y seguidores sin exponerse tanto a los errores causados por el uso de la API de Twitter, muy frecuente entre personas con más de 600 amigos o seguidores. - -Ten en cuenta que por defecto la configuración solo permite obtener los 200 últimos Tuits para las listas principal, menciones, mensajes directos y líneas temporales. Esto puedes cambiarlo desde el diálogo de configuración. Para los enviados se obtendrán los últimos 200 Tuits y 200 mensajes directos. En versiones futuras se permitirá ajustar este parámetro. - -Si hay una dirección URL en algún tuit, TW Blue intentará abrirla cuando presiones Intro sobre ella. Si hay más de una, te mostrará una lista con todas para que selecciones la que quieras abrir. Si estás en el cuadro de diálogo de los amigos o seguidores, la tecla intro te mostrará detalles del mismo. - -Si pulsas Control+Intro, TW Blue intentará reproducir el audio que tenga el tuit sobre el que está el foco del sistema, siempre que tenga una URL. Si el tuit lleva la etiqueta #audio, un sonido al pasar por él te alertará que es un audio y puedes intentar reproducirlo. No obstante, también puede que no esté etiquetado y que TW Blue pueda reproducirlo, siempre que lleve a una dirección URL donde exista audio. - -## Controles {#controles} - -A partir de la versión 0.36, existe soporte para una interfaz que no requiere de una ventana visible. Esta puede ser activada pulsando Control+m, o seleccionando desde el menú aplicación la opción "Esconder ventana". Esta interfaz se maneja completamente con atajos de teclado. Estos atajos son diferentes a los que se utilizan para la interfaz gráfica. Cada una de ellas podrá utilizar solo los atajos que le correspondan, lo que quiere decir que no se permitirá utilizar los atajos de la interfaz no visible si se tiene activada la interfaz gráfica. En esta sección se detallará tanto la interfaz gráfica como la no visible. - -### Interfaz gráfica (GUI) {#gui} - -Aquí una lista dividida en dos partes. Por un lado, los botones que encontrarás si presionas Tab o Shift+Tab en la interfaz del programa, y por otro, los diferentes elementos que hay en la barra de menú. - -#### Botones de la aplicación {#botones} - -* Twit: Este botón abre el diálogo para escribir un tuit. El mensaje solo debe tener 140 caracteres. Al escribir el caracter número 141, un sonido será reproducido para indicarte que te has pasado del límite permitido por Twitter. Puedes querer acortar o desacortar una URL si la incluye tu tuit a fin de ganar más espacio donde escribir, para eso están los botones con esos nombres. Pulsa Intro para enviar el tuit. Si todo sale bien, el mensaje se enviará y tú escucharás un sonido que te lo confirme, si no, el lector de pantalla te responderá con un error en inglés, que indica por qué no se ha podido enviar el mensaje. -* Retuit: Este botón se encarga de reenviar el tuit sobre el que estás leyendo. Al presionarlo se te preguntará si deseas añadirle un comentario al tuit original (citándolo) o simplemente enviarlo como se ha escrito sin añadir nada más. -* Responder: Cuando estés visualizando un Tuit, puedes responderle al usuario que lo escribió pulsando sobre este botón. Se abrirá el mismo diálogo de Tuit, pero con el nombre del usuario (por ejemplo @usuario) en el, para que solo escribas el mensaje que quieres responderle. Si en el tuit hay más de un usuario mencionado, pulsa Shift+Tab y pulsa el botón "Mencionar a todos los usuarios". Cuando estés en la lista de amigos o seguidores, este botón se llamará mencionar. -* mensaje directo: Exactamente igual que enviar un Tuit, pero es un mensaje privado que solo podrá ver el usuario al que se lo envías. Pulsa Shift+Tab para ver el destinatario de tu mensaje. Si en el Tuit donde estabas para enviar el mensaje había más de un usuario mencionado, puedes navegar con las flechas de arriba y abajo para seleccionar otro, o escribir tú mismo el usuario (sin el signo de arroba). - -Ten en cuenta que los botones aparecerán según las acciones que se puedan hacer en la lista donde estés. Por ejemplo, en la línea principal, menciones, enviados, favoritos y las líneas temporales de los usuarios podrás ver los cuatro botones; mientras que en la lista de mensajes directos solo estará disponible el botón de "Mensaje Directo" y "tuit", y en las listas de amigos y seguidores, se verá el botón para "Twit" y el de "Mensaje directo" junto a "mencionar". - -#### Menús {#menus} - -En la parte superior de la ventana del programa podrás encontrar una barra de menú que hace las mismas cosas, y algunas cuantas más. A la barra de menú se accede presionando la tecla ALT, y cuenta en este momento con cuatro menús para diferentes acciones: Aplicación, Tuit, usuario y Ayuda. En esta sección se describen las acciones para cada uno de ellos. - -##### Menú aplicación {#app} - -* Actualizar Perfil: Abre un diálogo desde donde se podrá actualizar parte de tu información en Twitter. Nombre, ubicación, dirección URL y descripción. Si ya tienes alguno de estos campos actualmente en el perfil se llenarán automáticamente con lo que tiene tu configuración de Twitter. También podrás subir una foto a tu perfil. -* Esconder Ventana: Desactiva la interfaz gráfica. Lee el apartado sobre la interfaz no visible para más detalles sobre este comportamiento. -* Búsqueda: Muestra un cuadro de diálogo desde donde puedes buscar por tuits o por usuarios en twitter. -* Gestor de listas: Para poder utilizar las listas de Twitter, primero necesitarás crearlas. Este diálogo permite ver tus listas, editarlas, crearlas, borrarlas y, opcionalmente, verlas en buffers tal como lo harías con las líneas temporales. -* Tutorial de sonidos: Abre un diálogo donde verás una lista de los sonidos de TW blue, para que puedas aprenderlos y no te cueste trabajo familiarizarte con TW Blue. -* Preferencias: Abre un diálogo de configuración desde donde se pueden controlar algunos aspectos del programa. Las opciones no necesitan de explicación. -* Salir: pregunta si quieres salir o no del programa. Si la respuesta es que sí, cierra la aplicación. - -##### Menú Tuit {#tuit} - -* Las primeras opciones del menú son Twit, responder y retuit, que corresponden a los botones del mismo nombre. -* Marcar como favorito: Marca el tuit que estés viendo como favorito. -* Quitar tuit de favoritos: Elimina el tuit de tus favoritos. Esto no significa que se borra de Twitter, solo deja de estar en tu lista de favoritos. -* Ver Tuit: Abre un diálogo donde puedes ver el Tuit, mensaje directo, amigo o seguidor sobre el que esté el foco de la aplicación. Puedes leer el texto con los cursores. El diálogo es el mismo que el que se usa para escribir un Tuit. -* Eliminar: Elimina el Tuit o mensaje directo sobre el que estés, borrándolo definitivamente de Twitter y qitándolo de tus listas. Ten en cuenta que en el caso de los Tuits, Twitter solo permite borrar los que tú mismo has escrito. - -##### Menú usuario {#usuario} - -Ten en cuenta que las primeras seis opciones de este menú abren un mismo diálogo. Este diálogo tiene un cuadro de edición donde puedes seleccionar el usuario sobre el que deseas actuar, bien con los cursores arriba y abajo o escribiendo tú mismo el nombre. Después, hay un grupo de botones de radio para seguir, dejar de seguir, silenciar, des-silenciar, reportar como Spam y bloquear. Si seleccionas desde el menú la opción seguir, el botón del cuadro de diálogo estará marcado con esa opción, así como sucederá respectivamente con dejar de seguir, reportar como Spam y bloquear. Pulsa el botón Aceptar para que el programa trate de hacer lo que le pides. Si no se ha podido, escucharás el error en inglés. - -A continuación se describen las opciones restantes para este menú: - -* Mensaje Directo: La misma acción que el botón. -* Añadir a lista: Para que puedas ver los tweets de un usuario en tus listas, primero hay que añadirlo. Esta opción abrirá un diálogo desde donde puedes seleccionar al usuario que deseas añadir, para después abrir otra ventana donde puedes seleccionar la lista a la cual añadir a ese usuario. Una vez hecho esto, la lista contendrá un nuevo usuario y podrás ver sus tweets. -* Ver Perfil del usuario: Abre un diálogo desde donde te permite seleccionar el usuario al que quieres ver el perfil. -* Línea temporal: Abre un diálogo desde donde puedes seleccionar el usuario para el que se creará la línea temporal. Al presionar intro, se creará. Si se hace una línea temporal de un usuario que no tenga Tuits, el programa fallará. Si se crea una línea que ya existe el programa te avisará y no permitirá crearla de nuevo. -* Ver favoritos: Abre un buffer para seguir los favoritos que marca el usuario seleccionado. - -##### Menú Buffer {#buffer} - -* Silenciar: Silencia completamente el buffer, con lo que no escucharás sonido alguno cuando nuevos elementos aparezcan. -* Leer automáticamente tuits para este buffer: Esta opción activa o desactiva la lectura automática de tuits. Si está activada, el lector de pantalla o la voz Sapi5 (si está activada una) leerá automáticamente los nuevos tuits conforme estos vayan llegando al buffer. -* Limpiar Buffer: Vacía los elementos de este buffer. -* Eliminar buffer: Borra la lista sobre la que te encuentras actualmente. - -##### Menú Ayuda {#ayuda} - -* Documentación: Abre este archivo, donde puedes leer algunos conceptos interesantes del programa. -* ¿Qué hay de nuevo en esta versión?: Abre un documento con la lista de cambios desde la versión actual, hasta la primera en existencia. -* Buscar actualizaciones: Cada que se abre el programa él mismo busca automáticamente si hay una nueva versión. Si lo hay, te preguntará si quieres descargarla; si aceptas, TW Blue descargará la actualización, la instalará y te pedirá reiniciarla (algo que hace automáticamente). Esta opción comprueba si hay actualizaciones sin tener que reiniciar la aplicación. -* Sitio web de TW Blue. Ve a nuestra [página principal](http://twblue.com.mx) donde podrás encontrar toda la información y descargas relativas a TW Blue, así como participar de la comunidad. -* Reportar un error: Lanza un diálogo desde donde puedes reportar un error solo llenando un par de campos. El título y una pequeña descripción de lo que pasó. Al pulsar en "enviar" el error se reportará. Si no se ha podido el programa te mostrará un mensaje informándolo. -* Sobre TW Blue: Muestra información de créditos del programa. - -### Interfaz no visible {#interfaz_no_visible} - -Si presionas Control+M, o si desde el menú aplicación seleccionas esconder ventana, estarás activando una interfaz a la que no se podrá acceder por la manera convencional, porque no se ve. - -En la interfaz no visible todo lo que hagas será mediante atajos de teclado, incluso para recorrer las listas. Eventualmente se abrirán diálogos y estos sí serán visibles, pero la ventana principal de la aplicación no. Ve a la sección de atajos de teclado de la interfaz no visible para saber cuales puedes usar de momento. - -### Atajos de teclado para la Interfaz Gráfica {#atajos} - -Además de los botones y menús, la mayoría de las acciones pueden hacerse presionando una combinación de teclado. Aquí están las existentes en este momento: - -* Intro: Abrir una dirección URL. Si hay más de una podrás ver una lista que te permitirá seleccionar la que quieras. Si estás en la lista de amigos o seguidores, mostrará detalles del seleccionado. -* Control+Intro: Intenta reproducir un audio si en el Tuit hay una dirección URL. -* F5: Baja un 5% el volumen de los sonidos. Esto afecta a los sonidos que reproduce el programa y al audio que puedas escuchar a través de él. -* F6: Sube un 5% el volumen de los sonidos de la aplicación. -* Control+N: Abre el diálogo para escribir un nuevo Tuit. -* Control+M: Oculta la ventana. -* Control+Q: Sale de la aplicación. -* Control+R: Abre el diálogo para responder. -* Control+Shift+R: Equivalente a la acción Retuit. -* Control+D: Enviar mensaje directo. -* Control+F: Marcar como favorito. -* Control+Shift+F: Quitar de favoritos. -* Control+Shift+V: Ver Tuit. -* Control+S: Seguir a un usuario. -* Control+Shift+S: Dejar de seguir a un usuario. -* Control+K: Bloquear a un usuario. -* Control+Shift+K: Reportar como Spam. -* Control+I: Abrir línea temporal a un usuario. -* Control+Shift+I: Eliminar línea temporal. -* Control+p: Editar tu perfil. -* Suprimir: Eliminar tuit o mensaje directo. -* Shift+suprimir: vacía el buffer, quitando todos los elementos hasta ese entonces. Esto ocurre sin borrar nada de Twitter. - -### Atajos de teclado para la Interfaz no Visible {#atajos_invisibles} - -Estos son los atajos de teclado que puedes usar desde la interfaz no visible. Ten en cuenta que cuando la vista de la interfaz gráfica esté activada ninguno de ellos podrá usarse. Al decir "windows", nos estamos refiriendo a la tecla de Windows izquierda. - -* Control+Windows+Flecha Arriba: Va arriba en la lista actual. -* Control+Windows+Flecha abajo: Va hacia abajo en la lista actual. -* Control+Windows+Izquierda: Se desplaza a la pestaña de la izquierda. -* Control+Windows+Derecha: Se desplaza hacia la pestaña de la derecha. -* Control+Windows+Inicio: Ir al primer elemento de la lista. -* Control+Windows+Fin: Ir al final de la lista. -* Control+Windows+Avance de página: Ir 20 elementos hacia abajo en la lista actual. -* Control+Windows+Retroceso de página: ir 20 elementos hacia arriba en la lista actual. -* Control+Windows+Alt+Flecha Arriba: Subir volumen un 5%. -* Control+Windows+Alt+Flecha Abajo: Bajar volumen un 5%. -* Control+Windows+Intro: Abrir URL en el tuit, o ver detalles del usuario si estás en la lista de amigos o seguidores. -* Control+Windows+Alt+Intro: Intentar reproducir un audio. -* Control+Windows+M: Muestra la interfaz gráfica, desactivando la no visible. -* Control+Windows+N: Hacer un nuevo Tuit. -* Control+Windows+R: Responder a un tuit. -* Control+Windows+Shift+R: Hacer un retuit. -* Control+Windows+D: Enviar un mensaje directo. -* Control+Windows+Suprimir: Eliminar un tuit o mensaje directo. -* control+win+Shift+suprimir: vacía el buffer, quitando todos los elementos hasta ese entonces. Esto ocurre sin borrar nada de Twitter. -* Windows+Alt+F: Marcar como favorito. -* Windows+Alt+Shift+F: Quitar de favoritos. -* Control+Windows+S: Seguir a un usuario. -* Control+Windows+Shift+S: Dejar de seguir a alguien. -* Control+Windows+Alt+N: Ver detalles de un usuario, -* Control+Windows+V: Ver tuit en un cuadro de texto. -* Control+Windows+I: Abrir línea temporal. -* Control+Windows+Shift+I: Eliminar línea temporal de un usuario. -* Alt+Windows+P: Editar tu perfil. -* Control+win+espacio: ver tweet actual. -* Control+win+c: Copiar tweet al portapapeles. -* Control+windows+a: Añadir a un usuario a la lista. -* Control+shift+windows+a: qitar de la lista. -* Control+Windows+Shift+Flecha arriba: Ir un tuit hacia arriba en la conversación. -* Control+Windows+Flecha Abajo: Ir un tuit hacia abajo en la conversación. -* Control+Windows+Shift+M: Activar o desactivar el sonido para el buffer actual. -* Windows+Alt+M: Activar o desactivar el silencio global de TW Blue. -* Control+Windows+E: Activar o desactivar la lectura automática de los tuits en el buffer actual. -* Control+windows+Guion: buscar en Twitter. -* Control+Windows+F4: Cerrar el programa. - -## Listas {#listas} - -Una de las características más interesantes de Twitter son las listas, ya que son una manera de mantenerse actualizado sin tener que leer los tweets de todos los usuarios a los que sigues. Con una lista de Twitter solo verás los tweets de sus miembros (la gente que está dentro de la lista). Es parecido a una línea temporal, pero para muchos más usuarios. - -En TW blue hemos empezado a dar soporte para esta característica. De momento vamos poco a poco, pero ya es posible usar esta función. Te presentamos los pasos que hay que dar para poder tener una lista abierta en TW Blue. - -* Primero necesitarás ir al gestor de listas, ubicado bajo el menú aplicación. -* en el gestor de listas podrás ver todas las listas a las que estás unido, empezando por las que tú has creado. Si no ves ninguna lista en este diálogo, significa que no has creado ni te has unido a ninguna lista. Está bien. -* Verás un grupo de botones que se explican por sí solos: Crear nueva lista, editar, eliminar, abrir en buffer (este quizá es el menos claro, se refiere a abrir un nuevo buffer para que TW Blue actualice los tweets de la lista, como cuando pasa con las líneas temporales). - -Una vez que hayas creado una nueva lista, no deberías abrirla en buffer. Al menos no de inmediato, porque en este momento no tiene miembro alguno y eso significa que cuando se carguen los tweets para empezar a actualizarla no verás nada. Es recomendable primero añadir a gente a la lista, tal como sigue: - -* Cuando hayas cerrado el gestor de listas y estés navegando por entre los tweets de los usuarios, busca el usuario al que quieres añadir a la lista. -* Una vez encontrado, presiona el atajo Ctrl+Win+A o ve al menú usuario y selecciona la opción "Añadir a lista". -* Lo siguiente que verás es un diálogo que te permitirá seleccionar el usuario, asegúrate que el que está como predeterminado es el que deseas, o cámbialo si es necesario, y presiona Aceptar. -* Ahora verás otro diálogo, pero aquí están todas tus listas. Selecciona una (simplemente lleva el cursor hacia ella), y presiona el botón añadir. -* Para qitar a un usuario de una lista repite el mismo proceso, pero presiona Control+Win+Shift+A o selecciona la opción "Quitar de lista", y en el diálogo de las listas presiona sobre el botón "remover". - -## Reportando Errores Desde la Web {#reportar} - -Nota: Si estás usando el programa también puedes reportar un error desde el mismo, usando para ello la opción del menú ayuda. Este proceso solo te pide llenar dos cuadros de edición, y se encarga del resto. Estos pasos están escritos para quienes no pueden abrir el programa, no lo tienen en uso en este momento o sencillamente quieran reportar desde la web en lugar del sistema integrado de reporte de errores. - -Las cosas en este mundo (sí, incluidos los programas informáticos) están muy lejos de ser perfectas, con lo que a menudo te encontrarás con errores no previstos en la aplicación. Pero como la intención es siempre mejorar, eres libre (es más, sería genial que lo hicieras) de reportar los errores que vayas encontrando del programa para que se puedan revisar y eventualmente corregir. - -Para entrar a la web de reporte de incidencias, sigue [Este enlace.](http://twblue.com.mx/errores/bug_report_page.php) Es una web con un formulario donde tienes que llenar varios campos. Solo tres de ellos son realmente obligatorios (los que tienen marcado un asterisco), pero entre más campos puedas llenar, será mejor. - -Aquí están los diferentes campos del formulario y lo que deberías introducir en cada uno de ellos. Recuerda que son obligatorios solamente los campos marcados con un asterisco (*): - -* Categoría: Este cuadro combinado permite seleccionar a qué categoría asignar el error. Puede ser a la categoría General, si es un error del programa, o a documentación, si has encontrado un error en este archivo o en la lista de cambios. Este campo es obligatorio. -* Reproducibilidad: Aquí deberías indicar qué tan fácil o no es de reproducir el error. Las opciones disponibles son Desconocido, No reproducible, No se ha intentado (por defecto), aleatorio, a veces o siempre. Dependiendo de si se puede reproducir el error o no, deberías indicar lo que se parezca más a tu caso. Si estás solicitando una nueva funcionalidad, no importa este cuadro combinado. -* Severidad: Aquí se selecciona que tanto afecta esto al programa. Las opciones disponibles son funcionalidad (selecciona esto para solicitar una nueva funcionalidad), Trivial, Texto, Ajuste, Menor, Mayor, fallo o bloqueo. Nota que las opciones aumentan de nivel. Selecciona lo que más creas. Si no estás seguro de que seleccionar puedes dejarlo como está. -* Prioridad: En este cuadro se selecciona la opción de acuerdo con la importancia del error o funcionalidad solicitada. Las opciones disponibles son Ninguna, baja, normal, alta, hurgente e inmediata. -* Seleccionar Perfil: Aquí puedes escojer entre la configuración de arquitectura (32 o 64 bits), y el sistema operativo (Windows siete de momento). Si no, puedes llenar los tres cuadros de edición que están en la siguiente tabla con tus datos en específico. -* Versión del producto: Selecciona la versión del programa que estás utilizando para poder averiguar donde se ha generado el error. Este cuadro combinado tendrá la lista de las versiones en orden. Si bien no es obligatorio, ayudaría mucho a resolver más rápidamente el error. -* Resumen: Un título para el error, que explique en pocas palabras qué ocurre. Es un cuadro de texto obligatorio. -* Descripción: Este campo también obligatorio, te pide que describas con más detalles qué fue lo que ha ocurrido con el programa. -* Pasos para reproducir: Este campo de texto te sirve si sabes como hacer que la aplicación genere el error. Esto no es obligatorio, pero ayudaría mucho conocer como hacer que el programa tenga este error para rastrearlo mejor. -* Información adicional: Si tienes un comentario o nota que añadir, aquí puede ir. No es obligatorio. -* Subir archivo: Puedes subir aquí el archivo TW Blue.exe.log que se creó con el error que el programa tuvo. No es obligatorio. -* Visibilidad: Selecciona si quieres que el error sea público o privado. Por defecto es público, y es recomendable que así continúe. -* Enviar reporte. Presiona aquí para publicar el error y que este sea atendido. - -Muchas gracias por participar reportando errores y probando las funciones nuevas. - -## Contacto {#contacto} - -Si lo que se expone en este documento no es suficiente, si deseas colaborar de alguna otra forma o si simplemente deseas mantenerte en contacto con quien hace esta aplicación, sigue a la cuenta [@tw_blue2](https://twitter.com/tw_blue2) o a [@manuelcortez00.](https://twitter.com/manuelcortez00) También puedes visitar nuestro [Sitio web](http://twblue.com.mx) - ---- -Copyright © 2013-2014. Manuel Cortéz. \ No newline at end of file diff --git a/doc/locales/ro/LC_MESSAGES/twblue-changelog.mo b/doc/locales/ro/LC_MESSAGES/twblue-changelog.mo index 4fc2e2acc33a12625d597d31be7df4260c5c9e90..cb94a33d3fe4c83c792152b287953ae3bc106c38 100644 GIT binary patch delta 2334 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\n" "Language-Team: \n" diff --git a/doc/locales/ro/LC_MESSAGES/twblue-documentation.mo b/doc/locales/ro/LC_MESSAGES/twblue-documentation.mo index ceb4a89bd43c491ac87c9b787cc22a7425083709..c55a7dd5ecd6dd1825704f310ecf1da0d1a2294a 100644 GIT binary patch delta 4320 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 delta 5763 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\n" "Language-Team: Spanish \n" diff --git a/doc/locales/ru/lc_messages/twblue-changelog.mo b/doc/locales/ru/lc_messages/twblue-changelog.mo index f84dcfa36b9ab8b640460dac9001aeb423d9e099..722647bb8e7e791739959289d6df28615116eae0 100644 GIT binary patch delta 2483 zcmYM$dr;I>6u|Mb3uPjT;xo-!Q#Qq2k_AGxG(i-3DK9D0%mvr=!774esJNKV6nwNk zK^dX2e5A>mnKsRshD2$pHR(7($YUlo4(h(GwlrX`JMZ_dmrbX-*0KYYrJsH z=xGTJ+$4O~@%I#e8v|AJ|0lS;$O^)a7=s(pgUwinDM2DOY{OL|=a29E?b1?;zEHP{coMzw%eRO3WFEwUZAVjjjkBT}Sd^fQ zev1XqicB`Jd-DG(@zwz%X?O>7ad;T%<^CqzP26M_c^QjHYXUZ41m43JZ~*E33?~j` zANgE#AEZ}Yij~C2aR`oMTO+X?>+vMACYd={r@R8)#DAgMX`Y2e;3*{Q^14-IH5Mat z%fDEQW>zy1n|1zy7b>}+}@g+^Rq<6Lnvd5^&dxCU*}dV()7 zp7;i;2?o+hEod3e#NKSb6_;ZU&h^BK9Oj}C=VRGWouYfl@rZ?rGhrI`K)2sz*ps*# zGtr0R@iDu|O`M2o+>tLb8UBsOv7FLZ8A%w%Ced@63+58XaFM%Mg~?dS0lM)gRMk6b zgx>L5G+BaW=tH&ONY1kqld)LU@d+*#(-4~|5`c%X zD;~uS29Yy(l6cB!U6f(!d}yylBi6CHS7@qd)$52KVlHuIs(vc2A*UfBX(EF$5h)`n ze58jI`WqTib-d$`&FQ*hCaUUPgzElYT!vRs6{&M9i)G@?s4|h6!4pLsz`1nBkSzUJ zo3hC!_mAK#Tu%Y)@X+A_7t?5{V%arlU^|Qf9QowMT4shBOak9bpO;sTx}o;07q=@;=9X{X<5DvXnr zvkNIe%v_{@8_pv`%P=a^LjV0`^lGNz5*1j1yNFL=RJnc+{DZfMM>0wID2Q#Cyr+^`pl^ z_N~#+v58f+aQ}%)9x1%JmegVU^}0q5Z_w@S-sKTyz(HOL6xZPU7`svAS2YnfU?Xp% zi+sOyvpxb(_Ez3Xq)aXU1oWvU?RW*F(YBrRqYKUWiQmh919phKM|(J)$1_;M1a(w$ z8TQ)A?+ERiYsn7r$~yf9yu_D+44l#_miYl4&ed}^bXc%UpIIx7y@}l)>Iqiu*1ujB zDu^dd)?pd8pnBXUvF)40)2XbFF@tj`LBoFi|G|7z8^|H=f%IR9x7EKq<@7$vjadiv z3&>2Kti<6BzOlih4Zb~{;)eQilO`C$OhH-B!Z}6rtm(zB8B?tZC9Yy?&K$dGRC;`J z+KBkX#H>--+1>-mJwxNHL!zvav8Ko z-Q~@dKPO(glNi3OZ;KT5F*hhDDE?#jh&d=lQ(#14Ph5E&!IG4n^Fw?1ug#E;wR<$YHn@?tx>Kh#y{tx}V&E^Z_rxWOxtqFAong4&*`I zPd$7A-htsoWVW#&0bKwc&>AfAYj_bJgS&=^tb|Vv6?q4~4HqVeLzjOlP@Dt?b5vxb6`un9V$FU@#-8P;R>q4h|32u^`l zq26@;A2Bn$0CmVefR%6tjrB}VL%q8PW{9w=asoaF--Y-trJ2O-0GXOhk*DAw;`cFJ z18bn?G2_U`uns#bi*Pct^Dv720p9P0&7;lfC>bNN1-lOF0eX!UnFJ?7-G43A4qbrR8h`65f8V(09oz7CdQCokZVf(?*K$jF5vydrDi z3V02!gC)fMhwv&q1w+r6t3AVEF1ougtT#(LC*fd#r=Ye!beYYUV-dPUkw$oc^5f+= zNW0Ps6VgxIW)pqNRz6RC6W)FVmwQBRKqnjKFEH0j$YHY2d^1`gt0u{Q;(wFOQoqP= zVd=9X_c1_vz}$3MReX>rzX5ee^+A@4`l=8!hYd?b{z>_tmT{+J|6w^Z$Kh#&VHf50 zDieu{)#kX~hWluDb`5)qb_;4)fBwZ$OZebT$fU$c{P0QMg{izSo`t-Gy<~&A2S#n= z=wbgHvTtR}CQbsp3_H;N^!Ml-`hP zYnif@%LQ(LZ$J<6TR=yBx0{f!XfUT_+zxZTkHG8H?~ZWW!DTy%9NhB*vq$oGoAO=I zL4POrh`a{FeQ@g_nTzm4J<#*!&M)B$@q0RGx7RGe`}_C|6SD35nKkWRJ0QXV5#Nhu zx1Wd8vG2m6Fz-i(o;V|re`(=y87^edPy)fve2FkH(5o+td_u+0S4C!H_dH~7#wCYE zlCbCE?km(UVng_`lZfA1?3F*kG33d)nQGwlo_Yi8 ziKL)Wh^-+LQESSJXU4;DG7mOm?1zIc@1`H$NK>%chq4r{M8i-e(rGMu2I;-fn%a_? zgE*D3Z-g%YHsaXFzM`|>bEtO;%LV{RN7Xk zA9@gFpj@QWWHcd``||NPSr1x>#)aq73t(cWxaWHLJy$MNGE-4o{r_rEvU20<8~3eAI(IC zD1frjJfzc5)C(1BBc9etV^X{Pgwe$nma4M6LFIA>EN4(vT2)n!a;r)$3YC>v0af83 zYgt|uuqu5^Emyjlf;Z{j<@S~< z$2Z1ERn@+bTIQy|3d<3ozRDN!(qEYh;#J&}FFlC4=@0n)R=`u8suoQM1!E1r?z!pE z>kHzxa=2VL81%*3#b@O9R$4B%BWN||CrugSwwy~A`If6PUx10Y+)hVO`?}1+g@7ua zJJ}PmOqXu2(-U%8%35j#s`Z4Kw}Y_wJ=Kbr88Ou~WZaO~SwY8)y{KBbtTIQ)6Ko7m zb|&T~70oP8n-Z`X#^+7T#f@y0IWl8R+DQIKtBgmpGsdPA`T_*YQjFyA`jnIP2{=4z z_;hQz+vyt-8JV}Lds?yOsLWPL(;VLN5G$6g0-?x9d0B1d6z4|<M(*V|3e8fBl2 z*4pQyHTDtvn0?A_vd`FOqFbUHBK;Suu(FRvx7eptbe;Vs4NgTH>@(@g-Vt4EHz`^- zM>px#7?hml?`U*$tc&L8HbuWp_BlOBv`%+KAB|+c{e`k1}j#U^}?51?Vwf*?g zY}^XB`qlE4;drajKKp+LOjY&?`xwKte0@@}mt(`@3&ZP9&)Us)BaUrh(nq4T(Yol` z=r%gQr?2$f+ss7|envme5v*;z(HyOfBpmKBswuiT+Mws7r%EVv@S1hQ7J}7c98II{ wENvLH$v&-{H0~=bvl0$Q0{)>1D&pVSvwu7~#yv)gtqE;SmyQ2\n" "Language-Team: \n" diff --git a/doc/locales/ru/lc_messages/twblue-documentation.mo b/doc/locales/ru/lc_messages/twblue-documentation.mo index 0e690af5eebc5a51b477aca48dfc8421392cfe5d..f3e178bda86797f93f12a8cc86d82da1c5036c09 100644 GIT binary patch delta 4372 zcmYkDSMFUr&LkR(fSE6?0kLW&jd=PPCIg?Jn{QhISOm#ep6oe)uU~#VU-$zjqSh5pnSpX^kFD zc0-CtKWvX-$d6b&#UZ`8NG8Rz@-}wGQf!Gwu?>ES-SInA6+cE*VFLzXyUrpZ7=b-7 z2YX{Fn(z#&@;@Ly(!eiOpSu_1S3M5&(ho+UYG6LL!^|dEqYvpkROR=gs_0l#`Z5wE zsYNxyx~6>BE;`*A=aSzW12Gqq@rZ*9e?sm1ibxR|qrC|;=_-sT-H}#b#f7LMQGzS5 z3|FDAFVloOFcd?&iHtxS#!=4!98B8HB+f{O;84;@$SrXcap9axq)w?qe|(BPunWJG zq5M)IOTw1A)X#IT=-`GEh~#7ga@7I1wif(Ge*^HS!Bh z>253x6|s1;$Hl^mAnPBq@=y2J>ISg<2dJXX_A+o1;gx8dU^#p&I!E zv|%eIj<#eqUcoB#!-~0j+g?BwVlOK@h5S?VSb(I*CF_pdpqK1$nL%&5tNribBEUuD zeSAW}i)s37{*sB!B;9ABUNprSB8z#@Z4rx)@-{p}dNV8P&ls1fx9=^?Cf$1}hZO!5 zw^4r1GOnrbS(eCO$S+~kg|sh$EY)#%7E`h98+sAhFq;RC<02{;zEZz__fWekXJ*0p zG9`sb@Z=zssVVI677Gz8@mI91VI5J=f=z5m(A}$>SOFyWw@x4Vy%wDSv4*JA!<_t#k&*6zK1U-&oOVZTwio zt{~sS@IN4ZqnP-6a*<8z?wF6hxEuZObM(M_H~{OBjUYW)v0j*oeK8l+a|f^!Ucgte z7Tcjm3DbyvI2|V<>sfY{5VCMCo{}*chwRWt?OGf`dLOEWA7XFxd{4hNM>d&&ZOMNV zO}GJlupHI%XPfd}cItPGKfXf#c=SfAgNv?QyRG91ytm= zS8uOO4gt;}`3l*2(s3X2iOW#sSE2=9VhCFH>-=0CPWlp##MU3{4voh+(&dj~s-37RtijRP=M&wLbev223tWc&2RXm72-OJcF$Tj9F#ycRb=ZJ!qvKP(9a~lE z0j$Sh^1sH(YX2Mm&~K$^R26-NYQ#RopDixgxCDR1OpHHFxbYmmgN>MnxkvOi_B^V~ zCn86NoJTd{;A485mSU264p-5>Bp%n_dN)vwVDJe&XFG5dY2VLu{v4c3`W!}M-;*pj zT#2FRa!Q9d3}=!qz^V8%PGqfwf36R(cfJt0)r`oYBc1}+&a%o~I8e@U#*?1;wexJ2 zwyZccC1cL(ZI+L3QSKF@w z;y;cH`xX7*ab*38%T@L;?!()dbBzN9XI&TRk8P{iHB>wt)d*v&^?SbzgGuMraNuzN z4Ax-(n|i-Dr?NkCKOT$m;%yawMzr8xBKNsW|6XsSDR)Kwz=OZyf613x{e|=keoy&J z_e8dG|KI~6#qG$4`oPM@1k$Cr78|f7S@ChqgcEjHd%-b^4_M-|@Ec4bZExVH<+*F9 z&Wja|P22Z>M27p0mt1V;qUMFjB+Pore;PcAACnGhW(dndYEj*M7gQ%h7>aZe-A?p_5MHRX-HQxPINY;f&w*N z4Chp=_cok=bY?Koxl}Nlm9&s@_py?6ba%tKE!}wIsB^%MTk$Byp{0l69KdcoL^{UL zkag7G!ryQn^&5K{eC9L%H`N6r?%B(5ez7d>Yls`^8T|~Qlaj>ejoMyWX2bc1$$q@X z{aaXr2YE%RMZ1yDnJhXOJWLOuVz}Y_>o`Azj!`a^zw1({?|GOZPbi-hZb&)p%d}C3 zbmB%M?nd_rLpJk3Tw)$;wWWlb1_uO&m;-{$fx)K0pwOTp0|NM0(6}|ZQ>baVy>*mzNt)f7 vmST=gu`UiZ6}T1J3bG1@HnZDO3n~f%+eBFBr7SWH9uzVt@X+?c_wN56)j#L@ delta 5783 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 ARR910 diff --git a/doc/locales/ru/lc_messages/twblue-documentation.po b/doc/locales/ru/lc_messages/twblue-documentation.po index c4660bdb..de56bbe5 100644 --- a/doc/locales/ru/lc_messages/twblue-documentation.po +++ b/doc/locales/ru/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue documentation 0.46\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-08-14 21:44+0400\n" "Last-Translator: Valeria \n" "Language-Team: \n" diff --git a/doc/locales/sr/lc_messages/twblue-changelog.mo b/doc/locales/sr/lc_messages/twblue-changelog.mo index 005347b963a986980a7acbb10c92b9a6885bbc72..d570b36f134ca3f0bc54014d102e200b782b5357 100644 GIT binary patch delta 3000 zcmYk;dsNS79Ki8Ua-7_9$+ggrT*9K<<&v&$xs{@jLViMJs!=XKmqjJS&vhP-!&);IhwbdRvvDSeW1EpP+xyw)_s9J6dOpwh`};o6^Ld`iF@HJLqcURuUSLlv@jYPaK96fLW zn*RJoe8w~mIXb>_ym;FYJ2lo9+c@m+Fapg7lhI6Q6PgeIg}2bHiAWN@z||PrR3sDc zU|BowTKn#u-Xbt!Qt57#8Tb$vnwT^t;0e5n9$iI_;!|9Ld-?cfbnh+_=fwU$rZJh0 zFdq&G7CNlPXySoAI9yI51z1Ga zt1^n!2AgBNgvLQS&Z0?WB1he<{BN|PCs!dE*P^)vf1=4mH%8lv8?iZd>aS;E5atnQ zAW0D!AaV`7aX-GrBe;iyGsRq^G5#XYun1S+_CY%1R-DLu;&}8T1JAIExXDm{j1Q5y z$jSgtGag4XVDK=JK%9qDuoUfBmrgU`JvbM8lRn#18hdHfU|z6DF=mHwGM%`$p&}EB zlfp!f;Tc?n8N)Tz&oG|2BPY}ov+)Z&h!%__iC>o7M>7h!* z$HcWqi>$(GGy|t{FygTD7zV*?+=cbWik!zoXi}auPPgh0G%KDlUgQbBLb5J*8TBQ$ ziV$HAQa_UXoBJ6RsXx4qOkM(6wn=RsnpB@dZ;WHMWL?%`8D2tj2p30-OvjU$h8~m1 z9&SYQ{qty69xz!8(IhnQRoQ4Prx6+>;*1xNnH4}@Rs<$Q= zhY>$Ob11#0>2=P*1H>+*jRP;mSc!L#VZAN8xBnnHg1eclnA2V0)`Hxt^ zgMfK@{aog2X&#Rw=s!mhFsZA{EUPgDO}}5N{*lQ-Q<~o)7f3q4uk~aenyqnOsHJ%h z?j&~O04!j9DW$Oi+oh|e_<(qDhVG^32U?m7u^au@u|2-S;b>W;1I)of;_q=cCNI{~ zTrX2gb228-e-E!>P!``mN~7r#t<4wlGI8M2|7x?ia&$SLlFSJW$4h8dZ2oFS<5V=I zxg3j#e_f%axnQNsX-`K7dvfBM zcjP6K1X*0DrP*blro0k4RuZ*e7kmw$nDagRfY#=5A8T#S!I8YUiCt#?(>H)dOFE9BS=kjd zFOE2@rTG*(6AvoZ(j0)zh-VjxCzzSTho=i9Qn(6O#Qc_NLR*?aSl( kI%lNMwjYc0YY>z$BXPc^SC4@`{OZ|XyIv@diLV~}FWGeNwg3PC delta 3977 zcmYk;2~btn8Nl&RY*fUEfM{KL1Q8KM9)c+1f*|4=MMQmI;sag~jX+pM#7B%vq9Piw z#x01NhAl3bWt_3o%}hvYY9)@QjdpA%)7XfUOiY)=rtSZG=hETKeEiOL@8#Zm&OPUY z$G5!R|FhS@q3*9mB*BLtw0{j2*^S?0EY|pn%)xgt2LFLBj2I%~#zS}-{rp6t@ooGF zzr=X#@D~}04>1G>1c;2nNvOwD1GtTLa;yW}Q7=4d<-f4})bf$#;GyQaaMTxCihAQq zcn7azKDGynyoAGsiB#e-EWn||MfUaK+;E1WH}D<7EMOV>aiRmm$glEtdcGScU>Z-E zgjJ|{GtR&pxEy^(a}8!;1D?lfOdcbWhrhv2oH$lw0X}lmDdd4OgP0BuwAswmeTUuT zQ-aO$(NBqNC3j&M*WW|^Gy}$o9Klq~#e3L_^Fx_M{056~?|6~z_!u?c%IH2s_X9fm zE#F}{Q!zH2x5Iqo+0uaerthLY;6L~}=5Wyo^okJ4#zrjGoau358D7WR*nw|OX4cRV zDRK>O;WK@B^qDClYdGL#7g>Utmd%(!{&$RK#7m+@TFBkJrH(v2Mr0o5BlnVaoQ9v_ zW%OqS=ioKe0Yq`K7Pnv&_KOoq(xJ!Ed4mI0s8bm{-HiM)=8=Dfn=y$G&AsI!>P-9< z598u^kwE+la!CG(d(l4Atf4E|Mg9dg;d=?J3tT&k!Rpj|&t{9D3u|yC!_zmuiTiQ% zTvj_X(1JI}KTZ@miH!`O!O5&7Rx_4h82%TzM8cAJ0On&ozK{CCYv+q>#IMo)fQ}6rQbP?Ylw_*j_7n`YW!S&?#FbEU*eizV*HuPW0*2Afmi*UG} z#}!z)l=)vp=XV^?MHRe^;(@=y9oYP|d2qyX77O|3xC;~c?c?|X{u*=A%#??&G@t4M z>WIhk_V=*^`HFI!hkc7TaUp(?!TeX#@mpwo*HrjD9^RM@>MjiQMti*sUb6u^Q&UOy;StrsLYmhA}J23#;@D`uq zm$;k!XFNq;Y|MJIYgXc1@^;L{hsc;D&1p(=7qW4rEZdakW{f8<$uT9^eU45D2R_76 z_|Q7x&D}ZqUWm>=>EOlGV~&hGFD;HktG1Q9n)K^QJVbSa}`ox_IVR_a>BdNY`-ql(mb-rtckrZn5p{&ySZ*~u{r)2Um{QD!)s~o z#ANbsN=-e9Ei<3yV{GMkbh#xR+&3{18{`Y#zjJyUbx!^U_3;oZT(!3k{l0R|YlxA-nN*;xL2~T^5pAM_9EGG1& z1BiJ9&+`0EAZmNjAe-ED*zTSY=rr|iKOxbn3L)ka+H`7ti6Mj^(T~v4*@&@3HnEFf z{R;2x`JZtV1`)adwe2(rOG@0#il;5%XBDB}`UOH~U=pEI-qV)S8AC8|Pt$4EHiytU z!J3qx68Xe-LK|OG_7JR3PxG>zjph3N6RiUYmdU8!eKql_b?lJkN@Tfs$}Ky}^UsB@ z>MWv=c$&y177$w4RuChIFZAOCp`5(s@KW!^y3L#aFhb+PiUJ(gcB*6^lH=TPbS{# zb*!iBV|5s#=TEur8g1-6&wp3@(LIhI3yJlF77jacig=z#Cr%LF1iQ-f4+wbvnB-s{ zkwGjY4ilxsK0@okMnc;Y#8bp`L=(|Wv=Gq*%`LC+a{v*esnu%GNt`5-h#ABpqNkmq z(@10zE@CRt)1I_CQ?P(oM@%Fti8NvxQ9%qMR>`G!pS#QI6C9z#QVWZnHdjgMZ<`8o zoyE4|!p+Wt99O-|k>7uEy34sa-d3NH8QXVNdP@C)OnXF8WuB|F)U~BFvZ&H#kBl9- zX7U18fvebAT38%!TVCkO%`fHnv`BkY{pXHS-* Gm;DcUv_I_t diff --git a/doc/locales/sr/lc_messages/twblue-changelog.po b/doc/locales/sr/lc_messages/twblue-changelog.po index da0030fe..16f1e60f 100644 --- a/doc/locales/sr/lc_messages/twblue-changelog.po +++ b/doc/locales/sr/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2021-06-27 04:17+0100\n" "Last-Translator: Nikola Jović \n" "Language-Team: \n" diff --git a/doc/locales/sr/lc_messages/twblue-documentation.mo b/doc/locales/sr/lc_messages/twblue-documentation.mo index 09645852b04bd260100df7375b7da4d000538db5..9f87c7285ba5d438ce4ceb295fc2bbc27f0aebe4 100644 GIT binary patch delta 4342 zcmYkDSMPb4~2k}%Z|D?=eb z%rUk~5wy081Ta!=#cn;Wle zZIi$JOLi9tC!UA_7LoOsPyCsO$Q=x8CGrjidWv+yeRv70aV+j^Ey69*$V;R-dOGw) zibz*p%_A(f?N_?2?q^xiPS08*ctC)M{LWF8pe;N zEE#*?Jk*MIppNL8gQ9-^J%K=s8ny25Lvw;z;}k8JTpYH+p^oMq(*y2e0xo0GoEB1GFzg zIncSw#o@Rc8Jyh5f#^e8^u{EN!ng4_o6IW4wZ6@oN^)Z0t_2 z24flWBuky~O?a(ESQ5_^+heM-DBAeF&-<>BhEZ-2k>R$S{#fa@g|e6;h)rh5c!h>%#%)` z^C(l!Hiv_?oH&G=F>y5eI6gqKClzDN<9HqSI?*7#VenEpPUI=NjAw1ofXhqln#3XW zq8>}}Hm;mtHmbQvOfT^RWcDN_nX(q%c#Qpd?<`uGzsAt*&o(g=p&@9?l-)8U(PHH)L7o!cNq#%=bbeP9q*? zC;x679J8C(?s;rMT!XFfKiCu>p%*&wXmrAM=!yfd4aT6>lY%WV2cN+LY=))S4mV>r zJc^O{qvqd_gTNBAi5Al+(_JEE$f2#7{(LdFEv|l z^g5G?1<3M|B8ScX$swKy2N zRG9bpG>jnLikID&W$ zCgAt@9QNC8&Zl61;_cW6uRG3r?=a=kP#au=n)1^ag^zF#M(i}1zJnba@fhzS|5{;) zUbV2x;babT-lvy%0d>S_A215sjD09~1TPc+`k|ToQ+wHnh;N}zS(AO{dteCW5Zf^p zo%WjykHnG0OZJohejLQ10$?A)j3KQ8A_n2qQM)Tw!d3E1;9USPNob%6er=53pfp~O#Y9K>+&{7DgZ zQJIhR=yuBVw8?3aT{JWdsZ;7dXY|Aet3=))etL#iEWUBpEIQXO%mCsri1RzK4r`EP z$f0xQvCKbj-Wj%a9K>_s0Y>1k3%np`U@^uKzx9>*R{Ik5dY_AC1o^m|*zFP@qIeYb z>G{Xkj+Ys_H)e5PHUspnAz{>;iIJF9+weNK$(vv7T~1Kbh|X&!72(CtiSaDfh=OW+1bF z36fXF5yVpmq~X`!@H3zN-zsx4L3Od!TeES*?p7p*oW+HT)%-4nES}M zABPd&!*a@pKV~=O{u@us8YyL^zRYzm@*nD?A2pVS?}u%T`Tp9+1@|VFhB>T6Cn_j% zwn!3|G_}ZRyyIeN_-Gu`+|uyg{s=3$&(GB&i@AOh=g{D&7M6zpbXK`pgu#o|!_x4* z;NFTt)^66w?40x&VTN35sx?11V{e_;v3dU1=3_Eu<;>0tiqFl=ni3S5pP3t!m=k7= zijNo`H#lPG&@oX73HGv8{*8O_&;HG-tkz-H+}X|JQeVl;PtD8-O3X-|8D_O#wddJ~ g+e4i4^QPJh?ZK{*sc9M6*4{lrdj#)IDGpxve=ud-Q~&?~ delta 5731 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 TA diff --git a/doc/locales/sr/lc_messages/twblue-documentation.po b/doc/locales/sr/lc_messages/twblue-documentation.po index 7c302577..af46ec53 100644 --- a/doc/locales/sr/lc_messages/twblue-documentation.po +++ b/doc/locales/sr/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estándar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2021-06-27 01:40+0100\n" "Last-Translator: Nikola Jović \n" "Language-Team: \n" diff --git a/doc/locales/tr/lc_messages/twblue-changelog.mo b/doc/locales/tr/lc_messages/twblue-changelog.mo index 784f3392fd7d0ea89e9e6854a2efbeb84f71869e..e99f49178362073c1e849a0cdfda7b963b9da837 100644 GIT binary patch delta 547 zcmYk&ze^io7zgmLF=?9^lUSqG*5T@?ypl`&LC(RNCWAE5ph3DQp7r&5rFwd~Oe$_7 zf;a@7bg-?69fG9AQP5GO|3N!dW1)2FT>J(d`ohEKzVE%y^TPWz{7djumr5a zd~kQ^6`kaP@y!(;{<_2 z<}*4#%@B~FNAx-G$8Ua2b0g3Iw9rLr(ha)Kfq&^I=9NZZi?)Y>U$ji$^8aoVpfh`( z0NtxM?B^1Tx6ig&3W H*Ms%9`V3;{ delta 756 zcmZwEPe>GD7{~G7rlqd#R{klipz&(Wva_--PEes{6h=au?LmSmU)IfS*R~PT4&Flg zL&6qxD3+`!J494;@|1s0(J2Td>S9Dem!Ny!X0JW)>}Q{MW}bQ9XEsuAdS|~h*WMMe zliWjoB=?dxL;Mi+o1|;lfJvOk1zf`f=4vDt@8d4~ga&`(Zp_qHYafgBT*v3EAKxNf zm1gyaKkr$%R41L~hJ*Fe5cPuwX%TU0WsgL*T1b;eNn8$PY3fr-*nbTnm=V*8jA5(X>O1E(hf8a=) zG|u(IJ0y>Kkx_oYMw-0Db$o$0I;zjRjOiWqSNz8NwZNSA;T-d)PY@hh^cR~Af;|Pn zyTrl8;l#m$`1k2r$jv0f5MM@2U+h=xDF}uq1{4GX4}veDFw+jAPOoP|Elrux?qq5- zk?JN>=`(%#DP#4IdxfmY7qc2J6)%|czI|-W9x^cGxkwaFeT3~mRxJNXvT8Bm59Y-$?{;dD|Fz|Ml`bjKU*F!E0x@8B{z}J RO<39Gr9ysrX{EBfq`xENfU*Dp diff --git a/doc/locales/tr/lc_messages/twblue-changelog.po b/doc/locales/tr/lc_messages/twblue-changelog.po index 34eb2b92..da26ff0d 100644 --- a/doc/locales/tr/lc_messages/twblue-changelog.po +++ b/doc/locales/tr/lc_messages/twblue-changelog.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2018-01-05 17:01+0300\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/doc/locales/tr/lc_messages/twblue-documentation.mo b/doc/locales/tr/lc_messages/twblue-documentation.mo index d2dfd9adbf9d661ec4b28b1c249068891a6f99a6..abe35fbd108e2ae78115271b5696e7964062bd14 100644 GIT binary patch delta 475 zcmYk%O(;ZB6bJA>ldmyf7);FKF&m|)_vVr2v0%&;nu%tnlvq4GuQ3?L8ygE*DH|UX zS(&n8%N|h@Wh2?xDcRXsNbw&wZry&JbI-l!+;{alu;pIGzcp3_)G!{WPP$0T=^Cx1 z8?=?~QH5U8Ci+2}sizp2q+N85=4k`B-2xo4rlkZpWB#rb*k-&@hE>ck;jIAn={h~; z1;Gl)EV#7+yn`=0u*1060aP>I<#a5?5oHNZXkqYkS{U$wO7xrhsN@3bXo8N=6dj~j zu73W64INc~4T5~-h6j&s;F%2%YVkYZN5M5xmyG0;7|a?=Vj`^y;b`wbq^CC&iiP8G>+n!Q?91qynM}`%AXOda&L~5TNTWVHKNTMSJ delta 646 zcmXxhPizcP9Ki8kyC|#OwYmf$`=|q&+3eVq-4S(IQ4ykIrGm@L_GP=(&TPhO(aZ*IhDruP2-o%eBS@}d%t~O{}rqjdxu2iP9GoQ6At5N z%;OK-j=ymyZr~_p`$ejF3J>Ef9>K@h!Z$dN!x@nSv>)M1_P*FE@{aLy10ql8ZwyFJ zW*J!BA@Us8@iiNsWkq}zj1P&hN4hzY5A+vtH~sNlA}p0_IEc5=B|d{L!TVUjS2%)S zaWDSGDJ&L5F5z6E$4j{IEdx)v;3ubiWa8l-k#F=T*yR#Dx=&;USMWRQOZ!C(^O=L2 z33ezW-85X~$U9At`_kCPm)z5E5BMMbXKA?-yH~oGxNtAolD5bcDTYw7G~D0df{IE( z)^7EE8Ei~mZF-H^XxoWG@4U7qP$w&X&8zS`t^8`>*GDf#u~ySYEt*(|k!qRH#(GX2 zyJD6)t>}32Aa}RuHI1GRRQ9qC+Y7qQF*Z(0`LWE6=7nS`@1N){w~e)C$(Fmz$}f*) zZ+a6Z(N5oGL0D>-!nE)9O%{7l6-aOA3Jnr AWB>pF diff --git a/doc/locales/tr/lc_messages/twblue-documentation.po b/doc/locales/tr/lc_messages/twblue-documentation.po index 5edfd06b..0d4c3d42 100644 --- a/doc/locales/tr/lc_messages/twblue-documentation.po +++ b/doc/locales/tr/lc_messages/twblue-documentation.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue documentation 0.46\n" -"POT-Creation-Date: 2019-03-17 13:34+Hora estndar romance\n" +"POT-Creation-Date: 2019-03-17 13:34\n" "PO-Revision-Date: 2019-02-03 17:01+0300\n" "Last-Translator: Manuel Cortéz \n" "Language-Team: \n" From 8b06437cadfda937317a16628bc1a0e357ebf553 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 2 Nov 2021 17:52:07 -0600 Subject: [PATCH 195/245] Started to update documentation --- doc/changelog.md | 2 +- doc/manual.md | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index aafc305d..bb3ddd2f 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -253,4 +253,4 @@ TWBlue Changelog * New followers and friends buffer for user timelines. --- -Copyright © 2014-2017, Manuel Cortez. \ No newline at end of file +Copyright © 2014-2021, Manuel Cortez. \ No newline at end of file diff --git a/doc/manual.md b/doc/manual.md index 57eb0cc0..8c41fd6c 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -1,4 +1,4 @@ -Documentation for TWBlue - 0.88 +Documentation for TWBlue ## Table of contents @@ -42,7 +42,7 @@ You can log into several Twitter accounts simultaneously. The program refers to Your default browser will open on the Twitter page to request authorisation. Enter your username and password into the appropriate edit fields if you're not already logged in, select the authorise button, and press it. -Once you've authorised your twitter account, the website will redirect you to a page which will notify you that TWBlue has been authorised successfully. Now you are able to close the page by pressing ALT+F4 which will return you to the Session Manager. On the session list, you will see a new item temporarily called "Authorised account x" -where x is a number. The session name will change once you open that session. +Once you've authorised your twitter account, the website will redirect you to a page which will notify you that TWBlue has been authorised successfully. On this page, you will be shown a code composed of several numbers that you must paste in the TWBlue authorization dialogue in order to allow the application to access your account. Once you have pasted the code in the corresponding text field, press enter to finish the account setup and go back to the session manager. On the session list, you will see a new item temporarily called "Authorised account x" -where x is a number. The session name will change once you open that session. To start running TWBlue, press the Ok button in the Session Manager dialogue. By default, the program starts all the configured sessions automatically, however, you can change this behavior. @@ -56,7 +56,7 @@ Before starting to describe TWBlue's usage, we'll explain some concepts that wil ### Buffer -A buffer is a list of items to manage the data which arrives from Twitter, after being processed by the application. When you configure a new session on TWBlue and start it, many buffers are created. Each of them may contain some of the items which this program works with: Tweets, direct messages, users, trends or events. According to the buffer you are focusing, you will be able to do different actions with these items. +A buffer is a list of items to manage the data which arrives from Twitter, after being processed by the application. When you configure a new session on TWBlue and start it, many buffers are created. Each of them may contain some of the items which this program works with: Tweets, direct messages, users, trends or. According to the buffer you are focusing, you will be able to do different actions with these items. The following is a description for every one of TWBlue's buffers and the kind of items they work with. @@ -69,17 +69,17 @@ The following is a description for every one of TWBlue's buffers and the kind of * Followers: when users follow you, you'll be able to see them on this buffer, with some of their account details. * Friends: the same as the previous buffer, but these are the users you follow. * User timelines: these are buffers you may create. They contain only the tweets by a specific user. They're used so you can see the tweets by a single person and you don't want to look all over your timeline. You may create as many as you like. -* Events: An event is anything that happens on Twitter, such as when someone follows you, when someone adds or removes one of your tweets from their likes list, or when you subscribe to a list. There are many more, but the program shows the most common ones in the events buffer so that you can easily keep track of what is happening on your account. * Lists: A list is similar to a user timeline, except that you can configure it to contain tweets from multiple users. * Search: A search buffer contains the results of a search operation. * User likes: You can have the program create a buffer containing tweets liked by a particular user. +* Followers or following timeline: You can have TWBlue create a buffer containing all users who follow, or are followed by a specific user. * Trending Topics: a trend buffer shows the top ten most used terms in a geographical region. This region may be a country or a city. Trends are updated every five minutes. -If a tweet contains a URL, you can press enter in the GUI or Control + Windows + Enter in the invisible interface to open it. If it contains audio, you can press Control + Enter or Control + Windows + Alt + Enter to play it, respectively. TWBlue will play a sound if the tweet contains the \#audio hashtag, but there may be tweets which contain audio without this. Finally, if a tweet contains geographical information, you can press Control + Windows + G in the invisible interface to retrieve it. +If a tweet contains a URL, you can press enter in the GUI or Control + Windows + Enter in the invisible interface to open it. If it contains video or audio, including live stream content, you can press Control + Enter or Control + Windows + Alt + Enter to play it, respectively. TWBlue will play a sound if the tweet contains video metadata or the \#audio hashtag, but there may be tweets which contain media without this. Finally, if a tweet contains geographical information, you can press Control + Windows + G in the invisible interface to retrieve it. ### Username fields -These fields accept a Twitter username (without the at sign) as the input. They are present in the send direct message and the user actions dialogue boxes. Those dialogues will be discussed later. The initial value of these fields depends on where they were opened from. They are prepopulated with the username of the sender of the focused tweet (if they were opened from the home and sent timelines, from users' timelines or from lists), the sender of the focused direct message (if from the received or sent direct message buffers) or in the focused user (if from the followers' or friends' buffer). If one of those dialogue boxes is opened from a tweet, and if there are more users mentioned in it, you can use the arrow keys to switch between them. Alternatively, you can also type a username. +These fields accept a Twitter username (without the at sign) as the input. They are present in the send direct message, the user actions dialogue and the user alias dialogue boxes, to name a few examples. Those dialogues will be discussed later. The initial value of these fields depends on where they were opened from. They are prepopulated with the username of the sender of the focused tweet (if they were opened from the home and sent timelines, from users' timelines or from lists), the sender of the focused direct message (if from the received or sent direct message buffers) or in the focused user (if from the followers' or friends' buffer). If one of those dialogue boxes is opened from a tweet, and if there are more users mentioned in it, you can use the arrow keys to switch between them. Alternatively, you can also type a username. ## The program's interfaces @@ -98,9 +98,9 @@ In summary, the GUI contains two core components. These are the controls you wil #### Buttons in the application -* Tweet: this button opens up a dialogue box to write your tweet. Normal tweets must not exceed 280 characters. However you can press the long tweet checkbox and your tweet will be posted throught Twishort, wich will allow you to write longer tweets (10000 characters). If you write past this limit, a sound will play to warn you. Note that the character count is displayed in the title bar. You may use the shorten and expand URL buttons to comply with the character limit. You can upload a picture, check spelling, attach audio or translate your message by selecting one of the available buttons in the dialogue box. In addition, you can autocomplete the entering of users by pressing Alt + C or the button for that purpose if you have the database of users configured. Press enter to send the tweet. If all goes well, you'll hear a sound confirming it. Otherwise, the screen reader will speak an error message in English describing the problem. +* Tweet: this button opens up a dialogue box to write your tweet. Normal tweets must not exceed 280 characters. However you can press the long tweet checkbox and your tweet will be posted throught Twishort, wich will allow you to write longer tweets (10000 characters). If you write past this limit, a sound will play to warn you. Note that the character count is displayed in the title bar. You can upload a picture, check spelling, attach audio or translate your message by selecting one of the available buttons in the dialogue box. In addition, you can autocomplete the entering of users by pressing Alt + C or the button for that purpose if you have the database of users configured. Press enter to send the tweet. If all goes well, you'll hear a sound confirming it. Otherwise, the screen reader will speak an error message in English describing the problem. * Retweet: this button retweets the message you're reading. After you press it, if you haven't configured the application not to do so, you'll be asked if you want to add a comment or simply send it as written. If you choose to add a comment, it will post a quoted tweet, that is, the comment with a link to the originating tweet. -* Reply: when you're viewing a tweet, you can reply to the user who sent it by pressing this button. A dialogue will open up similar to the one for tweeting. If there are more users referred to in the tweet, you can press tab and activate the mention to all checkbox, or enabling checkbox for the users you want to mention separately. When you're on the friends or followers lists, the button will be called mention instead. +* Reply: when you're viewing a tweet, you can reply to the user who sent it by pressing this button. A dialogue will open up similar to the one for tweeting. If there are more users referred to in the tweet, you can press tab and activate the mention to all checkbox, or enabling checkbox for the users you want to mention separately. Note, however, that sometimes -especially when replying to a retweet or quoted tweet, the user who made the retweet or quote may also be mentioned. This is done by Twitter automatically. When you're on the friends or followers lists, the button will be called mention instead. * Direct message: exactly like sending a tweet, but it's a private message which can only be read by the user you send it to. Press shift-tab twice to see the recipient. If there were other users mentioned in the tweet you were reading, you can arrow up or down to choose which one to send it to, or write the username yourself without the at sign. In addition, you can autocomplete the entering of users by pressing Alt + C or the button for that purpose if you have the database of users configured. Bear in mind that buttons will appear according to which actions are possible on the list you are browsing. For example, on the home timeline, mentions, sent, likes and user timelines you will see the four buttons, while on the direct messages list you'll only get the direct message and tweet buttons, and on friends and followers lists the direct message, tweet, and mention buttons will be available. @@ -116,6 +116,7 @@ Visually, Towards the top of the main application window, can be found a menu ba * Hide window: turns off the Graphical User Interface. Read the section on the invisible interface for further details. * Search: shows a dialogue box where you can search for tweets or users on Twitter. * Lists Manager: This dialogue box allows you to manage your Twitter lists. In order to use them, you must first create them. Here, you can view, edit, create, delete or, optionally, open them in buffers similar to user timelines. +* Manage user aliases: Opens up a dialogue where you can manage user aliases for the active session. In this dialog you can add new aliases, as well as edit and delete existing ones. * Edit keystrokes: this opens a dialogue where you can see and edit the shortcuts used in the invisible interface. * Account settings: Opens a dialogue box which lets you customize settings for the current account. * Global settings: Opens a dialogue which lets you configure settings for the entire application. @@ -145,6 +146,7 @@ Visually, Towards the top of the main application window, can be found a menu ba * Ignore tweets from this client: Adds the client from which the focused tweet was sent to the ignored clients list. * View timeline: Lets you open a user's timeline by choosing the user in a dialog box. It is created when you press enter. If you invoke this option relative to a user that has no tweets, the operation will fail. If you try creating an existing timeline the program will warn you and will not create it again. * Direct message: same action as the button. +* Add Alias: An user alias allows you to rename user's display names on Twitter, so the next time you'll read an user it will be announced as you configured. This feature works only if you have set display screen names unchecked, in account settings. * Add to List: In order to see someone's tweets in one or more of your lists, you must add them first. In the dialogue box that opens after selecting the user, you will be asked to select the list you wish to add the user to. Thereafter, the list will contain a new member and their tweets will be displayed there. * Remove from list: lets you remove a user from a list. * View lists: Shows the lists created by a specified user. @@ -153,8 +155,12 @@ Visually, Towards the top of the main application window, can be found a menu ba ##### Buffer menu +* Update buffer: Retrieves the newest items for the focused buffer. Normally, every buffer gets updated every couple of minutes, however you can force a specific buffer to be updated inmediately. Take into account, however, that the usage of this option repeatedly might exceed your allowed Twitter's API usage, in which case you would have to wait until it gets reset, tipycally within the next 15 minutes. * New trending topics buffer: This opens a buffer to get the worlwide trending topics or those of a country or a city. You'll be able to select from a dialogue box if you wish to retrieve countries' trends, cities' trends or worldwide trends (this option is in the cities' list) and choose one from the selected list. The trending topics buffer will be created once the "OK" button has been activated within the dialogue box. Remember this kind of buffer will be updated every five minutes. * Load previous items: This allows more items to be loaded for the specified buffer. +* Create filter: Creates a filter in the current buffer. Filters allow loading or ignoring tweets that meet certain conditions into a buffer. You can, for example, set a filter in the "home" buffer that loads tweets that are in English language only. By default, the filter creation dialog will place the focus on the field to name the filter. Currently, you can filter by word, by language, or both. In the filter by word, you can make TWBlue allow or ignore tweets with the desired word. In the filter by language, you can make the program load tweets in the languages you want, or ignore tweets written in certain languages. Once created, every filter will be saved in the session config and will be kept across application restarts. +* Manage filters: Opens up a dialogue which allows you to delete filters for the current session. +* Find a string in the currently focused buffer: Opens a dialogue where you can search for items in the current buffer. * Mute: Mutes notifications of a particular buffer so you will not hear when new tweets arrive. * autoread: When enabled, the screen reader or SAPI 5 Text to Speech voice (if enabled) will read the text of incoming tweets. Please note that this could get rather chatty if there are a lot of incoming tweets. * Clear buffer: Deletes all items from the buffer. @@ -350,4 +356,4 @@ Many thanks also to the people who worked on the documentation. Initially, [Manu ------------------------------------------------------------------------ -Copyright © 2013-2017. Manuel Cortéz \ No newline at end of file +Copyright © 2013-2021. Manuel Cortéz \ No newline at end of file From 6904c153d45840a2358151eefb32b5234fdbfb2a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 3 Nov 2021 09:10:35 -0600 Subject: [PATCH 196/245] Display error if user has not provided a name for a filter upon creation --- doc/changelog.md | 1 + src/controller/filterController.py | 2 -- src/wxUI/dialogs/filterDialogs.py | 12 ++++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index bb3ddd2f..e78fc5e0 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -7,6 +7,7 @@ TWBlue Changelog * TWBlue should retrieve tweets from threads and conversations in a more reliable way. Tweets in the same thread (made by the same author) will be sorted correctly, although replies to the thread (made by different people) may not be ordered in the same way they are displayed in Twitter apps. ([#417](https://github.com/manuelcortez/TWBlue/issues/417)) * fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) * fixed an issue that was making TWBlue to show incorrectly titles for trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/TWBlue/issues/421)) +* When creating a filter, TWBlue will show an error if user has not provided a name for the filter. Before, unnamed filters were a cause of config breaks in the application. ## Changes in Version 2021.10.30 diff --git a/src/controller/filterController.py b/src/controller/filterController.py index f1262d19..79684801 100644 --- a/src/controller/filterController.py +++ b/src/controller/filterController.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals -from builtins import object import time import widgetUtils import application diff --git a/src/wxUI/dialogs/filterDialogs.py b/src/wxUI/dialogs/filterDialogs.py index bf7f45b2..53dc202a 100644 --- a/src/wxUI/dialogs/filterDialogs.py +++ b/src/wxUI/dialogs/filterDialogs.py @@ -1,10 +1,7 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import unicode_literals -# -*- coding: utf-8 -*- -from . import baseDialog import wx import widgetUtils +from . import baseDialog from multiplatform_widgets import widgets class filterDialog(baseDialog.BaseWXDialog): @@ -19,6 +16,7 @@ class filterDialog(baseDialog.BaseWXDialog): dc = wx.WindowDC(self.title) dc.SetFont(self.title.GetFont()) self.title.SetSize(dc.GetTextExtent("0"*40)) + self.title.SetFocus() tsizer = wx.BoxSizer(wx.HORIZONTAL) tsizer.Add(label, 0, wx.ALL, 5) tsizer.Add(self.title, 0, wx.ALL, 5) @@ -81,6 +79,7 @@ class filterDialog(baseDialog.BaseWXDialog): sizer.Add(selectionSizer, 0, wx.ALL, 5) ok = wx.Button(panel, wx.ID_OK, _(u"OK")) ok.SetDefault() + ok.Bind(wx.EVT_BUTTON, self.validate_title) cancel = wx.Button(panel, wx.ID_CANCEL, _(u"Cancel")) btnsizer = wx.BoxSizer() btnsizer.Add(ok, 0, wx.ALL, 5) @@ -116,6 +115,11 @@ class filterDialog(baseDialog.BaseWXDialog): for i in [self.cb, self.add, self.langs, self.remove]: i.Show() + def validate_title(self, *args, **kwargs): + if self.title.GetValue() == "" or self.title.GetValue() == None: + return wx.MessageDialog(self, _("You must define a name for the filter before creating it."), _("Missing filter name"), wx.ICON_ERROR).ShowModal() + self.EndModal(wx.ID_OK) + class filterManagerDialog(widgetUtils.BaseDialog): def __init__(self, *args, **kwargs): From 2d46315de990f60a3b792e460413d6bafbc99725 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 3 Nov 2021 09:31:23 -0600 Subject: [PATCH 197/245] Removed old pyinstaller file --- src/main.spec | 84 --------------------------------------------------- 1 file changed, 84 deletions(-) delete mode 100644 src/main.spec diff --git a/src/main.spec b/src/main.spec deleted file mode 100644 index 8c0f9cf7..00000000 --- a/src/main.spec +++ /dev/null @@ -1,84 +0,0 @@ -# -*- mode: python -*- -""" specification file for creating distributable versions using Pyinstaller. """ -import os -import glob -import wx -import platform -from requests import certs - -block_cipher = None - -def get_architecture_files(): - """ Returns architecture files for 32 or 64 bits. """ - if platform.architecture()[0][:2] == "32": - return [ - ("..\\windows-dependencies\\x86\\oggenc2.exe", "."), - ("..\\windows-dependencies\\x86\\bootstrap.exe", "."), - ("..\\windows-dependencies\\x86\\*.dll", "."), - ("..\\windows-dependencies\\x86\\plugins", "plugins"), - ] - elif platform.architecture()[0][:2] == "64": - return [ - ("..\\windows-dependencies\\x64\\oggenc2.exe", "."), - ("..\\windows-dependencies\\x64\\bootstrap.exe", "."), - ("..\\windows-dependencies\\x64\\*.dll", "."), - ("..\\windows-dependencies\\x64\\plugins", "plugins"), - ] - -def wx_files(): - wxDir=wx.__path__[0] - localeMoFiles=set() - for f in glob.glob("locales/*/LC_MESSAGES"): - g=f.replace("locales", "locale") - wxMoFile=os.path.join(wxDir,g,"wxstd.mo") - if os.path.isfile(wxMoFile): - localeMoFiles.add((wxMoFile, f)) - lang=os.path.split(os.path.split(f)[0])[1] - if '_' in lang: - lang=lang.split('_')[0] - f=os.path.join('locale',lang,'lc_messages') - g=f.replace("locale", "locales") - wxMoFile=os.path.join(wxDir,f,"wxstd.mo") - if os.path.isfile(wxMoFile): - localeMoFiles.add((wxMoFile, g)) - return list(localeMoFiles) - -a = Analysis(['main.py'], - pathex=['.'], - binaries=[("sounds", "sounds"), -("documentation", "documentation"), -("locales", "locales"), -("keymaps", "keymaps"), -("keys/lib", "keys/lib"), -("..\\windows-dependencies\\dictionaries", "enchant\\share\\enchant\\myspell"), -(certs.where(), "."), -("app-configuration.defaults", "."), -("conf.defaults", "."), -("icon.ico", "."), -]+get_architecture_files()+wx_files(), - - datas=[], - hiddenimports=[], - hookspath=[], - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher) -pyz = PYZ(a.pure, a.zipped_data, - cipher=block_cipher) -exe = EXE(pyz, - a.scripts, - exclude_binaries=True, - name='TWBlue', - debug=False, - strip=False, - upx=True, - console=False) -coll = COLLECT(exe, - a.binaries, - a.zipfiles, - a.datas, - strip=False, - upx=True, - name='TWBlue') From c4b7c35c7f4995017d9fae519c2d58a48e198087 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 3 Nov 2021 09:49:52 -0600 Subject: [PATCH 198/245] Updated changelog --- doc/changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index e78fc5e0..1222937d 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,12 +2,12 @@ TWBlue Changelog ## changes in this version -## changes in this version - * TWBlue should retrieve tweets from threads and conversations in a more reliable way. Tweets in the same thread (made by the same author) will be sorted correctly, although replies to the thread (made by different people) may not be ordered in the same way they are displayed in Twitter apps. ([#417](https://github.com/manuelcortez/TWBlue/issues/417)) * fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) * fixed an issue that was making TWBlue to show incorrectly titles for trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/TWBlue/issues/421)) * When creating a filter, TWBlue will show an error if user has not provided a name for the filter. Before, unnamed filters were a cause of config breaks in the application. +* It is again possible to read the changelog for TWBlue from the help menu in the menu bar. +* Updated Spanish, Japanese and french translations. ## Changes in Version 2021.10.30 From 2c4ec7b1c0db210dbc2cc4865b9bb42fe69919bb Mon Sep 17 00:00:00 2001 From: Oreonan Date: Wed, 3 Nov 2021 18:58:59 +0100 Subject: [PATCH 199/245] Update french interface --- src/locales/fr/LC_MESSAGES/twblue.po | 107 +++++++++++++++------------ 1 file changed, 58 insertions(+), 49 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index cd6eb5be..a22173de 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2021-10-28 12:29+Paris, Madrid (heure d’été)\n" -"PO-Revision-Date: 2021-10-28 18:29+0200\n" +"POT-Creation-Date: 2021-11-03 18:55+0100\n" +"PO-Revision-Date: 2021-11-03 18:57+0100\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -99,7 +99,7 @@ msgid "Unknown buffer" msgstr "Tampon inconnu" #: ../src\controller\buffers\twitter\base.py:88 -#: ../src\controller\buffers\twitter\trends.py:121 +#: ../src\controller\buffers\twitter\trends.py:122 #: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 #: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 #: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 @@ -107,7 +107,7 @@ msgid "Tweet" msgstr "Tweet" #: ../src\controller\buffers\twitter\base.py:89 -#: ../src\controller\buffers\twitter\trends.py:122 +#: ../src\controller\buffers\twitter\trends.py:123 msgid "Write the tweet here" msgstr "Écrivez le tweet ici" @@ -120,7 +120,7 @@ msgid "{0} new tweets in {1}." msgstr "{0} nouveau tweet dans {1}" #: ../src\controller\buffers\twitter\base.py:261 -#: ../src\controller\buffers\twitter\directMessages.py:87 +#: ../src\controller\buffers\twitter\directMessages.py:88 #: ../src\controller\buffers\twitter\people.py:180 msgid "%s items retrieved" msgstr "%s éléments récupérés" @@ -144,7 +144,7 @@ msgid "Reply to %s" msgstr "Répondre à %s" #: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\buffers\twitter\directMessages.py:129 +#: ../src\controller\buffers\twitter\directMessages.py:130 msgid "New direct message" msgstr "Nouveau message privé" @@ -173,26 +173,26 @@ msgstr "Détails de l'utilisateur" msgid "Opening item in web browser..." msgstr "Ouverture de l'élément dans le navigateur Web..." -#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\directMessages.py:93 #: ../src\controller\buffers\twitter\people.py:95 msgid "Mention to %s" msgstr "Mention pour %s" -#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\directMessages.py:93 #: ../src\controller\buffers\twitter\people.py:95 #: ../src\wxUI\buffers\people.py:17 msgid "Mention" msgstr "Mention" -#: ../src\controller\buffers\twitter\directMessages.py:132 +#: ../src\controller\buffers\twitter\directMessages.py:133 msgid "{0} new direct messages." msgstr "{0} nouveau message privé" -#: ../src\controller\buffers\twitter\directMessages.py:135 +#: ../src\controller\buffers\twitter\directMessages.py:136 msgid "This action is not supported in the buffer yet." msgstr "Cette action n'est pas supportée dans le tampon actuel" -#: ../src\controller\buffers\twitter\directMessages.py:145 +#: ../src\controller\buffers\twitter\directMessages.py:146 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -204,7 +204,7 @@ msgstr "" msgid "{0} new followers." msgstr "{0} nouvel abonné" -#: ../src\controller\buffers\twitter\trends.py:145 +#: ../src\controller\buffers\twitter\trends.py:146 msgid "This action is not supported in the buffer, yet." msgstr "Cette action n'est pas supportée pour le tampon actuel" @@ -277,6 +277,7 @@ msgstr "Recherche de {}" #: ../src\controller\mainController.py:381 #: ../src\controller\mainController.py:982 +#: ../src\controller\mainController.py:1593 msgid "Trending topics for %s" msgstr "Tendances pour %s" @@ -425,20 +426,20 @@ msgstr "Actualisation..." msgid "{0} items retrieved" msgstr "{0} éléments récupérés" -#: ../src\controller\mainController.py:1598 -#: ../src\controller\mainController.py:1618 +#: ../src\controller\mainController.py:1600 +#: ../src\controller\mainController.py:1620 msgid "Invalid buffer" msgstr "Tampon invalide" -#: ../src\controller\mainController.py:1609 +#: ../src\controller\mainController.py:1611 msgid "Picture {0}" msgstr "Photo {0}" -#: ../src\controller\mainController.py:1610 +#: ../src\controller\mainController.py:1612 msgid "Select the picture" msgstr "Sélectionner la photo" -#: ../src\controller\mainController.py:1629 +#: ../src\controller\mainController.py:1631 msgid "Unable to extract text" msgstr "Impossible d'extraire le texte" @@ -1487,7 +1488,7 @@ msgstr "" msgid "Send report" msgstr "Envoyer le rapport" -#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:83 #: ../src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "Annuler" @@ -1780,7 +1781,7 @@ msgstr "Raccourci" msgid "Action" msgstr "Action" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:135 #: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 msgid "Edit" msgstr "Modifier" @@ -1830,7 +1831,7 @@ msgstr "Windows" msgid "Key" msgstr "Touche" -#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:80 #: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 #: ../src\wxUI\dialogs\utils.py:36 msgid "OK" @@ -2007,16 +2008,16 @@ msgstr "privé" msgid "public" msgstr "public" -#: ../src\sessions\twitter\session.py:209 +#: ../src\sessions\twitter\session.py:211 msgid "%s failed. Reason: %s" msgstr "%s erreur. Raison: %s" -#: ../src\sessions\twitter\session.py:215 +#: ../src\sessions\twitter\session.py:217 msgid "%s succeeded." msgstr "%s réussi." -#: ../src\sessions\twitter\session.py:424 -#: ../src\sessions\twitter\session.py:502 +#: ../src\sessions\twitter\session.py:426 +#: ../src\sessions\twitter\session.py:504 msgid "Deleted account" msgstr "Compte supprimé" @@ -2561,7 +2562,7 @@ msgid "Status" msgstr "Statut" #: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Buffer" msgstr "Tampon" @@ -2686,91 +2687,99 @@ msgstr "Supplémentaires" msgid "Save" msgstr "Enregistrer" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:13 msgid "Create a filter for this buffer" msgstr "Créer un filtre pour ce tampon" -#: ../src\wxUI\dialogs\filterDialogs.py:17 +#: ../src\wxUI\dialogs\filterDialogs.py:14 msgid "Filter title" msgstr "Titre du filtre" -#: ../src\wxUI\dialogs\filterDialogs.py:26 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:24 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter by word" msgstr "Filtrer par mot" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:25 msgid "Ignore tweets wich contain the following word" msgstr "Ignorer les tweets contenant le mot suivant" -#: ../src\wxUI\dialogs\filterDialogs.py:28 +#: ../src\wxUI\dialogs\filterDialogs.py:26 msgid "Ignore tweets without the following word" msgstr "Ignorer les tweets ne contenant pas le mot suivant" -#: ../src\wxUI\dialogs\filterDialogs.py:33 +#: ../src\wxUI\dialogs\filterDialogs.py:31 msgid "word" msgstr "Mot" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:36 msgid "Allow retweets" msgstr "Permettre les retweets" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:37 msgid "Allow quoted tweets" msgstr "Permettre les tweets cités" -#: ../src\wxUI\dialogs\filterDialogs.py:40 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow replies" msgstr "Permettre les réponses" -#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:46 msgid "Use this term as a regular expression" msgstr "Utiliser ce terme comme une expression régulière" -#: ../src\wxUI\dialogs\filterDialogs.py:50 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter by language" msgstr "Filtrer par langue" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:49 msgid "Load tweets in the following languages" msgstr "Charger tweets dans les suivantes langues" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:50 msgid "Ignore tweets in the following languages" msgstr "Ignorer tweets dans les suivantes langues" -#: ../src\wxUI\dialogs\filterDialogs.py:53 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Don't filter by language" msgstr "Ne pas filtrer par langue" -#: ../src\wxUI\dialogs\filterDialogs.py:64 +#: ../src\wxUI\dialogs\filterDialogs.py:62 msgid "Supported languages" msgstr "Langues supportées" -#: ../src\wxUI\dialogs\filterDialogs.py:69 +#: ../src\wxUI\dialogs\filterDialogs.py:67 msgid "Add selected language to filter" msgstr "Ajouter la langue sélectionnée au filtre" -#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:71 msgid "Selected languages" msgstr "Langue sélectionnée" -#: ../src\wxUI\dialogs\filterDialogs.py:75 -#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:137 ../src\wxUI\dialogs\lists.py:21 #: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "Effacer" -#: ../src\wxUI\dialogs\filterDialogs.py:123 +#: ../src\wxUI\dialogs\filterDialogs.py:120 +msgid "Missing filter name" +msgstr "Nom de filtre manquant" + +#: ../src\wxUI\dialogs\filterDialogs.py:120 +msgid "You must define a name for the filter before creating it." +msgstr "Vous devez définir un nom pour le filtre avant de le créer." + +#: ../src\wxUI\dialogs\filterDialogs.py:127 msgid "Manage filters" msgstr "Gérer les filtres" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:129 msgid "Filters" msgstr "Filtres" -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter" msgstr "Filtre" From 13c441557b1b9c80fb5b828bde06dc378586a3fc Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 3 Nov 2021 12:30:06 -0600 Subject: [PATCH 200/245] Updated manual --- doc/manual.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/manual.md b/doc/manual.md index 8c41fd6c..32799859 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -179,6 +179,8 @@ Visually, Towards the top of the main application window, can be found a menu ba * What's new in this version?: opens up a document with the list of changes from the current version to the earliest. * Check for updates: every time you open the program it automatically checks for new versions. If an update is available, it will ask you if you want to download the update. If you accept, the updating process will commence. When complete, TWBlue will be restarted. This item checks for new updates without having to restart the application. * TWBlue's website: visit our [home page](http://twblue.es) where you can find all relevant information and downloads for TWBlue and become a part of the community. +* Get soundpacks for TWBlue: +* Make a Donation: Opens a website from which you can donate to the TWBlue project. Donations are made through paypal and you don't need an account to donate. * About TWBlue: shows the credits of the program. ### The invisible user interface From 924f5d8e9f2ddb89e697833c80a70c9ffd391429 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 3 Nov 2021 12:30:46 -0600 Subject: [PATCH 201/245] Updated main controller file --- src/controller/mainController.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 1d0c3469..ddedb068 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1529,13 +1529,10 @@ class Controller(object): os.chdir("../../") def view_changelog(self, *args, **kwargs): - if application.snapshot == True: - webbrowser.open("https://github.com/manuelcortez/twblue/blob/next-gen/doc/changelog.md") - else: - lang = localization.get("documentation") - os.chdir("documentation/%s" % (lang,)) - webbrowser.open("changelog.html") - os.chdir("../../") + lang = localization.get("documentation") + os.chdir("documentation/%s" % (lang,)) + webbrowser.open("changelog.html") + os.chdir("../../") def insert_buffer(self, buffer, position): self.buffers.insert(position, buffer) From 4ddb406c8d4ced858c554f68009a9d6fc037728c Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 4 Nov 2021 17:00:59 +0100 Subject: [PATCH 202/245] Reduce texts --- src/locales/fr/LC_MESSAGES/twblue.po | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index a22173de..e31dd0e1 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" "POT-Creation-Date: 2021-11-03 18:55+0100\n" -"PO-Revision-Date: 2021-11-03 18:57+0100\n" +"PO-Revision-Date: 2021-11-04 17:00+0100\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -37,12 +37,12 @@ msgstr "Mentions" #: ../src\controller\buffers\twitter\base.py:70 #: ../src\controller\mainController.py:341 msgid "Direct messages" -msgstr "Messages privés" +msgstr "Messages" #: ../src\controller\buffers\twitter\base.py:70 #: ../src\controller\mainController.py:343 ../src\controller\settings.py:289 msgid "Sent direct messages" -msgstr "Messages privés envoyés" +msgstr "Messages envoyés" #: ../src\controller\buffers\twitter\base.py:70 #: ../src\controller\mainController.py:345 ../src\controller\settings.py:290 @@ -146,12 +146,12 @@ msgstr "Répondre à %s" #: ../src\controller\buffers\twitter\base.py:480 #: ../src\controller\buffers\twitter\directMessages.py:130 msgid "New direct message" -msgstr "Nouveau message privé" +msgstr "Nouveau message" #: ../src\controller\buffers\twitter\base.py:480 #: ../src\controller\messages.py:200 msgid "Direct message to %s" -msgstr "Message privé à %s" +msgstr "Message à %s" #: ../src\controller\buffers\twitter\base.py:520 msgid "Add your comment to the tweet" @@ -186,7 +186,7 @@ msgstr "Mention" #: ../src\controller\buffers\twitter\directMessages.py:133 msgid "{0} new direct messages." -msgstr "{0} nouveau message privé" +msgstr "{0} nouveau message" #: ../src\controller\buffers\twitter\directMessages.py:136 msgid "This action is not supported in the buffer yet." @@ -198,7 +198,7 @@ msgid "" "buffer instead." msgstr "" "Récupérer plus d'élément est impossible dans ce tampon, utilisez le tampon " -"des messages privés à la place." +"des messages à la place." #: ../src\controller\buffers\twitter\people.py:253 msgid "{0} new followers." @@ -523,7 +523,7 @@ msgstr "Paramètres du compte de %s" #: ../src\controller\settings.py:288 msgid "Direct Messages" -msgstr "Messages privés" +msgstr "Messages" #: ../src\controller\user.py:29 ../src\controller\user.py:31 #: ../src\extra\SpellChecker\wx_ui.py:80 ../src\issueReporter\wx_ui.py:84 @@ -619,7 +619,7 @@ msgstr "Favoris: %s" #: ../src\controller\userActionsController.py:74 msgid "You can't ignore direct messages" -msgstr "Vous ne pouvez pas ignorer les messages privés" +msgstr "Vous ne pouvez pas ignorer les messages" #: ../src\controller\userAliasController.py:32 msgid "Edit alias for {}" @@ -783,11 +783,11 @@ msgstr "Tampon détruit." #: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 msgid "Direct message received." -msgstr "Message privé reçu." +msgstr "Message reçu." #: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 msgid "Direct message sent." -msgstr "Message privé envoyé." +msgstr "Message envoyé." #: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 msgid "Error." @@ -1569,7 +1569,7 @@ msgstr "Retweet" #: ../src\keystrokeEditor\constants.py:13 msgid "Send direct message" -msgstr "Envoyer un message privé" +msgstr "Envoyer un message" #: ../src\keystrokeEditor\constants.py:14 msgid "Like a tweet" @@ -1649,7 +1649,7 @@ msgstr "Modifier le profil" #: ../src\keystrokeEditor\constants.py:33 msgid "Delete a tweet or direct message" -msgstr "Supprimer un tweet ou un message privé" +msgstr "Supprimer un tweet ou un message" #: ../src\keystrokeEditor\constants.py:34 msgid "Empty the current buffer" @@ -2116,7 +2116,7 @@ msgstr "Utilisateur" #: ../src\wxUI\buffers\base.py:28 msgid "Direct message" -msgstr "Message privé" +msgstr "Message" #: ../src\wxUI\buffers\events.py:14 msgid "Event" @@ -3235,7 +3235,7 @@ msgstr "&Actions de l'utilisateur..." #: ../src\wxUI\menus.py:40 msgid "&Show direct message" -msgstr "&Afficher le message privé" +msgstr "&Afficher le message" #: ../src\wxUI\menus.py:68 msgid "&Show event" @@ -3243,7 +3243,7 @@ msgstr "&Afficher l'événement" #: ../src\wxUI\menus.py:78 msgid "Direct &message" -msgstr "&Message privé" +msgstr "&Message" #: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:50 msgid "&View lists" @@ -3343,7 +3343,7 @@ msgstr "Voir &chronologie..." #: ../src\wxUI\view.py:46 msgid "Direct me&ssage" -msgstr "&Message privé" +msgstr "&Message" #: ../src\wxUI\view.py:47 msgid "Add a&lias" From a80184bf204e303c2f8fc4a4344f589ea3fc6150 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 4 Nov 2021 11:17:07 -0600 Subject: [PATCH 203/245] Restored conversation support with API V1 as V2 hits the limits quickly. Closes #427 --- src/controller/buffers/twitter/search.py | 33 +++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index 7a75d702..db72fd35 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -69,7 +69,7 @@ class ConversationBuffer(SearchBuffer): current_time = time.time() if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: self.execution_time = current_time - results = self.get_replies(self.tweet) + results = self.get_replies_v1(self.tweet) number_of_items = self.session.order_buffer(self.name, results) log.debug("Number of items retrieved: %d" % (number_of_items,)) self.put_items_on_list(number_of_items) @@ -147,4 +147,35 @@ class ConversationBuffer(SearchBuffer): results.extend(reply_results) except TweepyException as e: log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) + return results + + def get_replies_v1(self, tweet): + try: + tweet = self.session.twitter.get_status(id=tweet.id, tweet_mode="extended") + except: + log.exception("Error getting tweet for making a conversation buffer.") + return [] + results = [] + results.append(tweet) + if hasattr(tweet, "in_reply_to_status_id") and tweet.in_reply_to_status_id != None: + while tweet.in_reply_to_status_id != None: + original_tweet = self.session.twitter.get_status(id=tweet.in_reply_to_status_id, tweet_mode="extended") + results.insert(0, original_tweet) + tweet = original_tweet + try: + term = "from:{} to:{}".format(tweet.user.screen_name, tweet.user.screen_name) + thread_tweets = self.session.twitter.search_tweets(term, count=100, since_id=tweet.id, tweet_mode="extended") + results.extend(thread_tweets) + except TweepyException as e: + log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name)) + + try: + term = "to:{}".format(tweet.user.screen_name) + reply_tweets = self.session.twitter.search_tweets(term, count=100, since_id=tweet.id, tweet_mode="extended") + ids = [t.id for t in results] + reply_tweets = [t for t in reply_tweets if hasattr(t, "in_reply_to_status_id") and t.in_reply_to_status_id in ids] + results.extend(reply_tweets) + except TweepyException as e: + log.exception("There was an error when attempting to retrieve the whole conversation for buffer {}".format(self.buffer.name)) + results.sort(key=lambda x: x.id) return results \ No newline at end of file From 0cf0a64f40522cc29e07adb65d6a47120898efed Mon Sep 17 00:00:00 2001 From: riku Date: Fri, 5 Nov 2021 07:15:33 +0900 Subject: [PATCH 204/245] Update Japanese translation --- src/locales/ja/lc_messages/twblue.mo | Bin 61631 -> 61905 bytes src/locales/ja/lc_messages/twblue.po | 105 +++++++++++++++------------ 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/locales/ja/lc_messages/twblue.mo b/src/locales/ja/lc_messages/twblue.mo index e85315e4c8b7b687bba9266d803ab2abfab0fab7..9adb0dd5fdce74e3de3f266a30143e8ff88b2185 100644 GIT binary patch delta 16936 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 U>*n9yoj9}XodO$|-3|@-A7ch34gdfE delta 16717 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 F^MBHkyAc2Y diff --git a/src/locales/ja/lc_messages/twblue.po b/src/locales/ja/lc_messages/twblue.po index 496f81c5..d58a1594 100644 --- a/src/locales/ja/lc_messages/twblue.po +++ b/src/locales/ja/lc_messages/twblue.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-11-01 11:40+0900\n" +"PO-Revision-Date: 2021-11-05 07:15+0900\n" "Last-Translator: 陸 \n" "Language-Team: \n" "Language: ja_JP\n" @@ -101,7 +101,7 @@ msgid "Unknown buffer" msgstr "不明なバッファ" #: ../src\controller\buffers\twitter\base.py:88 -#: ../src\controller\buffers\twitter\trends.py:121 +#: ../src\controller\buffers\twitter\trends.py:122 #: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 #: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 #: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 @@ -109,7 +109,7 @@ msgid "Tweet" msgstr "ツイート" #: ../src\controller\buffers\twitter\base.py:89 -#: ../src\controller\buffers\twitter\trends.py:122 +#: ../src\controller\buffers\twitter\trends.py:123 msgid "Write the tweet here" msgstr "ツイートを入力" @@ -122,7 +122,7 @@ msgid "{0} new tweets in {1}." msgstr "「{1}」への{0}個の新規ツイート。" #: ../src\controller\buffers\twitter\base.py:261 -#: ../src\controller\buffers\twitter\directMessages.py:87 +#: ../src\controller\buffers\twitter\directMessages.py:88 #: ../src\controller\buffers\twitter\people.py:180 msgid "%s items retrieved" msgstr "%s個のアイテムを取得しました" @@ -146,7 +146,7 @@ msgid "Reply to %s" msgstr "「%s」への返信" #: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\buffers\twitter\directMessages.py:129 +#: ../src\controller\buffers\twitter\directMessages.py:130 msgid "New direct message" msgstr "新しいダイレクトメッセージ" @@ -175,26 +175,26 @@ msgstr "ユーザーの詳細" msgid "Opening item in web browser..." msgstr "ブラウザでアイテムを開いています…" -#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\directMessages.py:93 #: ../src\controller\buffers\twitter\people.py:95 msgid "Mention to %s" msgstr "%sへのメンション" -#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\directMessages.py:93 #: ../src\controller\buffers\twitter\people.py:95 #: ../src\wxUI\buffers\people.py:17 msgid "Mention" msgstr "メンション" -#: ../src\controller\buffers\twitter\directMessages.py:132 +#: ../src\controller\buffers\twitter\directMessages.py:133 msgid "{0} new direct messages." msgstr "{0}件の新しいダイレクトメッセージ。" -#: ../src\controller\buffers\twitter\directMessages.py:135 +#: ../src\controller\buffers\twitter\directMessages.py:136 msgid "This action is not supported in the buffer yet." msgstr "この動作は、現在のバッファではサポートされていません。" -#: ../src\controller\buffers\twitter\directMessages.py:145 +#: ../src\controller\buffers\twitter\directMessages.py:146 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -206,7 +206,7 @@ msgstr "" msgid "{0} new followers." msgstr "{0}人の新しいフォロワー。" -#: ../src\controller\buffers\twitter\trends.py:145 +#: ../src\controller\buffers\twitter\trends.py:146 msgid "This action is not supported in the buffer, yet." msgstr "この動作は、現在のバッファではサポートされていません。" @@ -279,6 +279,7 @@ msgstr "「{}」の検索結果" #: ../src\controller\mainController.py:381 #: ../src\controller\mainController.py:982 +#: ../src\controller\mainController.py:1593 msgid "Trending topics for %s" msgstr "%s のトレンド" @@ -426,20 +427,20 @@ msgstr "バッファを更新中…" msgid "{0} items retrieved" msgstr "{0}個のアイテムを取得しました" -#: ../src\controller\mainController.py:1598 -#: ../src\controller\mainController.py:1618 +#: ../src\controller\mainController.py:1600 +#: ../src\controller\mainController.py:1620 msgid "Invalid buffer" msgstr "無効なバッファ" -#: ../src\controller\mainController.py:1609 +#: ../src\controller\mainController.py:1611 msgid "Picture {0}" msgstr "画像{0}" -#: ../src\controller\mainController.py:1610 +#: ../src\controller\mainController.py:1612 msgid "Select the picture" msgstr "画像を選択" -#: ../src\controller\mainController.py:1629 +#: ../src\controller\mainController.py:1631 msgid "Unable to extract text" msgstr "テキストを抽出できません" @@ -1483,7 +1484,7 @@ msgstr "" msgid "Send report" msgstr "レポートを送信" -#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:83 #: ../src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "キャンセル" @@ -1769,7 +1770,7 @@ msgstr "キーストローク" msgid "Action" msgstr "操作" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:135 #: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 msgid "Edit" msgstr "編集" @@ -1819,7 +1820,7 @@ msgstr "ウィンドウズ" msgid "Key" msgstr "キー名" -#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:80 #: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 #: ../src\wxUI\dialogs\utils.py:36 msgid "OK" @@ -1994,16 +1995,16 @@ msgstr "プライベート" msgid "public" msgstr "公式" -#: ../src\sessions\twitter\session.py:209 +#: ../src\sessions\twitter\session.py:211 msgid "%s failed. Reason: %s" msgstr "%s が失敗しました。理由: %s" -#: ../src\sessions\twitter\session.py:215 +#: ../src\sessions\twitter\session.py:217 msgid "%s succeeded." msgstr "%sに成功しました。" -#: ../src\sessions\twitter\session.py:424 -#: ../src\sessions\twitter\session.py:502 +#: ../src\sessions\twitter\session.py:426 +#: ../src\sessions\twitter\session.py:504 msgid "Deleted account" msgstr "削除されたアカウント" @@ -2541,7 +2542,7 @@ msgid "Status" msgstr "ステータス" #: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Buffer" msgstr "バッファ" @@ -2666,91 +2667,99 @@ msgstr "その他" msgid "Save" msgstr "保存" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:13 msgid "Create a filter for this buffer" msgstr "このバッファのフィルタを作成" -#: ../src\wxUI\dialogs\filterDialogs.py:17 +#: ../src\wxUI\dialogs\filterDialogs.py:14 msgid "Filter title" msgstr "フィルター名" -#: ../src\wxUI\dialogs\filterDialogs.py:26 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:24 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter by word" msgstr "単語でフィルター" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:25 msgid "Ignore tweets wich contain the following word" msgstr "次の単語が含まれるツイートを無視する" -#: ../src\wxUI\dialogs\filterDialogs.py:28 +#: ../src\wxUI\dialogs\filterDialogs.py:26 msgid "Ignore tweets without the following word" msgstr "次の単語が含まれないツイートを無視する" -#: ../src\wxUI\dialogs\filterDialogs.py:33 +#: ../src\wxUI\dialogs\filterDialogs.py:31 msgid "word" msgstr "単語" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:36 msgid "Allow retweets" msgstr "リツイートを許可する" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:37 msgid "Allow quoted tweets" msgstr "引用ツイートを許可する" -#: ../src\wxUI\dialogs\filterDialogs.py:40 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow replies" msgstr "リプライを許可するフォロワー一覧" -#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:46 msgid "Use this term as a regular expression" msgstr "正規表現を利用" -#: ../src\wxUI\dialogs\filterDialogs.py:50 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter by language" msgstr "言語でフィルター" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:49 msgid "Load tweets in the following languages" msgstr "下記の言語のツイートを表示" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:50 msgid "Ignore tweets in the following languages" msgstr "下記の言語のツイートを無視する" -#: ../src\wxUI\dialogs\filterDialogs.py:53 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Don't filter by language" msgstr "言語でフィルタしない" -#: ../src\wxUI\dialogs\filterDialogs.py:64 +#: ../src\wxUI\dialogs\filterDialogs.py:62 msgid "Supported languages" msgstr "サポートしている言語" -#: ../src\wxUI\dialogs\filterDialogs.py:69 +#: ../src\wxUI\dialogs\filterDialogs.py:67 msgid "Add selected language to filter" msgstr "選択した言語をフィルターに追加" -#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:71 msgid "Selected languages" msgstr "選択した言語" -#: ../src\wxUI\dialogs\filterDialogs.py:75 -#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:137 ../src\wxUI\dialogs\lists.py:21 #: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "削除" -#: ../src\wxUI\dialogs\filterDialogs.py:123 +#: ../src\wxUI\dialogs\filterDialogs.py:120 +msgid "Missing filter name" +msgstr "フィルター名がありません" + +#: ../src\wxUI\dialogs\filterDialogs.py:120 +msgid "You must define a name for the filter before creating it." +msgstr "フィルターを作成する前に、フィルターの名前を定義する必要があります。" + +#: ../src\wxUI\dialogs\filterDialogs.py:127 msgid "Manage filters" msgstr "フィルターの管理" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:129 msgid "Filters" msgstr "フィルター" -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter" msgstr "フィルター" From 4f0db5537e8b60096cd548d7db340a09a0250e46 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 5 Nov 2021 11:49:51 -0600 Subject: [PATCH 205/245] Added function to send tweets and threads in session module so it will be used globally later --- src/sessions/twitter/session.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index a219016c..f9de86fd 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -590,4 +590,20 @@ class Session(base.baseSession): if self.logged == False: return if user != self.db["user_name"]: - log.debug("Connected streaming endpoint on account {}".format(user)) \ No newline at end of file + log.debug("Connected streaming endpoint on account {}".format(user)) + + def send_tweet(self, *tweets): + """ Convenience function to send a thread. """ + in_reply_to_status_id = None + for obj in tweets: + if len(obj["attachments"]) == 0: + item = self.api_call(call_name="update_status", status=obj["text"], _sound="tweet_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id) + in_reply_to_status_id = item.id + else: + media_ids = [] + for i in obj["attachments"]: + img = self.api_call("media_upload", filename=i["file"]) + self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) + media_ids.append(img.media_id) + item = self.api_call(call_name="update_status", status=obj["text"], _sound="tweet_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids) + in_reply_to_status_id = item.id \ No newline at end of file From 66bf95ee6245d515de3a306447cae1d07358edb7 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 5 Nov 2021 13:10:45 -0600 Subject: [PATCH 206/245] Added reply function to session module --- src/sessions/twitter/session.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index f9de86fd..a32ead2d 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -606,4 +606,15 @@ class Session(base.baseSession): self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) item = self.api_call(call_name="update_status", status=obj["text"], _sound="tweet_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids) - in_reply_to_status_id = item.id \ No newline at end of file + in_reply_to_status_id = item.id + + def reply(self, text="", in_reply_to_status_id=None, attachments=[], *args, **kwargs): + if len(attachments) == 0: + item = self.api_call(call_name="update_status", status=text, _sound="reply_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, *args, **kwargs) + else: + media_ids = [] + for i in attachments: + img = self.api_call("media_upload", filename=i["file"]) + self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) + media_ids.append(img.media_id) + item = self.api_call(call_name="update_status", status=text, _sound="reply_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids, *args, **kwargs) From cedb290956fec7345c893054ac0121bade2e6b28 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 5 Nov 2021 22:35:12 -0600 Subject: [PATCH 207/245] fixed an issue when deleting a buffer in a session where there were trending topics opened --- doc/changelog.md | 5 +++-- src/wxUI/buffers/trends.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index 1222937d..513204c2 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -3,10 +3,11 @@ TWBlue Changelog ## changes in this version * TWBlue should retrieve tweets from threads and conversations in a more reliable way. Tweets in the same thread (made by the same author) will be sorted correctly, although replies to the thread (made by different people) may not be ordered in the same way they are displayed in Twitter apps. ([#417](https://github.com/manuelcortez/TWBlue/issues/417)) -* fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) -* fixed an issue that was making TWBlue to show incorrectly titles for trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/TWBlue/issues/421)) * When creating a filter, TWBlue will show an error if user has not provided a name for the filter. Before, unnamed filters were a cause of config breaks in the application. * It is again possible to read the changelog for TWBlue from the help menu in the menu bar. +* fixed a bug when clearing the direct messages buffer. ([#418](https://github.com/manuelcortez/TWBlue/issues/418)) +* fixed an issue that was making TWBlue to show incorrectly titles for trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/TWBlue/issues/421)) +* fixed an issue that was making users of the graphical user interface to delete a buffer if a trends buffer was opened in the same session. * Updated Spanish, Japanese and french translations. ## Changes in Version 2021.10.30 diff --git a/src/wxUI/buffers/trends.py b/src/wxUI/buffers/trends.py index 975a88ca..b9e67101 100644 --- a/src/wxUI/buffers/trends.py +++ b/src/wxUI/buffers/trends.py @@ -32,3 +32,5 @@ class trendsPanel(wx.Panel): else: self.list.select_item(0) + def set_focus_in_list(self): + self.list.list.SetFocus() From 556ffd832b8e827b74d8c10fa9ab664c1f443027 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Sun, 7 Nov 2021 06:34:27 -0600 Subject: [PATCH 208/245] Updated translation machine catalog for french translation --- src/locales/fr/LC_MESSAGES/twblue.mo | Bin 52802 -> 56563 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.mo b/src/locales/fr/LC_MESSAGES/twblue.mo index c83284cf0f3be22bf81f266e6aa87282f93e65b5..2d8ceb5cd79bfc8523ba19a9b3344d478969ea03 100644 GIT binary patch delta 20359 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 Date: Mon, 8 Nov 2021 15:29:23 -0600 Subject: [PATCH 209/245] Removed URL Shorteners --- src/url_shortener/__init__.py | 3 -- src/url_shortener/__main__.py | 46 ------------------- src/url_shortener/shorteners/__init__.py | 11 ----- src/url_shortener/shorteners/acortame.py | 30 ------------ src/url_shortener/shorteners/clckru.py | 22 --------- src/url_shortener/shorteners/hkcim.py | 21 --------- src/url_shortener/shorteners/isgd.py | 22 --------- src/url_shortener/shorteners/onjme.py | 21 --------- src/url_shortener/shorteners/tinyarrows.py | 21 --------- src/url_shortener/shorteners/tinyurl.py | 20 -------- src/url_shortener/shorteners/url_shortener.py | 44 ------------------ src/url_shortener/shorteners/xedcc.py | 21 --------- 12 files changed, 282 deletions(-) delete mode 100644 src/url_shortener/__init__.py delete mode 100644 src/url_shortener/__main__.py delete mode 100644 src/url_shortener/shorteners/__init__.py delete mode 100644 src/url_shortener/shorteners/acortame.py delete mode 100644 src/url_shortener/shorteners/clckru.py delete mode 100644 src/url_shortener/shorteners/hkcim.py delete mode 100644 src/url_shortener/shorteners/isgd.py delete mode 100644 src/url_shortener/shorteners/onjme.py delete mode 100644 src/url_shortener/shorteners/tinyarrows.py delete mode 100644 src/url_shortener/shorteners/tinyurl.py delete mode 100644 src/url_shortener/shorteners/url_shortener.py delete mode 100644 src/url_shortener/shorteners/xedcc.py diff --git a/src/url_shortener/__init__.py b/src/url_shortener/__init__.py deleted file mode 100644 index 419c8170..00000000 --- a/src/url_shortener/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import unicode_literals -from . import shorteners -from . __main__ import * diff --git a/src/url_shortener/__main__.py b/src/url_shortener/__main__.py deleted file mode 100644 index 7e3dcf05..00000000 --- a/src/url_shortener/__main__.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import unicode_literals -from functools import wraps -from . import shorteners - - -def service_selecter (func): - @wraps(func) - def wrapper (*args, **kwargs): - tmp = dict(kwargs) - if 'service' in tmp: - del(tmp['service']) - kwargs['service'] = find_service(kwargs['service'], **tmp) or default_service() - else: - kwargs['service'] = default_service() - return func(*args, **kwargs) - return wrapper - -@service_selecter -def shorten (url, service=None, **kwargs): - return service(**kwargs).shorten(url) - - -@service_selecter -def unshorten (url, service=None, **kwargs): - return service(**kwargs).unshorten(url) - - -def default_service (): - return shorteners.AcortameShortener - -def find_service (service, **kwargs): - for i in shorteners.__all__: - obj = getattr(shorteners, i)(**kwargs) - if obj.name.lower() == service.lower(): - return getattr(shorteners, i) - -def list_services (): - return [getattr(shorteners, i)().name for i in shorteners.__all__] - -def unshorten_any (url): - """Unshortens an URL using any available unshortener. Check to see if unshortened URL was created by a shortener (nested) and unshorten if so.""" - unshortened_url = shorteners.URLShortener().unshorten(url) - # None is returned if URL not unshortened - if unshortened_url: - return unshorten_any(unshortened_url) - return url diff --git a/src/url_shortener/shorteners/__init__.py b/src/url_shortener/shorteners/__init__.py deleted file mode 100644 index aa0b763d..00000000 --- a/src/url_shortener/shorteners/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -from .url_shortener import URLShortener -from .hkcim import HKCShortener -from . isgd import IsgdShortener -from . onjme import OnjmeShortener -from . tinyarrows import TinyArrowsShortener -from . tinyurl import TinyurlShortener -from . xedcc import XedccShortener -from . clckru import ClckruShortener -from . acortame import AcortameShortener -__all__ = ["HKCShortener", "IsgdShortener", "OnjmeShortener", "TinyArrowsShortener", "TinyurlShortener", "XedccShortener", "ClckruShortener", "AcortameShortener"] diff --git a/src/url_shortener/shorteners/acortame.py b/src/url_shortener/shorteners/acortame.py deleted file mode 100644 index e7adafb6..00000000 --- a/src/url_shortener/shorteners/acortame.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -from . url_shortener import URLShortener -import requests -import urllib.request, urllib.parse, urllib.error -class AcortameShortener (URLShortener): - def __init__(self, *args, **kwargs): - self.name = "acorta.me" - super(AcortameShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("https://acorta.me/api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'acorta.me' in url - - def unshorten (self, url): - if not 'acorta.me' in url: - #use generic expand method - return super(AcortameShortener, self).unshorten(url) - answer = url - api = requests.get ("https://acorta.me/api.php?action=expand&format=simple&shorturl=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer diff --git a/src/url_shortener/shorteners/clckru.py b/src/url_shortener/shorteners/clckru.py deleted file mode 100644 index 9c527ea1..00000000 --- a/src/url_shortener/shorteners/clckru.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import urllib.request, urllib.parse, urllib.error -import requests -from . url_shortener import URLShortener - - -class ClckruShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "clck.ru" - super(ClckruShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("http://clck.ru/--?url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'clck.ru' in url diff --git a/src/url_shortener/shorteners/hkcim.py b/src/url_shortener/shorteners/hkcim.py deleted file mode 100644 index 29ecd9ea..00000000 --- a/src/url_shortener/shorteners/hkcim.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import urllib.request, urllib.parse, urllib.error -import requests -from . url_shortener import URLShortener - -class HKCShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "HKC.im" - super(HKCShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'hkc.im' in url.lower() diff --git a/src/url_shortener/shorteners/isgd.py b/src/url_shortener/shorteners/isgd.py deleted file mode 100644 index ee817360..00000000 --- a/src/url_shortener/shorteners/isgd.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import urllib.request, urllib.parse, urllib.error -import requests -from . url_shortener import URLShortener - - -class IsgdShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "Is.gd" - super(IsgdShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("http://is.gd/api.php?longurl=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'is.gd' in url diff --git a/src/url_shortener/shorteners/onjme.py b/src/url_shortener/shorteners/onjme.py deleted file mode 100644 index c6a21315..00000000 --- a/src/url_shortener/shorteners/onjme.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import urllib.request, urllib.parse, urllib.error -import requests -from . url_shortener import URLShortener - -class OnjmeShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "Onj.me" - super(OnjmeShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'onj.me' in url.lower() diff --git a/src/url_shortener/shorteners/tinyarrows.py b/src/url_shortener/shorteners/tinyarrows.py deleted file mode 100644 index 45a8990c..00000000 --- a/src/url_shortener/shorteners/tinyarrows.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import urllib.request, urllib.parse, urllib.error -import requests -from . url_shortener import URLShortener - -class TinyArrowsShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "TinyArro.ws" - super(TinyArrowsShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer.decode('UTF-8') - - def created_url(self, url): - return "tinyarro.ws" in url diff --git a/src/url_shortener/shorteners/tinyurl.py b/src/url_shortener/shorteners/tinyurl.py deleted file mode 100644 index 0a5703a3..00000000 --- a/src/url_shortener/shorteners/tinyurl.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -from .url_shortener import URLShortener -import requests -import urllib.request, urllib.parse, urllib.error -class TinyurlShortener (URLShortener): - def __init__(self, *args, **kwargs): - self.name = "TinyURL.com" - super(TinyurlShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("http://tinyurl.com/api-create.php?url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'tinyurl.com' in url diff --git a/src/url_shortener/shorteners/url_shortener.py b/src/url_shortener/shorteners/url_shortener.py deleted file mode 100644 index cf1d6f76..00000000 --- a/src/url_shortener/shorteners/url_shortener.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import unicode_literals -from builtins import object -import requests - -class URLShortener (object): - - def __init__ (self, *args, **kwargs): - #Stub out arguments, silly object. :( - return super(URLShortener, self).__init__() - - def shorten (self, url): - if self.created_url(url): - return url - else: - return self._shorten(url) - - def _shorten (self, url): - raise NotImplementedError - - def created_url (self, url): - """Returns a boolean indicating whether or not this shortener created a provided url""" - raise NotImplementedError - - def unshorten(self, url): - try: - r=requests.head(url) - if 'location' in list(r.headers.keys()): - if 'dropbox.com' in r.headers['location']: - return handle_dropbox(r.headers['location']) - else: - return r.headers['location'] - else: # if the head method does not work, use get instead. Performance may decrease - r=requests.get(url, allow_redirects=False, stream=True) - # release the connection without downloading the content, we only need the response headers - r.close() - return r.headers['location'] - except: - return url #we cannot expand - -def handle_dropbox(url): - if url.endswith("dl=1"): - return url - else: - return url.replace("dl=0", "dl=1") diff --git a/src/url_shortener/shorteners/xedcc.py b/src/url_shortener/shorteners/xedcc.py deleted file mode 100644 index 117b4f7c..00000000 --- a/src/url_shortener/shorteners/xedcc.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import urllib.request, urllib.parse, urllib.error -import requests -from . url_shortener import URLShortener - -class XedccShortener (URLShortener): - def __init__ (self, *args, **kwargs): - self.name = "Xed.cc" - super(XedccShortener, self).__init__(*args, **kwargs) - - def _shorten (self, url): - answer = url - api = requests.get ("http://xed.cc/yourls-api.php?action=shorturl&format=simple&url=" + urllib.parse.quote(url)) - if api.status_code == 200: - answer = api.text - return answer - - def created_url (self, url): - return 'xed.cc' in url.lower() From 2c70fe46b7cc9f682bed849fd92072939654c8c9 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 15:30:40 -0600 Subject: [PATCH 210/245] Removed url_shortener from sound handling module --- src/sound.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sound.py b/src/sound.py index df47f221..cd0f5a93 100644 --- a/src/sound.py +++ b/src/sound.py @@ -6,7 +6,6 @@ import subprocess import platform import tempfile import glob -import url_shortener import audio_services import paths import sound_lib @@ -121,7 +120,7 @@ class URLStream(object): """ Takes an URL and prepares it to be streamed. This function will try to unshorten the passed URL and, if needed, to transform it into a valid URL.""" log.debug("Preparing URL: %s" % (url,)) self.prepared = False - self.url = url_shortener.unshorten(url) + self.url = url if self.url == None: self.url = url log.debug("Expanded URL: %s" % (self.url,)) From 38e3274adc1a59243a6768a3e6ac2104a19ad11c Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:09:32 -0600 Subject: [PATCH 211/245] Removed GUI for tweets/reply/dm/viewTweets items and attachment code --- src/controller/attach.py | 40 --- src/wxUI/dialogs/attach.py | 48 ---- src/wxUI/dialogs/message.py | 471 ------------------------------------ 3 files changed, 559 deletions(-) delete mode 100644 src/controller/attach.py delete mode 100644 src/wxUI/dialogs/attach.py delete mode 100644 src/wxUI/dialogs/message.py diff --git a/src/controller/attach.py b/src/controller/attach.py deleted file mode 100644 index 08427142..00000000 --- a/src/controller/attach.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals -from builtins import object -import os -import widgetUtils -import logging -from wxUI.dialogs import attach as gui -log = logging.getLogger("controller.attach") - -class attach(object): - def __init__(self): - self.attachments = list() - self.dialog = gui.attachDialog() - widgetUtils.connect_event(self.dialog.photo, widgetUtils.BUTTON_PRESSED, self.upload_image) - widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_attachment) - self.dialog.get_response() - log.debug("Attachments controller started.") - - def upload_image(self, *args, **kwargs): - image, description = self.dialog.get_image() - if image != None: - imageInfo = {"type": "photo", "file": image, "description": description} - log.debug("Image data to upload: %r" % (imageInfo,)) - self.attachments.append(imageInfo) - info = [_(u"Photo"), description] - self.dialog.attachments.insert_item(False, *info) - self.dialog.remove.Enable(True) - - def remove_attachment(self, *args, **kwargs): - current_item = self.dialog.attachments.get_selected() - log.debug("Removing item %d" % (current_item,)) - if current_item == -1: current_item = 0 - self.attachments.pop(current_item) - self.dialog.attachments.remove_item(current_item) - self.check_remove_status() - log.debug("Removed") - - def check_remove_status(self): - if len(self.attachments) == 0 and self.dialog.attachments.get_count() == 0: - self.dialog.remove.Enable(False) diff --git a/src/wxUI/dialogs/attach.py b/src/wxUI/dialogs/attach.py deleted file mode 100644 index 0b20a422..00000000 --- a/src/wxUI/dialogs/attach.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -""" Attach dialog. Taken from socializer: https://github.com/manuelcortez/socializer""" -from __future__ import unicode_literals -import wx -import widgetUtils -from multiplatform_widgets import widgets - -class attachDialog(widgetUtils.BaseDialog): - def __init__(self): - super(attachDialog, self).__init__(None, title=_(u"Add an attachment")) - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - lbl1 = wx.StaticText(panel, wx.ID_ANY, _(u"Attachments")) - self.attachments = widgets.list(panel, _(u"Type"), _(u"Title"), style=wx.LC_REPORT) - box = wx.BoxSizer(wx.HORIZONTAL) - box.Add(lbl1, 0, wx.ALL, 5) - box.Add(self.attachments.list, 0, wx.ALL, 5) - sizer.Add(box, 0, wx.ALL, 5) - static = wx.StaticBox(panel, label=_(u"Add attachments")) - self.photo = wx.Button(panel, wx.ID_ANY, _(u"&Photo")) - self.remove = wx.Button(panel, wx.ID_ANY, _(u"Remove attachment")) - self.remove.Enable(False) - btnsizer = wx.StaticBoxSizer(static, wx.HORIZONTAL) - btnsizer.Add(self.photo, 0, wx.ALL, 5) - sizer.Add(btnsizer, 0, wx.ALL, 5) - ok = wx.Button(panel, wx.ID_OK) - ok.SetDefault() - cancelBtn = wx.Button(panel, wx.ID_CANCEL) - btnSizer = wx.BoxSizer() - btnSizer.Add(ok, 0, wx.ALL, 5) - btnSizer.Add(cancelBtn, 0, wx.ALL, 5) - sizer.Add(btnSizer, 0, wx.ALL, 5) - panel.SetSizer(sizer) - self.SetClientSize(sizer.CalcMin()) - - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return (None, None) - dsc = self.ask_description() - return (openFileDialog.GetPath(), dsc) - - def ask_description(self): - dlg = wx.TextEntryDialog(self, _(u"please provide a description"), _(u"Description")) - dlg.ShowModal() - result = dlg.GetValue() - dlg.Destroy() - return result diff --git a/src/wxUI/dialogs/message.py b/src/wxUI/dialogs/message.py deleted file mode 100644 index 8eadfdd9..00000000 --- a/src/wxUI/dialogs/message.py +++ /dev/null @@ -1,471 +0,0 @@ -# -*- coding: utf-8 -*- -import wx -import widgetUtils - -class textLimited(widgetUtils.BaseDialog): - def __init__(self, *args, **kwargs): - super(textLimited, self).__init__(parent=None, *args, **kwargs) - - def createTextArea(self, message="", text=""): - if not hasattr(self, "panel"): - self.panel = wx.Panel(self) - self.label = wx.StaticText(self.panel, -1, message) - self.SetTitle(str(len(text))) - self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1),style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) -# font = self.text.GetFont() -# dc = wx.WindowDC(self.text) -# dc.SetFont(font) -# x, y = dc.GetTextExtent("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") -# self.text.SetSize((x, y)) - self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) - self.text.SetFocus() - self.textBox = wx.BoxSizer(wx.HORIZONTAL) - self.textBox.Add(self.label, 0, wx.ALL, 5) - self.textBox.Add(self.text, 0, wx.ALL, 5) - - def text_focus(self): - self.text.SetFocus() - - def get_text(self): - return self.text.GetValue() - - def set_text(self, text): - return self.text.ChangeValue(text) - - def set_title(self, new_title): - return self.SetTitle(new_title) - - def enable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Enable() - - def disable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Disable() - - def onSelect(self, ev): - self.text.SelectAll() - - def handle_keys(self, event): - shift=event.ShiftDown() - if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'okButton'): - wx.PostEvent(self.okButton.GetEventHandler(), wx.PyCommandEvent(wx.EVT_BUTTON.typeId,wx.ID_OK)) - else: - event.Skip() - - def set_cursor_at_end(self): - self.text.SetInsertionPoint(len(self.text.GetValue())) - - def set_cursor_at_position(self, position): - self.text.SetInsertionPoint(position) - - def get_position(self): - return self.text.GetInsertionPoint() - - def popup_menu(self, menu): - self.PopupMenu(menu, self.text.GetPosition()) - -class tweet(textLimited): - def createControls(self, title, message, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, text) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.long_tweet = wx.CheckBox(self.panel, -1, _(u"&Long tweet")) - self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) - self.mainBox.Add(self.ok_cancelSizer) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ - (wx.ACCEL_CTRL, ord('A'), selectId), - ]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) - - def __init__(self, title, message, text, *args, **kwargs): - super(tweet, self).__init__() - self.shift=False - self.createControls(message, title, text) - self.SetClientSize(self.mainBox.CalcMin()) - - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return open(openFileDialog.GetPath(), "rb") - - -class retweet(tweet): - def createControls(self, title, message, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, "") - label = wx.StaticText(self.panel, -1, _(u"Retweet")) - self.text2 = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE|wx.TE_READONLY) - self.retweetBox = wx.BoxSizer(wx.HORIZONTAL) - self.retweetBox.Add(label, 0, wx.ALL, 5) - self.retweetBox.Add(self.text2, 0, wx.ALL, 5) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.mainBox.Add(self.retweetBox, 0, wx.ALL, 5) - self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) - self.mainBox.Add(self.ok_cancelSizer) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ - (wx.ACCEL_CTRL, ord('A'), selectId), - ]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) - - def __init__(self, title, message, text, *args, **kwargs): - super(tweet, self).__init__() - self.createControls(message, title, text) -# self.onTimer(wx.EVT_CHAR_HOOK) - self.SetClientSize(self.mainBox.CalcMin()) - - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return open(openFileDialog.GetPath(), "rb") - -class dm(textLimited): - def createControls(self, title, message, users): - self.panel = wx.Panel(self) - self.mainBox = wx.BoxSizer(wx.VERTICAL) - label = wx.StaticText(self.panel, -1, _(u"&Recipient")) - self.cb = wx.ComboBox(self.panel, -1, choices=users, value=users[0], size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.createTextArea(message, text="") - userBox = wx.BoxSizer(wx.HORIZONTAL) - userBox.Add(label, 0, wx.ALL, 5) - userBox.Add(self.cb, 0, wx.ALL, 5) - userBox.Add(self.autocompletionButton, 0, wx.ALL, 5) - self.mainBox.Add(userBox, 0, wx.ALL, 5) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - self.buttonsBox.Add(self.attach, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox, 0, wx.ALL, 5) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.shortenButton, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.unshortenButton, 0, wx.ALL, 5) - self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 5) - self.buttonsBox3 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox3.Add(self.okButton, 0, wx.ALL, 5) - self.buttonsBox3.Add(cancelButton, 0, wx.ALL, 5) - self.mainBox.Add(self.buttonsBox3, 0, wx.ALL, 5) - self.panel.SetSizer(self.mainBox) - self.SetClientSize(self.mainBox.CalcMin()) - - def __init__(self, title, message, users, *args, **kwargs): - super(dm, self).__init__() - self.createControls(title, message, users) -# self.onTimer(wx.EVT_CHAR_HOOK) -# self.SetClientSize(self.mainBox.CalcMin()) - - def get_user(self): - return self.cb.GetValue() - - def set_user(self, user): - return self.cb.SetValue(user) - -class reply(textLimited): - - def get_image(self): - openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if openFileDialog.ShowModal() == wx.ID_CANCEL: - return None - return open(openFileDialog.GetPath(), "rb") - - def createControls(self, title, message, text): - self.mainBox = wx.BoxSizer(wx.VERTICAL) - self.createTextArea(message, text) - self.mainBox.Add(self.textBox, 0, wx.ALL, 5) - self.usersbox = wx.BoxSizer(wx.VERTICAL) - self.mentionAll = wx.CheckBox(self.panel, -1, _(u"&Mention to all"), size=wx.DefaultSize) - self.mentionAll.Disable() - self.usersbox.Add(self.mentionAll, 0, wx.ALL, 5) - self.checkboxes = [] - for i in self.users: - user_checkbox = wx.CheckBox(self.panel, -1, "@"+i, size=wx.DefaultSize) - self.checkboxes.append(user_checkbox) - self.usersbox.Add(self.checkboxes[-1], 0, wx.ALL, 5) - self.mainBox.Add(self.usersbox, 0, wx.ALL, 10) - self.long_tweet = wx.CheckBox(self.panel, -1, _(u"&Long tweet")) - self.upload_image = wx.Button(self.panel, -1, _(u"&Upload image..."), size=wx.DefaultSize) - self.spellcheck = wx.Button(self.panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.attach = wx.Button(self.panel, -1, _(u"&Attach audio..."), size=wx.DefaultSize) - self.shortenButton = wx.Button(self.panel, -1, _(u"Sh&orten URL"), size=wx.DefaultSize) - self.unshortenButton = wx.Button(self.panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.shortenButton.Disable() - self.unshortenButton.Disable() - self.translateButton = wx.Button(self.panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - self.autocompletionButton = wx.Button(self.panel, -1, _(u"Auto&complete users")) - self.okButton = wx.Button(self.panel, wx.ID_OK, _(u"Sen&d"), size=wx.DefaultSize) - self.okButton.SetDefault() - cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox1.Add(self.upload_image, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10) - self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10) - self.buttonsBox2 = wx.BoxSizer(wx.HORIZONTAL) - self.buttonsBox2.Add(self.shortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.unshortenButton, 0, wx.ALL, 10) - self.buttonsBox2.Add(self.translateButton, 0, wx.ALL, 10) - self.mainBox.Add(self.buttonsBox2, 0, wx.ALL, 10) - self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL) - self.ok_cancelSizer.Add(self.autocompletionButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10) - self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10) - self.mainBox.Add(self.ok_cancelSizer, 0, wx.ALL, 10) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ - (wx.ACCEL_CTRL, ord('A'), selectId), - ]) - self.SetAcceleratorTable(self.accel_tbl) - self.panel.SetSizer(self.mainBox) - - def __init__(self, title, message, text, users=[], *args, **kwargs): - self.users = users - super(reply, self).__init__() - self.shift=False - self.createControls(message, title, text) - self.SetClientSize(self.mainBox.CalcMin()) - -class viewTweet(widgetUtils.BaseDialog): - def set_title(self, lenght): - self.SetTitle(_(u"Tweet - %i characters ") % (lenght,)) - - def __init__(self, text, rt_count, favs_count, source, date="", *args, **kwargs): - super(viewTweet, self).__init__(None, size=(850,850)) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Tweet")) - self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.text) - dc.SetFont(self.text.GetFont()) - (x, y) = dc.GetMultiLineTextExtent("0"*140) - self.text.SetSize((x, y)) - self.text.SetFocus() - textBox = wx.BoxSizer(wx.HORIZONTAL) - textBox.Add(label, 0, wx.ALL, 5) - textBox.Add(self.text, 1, wx.EXPAND, 5) - mainBox = wx.BoxSizer(wx.VERTICAL) - mainBox.Add(textBox, 0, wx.ALL, 5) - label2 = wx.StaticText(panel, -1, _(u"Image description")) - self.image_description = wx.TextCtrl(panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.image_description) - dc.SetFont(self.image_description.GetFont()) - (x, y) = dc.GetMultiLineTextExtent("0"*450) - self.image_description.SetSize((x, y)) - self.image_description.Enable(False) - iBox = wx.BoxSizer(wx.HORIZONTAL) - iBox.Add(label2, 0, wx.ALL, 5) - iBox.Add(self.image_description, 1, wx.EXPAND, 5) - mainBox.Add(iBox, 0, wx.ALL, 5) - rtCountLabel = wx.StaticText(panel, -1, _(u"Retweets: ")) - rtCount = wx.TextCtrl(panel, -1, rt_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - rtBox = wx.BoxSizer(wx.HORIZONTAL) - rtBox.Add(rtCountLabel, 0, wx.ALL, 5) - rtBox.Add(rtCount, 0, wx.ALL, 5) - favsCountLabel = wx.StaticText(panel, -1, _(u"Likes: ")) - favsCount = wx.TextCtrl(panel, -1, favs_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - favsBox = wx.BoxSizer(wx.HORIZONTAL) - favsBox.Add(favsCountLabel, 0, wx.ALL, 5) - favsBox.Add(favsCount, 0, wx.ALL, 5) - sourceLabel = wx.StaticText(panel, -1, _(u"Source: ")) - sourceTweet = wx.TextCtrl(panel, -1, source, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - sourceBox = wx.BoxSizer(wx.HORIZONTAL) - sourceBox.Add(sourceLabel, 0, wx.ALL, 5) - sourceBox.Add(sourceTweet, 0, wx.ALL, 5) - dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) - dateTweet = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - dc = wx.WindowDC(dateTweet) - dc.SetFont(dateTweet.GetFont()) - (x, y) = dc.GetTextExtent("0"*100) - dateTweet.SetSize((x, y)) - dateBox = wx.BoxSizer(wx.HORIZONTAL) - dateBox.Add(dateLabel, 0, wx.ALL, 5) - dateBox.Add(dateTweet, 0, wx.ALL, 5) - infoBox = wx.BoxSizer(wx.HORIZONTAL) - infoBox.Add(rtBox, 0, wx.ALL, 5) - infoBox.Add(favsBox, 0, wx.ALL, 5) - infoBox.Add(sourceBox, 0, wx.ALL, 5) - mainBox.Add(infoBox, 0, wx.ALL, 5) - mainBox.Add(dateBox, 0, wx.ALL, 5) - self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) - self.share.Enable(False) - self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Disable() - self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - cancelButton.SetDefault() - buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - buttonsBox.Add(self.share, 0, wx.ALL, 5) - buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) - buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) - buttonsBox.Add(cancelButton, 0, wx.ALL, 5) - mainBox.Add(buttonsBox, 0, wx.ALL, 5) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ - (wx.ACCEL_CTRL, ord('A'), selectId), - ]) - self.SetAcceleratorTable(self.accel_tbl) - panel.SetSizer(mainBox) - self.SetClientSize(mainBox.CalcMin()) - - def set_text(self, text): - self.text.ChangeValue(text) - - def get_text(self): - return self.text.GetValue() - - def set_image_description(self, desc): - self.image_description.Enable(True) - if len(self.image_description.GetValue()) == 0: - self.image_description.SetValue(desc) - else: - self.image_description.SetValue(self.image_description.GetValue()+"\n"+desc) - - def text_focus(self): - self.text.SetFocus() - - def onSelect(self, ev): - self.text.SelectAll() - - def enable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Enable() - -class viewNonTweet(widgetUtils.BaseDialog): - - def __init__(self, text, date="", *args, **kwargs): - super(viewNonTweet, self).__init__(None, size=(850,850)) - self.SetTitle(_(u"View")) - panel = wx.Panel(self) - label = wx.StaticText(panel, -1, _(u"Item")) - self.text = wx.TextCtrl(parent=panel, id=-1, value=text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) - dc = wx.WindowDC(self.text) - dc.SetFont(self.text.GetFont()) - (x, y) = dc.GetMultiLineTextExtent("0"*140) - self.text.SetSize((x, y)) - self.text.SetFocus() - textBox = wx.BoxSizer(wx.HORIZONTAL) - textBox.Add(label, 0, wx.ALL, 5) - textBox.Add(self.text, 1, wx.EXPAND, 5) - mainBox = wx.BoxSizer(wx.VERTICAL) - mainBox.Add(textBox, 0, wx.ALL, 5) - if date != "": - dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) - date = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) - dc = wx.WindowDC(date) - dc.SetFont(date.GetFont()) - (x, y) = dc.GetTextExtent("0"*100) - date.SetSize((x, y)) - dateBox = wx.BoxSizer(wx.HORIZONTAL) - dateBox.Add(dateLabel, 0, wx.ALL, 5) - dateBox.Add(date, 0, wx.ALL, 5) - mainBox.Add(dateBox, 0, wx.ALL, 5) - self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) - self.share.Enable(False) - self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) - self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) - self.unshortenButton.Disable() - self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) - cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) - cancelButton.SetDefault() - buttonsBox = wx.BoxSizer(wx.HORIZONTAL) - buttonsBox.Add(self.share, 0, wx.ALL, 5) - buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) - buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) - buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) - buttonsBox.Add(cancelButton, 0, wx.ALL, 5) - mainBox.Add(buttonsBox, 0, wx.ALL, 5) - selectId = wx.ID_ANY - self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) - self.accel_tbl = wx.AcceleratorTable([ - (wx.ACCEL_CTRL, ord('A'), selectId), - ]) - self.SetAcceleratorTable(self.accel_tbl) - panel.SetSizer(mainBox) - self.SetClientSize(mainBox.CalcMin()) - - def onSelect(self, ev): - self.text.SelectAll() - - def set_text(self, text): - self.text.ChangeValue(text) - - def get_text(self): - return self.text.GetValue() - - def text_focus(self): - self.text.SetFocus() - - def enable_button(self, buttonName): - if hasattr(self, buttonName): - return getattr(self, buttonName).Enable() From 6d505c6fe7fde6772f7bfcb32dc4b9c3bd30d435 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:11:09 -0600 Subject: [PATCH 212/245] Added new code for Tweet GUI and attachment of photos and gifts --- src/controller/messages.py | 253 +++++----- src/wxUI/dialogs/twitterDialogs/__init__.py | 1 + .../dialogs/twitterDialogs/tweetDialogs.py | 457 ++++++++++++++++++ 3 files changed, 601 insertions(+), 110 deletions(-) create mode 100644 src/wxUI/dialogs/twitterDialogs/__init__.py create mode 100644 src/wxUI/dialogs/twitterDialogs/tweetDialogs.py diff --git a/src/controller/messages.py b/src/controller/messages.py index a748464d..9417ad90 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -1,123 +1,67 @@ # -*- coding: utf-8 -*- -import re -import platform +import os import arrow import languageHandler -system = platform.system() +import wx import widgetUtils import output -import url_shortener import sound import config from pubsub import pub from twitter_text import parse_tweet -if system == "Windows": - from wxUI.dialogs import message, urlList - from wxUI import commonMessageDialogs - from extra import translator, SpellChecker, autocompletionUsers - from extra.AudioUploader import audioUploader -elif system == "Linux": - from gtkUI.dialogs import message +from wxUI.dialogs import twitterDialogs, urlList +#from wxUI.dialogs import twitterDialogs +from wxUI import commonMessageDialogs +from extra import translator, SpellChecker, autocompletionUsers +from extra.AudioUploader import audioUploader from sessions.twitter import utils -from . import attach class basicTweet(object): """ This class handles the tweet main features. Other classes should derive from this class.""" - def __init__(self, session, title, caption, text, messageType="tweet", max=280, *args, **kwargs): + def __init__(self, session, title, caption, text="", messageType="tweet", max=280, *args, **kwargs): super(basicTweet, self).__init__() self.max = max self.title = title self.session = session - self.message = getattr(message, messageType)(title, caption, text, *args, **kwargs) + self.message = getattr(twitterDialogs, messageType)(title=title, caption=caption, message=text, *args, **kwargs) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) - widgetUtils.connect_event(self.message.attach, widgetUtils.BUTTON_PRESSED, self.attach) + widgetUtils.connect_event(self.message.add_audio, widgetUtils.BUTTON_PRESSED, self.attach) widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor) - widgetUtils.connect_event(self.message.shortenButton, widgetUtils.BUTTON_PRESSED, self.shorten) - widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) - widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - if hasattr(self.message, "long_tweet"): - widgetUtils.connect_event(self.message.long_tweet, widgetUtils.CHECKBOX, self.text_processor) - if config.app["app-settings"]["remember_mention_and_longtweet"]: - self.message.long_tweet.SetValue(config.app["app-settings"]["longtweet"]) + widgetUtils.connect_event(self.message.translate, widgetUtils.BUTTON_PRESSED, self.translate) + if hasattr(self.message, "add"): + widgetUtils.connect_event(self.message.add, widgetUtils.BUTTON_PRESSED, self.on_attach) self.attachments = [] def translate(self, event=None): dlg = translator.gui.translateDialog() if dlg.get_response() == widgetUtils.OK: - text_to_translate = self.message.get_text() + text_to_translate = self.message.text.GetValue() language_dict = translator.translator.available_languages() for k in language_dict: if language_dict[k] == dlg.dest_lang.GetStringSelection(): dst = k msg = translator.translator.translate(text=text_to_translate, target=dst) - self.message.set_text(msg) + self.message.text.ChangeValue(msg) self.text_processor() - self.message.text_focus() + self.message.text.SetFocus() output.speak(_(u"Translated")) else: return - def shorten(self, event=None): - urls = utils.find_urls_in_text(self.message.get_text()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be shortened")) - self.message.text_focus() - elif len(urls) == 1: - self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.shorten(urls[0]))) - output.speak(_(u"URL shortened")) - self.text_processor() - self.message.text_focus() - elif len(urls) > 1: - list_urls = urlList.urlList() - list_urls.populate_list(urls) - if list_urls.get_response() == widgetUtils.OK: - self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.shorten(list_urls.get_string()))) - output.speak(_(u"URL shortened")) - self.text_processor() - self.message.text_focus() - - def unshorten(self, event=None): - urls = utils.find_urls_in_text(self.message.get_text()) - if len(urls) == 0: - output.speak(_(u"There's no URL to be expanded")) - self.message.text_focus() - elif len(urls) == 1: - self.message.set_text(self.message.get_text().replace(urls[0], url_shortener.unshorten(urls[0]))) - output.speak(_(u"URL expanded")) - self.text_processor() - self.message.text_focus() - elif len(urls) > 1: - list_urls = urlList.urlList() - list_urls.populate_list(urls) - if list_urls.get_response() == widgetUtils.OK: - self.message.set_text(self.message.get_text().replace(urls[list_urls.get_item()], url_shortener.unshorten(list_urls.get_string()))) - output.speak(_(u"URL expanded")) - self.text_processor() - self.message.text_focus() - def text_processor(self, *args, **kwargs): - if len(self.message.get_text()) > 1: - self.message.enable_button("shortenButton") - self.message.enable_button("unshortenButton") - else: - self.message.disable_button("shortenButton") - self.message.disable_button("unshortenButton") - if self.message.get("long_tweet") == False and hasattr(self, "max"): - text = self.message.get_text() - results = parse_tweet(text) - self.message.set_title(_(u"%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) - if results.weightedLength > self.max: - self.session.sound.play("max_length.ogg") - else: - self.message.set_title(_(u"%s - %s characters") % (self.title, len(self.message.get_text()))) + text = self.message.text.GetValue() + results = parse_tweet(text) + self.message.SetTitle(_("%s - %s of %d characters") % (self.title, results.weightedLength, self.max)) + if results.weightedLength > self.max: + self.session.sound.play("max_length.ogg") def spellcheck(self, event=None): - text = self.message.get_text() + text = self.message.text.GetValue() checker = SpellChecker.spellchecker.spellChecker(text, "") if hasattr(checker, "fixed_text"): - self.message.set_text(checker.fixed_text) + self.message.text.ChangeValue(checker.fixed_text) self.text_processor() - self.message.text_focus() + self.message.text.SetFocus() def attach(self, *args, **kwargs): def completed_callback(dlg): @@ -125,48 +69,145 @@ class basicTweet(object): pub.unsubscribe(dlg.uploaderDialog.update, "uploading") dlg.uploaderDialog.destroy() if "sndup.net/" in url: - self.message.set_text(self.message.get_text()+url+" #audio") + self.message.text.ChangeValue(self.message.text.GetValue()+url+" #audio") self.text_processor() else: commonMessageDialogs.common_error(url) - dlg.cleanup() dlg = audioUploader.audioUploader(self.session.settings, completed_callback) - self.message.text_focus() + self.message.text.SetFocus() + + def can_attach(self): + if len(self.attachments) == 0: + return True + elif len(self.attachments) == 1 and (self.attachments[0]["type"] == "video" or self.attachments[0]["type"] == "gif"): + return False + elif len(self.attachments) < 4: + return True + return False + + def on_attach(self, *args, **kwargs): + can_attach = self.can_attach() + menu = self.message.attach_menu(can_attach) + self.message.Bind(wx.EVT_MENU, self.on_attach_image, self.message.add_image) + self.message.Bind(wx.EVT_MENU, self.on_attach_video, self.message.add_video) + self.message.Bind(wx.EVT_MENU, self.on_attach_poll, self.message.add_poll) + self.message.PopupMenu(menu, self.message.add.GetPosition()) + + def on_attach_image(self, *args, **kwargs): + image, description = self.message.get_image() + if image != None: + if image.endswith("gif"): + image_type = "gif" + else: + image_type = "photo" + imageInfo = {"type": image_type, "file": image, "description": description} + if len(self.attachments) > 0 and image_type == "gif": + return self.message.unable_to_attach_file() + self.attachments.append(imageInfo) + self.message.add_item(item=[os.path.basename(imageInfo["file"]), imageInfo["type"], imageInfo["description"]]) + self.text_processor() + + def on_attach_video(self, *args, **kwargs): + video = self.message.get_video() + if video != None: + videoInfo = {"type": "video", "file": video, "description": ""} + if len(self.attachments) > 0: + return self.message.unable_to_attach_file() + self.attachments.append(videoInfo) + self.message.add_item(item=[os.path.basename(videoInfo["file"]), videoInfo["type"], videoInfo["description"]]) + self.text_processor() + + def on_attach_poll(self, *args, **kwargs): + pass class tweet(basicTweet): def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs): + self.thread = [] super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) self.image = None - widgetUtils.connect_event(self.message.upload_image, widgetUtils.BUTTON_PRESSED, self.upload_image) - widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + if hasattr(self.message, "add_tweet"): + widgetUtils.connect_event(self.message.add_tweet, widgetUtils.BUTTON_PRESSED, self.add_tweet) + widgetUtils.connect_event(self.message.remove_tweet, widgetUtils.BUTTON_PRESSED, self.remove_tweet) + widgetUtils.connect_event(self.message.remove_attachment, widgetUtils.BUTTON_PRESSED, self.remove_attachment) self.text_processor() - def upload_image(self, *args, **kwargs): - a = attach.attach() - if len(a.attachments) != 0: - self.attachments = a.attachments - def autocomplete_users(self, *args, **kwargs): c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c.show_menu() + def add_tweet(self, event, update_gui=True, *args, **kwargs): + text = self.message.text.GetValue() + attachments = self.attachments[::] + tweetdata = dict(text=text, attachments=attachments) + self.thread.append(tweetdata) + if update_gui: + self.message.reset_controls() + self.message.add_item(item=[text, len(attachments)], list_type="tweet") + self.message.text.SetFocus() + self.text_processor() + + def get_tweet_data(self): + self.add_tweet(event=None, update_gui=False) + return self.thread + + def text_processor(self, *args, **kwargs): + super(tweet, self).text_processor(*args, **kwargs) + if len(self.thread) > 0: + self.message.tweets.Enable(True) + self.message.remove_tweet.Enable(True) + else: + self.message.tweets.Enable(False) + self.message.remove_tweet.Enable(False) + if len(self.attachments) > 0: + self.message.attachments.Enable(True) + self.message.remove_attachment.Enable(True) + else: + self.message.attachments.Enable(False) + self.message.remove_attachment.Enable(False) + + def remove_tweet(self, *args, **kwargs): + tweet = self.message.tweets.GetFocusedItem() + if tweet > -1 and len(self.thread) > tweet: + self.thread.pop(tweet) + self.message.remove_item(list_type="tweet") + self.text_processor() + self.message.text.SetFocus() + + def remove_attachment(self, *args, **kwargs): + attachment = self.message.attachments.GetFocusedItem() + if attachment > -1 and len(self.attachments) > attachment: + self.attachments.pop(attachment) + self.message.remove_item(list_type="attachment") + self.text_processor() + self.message.text.SetFocus() + class reply(tweet): def __init__(self, session, title, caption, text, users=[], ids=[]): super(reply, self).__init__(session, title, caption, text, messageType="reply", users=users) self.ids = ids self.users = users if len(users) > 0: - widgetUtils.connect_event(self.message.mentionAll, widgetUtils.CHECKBOX, self.mention_all) - self.message.enable_button("mentionAll") + widgetUtils.connect_event(self.message.mention_all, widgetUtils.CHECKBOX, self.mention_all) + self.message.mention_all.Enable(True) if config.app["app-settings"]["remember_mention_and_longtweet"]: - self.message.mentionAll.SetValue(config.app["app-settings"]["mention_all"]) + self.message.mention_all.SetValue(config.app["app-settings"]["mention_all"]) self.mention_all() - self.message.set_cursor_at_end() + self.message.text.SetInsertionPoint(len(self.message.text.GetValue())) self.text_processor() + def text_processor(self, *args, **kwargs): + super(tweet, self).text_processor(*args, **kwargs) + if len(self.attachments) > 0: + self.message.attachments.Enable(True) + self.message.remove_attachment.Enable(True) + else: + self.message.attachments.Enable(False) + self.message.remove_attachment.Enable(False) + def mention_all(self, *args, **kwargs): - if self.message.mentionAll.GetValue() == True: + if self.message.mention_all.GetValue() == True: for i in self.message.checkboxes: i.SetValue(True) i.Hide() @@ -190,14 +231,14 @@ class reply(tweet): return people class dm(basicTweet): - def __init__(self, session, title, caption, text): - super(dm, self).__init__(session, title, caption, text, messageType="dm", max=10000) - widgetUtils.connect_event(self.message.autocompletionButton, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) + def __init__(self, session, title, caption, users): + super(dm, self).__init__(session, title, caption, messageType="dm", max=10000, users=users) + widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) self.text_processor() widgetUtils.connect_event(self.message.cb, widgetUtils.ENTERED_TEXT, self.user_changed) def user_changed(self, *args, **kwargs): - self.title = _("Direct message to %s") % (self.message.get_user()) + self.title = _("Direct message to %s") % (self.message.cb.GetValue()) self.text_processor() def autocomplete_users(self, *args, **kwargs): @@ -264,29 +305,21 @@ class viewTweet(basicTweet): for z in tweet.retweeted_status.extended_entities["media"]: if "ext_alt_text" in z and z["ext_alt_text"] != None: image_description.append(z["ext_alt_text"]) - self.message = message.viewTweet(text, rt_count, favs_count, source, date) + self.message = twitterDialogs.viewTweet(text, rt_count, favs_count, source, date) results = parse_tweet(text) self.message.set_title(results.weightedLength) [self.message.set_image_description(i) for i in image_description] else: self.title = _(u"View item") text = tweet - self.message = message.viewNonTweet(text, date) + self.message = twitterDialogs.viewNonTweet(text, date) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) if item_url != "": self.message.enable_button("share") widgetUtils.connect_event(self.message.share, widgetUtils.BUTTON_PRESSED, self.share) self.item_url = item_url widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) - if self.contain_urls() == True: - self.message.enable_button("unshortenButton") - widgetUtils.connect_event(self.message.unshortenButton, widgetUtils.BUTTON_PRESSED, self.unshorten) - self.message.get_response() - - def contain_urls(self): - if len(utils.find_urls_in_text(self.message.get_text())) > 0: - return True - return False + self.message.ShowModal() def clear_text(self, text): urls = utils.find_urls_in_text(text) diff --git a/src/wxUI/dialogs/twitterDialogs/__init__.py b/src/wxUI/dialogs/twitterDialogs/__init__.py new file mode 100644 index 00000000..c6b568e0 --- /dev/null +++ b/src/wxUI/dialogs/twitterDialogs/__init__.py @@ -0,0 +1 @@ +from .tweetDialogs import tweet, reply, dm, viewTweet, viewNonTweet \ No newline at end of file diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py new file mode 100644 index 00000000..d07f10da --- /dev/null +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -0,0 +1,457 @@ +""" GUI dialogs for tweet writing and displaying. """ +import wx +from typing import List + +class tweet(wx.Dialog): + def __init__(self, title: str, caption: str, message: str = "", max_length: int = 280, thread_mode: bool = True, *args, **kwds) -> None: + """ Creates the basic Tweet dialog. This might be considered the base class for other dialogs. + title str: title to be used in the dialog. + caption str: This is the text to be placed alongside the text field. + message str: Text to be inserted in the tweet. + max_length int: Maximum amount of characters the tweet will accept. By default is 280 chahracters. + thread_mode bool: If set to False, disables the button that allows to make threads by adding more tweets. + """ + super(tweet, self).__init__(parent=None, *args, **kwds) + self.SetTitle(title) + self.create_controls(max_length=max_length, caption=caption, message=message, thread_mode=thread_mode) + + def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: + panel = wx.Panel(self) + mainBox = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(text_sizer, 1, wx.EXPAND, 0) + label_1 = wx.StaticText(panel, wx.ID_ANY, caption) + text_sizer.Add(label_1, 0, 0, 0) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetMinSize((1000, 158)) + self.text.SetMaxLength(max_length) + text_sizer.Add(self.text, 1, wx.EXPAND, 0) + list_sizer = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(list_sizer, 1, wx.EXPAND, 0) + Attachment_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(Attachment_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(panel, wx.ID_ANY, _("Attachments")) + Attachment_sizer.Add(label_2, 0, 0, 0) + self.attachments = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.attachments.AppendColumn(_("File")) + self.attachments.AppendColumn(_("Type")) + self.attachments.AppendColumn(_("Description")) + Attachment_sizer.Add(self.attachments, 1, wx.EXPAND, 0) + self.remove_attachment = wx.Button(panel, wx.ID_ANY, _("Delete attachment")) + self.remove_attachment.Enable(False) + Attachment_sizer.Add(self.remove_attachment, 0, 0, 0) + tweet_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(tweet_sizer, 1, wx.EXPAND, 0) + label_3 = wx.StaticText(panel, wx.ID_ANY, _("Added Tweets")) + tweet_sizer.Add(label_3, 0, 0, 0) + self.tweets = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.tweets.AppendColumn(_("Text")) + self.tweets.AppendColumn(_("Attachments")) + self.tweets.Enable(False) + tweet_sizer.Add(self.tweets, 1, wx.EXPAND, 0) + self.remove_tweet = wx.Button(panel, wx.ID_ANY, _("Delete tweet")) + self.remove_tweet.Enable(False) + tweet_sizer.Add(self.remove_tweet, 0, 0, 0) + btn_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) + self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) + btn_sizer_1.Add(self.add, 0, 0, 0) + self.add_tweet = wx.Button(panel, wx.ID_ANY, _("Add tweet")) + self.add_tweet.Enable(thread_mode) + btn_sizer_1.Add(self.add_tweet, 0, 0, 0) + self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) + btn_sizer_1.Add(self.add_audio, 0, 0, 0) + btn_sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_2, 1, wx.EXPAND, 0) + self.autocomplete_users = wx.Button(panel, wx.ID_ANY, _("Auto&complete users")) + btn_sizer_2.Add(self.autocomplete_users, 0, 0, 0) + self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling...")) + btn_sizer_2.Add(self.spellcheck, 0, 0, 0) + self.translate = wx.Button(panel, wx.ID_ANY, _("&Translate")) + btn_sizer_2.Add(self.translate, 0, 0, 0) + ok_cancel_sizer = wx.StdDialogButtonSizer() + mainBox.Add(ok_cancel_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.send = wx.Button(panel, wx.ID_OK, _("Sen&d")) + self.send.SetDefault() + ok_cancel_sizer.Add(self.send, 0, 0, 0) + self.cancel = wx.Button(panel, wx.ID_CANCEL, "") + ok_cancel_sizer.AddButton(self.cancel) + ok_cancel_sizer.Realize() + panel.SetSizer(mainBox) + self.Fit() + self.SetAffirmativeId(self.send.GetId()) + self.SetEscapeId(self.cancel.GetId()) + self.Layout() + + def handle_keys(self, event: wx.Event, *args, **kwargs) -> None: + """ Allows to react to certain keyboard events from the text control. """ + shift=event.ShiftDown() + if event.GetKeyCode() == wx.WXK_RETURN and shift==False and hasattr(self,'send'): + self.EndModal(wx.ID_OK) + else: + event.Skip() + + def reset_controls(self) -> None: + """ Resetss text control and attachments to their default, empty values. This is used while adding more tweets in a thread. """ + self.text.ChangeValue("") + self.attachments.DeleteAllItems() + + def add_item(self, list_type: str = "attachment", item: List[str] = []) -> None: + """ Adds an item to a list control. Item should be a list with the same amount of items for each column present in the ListCtrl. """ + if list_type == "attachment": + self.attachments.Append(item) + else: + self.tweets.Append(item) + + def remove_item(self, list_type: str = "attachment") -> None: + if list_type == "attachment": + item = self.attachments.GetFocusedItem() + if item > -1: + self.attachments.DeleteItem(item) + else: + item = self.tweets.GetFocusedItem() + if item > -1: + self.tweets.DeleteItem(item) + + def attach_menu(self, event=None, enabled=True, *args, **kwargs): + menu = wx.Menu() + self.add_image = menu.Append(wx.ID_ANY, _("Image")) + self.add_image.Enable(enabled) + self.add_video = menu.Append(wx.ID_ANY, _("Video")) + self.add_video.Enable(enabled) + self.add_poll = menu.Append(wx.ID_ANY, _("Poll")) + self.add_poll.Enable(enabled) + return menu + + def ask_description(self): + dlg = wx.TextEntryDialog(self, _(u"please provide a description"), _(u"Description")) + dlg.ShowModal() + result = dlg.GetValue() + dlg.Destroy() + return result + + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return (None, None) + dsc = self.ask_description() + return (openFileDialog.GetPath(), dsc) + + def get_video(self): + openFileDialog = wx.FileDialog(self, _("Select the video to be uploaded"), "", "", _("Video files (*.mp4)|*.mp4"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return None + return openFileDialog.GetPath() + + def unable_to_attach_file(self, *args, **kwargs): + return wx.MessageDialog(self, _("You need to delete other attachments first, as Videos and GIF's cannot be added with other attachments."), _("Error adding attachment"), wx.ICON_ERROR).ShowModal() + +class reply(tweet): + + def __init__(self, users: List[str] = [], *args, **kwargs) -> None: + self.users = users + super(reply, self).__init__(*args, **kwargs) + + def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: + panel = wx.Panel(self) + mainBox = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(text_sizer, 1, wx.EXPAND, 0) + label_1 = wx.StaticText(panel, wx.ID_ANY, caption) + text_sizer.Add(label_1, 0, 0, 0) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetMinSize((1000, 158)) + self.text.SetMaxLength(max_length) + text_sizer.Add(self.text, 1, wx.EXPAND, 0) + list_sizer = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(list_sizer, 1, wx.EXPAND, 0) + Attachment_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(Attachment_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(panel, wx.ID_ANY, _("Attachments")) + Attachment_sizer.Add(label_2, 0, 0, 0) + self.attachments = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.attachments.AppendColumn(_("File")) + self.attachments.AppendColumn(_("Type")) + self.attachments.AppendColumn(_("Description")) + Attachment_sizer.Add(self.attachments, 1, wx.EXPAND, 0) + self.remove_attachment = wx.Button(panel, wx.ID_ANY, _("Delete attachment")) + self.remove_attachment.Enable(False) + Attachment_sizer.Add(self.remove_attachment, 0, 0, 0) + user_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(user_sizer, 0, 0, 0) + self.mention_all = wx.CheckBox(panel, -1, _(u"&Mention to all"), size=wx.DefaultSize) + self.mention_all.Disable() + user_sizer.Add(self.mention_all, 0, wx.ALL, 5) + self.checkboxes = [] + for i in self.users: + user_checkbox = wx.CheckBox(panel, -1, "@"+i, size=wx.DefaultSize) + self.checkboxes.append(user_checkbox) + user_sizer.Add(self.checkboxes[-1], 0, wx.ALL, 5) + btn_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) + self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) + btn_sizer_1.Add(self.add, 0, 0, 0) + self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) + btn_sizer_1.Add(self.add_audio, 0, 0, 0) + btn_sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_2, 1, wx.EXPAND, 0) + self.autocomplete_users = wx.Button(panel, wx.ID_ANY, _("Auto&complete users")) + btn_sizer_2.Add(self.autocomplete_users, 0, 0, 0) + self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling...")) + btn_sizer_2.Add(self.spellcheck, 0, 0, 0) + self.translate = wx.Button(panel, wx.ID_ANY, _("&Translate")) + btn_sizer_2.Add(self.translate, 0, 0, 0) + ok_cancel_sizer = wx.StdDialogButtonSizer() + mainBox.Add(ok_cancel_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.send = wx.Button(panel, wx.ID_OK, _("Sen&d")) + self.send.SetDefault() + ok_cancel_sizer.Add(self.send, 0, 0, 0) + self.cancel = wx.Button(panel, wx.ID_CANCEL, "") + ok_cancel_sizer.AddButton(self.cancel) + ok_cancel_sizer.Realize() + panel.SetSizer(mainBox) + self.Fit() + self.SetAffirmativeId(self.send.GetId()) + self.SetEscapeId(self.cancel.GetId()) + self.Layout() + +class dm(tweet): + + def __init__(self, users: List[str] = [], *args, **kwargs) -> None: + self.users = users + super(dm, self).__init__(*args, **kwargs) + + def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: + panel = wx.Panel(self) + mainBox = wx.BoxSizer(wx.VERTICAL) + label_recipient = wx.StaticText(panel, -1, _(u"&Recipient")) + self.cb = wx.ComboBox(panel, -1, choices=self.users, value=self.users[0], size=wx.DefaultSize) + self.autocomplete_users = wx.Button(panel, -1, _(u"Auto&complete users")) + recipient_sizer = wx.BoxSizer(wx.HORIZONTAL) + recipient_sizer.Add(label_recipient, 0, 0, 0) + recipient_sizer.Add(self.cb, 1, wx.EXPAND, 0) + mainBox.Add(recipient_sizer, 0, wx.EXPAND, 0) + text_sizer = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(text_sizer, 1, wx.EXPAND, 0) + label_1 = wx.StaticText(panel, wx.ID_ANY, caption) + text_sizer.Add(label_1, 0, 0, 0) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) + self.text.SetMinSize((1000, 158)) + self.text.SetMaxLength(max_length) + self.text.SetFocus() + text_sizer.Add(self.text, 1, wx.EXPAND, 0) + list_sizer = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(list_sizer, 1, wx.EXPAND, 0) + Attachment_sizer = wx.BoxSizer(wx.VERTICAL) + list_sizer.Add(Attachment_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(panel, wx.ID_ANY, _("Attachments")) + Attachment_sizer.Add(label_2, 0, 0, 0) + self.attachments = wx.ListCtrl(panel, wx.ID_ANY, style=wx.BORDER_SUNKEN | wx.LC_HRULES | wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES) + self.attachments.AppendColumn(_("File")) + self.attachments.AppendColumn(_("Type")) + self.attachments.AppendColumn(_("Description")) + Attachment_sizer.Add(self.attachments, 1, wx.EXPAND, 0) + self.remove_attachment = wx.Button(panel, wx.ID_ANY, _("Delete attachment")) + self.remove_attachment.Enable(False) + Attachment_sizer.Add(self.remove_attachment, 0, 0, 0) + btn_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) + self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) + btn_sizer_1.Add(self.add, 0, 0, 0) + self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) + btn_sizer_1.Add(self.add_audio, 0, 0, 0) + btn_sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + mainBox.Add(btn_sizer_2, 1, wx.EXPAND, 0) + self.spellcheck = wx.Button(panel, wx.ID_ANY, _("Check &spelling...")) + btn_sizer_2.Add(self.spellcheck, 0, 0, 0) + self.translate = wx.Button(panel, wx.ID_ANY, _("&Translate")) + btn_sizer_2.Add(self.translate, 0, 0, 0) + ok_cancel_sizer = wx.StdDialogButtonSizer() + mainBox.Add(ok_cancel_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.send = wx.Button(panel, wx.ID_OK, _("Sen&d")) + self.send.SetDefault() + ok_cancel_sizer.Add(self.send, 0, 0, 0) + self.cancel = wx.Button(panel, wx.ID_CANCEL, "") + ok_cancel_sizer.AddButton(self.cancel) + ok_cancel_sizer.Realize() + panel.SetSizer(mainBox) + self.Fit() + self.SetAffirmativeId(self.send.GetId()) + self.SetEscapeId(self.cancel.GetId()) + self.Layout() + +class viewTweet(wx.Dialog): + def set_title(self, lenght): + self.SetTitle(_(u"Tweet - %i characters ") % (lenght,)) + + def __init__(self, text, rt_count, favs_count, source, date="", *args, **kwargs): + super(viewTweet, self).__init__(None, size=(850,850)) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Tweet")) + self.text = wx.TextCtrl(panel, -1, text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("W"*280) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + label2 = wx.StaticText(panel, -1, _(u"Image description")) + self.image_description = wx.TextCtrl(panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.image_description) + dc.SetFont(self.image_description.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*450) + self.image_description.SetSize((x, y)) + self.image_description.Enable(False) + iBox = wx.BoxSizer(wx.HORIZONTAL) + iBox.Add(label2, 0, wx.ALL, 5) + iBox.Add(self.image_description, 1, wx.EXPAND, 5) + mainBox.Add(iBox, 0, wx.ALL, 5) + rtCountLabel = wx.StaticText(panel, -1, _(u"Retweets: ")) + rtCount = wx.TextCtrl(panel, -1, rt_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + rtBox = wx.BoxSizer(wx.HORIZONTAL) + rtBox.Add(rtCountLabel, 0, wx.ALL, 5) + rtBox.Add(rtCount, 0, wx.ALL, 5) + favsCountLabel = wx.StaticText(panel, -1, _(u"Likes: ")) + favsCount = wx.TextCtrl(panel, -1, favs_count, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + favsBox = wx.BoxSizer(wx.HORIZONTAL) + favsBox.Add(favsCountLabel, 0, wx.ALL, 5) + favsBox.Add(favsCount, 0, wx.ALL, 5) + sourceLabel = wx.StaticText(panel, -1, _(u"Source: ")) + sourceTweet = wx.TextCtrl(panel, -1, source, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + sourceBox = wx.BoxSizer(wx.HORIZONTAL) + sourceBox.Add(sourceLabel, 0, wx.ALL, 5) + sourceBox.Add(sourceTweet, 0, wx.ALL, 5) + dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) + dateTweet = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + dc = wx.WindowDC(dateTweet) + dc.SetFont(dateTweet.GetFont()) + (x, y) = dc.GetTextExtent("0"*100) + dateTweet.SetSize((x, y)) + dateBox = wx.BoxSizer(wx.HORIZONTAL) + dateBox.Add(dateLabel, 0, wx.ALL, 5) + dateBox.Add(dateTweet, 0, wx.ALL, 5) + infoBox = wx.BoxSizer(wx.HORIZONTAL) + infoBox.Add(rtBox, 0, wx.ALL, 5) + infoBox.Add(favsBox, 0, wx.ALL, 5) + infoBox.Add(sourceBox, 0, wx.ALL, 5) + mainBox.Add(infoBox, 0, wx.ALL, 5) + mainBox.Add(dateBox, 0, wx.ALL, 5) + self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) + self.share.Enable(False) + self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + cancelButton.SetDefault() + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.share, 0, wx.ALL, 5) + buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) + + def set_text(self, text): + self.text.ChangeValue(text) + + def get_text(self): + return self.text.GetValue() + + def set_image_description(self, desc): + self.image_description.Enable(True) + if len(self.image_description.GetValue()) == 0: + self.image_description.SetValue(desc) + else: + self.image_description.SetValue(self.image_description.GetValue()+"\n"+desc) + + def text_focus(self): + self.text.SetFocus() + + def onSelect(self, ev): + self.text.SelectAll() + + def enable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Enable() + +class viewNonTweet(wx.Dialog): + + def __init__(self, text, date="", *args, **kwargs): + super(viewNonTweet, self).__init__(None, size=(850,850)) + self.SetTitle(_(u"View")) + panel = wx.Panel(self) + label = wx.StaticText(panel, -1, _(u"Item")) + self.text = wx.TextCtrl(parent=panel, id=-1, value=text, style=wx.TE_READONLY|wx.TE_MULTILINE, size=(250, 180)) + dc = wx.WindowDC(self.text) + dc.SetFont(self.text.GetFont()) + (x, y) = dc.GetMultiLineTextExtent("0"*140) + self.text.SetSize((x, y)) + self.text.SetFocus() + textBox = wx.BoxSizer(wx.HORIZONTAL) + textBox.Add(label, 0, wx.ALL, 5) + textBox.Add(self.text, 1, wx.EXPAND, 5) + mainBox = wx.BoxSizer(wx.VERTICAL) + mainBox.Add(textBox, 0, wx.ALL, 5) + if date != "": + dateLabel = wx.StaticText(panel, -1, _(u"Date: ")) + date = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE) + dc = wx.WindowDC(date) + dc.SetFont(date.GetFont()) + (x, y) = dc.GetTextExtent("0"*100) + date.SetSize((x, y)) + dateBox = wx.BoxSizer(wx.HORIZONTAL) + dateBox.Add(dateLabel, 0, wx.ALL, 5) + dateBox.Add(date, 0, wx.ALL, 5) + mainBox.Add(dateBox, 0, wx.ALL, 5) + self.share = wx.Button(panel, wx.ID_ANY, _("Copy link to clipboard")) + self.share.Enable(False) + self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize) + self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize) + self.unshortenButton.Disable() + self.translateButton = wx.Button(panel, -1, _(u"&Translate..."), size=wx.DefaultSize) + cancelButton = wx.Button(panel, wx.ID_CANCEL, _(u"C&lose"), size=wx.DefaultSize) + cancelButton.SetDefault() + buttonsBox = wx.BoxSizer(wx.HORIZONTAL) + buttonsBox.Add(self.share, 0, wx.ALL, 5) + buttonsBox.Add(self.spellcheck, 0, wx.ALL, 5) + buttonsBox.Add(self.unshortenButton, 0, wx.ALL, 5) + buttonsBox.Add(self.translateButton, 0, wx.ALL, 5) + buttonsBox.Add(cancelButton, 0, wx.ALL, 5) + mainBox.Add(buttonsBox, 0, wx.ALL, 5) + selectId = wx.ID_ANY + self.Bind(wx.EVT_MENU, self.onSelect, id=selectId) + self.accel_tbl = wx.AcceleratorTable([ + (wx.ACCEL_CTRL, ord('A'), selectId), + ]) + self.SetAcceleratorTable(self.accel_tbl) + panel.SetSizer(mainBox) + self.SetClientSize(mainBox.CalcMin()) + + def onSelect(self, ev): + self.text.SelectAll() + + def set_text(self, text): + self.text.ChangeValue(text) + + def get_text(self): + return self.text.GetValue() + + def text_focus(self): + self.text.SetFocus() + + def enable_button(self, buttonName): + if hasattr(self, buttonName): + return getattr(self, buttonName).Enable() From f0456af65670127dc7b6e1f971a6633a4cd587ee Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:12:47 -0600 Subject: [PATCH 213/245] Fixed an issue when uploading Videos to Twitter --- src/sessions/twitter/session.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index a32ead2d..df3ab809 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -204,7 +204,7 @@ class Session(base.baseSession): except TweepyException as e: output.speak(str(e)) val = None - if type(e) != NotFound and type(e) != Forvidden: + if type(e) != NotFound and type(e) != Forbidden: tries = tries+1 time.sleep(5) elif report_failure: @@ -603,7 +603,8 @@ class Session(base.baseSession): media_ids = [] for i in obj["attachments"]: img = self.api_call("media_upload", filename=i["file"]) - self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) + if i["type"] == "photo": + self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) item = self.api_call(call_name="update_status", status=obj["text"], _sound="tweet_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids) in_reply_to_status_id = item.id @@ -615,6 +616,7 @@ class Session(base.baseSession): media_ids = [] for i in attachments: img = self.api_call("media_upload", filename=i["file"]) - self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) + if i["type"] == "photo": + self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) item = self.api_call(call_name="update_status", status=text, _sound="reply_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids, *args, **kwargs) From 2b6efef831d8fbe9ffe6a0456450785a2cc5a28a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:13:59 -0600 Subject: [PATCH 214/245] Update code on autocompletion users module to use WX methods from controls in the new Tweet GUI'S --- src/extra/autocompletionUsers/completion.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/extra/autocompletionUsers/completion.py b/src/extra/autocompletionUsers/completion.py index 826dc699..9fa8c8ec 100644 --- a/src/extra/autocompletionUsers/completion.py +++ b/src/extra/autocompletionUsers/completion.py @@ -10,9 +10,9 @@ class autocompletionUsers(object): self.db = storage.storage(session_id) def show_menu(self, mode="tweet"): - position = self.window.get_position() + position = self.window.text.GetInsertionPoint() if mode == "tweet": - text = self.window.get_text() + text = self.window.text.GetValue() text = text[:position] try: pattern = text.split()[-1] @@ -24,14 +24,14 @@ class autocompletionUsers(object): users = self.db.get_users(pattern[1:]) if len(users) > 0: menu.append_options(users) - self.window.popup_menu(menu) + self.window.PopupMenu(menu, self.window.text.GetPosition()) menu.destroy() else: output.speak(_(u"There are no results in your users database")) else: output.speak(_(u"Autocompletion only works for users.")) elif mode == "dm": - text = self.window.get_user() + text = self.window.cb.GetValue() try: pattern = text.split()[-1] except IndexError: @@ -41,7 +41,7 @@ class autocompletionUsers(object): users = self.db.get_users(pattern) if len(users) > 0: menu.append_options(users) - self.window.popup_menu(menu) + self.window.PopupMenu(menu, self.window.text.GetPosition()) menu.destroy() else: output.speak(_(u"There are no results in your users database")) From cfc25eb89a3259eab292a412fa42afdec1d7b4b1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:14:45 -0600 Subject: [PATCH 215/245] Implemented tweet, reply and direct message in base buffer --- src/controller/buffers/twitter/base.py | 83 +++++--------------------- 1 file changed, 16 insertions(+), 67 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 8da54709..619b7f8f 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -85,41 +85,15 @@ class BaseBuffer(base.Buffer): def post_status(self, *args, **kwargs): item = None - title = _(u"Tweet") - caption = _(u"Write the tweet here") + title = _("Tweet") + caption = _("Write the tweet here") tweet = messages.tweet(self.session, title, caption, "") - if tweet.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = tweet.message.long_tweet.GetValue() - config.app.write() - text = tweet.message.get_text() - if len(text) > 280 and tweet.message.get("long_tweet") == True: - if not hasattr(tweet, "attachments"): - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - if not hasattr(tweet, "attachments") or len(tweet.attachments) == 0: - item = self.session.api_call(call_name="update_status", status=text, _sound="tweet_send.ogg", tweet_mode="extended") - else: - call_threaded(self.post_with_media, text=text, attachments=tweet.attachments) - # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. - # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. -# if item != None: -# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - if hasattr(tweet.message, "destroy"): tweet.message.destroy() - self.session.settings.write() - - def post_with_media(self, text, attachments): - media_ids = [] - for i in attachments: - img = self.session.twitter.media_upload(i["file"]) - self.session.twitter.create_media_metadata(media_id=img.media_id, alt_text=i["description"]) - media_ids.append(img.media_id) - item = self.session.twitter.update_status(status=text, media_ids=media_ids) - # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. - # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. -# if item != None: -# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + response = tweet.message.ShowModal() + if response == wx.ID_OK: + tweet_data = tweet.get_tweet_data() + call_threaded(self.session.send_tweet, *tweet_data) + if hasattr(tweet.message, "destroy"): + tweet.message.destroy() def get_formatted_message(self): if self.type == "dm" or self.name == "direct_messages": @@ -422,7 +396,6 @@ class BaseBuffer(base.Buffer): user = self.session.get_user(tweet.user) screen_name = user.screen_name id = tweet.id - twishort_enabled = hasattr(tweet, "twishort") users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name") ids = utils.get_all_mentioned(tweet, self.session.db, field="id") # Build the window title @@ -430,38 +403,14 @@ class BaseBuffer(base.Buffer): title=_("Reply to {arg0}").format(arg0=screen_name) else: title=_("Reply") - message = messages.reply(self.session, title, _(u"Reply to %s") % (screen_name,), "", users=users, ids=ids) - if message.message.get_response() == widgetUtils.OK: + message = messages.reply(self.session, title, _("Reply to %s") % (screen_name,), "", users=users, ids=ids) + if message.message.ShowModal() == widgetUtils.OK: if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() if len(users) > 0: - config.app["app-settings"]["mention_all"] = message.message.mentionAll.GetValue() + config.app["app-settings"]["mention_all"] = message.message.mention_all.GetValue() config.app.write() - params = {"_sound": "reply_send.ogg", "in_reply_to_status_id": id, "tweet_mode": "extended"} - text = message.message.get_text() - if twishort_enabled == False: - excluded_ids = message.get_ids() - params["exclude_reply_user_ids"] =excluded_ids - params["auto_populate_reply_metadata"] =True - else: - mentioned_people = message.get_people() - text = "@"+screen_name+" "+mentioned_people+u" "+text - if len(text) > 280 and message.message.get("long_tweet") == True: - if message.image == None: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - params["status"] = text - if message.image == None: - params["call_name"] = "update_status" - else: - params["call_name"] = "update_status_with_media" - params["media"] = message.file - item = self.session.api_call(**params) - # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. - # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. -# if item != None: -# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) + tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments) + call_threaded(self.session.reply, in_reply_to_status_id=id, text=message.message.text.GetValue(), attachments=message.attachments, exclude_reply_user_ids=message.get_ids(), auto_populate_reply_metadata=True) if hasattr(message.message, "destroy"): message.message.destroy() self.session.settings.write() @@ -478,11 +427,11 @@ class BaseBuffer(base.Buffer): screen_name = self.session.get_user(tweet.user).screen_name users = utils.get_all_users(tweet, self.session) dm = messages.dm(self.session, _(u"Direct message to %s") % (screen_name,), _(u"New direct message"), users) - if dm.message.get_response() == widgetUtils.OK: - screen_name = dm.message.get("cb") + if dm.message.ShowModal() == widgetUtils.OK: + screen_name = dm.message.cb.GetValue() user = self.session.get_user_by_screen_name(screen_name) recipient_id = user - text = dm.message.get_text() + text = dm.message.text.GetValue() val = self.session.api_call(call_name="send_direct_message", recipient_id=recipient_id, text=text) if val != None: sent_dms = self.session.db["sent_direct_messages"] From 269db95fe3fedc62a4b5ddeaafcf324557204a27 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 16:44:03 -0600 Subject: [PATCH 216/245] Implemented code to quote Tweets by using the new GUI --- src/controller/buffers/twitter/base.py | 37 +++++++------------------- src/controller/messages.py | 3 +-- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 619b7f8f..1113e46d 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -458,40 +458,21 @@ class BaseBuffer(base.Buffer): else: self._retweet_with_comment(tweet, id) - def _retweet_with_comment(self, tweet, id, comment=''): - # If quoting a retweet, let's quote the original tweet instead the retweet. + def _retweet_with_comment(self, tweet, id): if hasattr(tweet, "retweeted_status"): tweet = tweet.retweeted_status - if hasattr(tweet, "full_text"): - comments = tweet.full_text - else: - comments = tweet.text - retweet = messages.tweet(self.session, _(u"Quote"), _(u"Add your comment to the tweet"), u"“@%s: %s ”" % (self.session.get_user(tweet.user).screen_name, comments), max=256, messageType="retweet") - if comment != '': - retweet.message.set_text(comment) - if retweet.message.get_response() == widgetUtils.OK: - text = retweet.message.get_text() + retweet = messages.tweet(session=self.session, title=_("Quote"), caption=_("Add your comment to the tweet"), max=256, thread_mode=False) + retweet = messages.tweet(session=self.session, title=_("Quote"), caption=_("Add your comment to the tweet"), max=256, thread_mode=False) + if retweet.message.ShowModal() == widgetUtils.OK: + text = retweet.message.text.GetValue() text = text+" https://twitter.com/{0}/status/{1}".format(self.session.get_user(tweet.user).screen_name, id) - if retweet.image == None: - # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. - # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. - item = self.session.api_call(call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id, tweet_mode="extended") -# if item != None: -# new_item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") -# pub.sendMessage("sent-tweet", data=new_item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=text, media=retweet.image) - if hasattr(retweet.message, "destroy"): retweet.message.destroy() + tweet_data = dict(text=text, attachments=retweet.attachments) + call_threaded(self.session.send_tweet, *[tweet_data]) + if hasattr(retweet.message, "destroy"): + retweet.message.destroy() def _direct_retweet(self, id): item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id) - # We will no longer will reuse the sent item from here as Streaming API should give us the new and correct item. - # but in case we'd need it, just uncomment the following couple of lines and make sure we reduce the item correctly. -# if item != None: - # Retweets are returned as non-extended tweets, so let's get the object as extended - # just before sending the event message. See https://github.com/manuelcortez/TWBlue/issues/253 -# item = self.session.twitter.get_status(id=item.id, include_ext_alt_text=True, tweet_mode="extended") -# pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) def onFocus(self, *args, **kwargs): tweet = self.get_tweet() diff --git a/src/controller/messages.py b/src/controller/messages.py index 9417ad90..776ceb11 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -122,10 +122,9 @@ class basicTweet(object): pass class tweet(basicTweet): - def __init__(self, session, title, caption, text, max=280, messageType="tweet", *args, **kwargs): + def __init__(self, session, title, caption, text="", max=280, messageType="tweet", *args, **kwargs): self.thread = [] super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) - self.image = None widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) if hasattr(self.message, "add_tweet"): widgetUtils.connect_event(self.message.add_tweet, widgetUtils.BUTTON_PRESSED, self.add_tweet) From 80adf381c9bf718359e06739ce5674292f99c8e4 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 17:19:12 -0600 Subject: [PATCH 217/245] Implemented new GUI in people and direct message buffers --- .../buffers/twitter/directMessages.py | 18 ++++++------------ src/controller/buffers/twitter/people.py | 18 ++++++------------ src/controller/messages.py | 3 +++ 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/controller/buffers/twitter/directMessages.py b/src/controller/buffers/twitter/directMessages.py index b0c51e5b..60090c89 100644 --- a/src/controller/buffers/twitter/directMessages.py +++ b/src/controller/buffers/twitter/directMessages.py @@ -90,18 +90,12 @@ class DirectMessagesBuffer(base.BaseBuffer): def reply(self, *args, **kwargs): tweet = self.get_right_tweet() screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name - message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - config.app.write() - if message.image == None: - item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) - if hasattr(message.message, "destroy"): message.message.destroy() + message = messages.reply(session=self.session, title=_("Mention"), caption=_("Mention to %s") % (screen_name,), text="@%s " % (screen_name,), thread_mode=False, users=[screen_name,]) + if message.message.ShowModal() == widgetUtils.OK: + tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments) + call_threaded(self.session.send_tweet, *[tweet_data]) + if hasattr(message.message, "destroy"): + message.message.destroy() def onFocus(self, *args, **kwargs): tweet = self.get_tweet() diff --git a/src/controller/buffers/twitter/people.py b/src/controller/buffers/twitter/people.py index 7f5c90b1..faf03794 100644 --- a/src/controller/buffers/twitter/people.py +++ b/src/controller/buffers/twitter/people.py @@ -92,18 +92,12 @@ class PeopleBuffer(base.BaseBuffer): def reply(self, *args, **kwargs): tweet = self.get_right_tweet() screen_name = tweet.screen_name - message = messages.reply(self.session, _(u"Mention"), _(u"Mention to %s") % (screen_name,), "@%s " % (screen_name,), [screen_name,]) - if message.message.get_response() == widgetUtils.OK: - if config.app["app-settings"]["remember_mention_and_longtweet"]: - config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue() - config.app.write() - if message.image == None: - item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended") - if item != None: - pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"]) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file) - if hasattr(message.message, "destroy"): message.message.destroy() + message = messages.tweet(session=self.session, title=_("Mention"), caption=_("Mention to %s") % (screen_name,), text="@%s " % (screen_name,), thread_mode=False) + if message.message.ShowModal() == widgetUtils.OK: + tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments) + call_threaded(self.session.send_tweet, *[tweet_data]) + if hasattr(message.message, "destroy"): + message.message.destroy() def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): # starts stream every 3 minutes. diff --git a/src/controller/messages.py b/src/controller/messages.py index 776ceb11..89ffe176 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -24,6 +24,8 @@ class basicTweet(object): self.title = title self.session = session self.message = getattr(twitterDialogs, messageType)(title=title, caption=caption, message=text, *args, **kwargs) + self.message.text.SetValue(text) + self.message.text.SetInsertionPoint(len(self.message.text.GetValue())) widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck) widgetUtils.connect_event(self.message.add_audio, widgetUtils.BUTTON_PRESSED, self.attach) widgetUtils.connect_event(self.message.text, widgetUtils.ENTERED_TEXT, self.text_processor) @@ -42,6 +44,7 @@ class basicTweet(object): dst = k msg = translator.translator.translate(text=text_to_translate, target=dst) self.message.text.ChangeValue(msg) + self.message.text.SetInsertionPoint(len(self.message.text.GetValue())) self.text_processor() self.message.text.SetFocus() output.speak(_(u"Translated")) From a2393fe3e9eed5b36fa4d181dc33a6bc738f6358 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Mon, 8 Nov 2021 17:20:16 -0600 Subject: [PATCH 218/245] Updated dialogs package --- src/wxUI/dialogs/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/wxUI/dialogs/__init__.py b/src/wxUI/dialogs/__init__.py index a21239a7..e69de29b 100644 --- a/src/wxUI/dialogs/__init__.py +++ b/src/wxUI/dialogs/__init__.py @@ -1,3 +0,0 @@ -from __future__ import absolute_import -from __future__ import unicode_literals -from . import baseDialog, trends, configuration, lists, message, search, find, show_user, update_profile, urlList, userSelection, utils, filterDialogs, userAliasDialogs From 15d0f4c65efb708e736f22eee5ef38ebd03a48f5 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 9 Nov 2021 13:34:49 -0600 Subject: [PATCH 219/245] Restored some imports on dialogs --- src/wxUI/dialogs/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wxUI/dialogs/__init__.py b/src/wxUI/dialogs/__init__.py index e69de29b..d00a14c0 100644 --- a/src/wxUI/dialogs/__init__.py +++ b/src/wxUI/dialogs/__init__.py @@ -0,0 +1 @@ +from . import baseDialog, trends, configuration, lists, search, find, show_user, update_profile, urlList, userSelection, utils, filterDialogs, userAliasDialogs From 8fed52118fa829292f5e974ba1fa8dc6a4c5718e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 9 Nov 2021 13:46:36 -0600 Subject: [PATCH 220/245] Finished implementation of new tweet and reply calls in buffers --- src/controller/buffers/twitter/base.py | 1 - src/controller/buffers/twitter/trends.py | 14 +++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 1113e46d..72ea6449 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -84,7 +84,6 @@ class BaseBuffer(base.Buffer): return _(u"Unknown buffer") def post_status(self, *args, **kwargs): - item = None title = _("Tweet") caption = _("Write the tweet here") tweet = messages.tweet(self.session, title, caption, "") diff --git a/src/controller/buffers/twitter/trends.py b/src/controller/buffers/twitter/trends.py index e3be681d..ab623e05 100644 --- a/src/controller/buffers/twitter/trends.py +++ b/src/controller/buffers/twitter/trends.py @@ -4,7 +4,7 @@ import platform if platform.system() == "Windows": import wx from wxUI import buffers, commonMessageDialogs, menus - from controller import user + from controller import user, messages elif platform.system() == "Linux": from gi.repository import Gtk from gtkUI import buffers, commonMessageDialogs @@ -38,6 +38,18 @@ class TrendsBuffer(base.Buffer): self.get_formatted_message = self.get_message self.reply = self.search_topic + + def post_status(self, *args, **kwargs): + title = _("Tweet") + caption = _("Write the tweet here") + tweet = messages.tweet(self.session, title, caption, "") + response = tweet.message.ShowModal() + if response == wx.ID_OK: + tweet_data = tweet.get_tweet_data() + call_threaded(self.session.send_tweet, *tweet_data) + if hasattr(tweet.message, "destroy"): + tweet.message.destroy() + def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False): # starts stream every 3 minutes. current_time = time.time() From 605868eff9cf7bf0b563f8923c04087c980ca52a Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 09:47:53 -0600 Subject: [PATCH 221/245] Added functions to make TWBlue respect Twitter limits when adding media items --- src/controller/messages.py | 13 +++++++++++-- src/wxUI/dialogs/twitterDialogs/tweetDialogs.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 89ffe176..f613c436 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -10,7 +10,6 @@ import config from pubsub import pub from twitter_text import parse_tweet from wxUI.dialogs import twitterDialogs, urlList -#from wxUI.dialogs import twitterDialogs from wxUI import commonMessageDialogs from extra import translator, SpellChecker, autocompletionUsers from extra.AudioUploader import audioUploader @@ -87,7 +86,7 @@ class basicTweet(object): return False elif len(self.attachments) < 4: return True - return False + return False def on_attach(self, *args, **kwargs): can_attach = self.can_attach() @@ -98,6 +97,14 @@ class basicTweet(object): self.message.PopupMenu(menu, self.message.add.GetPosition()) def on_attach_image(self, *args, **kwargs): + can_attach = self.can_attach() + video_or_gif_present = False + for a in self.attachments: + if a["type"] == "video" or a["type"] == "gif": + video_or_gif = True + break + if can_attach == False or video_or_gif_present == True: + return self.message.unable_to_attach_file() image, description = self.message.get_image() if image != None: if image.endswith("gif"): @@ -112,6 +119,8 @@ class basicTweet(object): self.text_processor() def on_attach_video(self, *args, **kwargs): + if len(self.attachments) > 0: + return self.message.unable_to_attach_file() video = self.message.get_video() if video != None: videoInfo = {"type": "video", "file": video, "description": ""} diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index d07f10da..a7a20059 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -145,7 +145,7 @@ class tweet(wx.Dialog): return openFileDialog.GetPath() def unable_to_attach_file(self, *args, **kwargs): - return wx.MessageDialog(self, _("You need to delete other attachments first, as Videos and GIF's cannot be added with other attachments."), _("Error adding attachment"), wx.ICON_ERROR).ShowModal() + return wx.MessageDialog(self, _("It is not possible to add more attachments. Please make sure your tweet complies with Twitter'S attachment rules. You can add only one video or GIF in every tweet, and a maximum of 4 photos."), _("Error adding attachment"), wx.ICON_ERROR).ShowModal() class reply(tweet): From dbecf341ece9f0445634a8f66de660cca2b59b56 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 11:24:50 -0600 Subject: [PATCH 222/245] Stop using text_processor in tweet displayer --- src/controller/messages.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controller/messages.py b/src/controller/messages.py index f613c436..2777d2cc 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -332,6 +332,10 @@ class viewTweet(basicTweet): widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate) self.message.ShowModal() + # We won't need text_processor in this dialog, so let's avoid it. + def text_processor(self): + pass + def clear_text(self, text): urls = utils.find_urls_in_text(text) for i in urls: From 1e2464c4faf9f97c144822ae1cac86024fe27cbe Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 11:36:06 -0600 Subject: [PATCH 223/245] Made Dm dialog to hide attachments panel when needed --- src/controller/messages.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 2777d2cc..06159457 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -133,6 +133,14 @@ class basicTweet(object): def on_attach_poll(self, *args, **kwargs): pass + def remove_attachment(self, *args, **kwargs): + attachment = self.message.attachments.GetFocusedItem() + if attachment > -1 and len(self.attachments) > attachment: + self.attachments.pop(attachment) + self.message.remove_item(list_type="attachment") + self.text_processor() + self.message.text.SetFocus() + class tweet(basicTweet): def __init__(self, session, title, caption, text="", max=280, messageType="tweet", *args, **kwargs): self.thread = [] @@ -186,13 +194,6 @@ class tweet(basicTweet): self.text_processor() self.message.text.SetFocus() - def remove_attachment(self, *args, **kwargs): - attachment = self.message.attachments.GetFocusedItem() - if attachment > -1 and len(self.attachments) > attachment: - self.attachments.pop(attachment) - self.message.remove_item(list_type="attachment") - self.text_processor() - self.message.text.SetFocus() class reply(tweet): def __init__(self, session, title, caption, text, users=[], ids=[]): @@ -256,6 +257,18 @@ class dm(basicTweet): c = autocompletionUsers.completion.autocompletionUsers(self.message, self.session.session_id) c.show_menu("dm") + def text_processor(self, *args, **kwargs): + super(dm, self).text_processor(*args, **kwargs) + if len(self.attachments) > 0: + self.message.attachments.Enable(True) + self.message.remove_attachment.Enable(True) + else: + self.message.attachments.Enable(False) + self.message.remove_attachment.Enable(False) + + def get_data(self): + return dict(text=self.message.text.GetValue(), attachments=self.attachments) + class viewTweet(basicTweet): def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date="", item_url=""): """ This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event. From 6346651edf703660a11cd049ff9390ccdbaf239b Mon Sep 17 00:00:00 2001 From: Mohamed Date: Wed, 10 Nov 2021 12:53:18 -0500 Subject: [PATCH 224/245] Added a shortcut for the add new tweet button --- src/wxUI/dialogs/twitterDialogs/tweetDialogs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index a7a20059..d8504c3e 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -57,7 +57,7 @@ class tweet(wx.Dialog): mainBox.Add(btn_sizer_1, 1, wx.EXPAND, 0) self.add = wx.Button(panel, wx.ID_ANY, _("A&dd...")) btn_sizer_1.Add(self.add, 0, 0, 0) - self.add_tweet = wx.Button(panel, wx.ID_ANY, _("Add tweet")) + self.add_tweet = wx.Button(panel, wx.ID_ANY, _("Add t&weet")) self.add_tweet.Enable(thread_mode) btn_sizer_1.Add(self.add_tweet, 0, 0, 0) self.add_audio = wx.Button(panel, wx.ID_ANY, _("&Attach audio...")) From 9e7542f513e80319afdcf6447c6e6429403c617f Mon Sep 17 00:00:00 2001 From: Mohamed Date: Wed, 10 Nov 2021 13:01:24 -0500 Subject: [PATCH 225/245] Removed url_shortener import --- src/sessions/twitter/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index f84dfaca..d44e0e3f 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -import url_shortener, re +import re import output import config import logging From a43101e6949b33cfb588bb5f10f3d5c365416496 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 12:21:07 -0600 Subject: [PATCH 226/245] Reimplemented direct messages with support for media --- src/controller/buffers/twitter/base.py | 16 ++++++-------- src/controller/messages.py | 5 +++++ src/sessions/twitter/session.py | 21 +++++++++++++++++++ .../dialogs/twitterDialogs/tweetDialogs.py | 14 +++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 72ea6449..ae22a576 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -425,21 +425,17 @@ class BaseBuffer(base.Buffer): else: screen_name = self.session.get_user(tweet.user).screen_name users = utils.get_all_users(tweet, self.session) - dm = messages.dm(self.session, _(u"Direct message to %s") % (screen_name,), _(u"New direct message"), users) + dm = messages.dm(self.session, _("Direct message to %s") % (screen_name,), _("New direct message"), users) if dm.message.ShowModal() == widgetUtils.OK: screen_name = dm.message.cb.GetValue() user = self.session.get_user_by_screen_name(screen_name) recipient_id = user text = dm.message.text.GetValue() - val = self.session.api_call(call_name="send_direct_message", recipient_id=recipient_id, text=text) - if val != None: - sent_dms = self.session.db["sent_direct_messages"] - if self.session.settings["general"]["reverse_timelines"] == False: - sent_dms.append(val) - else: - sent_dms.insert(0, val) - self.session.db["sent_direct_messages"] = sent_dms - pub.sendMessage("sent-dm", data=val, user=self.session.db["user_name"]) + if len(dm.attachments) > 0: + attachment = dm.attachments[0] + else: + attachment = None + call_threaded(self.session.direct_message, text=text, recipient=recipient_id, attachment=attachment) if hasattr(dm.message, "destroy"): dm.message.destroy() @_tweets_exist diff --git a/src/controller/messages.py b/src/controller/messages.py index 06159457..461b155e 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -269,6 +269,11 @@ class dm(basicTweet): def get_data(self): return dict(text=self.message.text.GetValue(), attachments=self.attachments) + def can_attach(self): + if len(self.attachments) == 0: + return True + return False + class viewTweet(basicTweet): def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date="", item_url=""): """ This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event. diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index df3ab809..4e732b22 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -620,3 +620,24 @@ class Session(base.baseSession): self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) item = self.api_call(call_name="update_status", status=text, _sound="reply_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids, *args, **kwargs) + + def direct_message(self, text, recipient, attachment=None, *args, **kwargs): + if attachment == None: + item = self.api_call(call_name="send_direct_message", recipient_id=recipient, text=text) + else: + if attachment["type"] == "photo": + media_category = "DmImage" + elif attachment["type"] == "gif": + media_category = "DmGif" + elif attachment["type"] == "video": + media_category = "DmVideo" + media = self.api_call("media_upload", filename=attachment["file"], media_category=media_category) + item = self.api_call(call_name="send_direct_message", recipient_id=recipient, text=text, attachment_type="media", attachment_media_id=media.media_id) + if item != None: + sent_dms = self.db["sent_direct_messages"] + if self.settings["general"]["reverse_timelines"] == False: + sent_dms.append(item) + else: + sent_dms.insert(0, item) + self.db["sent_direct_messages"] = sent_dms + pub.sendMessage("sent-dm", data=item, user=self.db["user_name"]) diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index a7a20059..1e4f1a3a 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -283,6 +283,20 @@ class dm(tweet): self.SetEscapeId(self.cancel.GetId()) self.Layout() + def get_image(self): + openFileDialog = wx.FileDialog(self, _(u"Select the picture to be uploaded"), "", "", _("Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif"), wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return (None, None) + return (openFileDialog.GetPath(), "") + + def attach_menu(self, event=None, enabled=True, *args, **kwargs): + menu = wx.Menu() + self.add_image = menu.Append(wx.ID_ANY, _("Image")) + self.add_image.Enable(enabled) + self.add_video = menu.Append(wx.ID_ANY, _("Video")) + self.add_video.Enable(enabled) + return menu + class viewTweet(wx.Dialog): def set_title(self, lenght): self.SetTitle(_(u"Tweet - %i characters ") % (lenght,)) From d9f4b86d913e9b920ee69a4b904446e311b06ad1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 12:35:43 -0600 Subject: [PATCH 227/245] Empty attachments after adding a new tweet --- src/controller/messages.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/controller/messages.py b/src/controller/messages.py index 461b155e..67c8ec40 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -161,6 +161,7 @@ class tweet(basicTweet): attachments = self.attachments[::] tweetdata = dict(text=text, attachments=attachments) self.thread.append(tweetdata) + self.attachments = [] if update_gui: self.message.reset_controls() self.message.add_item(item=[text, len(attachments)], list_type="tweet") @@ -185,6 +186,11 @@ class tweet(basicTweet): else: self.message.attachments.Enable(False) self.message.remove_attachment.Enable(False) + if hasattr(self.message, "add_tweet"): + if len(self.message.text.GetValue()) > 0 or len(self.attachments) > 0: + self.message.add_tweet.Enable(True) + else: + self.message.add_tweet.Enable(False) def remove_tweet(self, *args, **kwargs): tweet = self.message.tweets.GetFocusedItem() @@ -266,9 +272,6 @@ class dm(basicTweet): self.message.attachments.Enable(False) self.message.remove_attachment.Enable(False) - def get_data(self): - return dict(text=self.message.text.GetValue(), attachments=self.attachments) - def can_attach(self): if len(self.attachments) == 0: return True From 77d13fdc28334d4e660af4e63bbb037542cc55b6 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 15:14:40 -0600 Subject: [PATCH 228/245] Added support for posting polls --- src/controller/buffers/twitter/base.py | 3 +- src/controller/messages.py | 12 +++- src/sessions/twitter/session.py | 33 ++++++++-- src/wxUI/dialogs/twitterDialogs/__init__.py | 2 +- .../dialogs/twitterDialogs/tweetDialogs.py | 65 +++++++++++++++++++ 5 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index ae22a576..34196b7b 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -457,11 +457,10 @@ class BaseBuffer(base.Buffer): if hasattr(tweet, "retweeted_status"): tweet = tweet.retweeted_status retweet = messages.tweet(session=self.session, title=_("Quote"), caption=_("Add your comment to the tweet"), max=256, thread_mode=False) - retweet = messages.tweet(session=self.session, title=_("Quote"), caption=_("Add your comment to the tweet"), max=256, thread_mode=False) if retweet.message.ShowModal() == widgetUtils.OK: text = retweet.message.text.GetValue() text = text+" https://twitter.com/{0}/status/{1}".format(self.session.get_user(tweet.user).screen_name, id) - tweet_data = dict(text=text, attachments=retweet.attachments) + tweet_data = dict(text=text, attachments=retweet.attachments, poll_period=retweet.poll_period, poll_options=retweet.poll_options) call_threaded(self.session.send_tweet, *[tweet_data]) if hasattr(retweet.message, "destroy"): retweet.message.destroy() diff --git a/src/controller/messages.py b/src/controller/messages.py index 67c8ec40..3fb52d38 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -131,7 +131,11 @@ class basicTweet(object): self.text_processor() def on_attach_poll(self, *args, **kwargs): - pass + dlg = twitterDialogs.poll() + if dlg.ShowModal() == wx.ID_OK: + self.poll_options = dlg.get_options() + self.poll_period = 60*24*dlg.period.GetValue() + dlg.Destroy() def remove_attachment(self, *args, **kwargs): attachment = self.message.attachments.GetFocusedItem() @@ -144,6 +148,8 @@ class basicTweet(object): class tweet(basicTweet): def __init__(self, session, title, caption, text="", max=280, messageType="tweet", *args, **kwargs): self.thread = [] + self.poll_options = None + self.poll_period = None super(tweet, self).__init__(session, title, caption, text, messageType, max, *args, **kwargs) widgetUtils.connect_event(self.message.autocomplete_users, widgetUtils.BUTTON_PRESSED, self.autocomplete_users) if hasattr(self.message, "add_tweet"): @@ -159,9 +165,11 @@ class tweet(basicTweet): def add_tweet(self, event, update_gui=True, *args, **kwargs): text = self.message.text.GetValue() attachments = self.attachments[::] - tweetdata = dict(text=text, attachments=attachments) + tweetdata = dict(text=text, attachments=attachments, poll_options=self.poll_options, poll_period=self.poll_period) self.thread.append(tweetdata) self.attachments = [] + self.poll_options = None + self.poll_period = None if update_gui: self.message.reset_controls() self.message.add_item(item=[text, len(attachments)], list_type="tweet") diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 4e732b22..40f40df5 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -218,6 +218,30 @@ class Session(base.baseSession): if _sound != None: self.sound.play(_sound) return val + def api_call_v2(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs): + finished = False + tries = 0 + if preexec_message: + output.speak(preexec_message, True) + while finished==False and tries < 25: + try: + val = getattr(self.twitter_v2, call_name)(*args, **kwargs) + finished = True + except TweepyException as e: + log.exception("Error sending the tweet.") + output.speak(str(e)) + val = None + if type(e) != NotFound and type(e) != Forbidden: + tries = tries+1 + time.sleep(5) + elif report_failure: + output.speak(_("%s failed. Reason: %s") % (action, str(e))) + finished = True + if report_success: + output.speak(_("%s succeeded.") % action) + if _sound != None: self.sound.play(_sound) + return val + def search(self, name, *args, **kwargs): """ Search in twitter, passing args and kwargs as arguments to the Twython function.""" tl = self.twitter.search_tweets(*args, **kwargs) @@ -597,8 +621,9 @@ class Session(base.baseSession): in_reply_to_status_id = None for obj in tweets: if len(obj["attachments"]) == 0: - item = self.api_call(call_name="update_status", status=obj["text"], _sound="tweet_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id) - in_reply_to_status_id = item.id + item = self.api_call_v2(call_name="create_tweet", text=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"]) + print(item) + in_reply_to_status_id = item.data.id else: media_ids = [] for i in obj["attachments"]: @@ -606,8 +631,8 @@ class Session(base.baseSession): if i["type"] == "photo": self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) - item = self.api_call(call_name="update_status", status=obj["text"], _sound="tweet_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids) - in_reply_to_status_id = item.id + item = self.api_call_v2(call_name="create_tweet", status=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"]) + in_reply_to_status_id = item.data.id def reply(self, text="", in_reply_to_status_id=None, attachments=[], *args, **kwargs): if len(attachments) == 0: diff --git a/src/wxUI/dialogs/twitterDialogs/__init__.py b/src/wxUI/dialogs/twitterDialogs/__init__.py index c6b568e0..6a829f06 100644 --- a/src/wxUI/dialogs/twitterDialogs/__init__.py +++ b/src/wxUI/dialogs/twitterDialogs/__init__.py @@ -1 +1 @@ -from .tweetDialogs import tweet, reply, dm, viewTweet, viewNonTweet \ No newline at end of file +from .tweetDialogs import tweet, reply, dm, viewTweet, viewNonTweet, poll \ No newline at end of file diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index d175b033..d5fd35a6 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -469,3 +469,68 @@ class viewNonTweet(wx.Dialog): def enable_button(self, buttonName): if hasattr(self, buttonName): return getattr(self, buttonName).Enable() + +class poll(wx.Dialog): + def __init__(self, *args, **kwds): + super(poll, self).__init__(parent=None, id=wx.NewId(), title=_("Add a poll")) + sizer_1 = wx.BoxSizer(wx.VERTICAL) + period_sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer_1.Add(period_sizer, 1, wx.EXPAND, 0) + label_period = wx.StaticText(self, wx.ID_ANY, _("Participation time (in days)")) + period_sizer.Add(label_period, 0, 0, 0) + self.period = wx.SpinCtrl(self, wx.ID_ANY) + self.period.SetFocus() + self.period.SetRange(1, 7) + self.period.SetValue(7) + period_sizer.Add(self.period, 0, 0, 0) + sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Choices")), wx.VERTICAL) + sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) + option1_sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer_2.Add(option1_sizer, 1, wx.EXPAND, 0) + label_2 = wx.StaticText(self, wx.ID_ANY, _("Option 1")) + option1_sizer.Add(label_2, 0, 0, 0) + self.option1 = wx.TextCtrl(self, wx.ID_ANY, "") + option1_sizer.Add(self.option1, 0, 0, 0) + option2_sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer_2.Add(option2_sizer, 1, wx.EXPAND, 0) + label_3 = wx.StaticText(self, wx.ID_ANY, _("Option 2")) + option2_sizer.Add(label_3, 0, 0, 0) + self.option2 = wx.TextCtrl(self, wx.ID_ANY, "") + option2_sizer.Add(self.option2, 0, 0, 0) + option3_sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer_2.Add(option3_sizer, 1, wx.EXPAND, 0) + label_4 = wx.StaticText(self, wx.ID_ANY, _("Option 3")) + option3_sizer.Add(label_4, 0, 0, 0) + self.option3 = wx.TextCtrl(self, wx.ID_ANY, "") + option3_sizer.Add(self.option3, 0, 0, 0) + option4_sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer_2.Add(option4_sizer, 1, wx.EXPAND, 0) + label_5 = wx.StaticText(self, wx.ID_ANY, _("Option 4")) + option4_sizer.Add(label_5, 0, 0, 0) + self.option4 = wx.TextCtrl(self, wx.ID_ANY, "") + option4_sizer.Add(self.option4, 0, 0, 0) + btn_sizer = wx.StdDialogButtonSizer() + sizer_1.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) + self.button_OK = wx.Button(self, wx.ID_OK) + self.button_OK.SetDefault() + self.button_OK.Bind(wx.EVT_BUTTON, self.validate_data) + btn_sizer.AddButton(self.button_OK) + self.button_CANCEL = wx.Button(self, wx.ID_CANCEL, "") + btn_sizer.AddButton(self.button_CANCEL) + btn_sizer.Realize() + self.SetSizer(sizer_1) + sizer_1.Fit(self) + self.SetAffirmativeId(self.button_OK.GetId()) + self.SetEscapeId(self.button_CANCEL.GetId()) + self.Layout() + + def get_options(self): + controls = [self.option1, self.option2, self.option3, self.option4] + options = [option.GetValue() for option in controls if option.GetValue() != ""] + return options + + def validate_data(self, *args, **kwargs): + options = self.get_options() + if len(options) < 2: + return wx.MessageDialog(self, _("Please make sure you have provided at least two options for the poll."), _("Not enough information"), wx.ICON_ERROR).ShowModal() + self.EndModal(wx.ID_OK) \ No newline at end of file From b0cfc5978c6922169bf643c02bed7a8aecbaa5f7 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 16:32:14 -0600 Subject: [PATCH 229/245] Updated reply dialog with some changes in add menu --- src/controller/buffers/twitter/base.py | 4 ++-- .../buffers/twitter/directMessages.py | 4 ++-- src/controller/buffers/twitter/people.py | 4 ++-- src/controller/buffers/twitter/trends.py | 22 ++++++------------- src/controller/messages.py | 7 +++--- src/sessions/twitter/session.py | 2 +- .../dialogs/twitterDialogs/tweetDialogs.py | 8 +++++++ 7 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 34196b7b..1d81a604 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -408,8 +408,8 @@ class BaseBuffer(base.Buffer): if len(users) > 0: config.app["app-settings"]["mention_all"] = message.message.mention_all.GetValue() config.app.write() - tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments) - call_threaded(self.session.reply, in_reply_to_status_id=id, text=message.message.text.GetValue(), attachments=message.attachments, exclude_reply_user_ids=message.get_ids(), auto_populate_reply_metadata=True) + tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments, poll_options=message.poll_options, poll_period=message.poll_period) + call_threaded(self.session.reply, in_reply_to_status_id=id, text=message.message.text.GetValue(), attachments=message.attachments, exclude_reply_user_ids=message.get_ids()) if hasattr(message.message, "destroy"): message.message.destroy() self.session.settings.write() diff --git a/src/controller/buffers/twitter/directMessages.py b/src/controller/buffers/twitter/directMessages.py index 60090c89..06cbed9a 100644 --- a/src/controller/buffers/twitter/directMessages.py +++ b/src/controller/buffers/twitter/directMessages.py @@ -92,8 +92,8 @@ class DirectMessagesBuffer(base.BaseBuffer): screen_name = self.session.get_user(tweet.message_create["sender_id"]).screen_name message = messages.reply(session=self.session, title=_("Mention"), caption=_("Mention to %s") % (screen_name,), text="@%s " % (screen_name,), thread_mode=False, users=[screen_name,]) if message.message.ShowModal() == widgetUtils.OK: - tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments) - call_threaded(self.session.send_tweet, *[tweet_data]) + tweet_data = message.get_tweet_data() + call_threaded(self.session.send_tweet, tweet_data) if hasattr(message.message, "destroy"): message.message.destroy() diff --git a/src/controller/buffers/twitter/people.py b/src/controller/buffers/twitter/people.py index faf03794..d29a46dc 100644 --- a/src/controller/buffers/twitter/people.py +++ b/src/controller/buffers/twitter/people.py @@ -94,8 +94,8 @@ class PeopleBuffer(base.BaseBuffer): screen_name = tweet.screen_name message = messages.tweet(session=self.session, title=_("Mention"), caption=_("Mention to %s") % (screen_name,), text="@%s " % (screen_name,), thread_mode=False) if message.message.ShowModal() == widgetUtils.OK: - tweet_data = dict(text=message.message.text.GetValue(), attachments=message.attachments) - call_threaded(self.session.send_tweet, *[tweet_data]) + tweet_data = message.get_tweet_data() + call_threaded(self.session.send_tweet, tweet_data) if hasattr(message.message, "destroy"): message.message.destroy() diff --git a/src/controller/buffers/twitter/trends.py b/src/controller/buffers/twitter/trends.py index ab623e05..39809df1 100644 --- a/src/controller/buffers/twitter/trends.py +++ b/src/controller/buffers/twitter/trends.py @@ -131,21 +131,13 @@ class TrendsBuffer(base.Buffer): def tweet_about_this_trend(self, *args, **kwargs): if self.buffer.list.get_count() == 0: return - title = _(u"Tweet") - caption = _(u"Write the tweet here") - tweet = messages.tweet(self.session, title, caption, self.get_message()+ " ") - tweet.message.set_cursor_at_end() - if tweet.message.get_response() == widgetUtils.OK: - text = tweet.message.get_text() - if len(text) > 280 and tweet.message.get("long_tweet") == True: - if tweet.image == None: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text) - else: - text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1) - if tweet.image == None: - call_threaded(self.session.api_call, call_name="update_status", status=text) - else: - call_threaded(self.session.api_call, call_name="update_status_with_media", status=text, media=tweet.image) + title = _("Tweet") + caption = _("Write the tweet here") + tweet = messages.tweet(session=self.session, title=title, caption=caption, text=self.get_message()+ " ") + tweet.message.SetInsertionPoint(len(tweet.message.GetValue())) + if tweet.message.ShowModal() == widgetUtils.OK: + tweet_data = tweet.get_tweet_data() + call_threaded(self.session.send_tweet, *tweet_data) if hasattr(tweet.message, "destroy"): tweet.message.destroy() def show_menu_by_key(self, ev): diff --git a/src/controller/messages.py b/src/controller/messages.py index 3fb52d38..421be6d7 100644 --- a/src/controller/messages.py +++ b/src/controller/messages.py @@ -93,7 +93,8 @@ class basicTweet(object): menu = self.message.attach_menu(can_attach) self.message.Bind(wx.EVT_MENU, self.on_attach_image, self.message.add_image) self.message.Bind(wx.EVT_MENU, self.on_attach_video, self.message.add_video) - self.message.Bind(wx.EVT_MENU, self.on_attach_poll, self.message.add_poll) + if hasattr(self.message, "add_poll"): + self.message.Bind(wx.EVT_MENU, self.on_attach_poll, self.message.add_poll) self.message.PopupMenu(menu, self.message.add.GetPosition()) def on_attach_image(self, *args, **kwargs): @@ -243,10 +244,10 @@ class reply(tweet): i.Show() def get_ids(self): - excluded_ids = "" + excluded_ids = [] for i in range(0, len(self.message.checkboxes)): if self.message.checkboxes[i].GetValue() == False: - excluded_ids = excluded_ids + "{0},".format(self.ids[i],) + excluded_ids.append(self.ids[i]) return excluded_ids def get_people(self): diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 40f40df5..38f4baae 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -636,7 +636,7 @@ class Session(base.baseSession): def reply(self, text="", in_reply_to_status_id=None, attachments=[], *args, **kwargs): if len(attachments) == 0: - item = self.api_call(call_name="update_status", status=text, _sound="reply_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, *args, **kwargs) + item = self.api_call_v2(call_name="create_tweet", text=text, _sound="reply_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, *args, **kwargs) else: media_ids = [] for i in attachments: diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index d5fd35a6..84ea5fde 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -217,6 +217,14 @@ class reply(tweet): self.SetEscapeId(self.cancel.GetId()) self.Layout() + def attach_menu(self, event=None, enabled=True, *args, **kwargs): + menu = wx.Menu() + self.add_image = menu.Append(wx.ID_ANY, _("Image")) + self.add_image.Enable(enabled) + self.add_video = menu.Append(wx.ID_ANY, _("Video")) + self.add_video.Enable(enabled) + return menu + class dm(tweet): def __init__(self, users: List[str] = [], *args, **kwargs) -> None: From e9f6fd529efd96a5db327a2fb39ee41c50059e18 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 16:32:39 -0600 Subject: [PATCH 230/245] Updated changelog --- doc/changelog.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/changelog.md b/doc/changelog.md index 513204c2..cc097af8 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,15 @@ TWBlue Changelog ## changes in this version +* Now it is possible to create a tweet from a trending topics buffer again. +* TWBlue now includes a completely new set of dialogs to handle tweeting, replying and sending direct messages that takes advantage of more Twitter features. + * It is possible to add videos in tweets and direct messages by using the new "add" button, located in every dialog where media can be added. Twitter suggests to add videos from 5 seconds up to 2 minutes lenght, in mp4 format (video Codec H.264 and audio codec AAC). Currently, TWBlue does not check if the uploaded video complies with Twitter media requirements. You can add only a video in a tweet or direct message. No other kind of media can be added after a video is in a tweet. If the video was unable to be uploaded successfully, the tweet or direct message won't be created. + * Now you can add a poll to tweets. Polls can have up to 4 different options and allow voting up to 7 days after being created. Take into account, though, that currently TWBlue does not support reading polls in tweets. + * TWBlue now support threads while creating a new tweet. There is a new button, called add tweet which will add the current tweet to the thread and will allow you to write another tweet in the thread. Every tweet might include media (up to 4 photos, or one GIF image or a video) or up to one poll. + * Some functionality was removed from tweet dialogs within TWBlue. Particularly, URL shorteners and long tweets via Twishort. You still can read long tweets posted via Twishort, though. + +## Changes in version 2021.11.07 + * TWBlue should retrieve tweets from threads and conversations in a more reliable way. Tweets in the same thread (made by the same author) will be sorted correctly, although replies to the thread (made by different people) may not be ordered in the same way they are displayed in Twitter apps. ([#417](https://github.com/manuelcortez/TWBlue/issues/417)) * When creating a filter, TWBlue will show an error if user has not provided a name for the filter. Before, unnamed filters were a cause of config breaks in the application. * It is again possible to read the changelog for TWBlue from the help menu in the menu bar. From b3bf0ab8e683625e1fa4d36b09528e6bf8cdf5b3 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 10 Nov 2021 17:35:24 -0600 Subject: [PATCH 231/245] Removed calls to SetMaxLength in dialogs --- src/wxUI/dialogs/twitterDialogs/tweetDialogs.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index 84ea5fde..e42bd9f4 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -25,7 +25,6 @@ class tweet(wx.Dialog): self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) self.text.SetMinSize((1000, 158)) - self.text.SetMaxLength(max_length) text_sizer.Add(self.text, 1, wx.EXPAND, 0) list_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(list_sizer, 1, wx.EXPAND, 0) @@ -163,7 +162,6 @@ class reply(tweet): self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) self.text.SetMinSize((1000, 158)) - self.text.SetMaxLength(max_length) text_sizer.Add(self.text, 1, wx.EXPAND, 0) list_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(list_sizer, 1, wx.EXPAND, 0) @@ -248,7 +246,6 @@ class dm(tweet): self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) self.text.SetMinSize((1000, 158)) - self.text.SetMaxLength(max_length) self.text.SetFocus() text_sizer.Add(self.text, 1, wx.EXPAND, 0) list_sizer = wx.BoxSizer(wx.HORIZONTAL) From 8abcb3623dff45e3b21ba93af72ca23d332aaec1 Mon Sep 17 00:00:00 2001 From: Oreonan Date: Thu, 11 Nov 2021 01:09:19 +0100 Subject: [PATCH 232/245] Update french interface --- src/locales/fr/LC_MESSAGES/twblue.po | 522 +++++++++++++++------------ 1 file changed, 294 insertions(+), 228 deletions(-) diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index e31dd0e1..3842a448 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" -"POT-Creation-Date: 2021-11-03 18:55+0100\n" -"PO-Revision-Date: 2021-11-04 17:00+0100\n" +"POT-Creation-Date: 2021-11-11 01:00+0100\n" +"PO-Revision-Date: 2021-11-11 01:08+0100\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" @@ -16,10 +16,6 @@ msgstr "" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Bookmarks: -1,-1,-1,-1,-1,384,-1,-1,-1,-1\n" -#: ../src\controller\attach.py:25 -msgid "Photo" -msgstr "Photo" - #: ../src\controller\buffers\base\base.py:91 msgid "This action is not supported for this buffer" msgstr "Cette action n'est pas supportée pour ce tampon" @@ -98,78 +94,81 @@ msgstr "Abonnements de {username}" msgid "Unknown buffer" msgstr "Tampon inconnu" -#: ../src\controller\buffers\twitter\base.py:88 -#: ../src\controller\buffers\twitter\trends.py:122 -#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\controller\buffers\twitter\base.py:87 +#: ../src\controller\buffers\twitter\trends.py:43 +#: ../src\controller\buffers\twitter\trends.py:134 +#: ../src\controller\messages.py:296 ../src\wxUI\buffers\base.py:25 #: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:312 +#: ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "Tweet" -#: ../src\controller\buffers\twitter\base.py:89 -#: ../src\controller\buffers\twitter\trends.py:123 +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:44 +#: ../src\controller\buffers\twitter\trends.py:135 msgid "Write the tweet here" msgstr "Écrivez le tweet ici" -#: ../src\controller\buffers\twitter\base.py:219 +#: ../src\controller\buffers\twitter\base.py:192 msgid "New tweet in {0}" msgstr "Nouveau tweet dans {0}" -#: ../src\controller\buffers\twitter\base.py:222 +#: ../src\controller\buffers\twitter\base.py:195 msgid "{0} new tweets in {1}." msgstr "{0} nouveau tweet dans {1}" -#: ../src\controller\buffers\twitter\base.py:261 +#: ../src\controller\buffers\twitter\base.py:234 #: ../src\controller\buffers\twitter\directMessages.py:88 -#: ../src\controller\buffers\twitter\people.py:180 +#: ../src\controller\buffers\twitter\people.py:174 msgid "%s items retrieved" msgstr "%s éléments récupérés" -#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\base.py:266 #: ../src\controller\buffers\twitter\people.py:80 msgid "This buffer is not a timeline; it can't be deleted." msgstr "Ce tampon n'est pas une chronologie ; Impossible de le supprimé." -#: ../src\controller\buffers\twitter\base.py:430 +#: ../src\controller\buffers\twitter\base.py:402 msgid "Reply to {arg0}" msgstr "Répondre à {arg0}" -#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\controller\buffers\twitter\base.py:404 #: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 msgid "Reply" msgstr "Répondre" -#: ../src\controller\buffers\twitter\base.py:433 +#: ../src\controller\buffers\twitter\base.py:405 msgid "Reply to %s" msgstr "Répondre à %s" -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\buffers\twitter\directMessages.py:130 +#: ../src\controller\buffers\twitter\base.py:428 +#: ../src\controller\buffers\twitter\directMessages.py:124 msgid "New direct message" msgstr "Nouveau message" -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\messages.py:200 +#: ../src\controller\buffers\twitter\base.py:428 +#: ../src\controller\messages.py:268 msgid "Direct message to %s" msgstr "Message à %s" -#: ../src\controller\buffers\twitter\base.py:520 +#: ../src\controller\buffers\twitter\base.py:459 msgid "Add your comment to the tweet" msgstr "Ajoutez votre commentaire pour le tweet" -#: ../src\controller\buffers\twitter\base.py:520 +#: ../src\controller\buffers\twitter\base.py:459 msgid "Quote" msgstr "Citer" -#: ../src\controller\buffers\twitter\base.py:596 +#: ../src\controller\buffers\twitter\base.py:520 msgid "Opening URL..." msgstr "Ouverture de l'URL..." -#: ../src\controller\buffers\twitter\base.py:633 +#: ../src\controller\buffers\twitter\base.py:557 msgid "User details" msgstr "Détails de l'utilisateur" -#: ../src\controller\buffers\twitter\base.py:654 +#: ../src\controller\buffers\twitter\base.py:578 msgid "Opening item in web browser..." msgstr "Ouverture de l'élément dans le navigateur Web..." @@ -184,15 +183,15 @@ msgstr "Mention pour %s" msgid "Mention" msgstr "Mention" -#: ../src\controller\buffers\twitter\directMessages.py:133 +#: ../src\controller\buffers\twitter\directMessages.py:127 msgid "{0} new direct messages." msgstr "{0} nouveau message" -#: ../src\controller\buffers\twitter\directMessages.py:136 +#: ../src\controller\buffers\twitter\directMessages.py:130 msgid "This action is not supported in the buffer yet." msgstr "Cette action n'est pas supportée dans le tampon actuel" -#: ../src\controller\buffers\twitter\directMessages.py:146 +#: ../src\controller\buffers\twitter\directMessages.py:140 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -200,11 +199,11 @@ msgstr "" "Récupérer plus d'élément est impossible dans ce tampon, utilisez le tampon " "des messages à la place." -#: ../src\controller\buffers\twitter\people.py:253 +#: ../src\controller\buffers\twitter\people.py:247 msgid "{0} new followers." msgstr "{0} nouvel abonné" -#: ../src\controller\buffers\twitter\trends.py:146 +#: ../src\controller\buffers\twitter\trends.py:150 msgid "This action is not supported in the buffer, yet." msgstr "Cette action n'est pas supportée pour le tampon actuel" @@ -222,7 +221,7 @@ msgstr "Chronologies" #: ../src\controller\mainController.py:359 #: ../src\controller\mainController.py:883 -#: ../src\controller\mainController.py:1585 +#: ../src\controller\mainController.py:1582 msgid "Timeline for {}" msgstr "Chronologie de {}" @@ -232,7 +231,7 @@ msgstr "Chronologies des favoris" #: ../src\controller\mainController.py:363 #: ../src\controller\mainController.py:902 -#: ../src\controller\mainController.py:1587 +#: ../src\controller\mainController.py:1584 msgid "Likes for {}" msgstr "Favoris de {}" @@ -242,7 +241,7 @@ msgstr "Chronologies des abonnés" #: ../src\controller\mainController.py:367 #: ../src\controller\mainController.py:921 -#: ../src\controller\mainController.py:1589 +#: ../src\controller\mainController.py:1586 msgid "Followers for {}" msgstr "Abonnés de {}" @@ -252,7 +251,7 @@ msgstr "Chronologies des abonnements" #: ../src\controller\mainController.py:371 #: ../src\controller\mainController.py:940 -#: ../src\controller\mainController.py:1591 +#: ../src\controller\mainController.py:1588 msgid "Friends for {}" msgstr "Abonnements de {}" @@ -277,7 +276,7 @@ msgstr "Recherche de {}" #: ../src\controller\mainController.py:381 #: ../src\controller\mainController.py:982 -#: ../src\controller\mainController.py:1593 +#: ../src\controller\mainController.py:1590 msgid "Trending topics for %s" msgstr "Tendances pour %s" @@ -320,7 +319,7 @@ msgstr "Ajoute un alias pour l'utilisateur" msgid "Alias has been set correctly for {}." msgstr "L'alias pour {} a correctement été définie" -#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:327 msgid "MMM D, YYYY. H:m" msgstr "D MMM YYYY à H:m" @@ -410,72 +409,52 @@ msgstr "Tampon muet" msgid "Buffer mute off" msgstr "Tampon non muet" -#: ../src\controller\mainController.py:1545 +#: ../src\controller\mainController.py:1542 msgid "Copied" msgstr "Copié" -#: ../src\controller\mainController.py:1575 +#: ../src\controller\mainController.py:1572 msgid "Unable to update this buffer." msgstr "Impossible de mettre à jour ce tampon." -#: ../src\controller\mainController.py:1578 +#: ../src\controller\mainController.py:1575 msgid "Updating buffer..." msgstr "Actualisation..." -#: ../src\controller\mainController.py:1581 +#: ../src\controller\mainController.py:1578 msgid "{0} items retrieved" msgstr "{0} éléments récupérés" -#: ../src\controller\mainController.py:1600 -#: ../src\controller\mainController.py:1620 +#: ../src\controller\mainController.py:1597 +#: ../src\controller\mainController.py:1617 msgid "Invalid buffer" msgstr "Tampon invalide" -#: ../src\controller\mainController.py:1611 +#: ../src\controller\mainController.py:1608 msgid "Picture {0}" msgstr "Photo {0}" -#: ../src\controller\mainController.py:1612 +#: ../src\controller\mainController.py:1609 msgid "Select the picture" msgstr "Sélectionner la photo" -#: ../src\controller\mainController.py:1631 +#: ../src\controller\mainController.py:1628 msgid "Unable to extract text" msgstr "Impossible d'extraire le texte" -#: ../src\controller\messages.py:56 +#: ../src\controller\messages.py:49 msgid "Translated" msgstr "Traduit" -#: ../src\controller\messages.py:63 -msgid "There's no URL to be shortened" -msgstr "Aucune URL à réduire" - -#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 -msgid "URL shortened" -msgstr "URL réduite" - -#: ../src\controller\messages.py:82 -msgid "There's no URL to be expanded" -msgstr "Aucune URL à élargir" - -#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 -msgid "URL expanded" -msgstr "URL élargi" - -#: ../src\controller\messages.py:108 +#: ../src\controller\messages.py:56 msgid "%s - %s of %d characters" msgstr "%s - %s/%d caractères" -#: ../src\controller\messages.py:112 -msgid "%s - %s characters" -msgstr "%s - %s caractères" - -#: ../src\controller\messages.py:272 +#: ../src\controller\messages.py:354 msgid "View item" msgstr "Voir l'élément" -#: ../src\controller\messages.py:301 +#: ../src\controller\messages.py:379 msgid "Link copied to clipboard." msgstr "Lien copié dans le Presse-papiers" @@ -666,7 +645,7 @@ msgstr "Arrêté" msgid "&Record" msgstr "&Enregistrer" -#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:147 msgid "Playing..." msgstr "Lecture..." @@ -718,6 +697,9 @@ msgid "%s seconds" msgstr "%s secondes" #: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:36 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:173 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:258 msgid "File" msgstr "Fichier" @@ -1563,7 +1545,7 @@ msgid "New tweet" msgstr "Nouveau tweet" #: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 -#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Retweet" msgstr "Retweet" @@ -2009,15 +1991,17 @@ msgid "public" msgstr "public" #: ../src\sessions\twitter\session.py:211 +#: ../src\sessions\twitter\session.py:238 msgid "%s failed. Reason: %s" msgstr "%s erreur. Raison: %s" #: ../src\sessions\twitter\session.py:217 +#: ../src\sessions\twitter\session.py:241 msgid "%s succeeded." msgstr "%s réussi." -#: ../src\sessions\twitter\session.py:426 -#: ../src\sessions\twitter\session.py:504 +#: ../src\sessions\twitter\session.py:450 +#: ../src\sessions\twitter\session.py:528 msgid "Deleted account" msgstr "Compte supprimé" @@ -2045,7 +2029,7 @@ msgstr "Compte en cours d'autorisation..." msgid "Enter your PIN code here" msgstr "Entrer votre code PIN ici" -#: ../src\sound.py:161 +#: ../src\sound.py:160 msgid "Stopped." msgstr "Arrêté." @@ -2099,10 +2083,6 @@ msgstr "" msgid "Client" msgstr "Client" -#: ../src\wxUI\buffers\base.py:12 -msgid "Text" -msgstr "Texte" - #: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 msgid "Date" msgstr "Date" @@ -2114,6 +2094,11 @@ msgstr "Date" msgid "User" msgstr "Utilisateur" +#: ../src\wxUI\buffers\base.py:12 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:48 +msgid "Text" +msgstr "Texte" + #: ../src\wxUI\buffers\base.py:28 msgid "Direct message" msgstr "Message" @@ -2375,55 +2360,6 @@ msgstr "" "{0} a été quitté inopinément lors de sa dernière exécution. Si ce problème " "perciste, veuillez le signaler aux développeurs de {0}." -#: ../src\wxUI\dialogs\attach.py:10 -msgid "Add an attachment" -msgstr "Ajouter un fichier" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Attachments" -msgstr "Fichiers joints" - -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Title" -msgstr "Titre" - -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Type" -msgstr "Type" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "Add attachments" -msgstr "Joindre des fichiers" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "&Photo" -msgstr "&Image" - -#: ../src\wxUI\dialogs\attach.py:21 -msgid "Remove attachment" -msgstr "Supprimer le fichier joint" - -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "Fichiers image (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Select the picture to be uploaded" -msgstr "Sélectionnez la photo à charger" - -#: ../src\wxUI\dialogs\attach.py:44 -msgid "please provide a description" -msgstr "Veuillez fournir une description" - -#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 -#: ../src\wxUI\dialogs\lists.py:70 -msgid "Description" -msgstr "Description" - #: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "Langue" @@ -2811,6 +2747,14 @@ msgstr "Propriétaire" msgid "mode" msgstr "mode" +#: ../src\wxUI\dialogs\lists.py:14 ../src\wxUI\dialogs\lists.py:70 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:38 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:127 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:175 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:260 +msgid "Description" +msgstr "Description" + #: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "Créer une nouvelle liste" @@ -2867,103 +2811,6 @@ msgstr "Sélectionnez une liste pour supprimer l'utilisateur" msgid "Do you really want to delete this list?" msgstr "Voulez-vous vraiment supprimer cette liste ?" -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "&Tweet long" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "&Joindre une image..." - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 -msgid "Check &spelling..." -msgstr "Correction &orthographique..." - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "&Joindre un audio..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "&Réduire URL" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 -msgid "&Expand URL" -msgstr "&Élargir URL" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 -msgid "&Translate..." -msgstr "&Traduire..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "Sai&sie automatique utilisateurs" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "Envoye&r" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 -msgid "C&lose" -msgstr "F&ermer" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "&Destinataire" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "&Répondre à tout le monde" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Tweet - %i caractères " - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Description de l'image" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "Retweets: " - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Favoris: " - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Source: " - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 -msgid "Date: " -msgstr "Date: " - -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 -msgid "Copy link to clipboard" -msgstr "Copier le lien dans le Presse-papiers" - -#: ../src\wxUI\dialogs\message.py:408 -msgid "View" -msgstr "Voir" - -#: ../src\wxUI\dialogs\message.py:410 -msgid "Item" -msgstr "Élément" - #: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "Rechercher sur Twitter" @@ -3045,6 +2892,225 @@ msgstr "Ville" msgid "&Location" msgstr "&Localisation" +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:33 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:49 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:170 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:255 +msgid "Attachments" +msgstr "Fichiers joints" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:37 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:174 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:259 +msgid "Type" +msgstr "Type" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:40 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:177 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:262 +msgid "Delete attachment" +msgstr "Supprimer la pièce jointe" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:45 +msgid "Added Tweets" +msgstr "Tweets ajoutés" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:52 +msgid "Delete tweet" +msgstr "Supprimer le tweet" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:57 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:192 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:267 +msgid "A&dd..." +msgstr "&Ajouter" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:59 +msgid "Add t&weet" +msgstr "A&jouter un tweet" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:62 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:194 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:269 +msgid "&Attach audio..." +msgstr "&Joindre un audio..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:66 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:198 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:237 +msgid "Auto&complete users" +msgstr "Sai&sie automatique utilisateurs" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:68 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:200 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:273 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:367 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:440 +msgid "Check &spelling..." +msgstr "Correction &orthographique..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:70 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:202 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:275 +msgid "&Translate" +msgstr "&Traduire" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:74 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:206 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:279 +msgid "Sen&d" +msgstr "Envoye&r" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:118 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:220 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:299 +msgid "Image" +msgstr "Image" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:120 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:222 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:301 +msgid "Video" +msgstr "Vidéo" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:122 +msgid "Poll" +msgstr "Sondage" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:127 +msgid "please provide a description" +msgstr "Veuillez fournir une description" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:134 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:292 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" +msgstr "Fichiers image (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:134 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:292 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Select the picture to be uploaded" +msgstr "Sélectionnez la photo à charger" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:141 +msgid "Select the video to be uploaded" +msgstr "Sélectionnez la vidéo à téléverser" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:141 +msgid "Video files (*.mp4)|*.mp4" +msgstr "Fichiers vidéo (*.mp4)|*.mp4" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:147 +msgid "Error adding attachment" +msgstr "Erreur à l'ajout de la pièce jointe" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:147 +msgid "" +"It is not possible to add more attachments. Please make sure your tweet " +"complies with Twitter'S attachment rules. You can add only one video or GIF " +"in every tweet, and a maximum of 4 photos." +msgstr "" +"Il est impossible de joindre plus de contenu. Assurez-vous que votre tweet " +"respecte les règles d'attachement de Twitter. Vous pouvez seulement inclure " +"une vidéo ou un GIF par tweet, et 4 photos au maximum." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:182 +msgid "&Mention to all" +msgstr "&Répondre à tout le monde" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:235 +msgid "&Recipient" +msgstr "&Destinataire" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:307 +msgid "Tweet - %i characters " +msgstr "Tweet - %i caractères " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:324 +msgid "Image description" +msgstr "Description de l'image" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:335 +msgid "Retweets: " +msgstr "Retweets: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:340 +msgid "Likes: " +msgstr "Favoris: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:345 +msgid "Source: " +msgstr "Source: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:350 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:428 +msgid "Date: " +msgstr "Date: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:365 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:438 +msgid "Copy link to clipboard" +msgstr "Copier le lien dans le Presse-papiers" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:368 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:443 +msgid "&Translate..." +msgstr "&Traduire..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:369 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:444 +msgid "C&lose" +msgstr "F&ermer" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:413 +msgid "View" +msgstr "Voir" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:415 +msgid "Item" +msgstr "Élément" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:441 +msgid "&Expand URL" +msgstr "&Élargir URL" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:480 +msgid "Add a poll" +msgstr "Ajouter un sondage" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:484 +msgid "Participation time (in days)" +msgstr "Temps de participation (en jours)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:491 +msgid "Choices" +msgstr "Choix" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:495 +msgid "Option 1" +msgstr "Option 1" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:501 +msgid "Option 2" +msgstr "Option 2" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:507 +msgid "Option 3" +msgstr "Option 3" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:513 +msgid "Option 4" +msgstr "Option 4" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:540 +msgid "Not enough information" +msgstr "Pas assez d'informations" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:540 +msgid "Please make sure you have provided at least two options for the poll." +msgstr "Assurez-vous d'avoir spécifier au moins 2 options pour le sondage." + #: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "Actualiser votre profil" From 0e91ca3d4d4007cc4d6a9875117fcda451160c22 Mon Sep 17 00:00:00 2001 From: Nikola Jovic Date: Thu, 11 Nov 2021 01:30:30 +0100 Subject: [PATCH 233/245] Updated Serbian translation --- src/locales/sr/LC_MESSAGES/twblue.mo | Bin 54001 -> 55001 bytes src/locales/sr/LC_MESSAGES/twblue.po | 631 ++++++++++++++++----------- 2 files changed, 371 insertions(+), 260 deletions(-) diff --git a/src/locales/sr/LC_MESSAGES/twblue.mo b/src/locales/sr/LC_MESSAGES/twblue.mo index 7701f9b14bede7ec7876a98982ea0b1f7f0d5221..4406f6caba50b773402c2458aa993947e8c8a32d 100644 GIT binary patch delta 18395 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 ZBwAVjX)*KI125N_6P-O>wNB6T{U3KBnK=Le diff --git a/src/locales/sr/LC_MESSAGES/twblue.po b/src/locales/sr/LC_MESSAGES/twblue.po index af9ba210..79d3e91d 100644 --- a/src/locales/sr/LC_MESSAGES/twblue.po +++ b/src/locales/sr/LC_MESSAGES/twblue.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: TwBlue 0.80\n" -"POT-Creation-Date: 2021-10-28 16:43+Central Europe Daylight Time\n" -"PO-Revision-Date: 2021-10-28 17:03+0100\n" +"POT-Creation-Date: 2021-11-11 01:16+0100\n" +"PO-Revision-Date: 2021-11-11 01:30+0100\n" "Last-Translator: Nikola Jović \n" "Language-Team: Aleksandar Đurić \n" "Language: sr_RS@latin\n" @@ -18,10 +18,6 @@ msgstr "" "X-Poedit-Bookmarks: -1,442,-1,-1,-1,-1,-1,-1,-1,-1\n" "X-Poedit-SourceCharset: UTF-8\n" -#: ../src\controller\attach.py:25 -msgid "Photo" -msgstr "Slika" - #: ../src\controller\buffers\base\base.py:91 msgid "This action is not supported for this buffer" msgstr "Ova radnja nije podržana na ovom kanalu" @@ -100,101 +96,104 @@ msgstr "Prijatelji korisnika {username}" msgid "Unknown buffer" msgstr "Nepoznat kanal" -#: ../src\controller\buffers\twitter\base.py:88 -#: ../src\controller\buffers\twitter\trends.py:121 -#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\controller\buffers\twitter\base.py:87 +#: ../src\controller\buffers\twitter\trends.py:43 +#: ../src\controller\buffers\twitter\trends.py:134 +#: ../src\controller\messages.py:296 ../src\wxUI\buffers\base.py:25 #: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:312 +#: ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "Tvit" -#: ../src\controller\buffers\twitter\base.py:89 -#: ../src\controller\buffers\twitter\trends.py:122 +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:44 +#: ../src\controller\buffers\twitter\trends.py:135 msgid "Write the tweet here" msgstr "Otkucajte tvit ovde:" -#: ../src\controller\buffers\twitter\base.py:219 +#: ../src\controller\buffers\twitter\base.py:192 msgid "New tweet in {0}" msgstr "Novi tvit u kanalu {0}" -#: ../src\controller\buffers\twitter\base.py:222 +#: ../src\controller\buffers\twitter\base.py:195 msgid "{0} new tweets in {1}." msgstr "{0} novih tvitova u kanalu {1}." -#: ../src\controller\buffers\twitter\base.py:261 -#: ../src\controller\buffers\twitter\directMessages.py:87 -#: ../src\controller\buffers\twitter\people.py:180 +#: ../src\controller\buffers\twitter\base.py:234 +#: ../src\controller\buffers\twitter\directMessages.py:88 +#: ../src\controller\buffers\twitter\people.py:174 msgid "%s items retrieved" msgstr "%s primljenih stavki" -#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\base.py:266 #: ../src\controller\buffers\twitter\people.py:80 msgid "This buffer is not a timeline; it can't be deleted." msgstr "Ovaj kanal nije vremenska linija i ne može biti izbrisan." -#: ../src\controller\buffers\twitter\base.py:430 +#: ../src\controller\buffers\twitter\base.py:402 msgid "Reply to {arg0}" msgstr "Odgovori {arg0}" -#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\controller\buffers\twitter\base.py:404 #: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 msgid "Reply" msgstr "Odgovori" -#: ../src\controller\buffers\twitter\base.py:433 +#: ../src\controller\buffers\twitter\base.py:405 msgid "Reply to %s" msgstr "Odgovori %s" -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\buffers\twitter\directMessages.py:129 +#: ../src\controller\buffers\twitter\base.py:428 +#: ../src\controller\buffers\twitter\directMessages.py:124 msgid "New direct message" msgstr "Nova direktna poruka" -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\messages.py:200 +#: ../src\controller\buffers\twitter\base.py:428 +#: ../src\controller\messages.py:268 msgid "Direct message to %s" msgstr "Direktna poruka za %s" -#: ../src\controller\buffers\twitter\base.py:520 +#: ../src\controller\buffers\twitter\base.py:459 msgid "Add your comment to the tweet" msgstr "Dodajte vaš komentar u tvit" -#: ../src\controller\buffers\twitter\base.py:520 +#: ../src\controller\buffers\twitter\base.py:459 msgid "Quote" msgstr "Citiraj" -#: ../src\controller\buffers\twitter\base.py:596 +#: ../src\controller\buffers\twitter\base.py:520 msgid "Opening URL..." msgstr "Otvaram vezu..." -#: ../src\controller\buffers\twitter\base.py:633 +#: ../src\controller\buffers\twitter\base.py:557 msgid "User details" msgstr "Podaci o korisniku" -#: ../src\controller\buffers\twitter\base.py:654 +#: ../src\controller\buffers\twitter\base.py:578 msgid "Opening item in web browser..." msgstr "Otvaram stavku u Web pretraživaču..." -#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\directMessages.py:93 #: ../src\controller\buffers\twitter\people.py:95 msgid "Mention to %s" msgstr "Spomeni %s" -#: ../src\controller\buffers\twitter\directMessages.py:92 +#: ../src\controller\buffers\twitter\directMessages.py:93 #: ../src\controller\buffers\twitter\people.py:95 #: ../src\wxUI\buffers\people.py:17 msgid "Mention" msgstr "Spomeni" -#: ../src\controller\buffers\twitter\directMessages.py:132 +#: ../src\controller\buffers\twitter\directMessages.py:127 msgid "{0} new direct messages." msgstr "{0} novih direktnih poruka." -#: ../src\controller\buffers\twitter\directMessages.py:135 +#: ../src\controller\buffers\twitter\directMessages.py:130 msgid "This action is not supported in the buffer yet." msgstr "Ova radnja još uvek nije podržana na ovom kanalu." -#: ../src\controller\buffers\twitter\directMessages.py:145 +#: ../src\controller\buffers\twitter\directMessages.py:140 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -202,11 +201,11 @@ msgstr "" "Nemoguće preuzeti dodatne stavke za ovaj kanal. Umesto toga, koristite kanal " "direktne poruke." -#: ../src\controller\buffers\twitter\people.py:253 +#: ../src\controller\buffers\twitter\people.py:247 msgid "{0} new followers." msgstr "{0} novih pratilaca." -#: ../src\controller\buffers\twitter\trends.py:145 +#: ../src\controller\buffers\twitter\trends.py:150 msgid "This action is not supported in the buffer, yet." msgstr "Ova radnja još uvek nije podržana na ovom kanalu" @@ -224,7 +223,7 @@ msgstr "Vremenske linije" #: ../src\controller\mainController.py:359 #: ../src\controller\mainController.py:883 -#: ../src\controller\mainController.py:1585 +#: ../src\controller\mainController.py:1582 msgid "Timeline for {}" msgstr "Vremenska linija od {}" @@ -234,7 +233,7 @@ msgstr "Vremenska linija omiljenih tvitova" #: ../src\controller\mainController.py:363 #: ../src\controller\mainController.py:902 -#: ../src\controller\mainController.py:1587 +#: ../src\controller\mainController.py:1584 msgid "Likes for {}" msgstr "Sviđanja od {}" @@ -244,7 +243,7 @@ msgstr "Vremenske linije pratilaca" #: ../src\controller\mainController.py:367 #: ../src\controller\mainController.py:921 -#: ../src\controller\mainController.py:1589 +#: ../src\controller\mainController.py:1586 msgid "Followers for {}" msgstr "Pratioci od {}" @@ -254,7 +253,7 @@ msgstr "Vremenske linije praćenih korisnika" #: ../src\controller\mainController.py:371 #: ../src\controller\mainController.py:940 -#: ../src\controller\mainController.py:1591 +#: ../src\controller\mainController.py:1588 msgid "Friends for {}" msgstr "Prijatelji od {}" @@ -279,6 +278,7 @@ msgstr "Pretraga za {}" #: ../src\controller\mainController.py:381 #: ../src\controller\mainController.py:982 +#: ../src\controller\mainController.py:1590 msgid "Trending topics for %s" msgstr "Teme u trendu za %s" @@ -321,7 +321,7 @@ msgstr "Dodaj nadimak za korisnika" msgid "Alias has been set correctly for {}." msgstr "Nadimak za {} je uspešno podešen." -#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:327 msgid "MMM D, YYYY. H:m" msgstr "MMM D, YYYY. H:m" @@ -410,72 +410,52 @@ msgstr "Utišavanje kanala uključeno" msgid "Buffer mute off" msgstr "Utišavanje kanala isključeno" -#: ../src\controller\mainController.py:1545 +#: ../src\controller\mainController.py:1542 msgid "Copied" msgstr "Kopirano" -#: ../src\controller\mainController.py:1575 +#: ../src\controller\mainController.py:1572 msgid "Unable to update this buffer." msgstr "Ne mogu da ažuriram ovaj kanal." -#: ../src\controller\mainController.py:1578 +#: ../src\controller\mainController.py:1575 msgid "Updating buffer..." msgstr "Ažuriram kanal..." -#: ../src\controller\mainController.py:1581 +#: ../src\controller\mainController.py:1578 msgid "{0} items retrieved" msgstr "{0} primljenih stavki" -#: ../src\controller\mainController.py:1598 -#: ../src\controller\mainController.py:1618 +#: ../src\controller\mainController.py:1597 +#: ../src\controller\mainController.py:1617 msgid "Invalid buffer" msgstr "Nevažeći kanal" -#: ../src\controller\mainController.py:1609 +#: ../src\controller\mainController.py:1608 msgid "Picture {0}" msgstr "Slika {0}" -#: ../src\controller\mainController.py:1610 +#: ../src\controller\mainController.py:1609 msgid "Select the picture" msgstr "Izaberite sliku" -#: ../src\controller\mainController.py:1629 +#: ../src\controller\mainController.py:1628 msgid "Unable to extract text" msgstr "Ne mogu da izdvojim tekst." -#: ../src\controller\messages.py:56 +#: ../src\controller\messages.py:49 msgid "Translated" msgstr "Prevedeno" -#: ../src\controller\messages.py:63 -msgid "There's no URL to be shortened" -msgstr "Nema veze koja bi mogla biti skraćena" - -#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 -msgid "URL shortened" -msgstr "Veza je skraćena" - -#: ../src\controller\messages.py:82 -msgid "There's no URL to be expanded" -msgstr "Nema veze koja bi mogla biti proširena" - -#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 -msgid "URL expanded" -msgstr "Veza je proširena" - -#: ../src\controller\messages.py:108 +#: ../src\controller\messages.py:56 msgid "%s - %s of %d characters" msgstr "%s - %s od %d znakova" -#: ../src\controller\messages.py:112 -msgid "%s - %s characters" -msgstr "%s - %s znakova" - -#: ../src\controller\messages.py:272 +#: ../src\controller\messages.py:354 msgid "View item" msgstr "Prikaži stavku" -#: ../src\controller\messages.py:301 +#: ../src\controller\messages.py:379 msgid "Link copied to clipboard." msgstr "Link kopiran u privremenu memoriju." @@ -667,7 +647,7 @@ msgstr "Zaustavljeno" msgid "&Record" msgstr "&Snimi" -#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:147 msgid "Playing..." msgstr "Reprodukujem..." @@ -719,6 +699,9 @@ msgid "%s seconds" msgstr "%s sekundi" #: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:36 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:173 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:258 msgid "File" msgstr "Datoteka" @@ -1486,7 +1469,7 @@ msgstr "" msgid "Send report" msgstr "Pošalji izveštaj" -#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 +#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:83 #: ../src\wxUI\dialogs\find.py:23 msgid "Cancel" msgstr "Otkaži" @@ -1560,7 +1543,7 @@ msgid "New tweet" msgstr "Novi tvit" #: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 -#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Retweet" msgstr "Retvituj" @@ -1773,7 +1756,7 @@ msgstr "Prečica" msgid "Action" msgstr "Radnja" -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 +#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:135 #: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 msgid "Edit" msgstr "Izmeni" @@ -1823,7 +1806,7 @@ msgstr "Windows" msgid "Key" msgstr "Taster" -#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 +#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:80 #: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 #: ../src\wxUI\dialogs\utils.py:36 msgid "OK" @@ -1999,16 +1982,18 @@ msgstr "Privatno" msgid "public" msgstr "Javno" -#: ../src\sessions\twitter\session.py:209 +#: ../src\sessions\twitter\session.py:211 +#: ../src\sessions\twitter\session.py:238 msgid "%s failed. Reason: %s" msgstr "%s nije uspelo. Razlog: %s" -#: ../src\sessions\twitter\session.py:215 +#: ../src\sessions\twitter\session.py:217 +#: ../src\sessions\twitter\session.py:241 msgid "%s succeeded." msgstr "%s uspelo." -#: ../src\sessions\twitter\session.py:424 -#: ../src\sessions\twitter\session.py:502 +#: ../src\sessions\twitter\session.py:450 +#: ../src\sessions\twitter\session.py:528 msgid "Deleted account" msgstr "Obrisan nalog" @@ -2036,7 +2021,7 @@ msgstr "Autorizacija naloga..." msgid "Enter your PIN code here" msgstr "Ovde upišite vaš PIN kod" -#: ../src\sound.py:161 +#: ../src\sound.py:160 msgid "Stopped." msgstr "Zaustavljeno" @@ -2088,10 +2073,6 @@ msgstr "" msgid "Client" msgstr "Klijent" -#: ../src\wxUI\buffers\base.py:12 -msgid "Text" -msgstr "Tekst" - #: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 msgid "Date" msgstr "Datum" @@ -2103,6 +2084,11 @@ msgstr "Datum" msgid "User" msgstr "Korisnik" +#: ../src\wxUI\buffers\base.py:12 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:48 +msgid "Text" +msgstr "Tekst" + #: ../src\wxUI\buffers\base.py:28 msgid "Direct message" msgstr "Direktna poruka" @@ -2359,55 +2345,6 @@ msgstr "" "{0} je neočekivano zatvoren pri poslednjem pokretanju. Ako se problem " "nastavi, molimo prijavite ga{0} programerima." -#: ../src\wxUI\dialogs\attach.py:10 -msgid "Add an attachment" -msgstr "Dodaj prilog" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Attachments" -msgstr "Prilozi" - -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Title" -msgstr "Naslov" - -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Type" -msgstr "Vrsta" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "Add attachments" -msgstr "Dodaj priloge" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "&Photo" -msgstr "Slika" - -#: ../src\wxUI\dialogs\attach.py:21 -msgid "Remove attachment" -msgstr "Ukloni prilog" - -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "Datoteke sa slikama" - -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Select the picture to be uploaded" -msgstr "Izaberite sliku koju želite da otpremite" - -#: ../src\wxUI\dialogs\attach.py:44 -msgid "please provide a description" -msgstr "Molimo vas navedite opis:" - -#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 -#: ../src\wxUI\dialogs\lists.py:70 -msgid "Description" -msgstr "Opis" - #: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "Jezik" @@ -2544,7 +2481,7 @@ msgid "Status" msgstr "Status" #: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Buffer" msgstr "Kanal" @@ -2669,91 +2606,99 @@ msgstr "Dodaci" msgid "Save" msgstr "Sačuvaj" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: ../src\wxUI\dialogs\filterDialogs.py:13 msgid "Create a filter for this buffer" msgstr "Napravi filter za ovaj kanal" -#: ../src\wxUI\dialogs\filterDialogs.py:17 +#: ../src\wxUI\dialogs\filterDialogs.py:14 msgid "Filter title" msgstr "Naziv filtera" -#: ../src\wxUI\dialogs\filterDialogs.py:26 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:24 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter by word" msgstr "Filtriraj na osnovu reči" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: ../src\wxUI\dialogs\filterDialogs.py:25 msgid "Ignore tweets wich contain the following word" msgstr "Zanemari tvitove koji sadrže sledeću reč" -#: ../src\wxUI\dialogs\filterDialogs.py:28 +#: ../src\wxUI\dialogs\filterDialogs.py:26 msgid "Ignore tweets without the following word" msgstr "Zanemari tvitove bez sledeće reči" -#: ../src\wxUI\dialogs\filterDialogs.py:33 +#: ../src\wxUI\dialogs\filterDialogs.py:31 msgid "word" msgstr "Reč" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: ../src\wxUI\dialogs\filterDialogs.py:36 msgid "Allow retweets" msgstr "Dozvoli retvitove" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: ../src\wxUI\dialogs\filterDialogs.py:37 msgid "Allow quoted tweets" msgstr "Dozvoli citirane tvitove" -#: ../src\wxUI\dialogs\filterDialogs.py:40 +#: ../src\wxUI\dialogs\filterDialogs.py:38 msgid "Allow replies" msgstr "Dozvoli odgovore" -#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:46 msgid "Use this term as a regular expression" msgstr "Koristi ovaj termin kao regulara nizraz" -#: ../src\wxUI\dialogs\filterDialogs.py:50 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter by language" msgstr "Filtriraj na osnovu jezika" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: ../src\wxUI\dialogs\filterDialogs.py:49 msgid "Load tweets in the following languages" msgstr "Učitaj tvitove na sledećim jezicima" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: ../src\wxUI\dialogs\filterDialogs.py:50 msgid "Ignore tweets in the following languages" msgstr "Zanemari tvitove na sledećim jezicima" -#: ../src\wxUI\dialogs\filterDialogs.py:53 +#: ../src\wxUI\dialogs\filterDialogs.py:51 msgid "Don't filter by language" msgstr "Ne filtriraj na osnovu jezika" -#: ../src\wxUI\dialogs\filterDialogs.py:64 +#: ../src\wxUI\dialogs\filterDialogs.py:62 msgid "Supported languages" msgstr "Podržani jezici" -#: ../src\wxUI\dialogs\filterDialogs.py:69 +#: ../src\wxUI\dialogs\filterDialogs.py:67 msgid "Add selected language to filter" msgstr "Dodaj izabrani jezik u filter" -#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:71 msgid "Selected languages" msgstr "Izabrani jezici" -#: ../src\wxUI\dialogs\filterDialogs.py:75 -#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 +#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: ../src\wxUI\dialogs\filterDialogs.py:137 ../src\wxUI\dialogs\lists.py:21 #: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 msgid "Remove" msgstr "Ukloni" -#: ../src\wxUI\dialogs\filterDialogs.py:123 +#: ../src\wxUI\dialogs\filterDialogs.py:120 +msgid "Missing filter name" +msgstr "Ime filtera nedostaje" + +#: ../src\wxUI\dialogs\filterDialogs.py:120 +msgid "You must define a name for the filter before creating it." +msgstr "Morate upisati ime za filter pre nego što ga napravite." + +#: ../src\wxUI\dialogs\filterDialogs.py:127 msgid "Manage filters" msgstr "Upravljanje filterima" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: ../src\wxUI\dialogs\filterDialogs.py:129 msgid "Filters" msgstr "Filteri" -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: ../src\wxUI\dialogs\filterDialogs.py:130 msgid "Filter" msgstr "Filter" @@ -2785,6 +2730,14 @@ msgstr "Vlasnik" msgid "mode" msgstr "Način" +#: ../src\wxUI\dialogs\lists.py:14 ../src\wxUI\dialogs\lists.py:70 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:38 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:127 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:175 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:260 +msgid "Description" +msgstr "Opis" + #: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "Stvori novu listu" @@ -2841,103 +2794,6 @@ msgstr "Izaberite listu sa koje želite da uklonite korisnika" msgid "Do you really want to delete this list?" msgstr "Želite li zaista da izbrišete ovu listu?" -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "Dug tvit" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "Otpremi sliku..." - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 -msgid "Check &spelling..." -msgstr "Proveri pravopis..." - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "Priloži zvučni zapis..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "Skrati vezu" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 -msgid "&Expand URL" -msgstr "Proširi vezu" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 -msgid "&Translate..." -msgstr "Prevedi..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "&Automatsko dovršavanje" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "Pošalji" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 -msgid "C&lose" -msgstr "Zatvori" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "Primalac" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "Spomeni sve" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Tvit - %i znakova" - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Opis slike" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "Retvitova" - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Sviđanja:" - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Izvor:" - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 -msgid "Date: " -msgstr "Datum:" - -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 -msgid "Copy link to clipboard" -msgstr "Kopiraj link u privremenu memoriju" - -#: ../src\wxUI\dialogs\message.py:408 -msgid "View" -msgstr "Vidi" - -#: ../src\wxUI\dialogs\message.py:410 -msgid "Item" -msgstr "Stavka" - #: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "Pretraži ttwitter" @@ -3019,6 +2875,225 @@ msgstr "Gradu" msgid "&Location" msgstr "Mesto" +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:33 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:49 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:170 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:255 +msgid "Attachments" +msgstr "Prilozi" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:37 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:174 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:259 +msgid "Type" +msgstr "Vrsta" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:40 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:177 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:262 +msgid "Delete attachment" +msgstr "Ukloni prilog" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:45 +msgid "Added Tweets" +msgstr "Dodati tvitovi" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:52 +msgid "Delete tweet" +msgstr "Obriši tvit" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:57 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:192 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:267 +msgid "A&dd..." +msgstr "&Dodaj..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:59 +msgid "Add t&weet" +msgstr "Dodaj t&vit" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:62 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:194 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:269 +msgid "&Attach audio..." +msgstr "Priloži zvučni zapis..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:66 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:198 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:237 +msgid "Auto&complete users" +msgstr "&Automatsko dovršavanje" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:68 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:200 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:273 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:367 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:440 +msgid "Check &spelling..." +msgstr "Proveri pravopis..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:70 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:202 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:275 +msgid "&Translate" +msgstr "&Prevedi" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:74 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:206 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:279 +msgid "Sen&d" +msgstr "Pošalji" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:118 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:220 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:299 +msgid "Image" +msgstr "Slika" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:120 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:222 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:301 +msgid "Video" +msgstr "Video" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:122 +msgid "Poll" +msgstr "Anketa" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:127 +msgid "please provide a description" +msgstr "Molimo vas navedite opis:" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:134 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:292 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" +msgstr "Datoteke sa slikama" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:134 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:292 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Select the picture to be uploaded" +msgstr "Izaberite sliku koju želite da otpremite" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:141 +msgid "Select the video to be uploaded" +msgstr "Izaberite video zapis koji želite da otpremite" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:141 +msgid "Video files (*.mp4)|*.mp4" +msgstr "Datoteke video zapisa (*.mp4)|*.mp4" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:147 +msgid "Error adding attachment" +msgstr "Greška pri dodavanju priloga" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:147 +msgid "" +"It is not possible to add more attachments. Please make sure your tweet " +"complies with Twitter'S attachment rules. You can add only one video or GIF " +"in every tweet, and a maximum of 4 photos." +msgstr "" +"Nije moguće dodati više priloga. Molimo uverite se da vaš tvit poštuje " +"Twitter pravila o prilozima. Možete dodati samo jedan video ili GIF u svaki " +"tvit, i najviše 4 slike." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:182 +msgid "&Mention to all" +msgstr "Spomeni sve" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:235 +msgid "&Recipient" +msgstr "Primalac" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:307 +msgid "Tweet - %i characters " +msgstr "Tvit - %i znakova" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:324 +msgid "Image description" +msgstr "Opis slike" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:335 +msgid "Retweets: " +msgstr "Retvitova" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:340 +msgid "Likes: " +msgstr "Sviđanja:" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:345 +msgid "Source: " +msgstr "Izvor:" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:350 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:428 +msgid "Date: " +msgstr "Datum:" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:365 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:438 +msgid "Copy link to clipboard" +msgstr "Kopiraj link u privremenu memoriju" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:368 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:443 +msgid "&Translate..." +msgstr "Prevedi..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:369 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:444 +msgid "C&lose" +msgstr "Zatvori" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:413 +msgid "View" +msgstr "Vidi" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:415 +msgid "Item" +msgstr "Stavka" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:441 +msgid "&Expand URL" +msgstr "Proširi vezu" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:480 +msgid "Add a poll" +msgstr "Dodaj anketu" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:484 +msgid "Participation time (in days)" +msgstr "Vreme učešća (u danima)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:491 +msgid "Choices" +msgstr "Opcije" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:495 +msgid "Option 1" +msgstr "Opcija 1" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:501 +msgid "Option 2" +msgstr "Opcija 2" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:507 +msgid "Option 3" +msgstr "Opcija 3" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:513 +msgid "Option 4" +msgstr "Opcija 4" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:540 +msgid "Not enough information" +msgstr "Nema dovoljno informacija" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:540 +msgid "Please make sure you have provided at least two options for the poll." +msgstr "Molimo uverite se da ste ponudili bar dve opcije u anketi." + #: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "Ažurirajte vaš profil" @@ -3435,6 +3510,42 @@ msgstr "Ažuriraj" msgid "Your {0} version is up to date" msgstr "Imate najnoviju verziju {0}." +#~ msgid "Photo" +#~ msgstr "Slika" + +#~ msgid "There's no URL to be shortened" +#~ msgstr "Nema veze koja bi mogla biti skraćena" + +#~ msgid "URL shortened" +#~ msgstr "Veza je skraćena" + +#~ msgid "There's no URL to be expanded" +#~ msgstr "Nema veze koja bi mogla biti proširena" + +#~ msgid "URL expanded" +#~ msgstr "Veza je proširena" + +#~ msgid "%s - %s characters" +#~ msgstr "%s - %s znakova" + +#~ msgid "Title" +#~ msgstr "Naslov" + +#~ msgid "Add attachments" +#~ msgstr "Dodaj priloge" + +#~ msgid "&Photo" +#~ msgstr "Slika" + +#~ msgid "&Long tweet" +#~ msgstr "Dug tvit" + +#~ msgid "&Upload image..." +#~ msgstr "Otpremi sliku..." + +#~ msgid "Sh&orten URL" +#~ msgstr "Skrati vezu" + #~ msgid "Friends' Timelines" #~ msgstr "Vremenska linija prijatelja" From 622b0e6128228de20d0b7ec913bed795809d4e8e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 11 Nov 2021 08:36:29 -0600 Subject: [PATCH 234/245] Access correctly on_reply_to_tweet_id from the dict response returned by call to V2 API --- src/sessions/twitter/session.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 38f4baae..1b985c9c 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -622,8 +622,7 @@ class Session(base.baseSession): for obj in tweets: if len(obj["attachments"]) == 0: item = self.api_call_v2(call_name="create_tweet", text=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"]) - print(item) - in_reply_to_status_id = item.data.id + in_reply_to_status_id = item.data["id"] else: media_ids = [] for i in obj["attachments"]: @@ -632,7 +631,7 @@ class Session(base.baseSession): self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) item = self.api_call_v2(call_name="create_tweet", status=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"]) - in_reply_to_status_id = item.data.id + in_reply_to_status_id = item.data["id"] def reply(self, text="", in_reply_to_status_id=None, attachments=[], *args, **kwargs): if len(attachments) == 0: From 538d6137d044e3f0f2eb0e61acc241b479d6cf2e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 11 Nov 2021 08:37:07 -0600 Subject: [PATCH 235/245] Limit Poll options to 25 characters each --- src/wxUI/dialogs/twitterDialogs/tweetDialogs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index e42bd9f4..8db397ec 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -495,24 +495,28 @@ class poll(wx.Dialog): label_2 = wx.StaticText(self, wx.ID_ANY, _("Option 1")) option1_sizer.Add(label_2, 0, 0, 0) self.option1 = wx.TextCtrl(self, wx.ID_ANY, "") + self.option1.SetMaxLength(25) option1_sizer.Add(self.option1, 0, 0, 0) option2_sizer = wx.BoxSizer(wx.HORIZONTAL) sizer_2.Add(option2_sizer, 1, wx.EXPAND, 0) label_3 = wx.StaticText(self, wx.ID_ANY, _("Option 2")) option2_sizer.Add(label_3, 0, 0, 0) self.option2 = wx.TextCtrl(self, wx.ID_ANY, "") + self.option2.SetMaxLength(25) option2_sizer.Add(self.option2, 0, 0, 0) option3_sizer = wx.BoxSizer(wx.HORIZONTAL) sizer_2.Add(option3_sizer, 1, wx.EXPAND, 0) label_4 = wx.StaticText(self, wx.ID_ANY, _("Option 3")) option3_sizer.Add(label_4, 0, 0, 0) self.option3 = wx.TextCtrl(self, wx.ID_ANY, "") + self.option3.SetMaxLength(25) option3_sizer.Add(self.option3, 0, 0, 0) option4_sizer = wx.BoxSizer(wx.HORIZONTAL) sizer_2.Add(option4_sizer, 1, wx.EXPAND, 0) label_5 = wx.StaticText(self, wx.ID_ANY, _("Option 4")) option4_sizer.Add(label_5, 0, 0, 0) self.option4 = wx.TextCtrl(self, wx.ID_ANY, "") + self.option4.SetMaxLength(25) option4_sizer.Add(self.option4, 0, 0, 0) btn_sizer = wx.StdDialogButtonSizer() sizer_1.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) From b329ac8e3e6a59076da3fa690b416b82fae85ec0 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 11 Nov 2021 12:33:38 -0600 Subject: [PATCH 236/245] Improved a little bit text dialogs's size for sending tweets, replies and dm's --- src/wxUI/dialogs/twitterDialogs/tweetDialogs.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py index 8db397ec..b917a25b 100644 --- a/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py +++ b/src/wxUI/dialogs/twitterDialogs/tweetDialogs.py @@ -18,13 +18,12 @@ class tweet(wx.Dialog): def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: panel = wx.Panel(self) mainBox = wx.BoxSizer(wx.VERTICAL) - text_sizer = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(text_sizer, 1, wx.EXPAND, 0) label_1 = wx.StaticText(panel, wx.ID_ANY, caption) text_sizer.Add(label_1, 0, 0, 0) - self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", size=(444, -1), style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) - self.text.SetMinSize((1000, 158)) text_sizer.Add(self.text, 1, wx.EXPAND, 0) list_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(list_sizer, 1, wx.EXPAND, 0) @@ -155,13 +154,12 @@ class reply(tweet): def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: panel = wx.Panel(self) mainBox = wx.BoxSizer(wx.VERTICAL) - text_sizer = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(text_sizer, 1, wx.EXPAND, 0) label_1 = wx.StaticText(panel, wx.ID_ANY, caption) text_sizer.Add(label_1, 0, 0, 0) - self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", size=(500, 200), style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) - self.text.SetMinSize((1000, 158)) text_sizer.Add(self.text, 1, wx.EXPAND, 0) list_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(list_sizer, 1, wx.EXPAND, 0) @@ -232,20 +230,19 @@ class dm(tweet): def create_controls(self, message: str, caption: str, max_length: int, thread_mode: bool) -> None: panel = wx.Panel(self) mainBox = wx.BoxSizer(wx.VERTICAL) - label_recipient = wx.StaticText(panel, -1, _(u"&Recipient")) + label_recipient = wx.StaticText(panel, -1, _("&Recipient")) self.cb = wx.ComboBox(panel, -1, choices=self.users, value=self.users[0], size=wx.DefaultSize) self.autocomplete_users = wx.Button(panel, -1, _(u"Auto&complete users")) recipient_sizer = wx.BoxSizer(wx.HORIZONTAL) recipient_sizer.Add(label_recipient, 0, 0, 0) recipient_sizer.Add(self.cb, 1, wx.EXPAND, 0) mainBox.Add(recipient_sizer, 0, wx.EXPAND, 0) - text_sizer = wx.BoxSizer(wx.VERTICAL) + text_sizer = wx.BoxSizer(wx.HORIZONTAL) mainBox.Add(text_sizer, 1, wx.EXPAND, 0) label_1 = wx.StaticText(panel, wx.ID_ANY, caption) text_sizer.Add(label_1, 0, 0, 0) - self.text = wx.TextCtrl(panel, wx.ID_ANY, "", style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + self.text = wx.TextCtrl(panel, wx.ID_ANY, "", size=(500, 200), style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_CHAR_HOOK, self.handle_keys, self.text) - self.text.SetMinSize((1000, 158)) self.text.SetFocus() text_sizer.Add(self.text, 1, wx.EXPAND, 0) list_sizer = wx.BoxSizer(wx.HORIZONTAL) From d6571a95cb35563a4b88fcc57a8f4aa3b58ab071 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 11 Nov 2021 15:13:58 -0600 Subject: [PATCH 237/245] Quote tweets properly according to Twitter's API V2 docs --- src/controller/buffers/twitter/base.py | 4 ++-- src/sessions/twitter/session.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/controller/buffers/twitter/base.py b/src/controller/buffers/twitter/base.py index 1d81a604..3ad5b77c 100644 --- a/src/controller/buffers/twitter/base.py +++ b/src/controller/buffers/twitter/base.py @@ -459,11 +459,11 @@ class BaseBuffer(base.Buffer): retweet = messages.tweet(session=self.session, title=_("Quote"), caption=_("Add your comment to the tweet"), max=256, thread_mode=False) if retweet.message.ShowModal() == widgetUtils.OK: text = retweet.message.text.GetValue() - text = text+" https://twitter.com/{0}/status/{1}".format(self.session.get_user(tweet.user).screen_name, id) tweet_data = dict(text=text, attachments=retweet.attachments, poll_period=retweet.poll_period, poll_options=retweet.poll_options) + tweet_data.update(quote_tweet_id=id) call_threaded(self.session.send_tweet, *[tweet_data]) if hasattr(retweet.message, "destroy"): - retweet.message.destroy() + retweet.message.Destroy() def _direct_retweet(self, id): item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index 1b985c9c..a311ab42 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -620,8 +620,9 @@ class Session(base.baseSession): """ Convenience function to send a thread. """ in_reply_to_status_id = None for obj in tweets: + # When quoting a tweet, the tweet_data dict might contain a parameter called quote_tweet_id. Let's add it, or None, so quotes will be posted successfully. if len(obj["attachments"]) == 0: - item = self.api_call_v2(call_name="create_tweet", text=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"]) + item = self.api_call_v2(call_name="create_tweet", text=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"], quote_tweet_id=obj.get("quote_tweet_id")) in_reply_to_status_id = item.data["id"] else: media_ids = [] @@ -630,7 +631,7 @@ class Session(base.baseSession): if i["type"] == "photo": self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) - item = self.api_call_v2(call_name="create_tweet", status=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"]) + item = self.api_call_v2(call_name="create_tweet", status=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"], quote_tweet_id=obj.get("quote_tweet_id")) in_reply_to_status_id = item.data["id"] def reply(self, text="", in_reply_to_status_id=None, attachments=[], *args, **kwargs): From f7a50d22e2f8ef3722baffdb730d37a63ee72230 Mon Sep 17 00:00:00 2001 From: riku Date: Fri, 12 Nov 2021 08:18:55 +0900 Subject: [PATCH 238/245] Update Japanese translation --- src/locales/ja/lc_messages/twblue.mo | Bin 61905 -> 62862 bytes src/locales/ja/lc_messages/twblue.po | 520 +++++++++++++++------------ 2 files changed, 293 insertions(+), 227 deletions(-) diff --git a/src/locales/ja/lc_messages/twblue.mo b/src/locales/ja/lc_messages/twblue.mo index 9adb0dd5fdce74e3de3f266a30143e8ff88b2185..aab8b3f01678e364549a838e3c41d175765a9c7e 100644 GIT binary patch delta 18267 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 diff --git a/src/locales/ja/lc_messages/twblue.po b/src/locales/ja/lc_messages/twblue.po index d58a1594..1354cdac 100644 --- a/src/locales/ja/lc_messages/twblue.po +++ b/src/locales/ja/lc_messages/twblue.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-11-05 07:15+0900\n" +"PO-Revision-Date: 2021-11-12 08:18+0900\n" "Last-Translator: 陸 \n" "Language-Team: \n" "Language: ja_JP\n" @@ -18,10 +18,6 @@ msgstr "" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../src\controller\attach.py:25 -msgid "Photo" -msgstr "画像" - #: ../src\controller\buffers\base\base.py:91 msgid "This action is not supported for this buffer" msgstr "この動作は、現在のバッファではサポートされていません" @@ -100,78 +96,81 @@ msgstr "「{username}」のフォロー" msgid "Unknown buffer" msgstr "不明なバッファ" -#: ../src\controller\buffers\twitter\base.py:88 -#: ../src\controller\buffers\twitter\trends.py:122 -#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 +#: ../src\controller\buffers\twitter\base.py:87 +#: ../src\controller\buffers\twitter\trends.py:43 +#: ../src\controller\buffers\twitter\trends.py:134 +#: ../src\controller\messages.py:296 ../src\wxUI\buffers\base.py:25 #: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:312 +#: ../src\wxUI\sysTrayIcon.py:35 msgid "Tweet" msgstr "ツイート" -#: ../src\controller\buffers\twitter\base.py:89 -#: ../src\controller\buffers\twitter\trends.py:123 +#: ../src\controller\buffers\twitter\base.py:88 +#: ../src\controller\buffers\twitter\trends.py:44 +#: ../src\controller\buffers\twitter\trends.py:135 msgid "Write the tweet here" msgstr "ツイートを入力" -#: ../src\controller\buffers\twitter\base.py:219 +#: ../src\controller\buffers\twitter\base.py:192 msgid "New tweet in {0}" msgstr "「{0}」への新規ツイート" -#: ../src\controller\buffers\twitter\base.py:222 +#: ../src\controller\buffers\twitter\base.py:195 msgid "{0} new tweets in {1}." msgstr "「{1}」への{0}個の新規ツイート。" -#: ../src\controller\buffers\twitter\base.py:261 +#: ../src\controller\buffers\twitter\base.py:234 #: ../src\controller\buffers\twitter\directMessages.py:88 -#: ../src\controller\buffers\twitter\people.py:180 +#: ../src\controller\buffers\twitter\people.py:174 msgid "%s items retrieved" msgstr "%s個のアイテムを取得しました" -#: ../src\controller\buffers\twitter\base.py:293 +#: ../src\controller\buffers\twitter\base.py:266 #: ../src\controller\buffers\twitter\people.py:80 msgid "This buffer is not a timeline; it can't be deleted." msgstr "このバッファは、タイムラインではないため、削除できません。" -#: ../src\controller\buffers\twitter\base.py:430 +#: ../src\controller\buffers\twitter\base.py:402 msgid "Reply to {arg0}" msgstr "「{arg0}」への返信:" -#: ../src\controller\buffers\twitter\base.py:432 +#: ../src\controller\buffers\twitter\base.py:404 #: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 msgid "Reply" msgstr "返信" -#: ../src\controller\buffers\twitter\base.py:433 +#: ../src\controller\buffers\twitter\base.py:405 msgid "Reply to %s" msgstr "「%s」への返信" -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\buffers\twitter\directMessages.py:130 +#: ../src\controller\buffers\twitter\base.py:428 +#: ../src\controller\buffers\twitter\directMessages.py:124 msgid "New direct message" msgstr "新しいダイレクトメッセージ" -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\messages.py:200 +#: ../src\controller\buffers\twitter\base.py:428 +#: ../src\controller\messages.py:268 msgid "Direct message to %s" msgstr "「%s」へのダイレクトメッセージ" -#: ../src\controller\buffers\twitter\base.py:520 +#: ../src\controller\buffers\twitter\base.py:459 msgid "Add your comment to the tweet" msgstr "ツイートにコメントを追加" -#: ../src\controller\buffers\twitter\base.py:520 +#: ../src\controller\buffers\twitter\base.py:459 msgid "Quote" msgstr "引用" -#: ../src\controller\buffers\twitter\base.py:596 +#: ../src\controller\buffers\twitter\base.py:520 msgid "Opening URL..." msgstr "URLを開いています…" -#: ../src\controller\buffers\twitter\base.py:633 +#: ../src\controller\buffers\twitter\base.py:557 msgid "User details" msgstr "ユーザーの詳細" -#: ../src\controller\buffers\twitter\base.py:654 +#: ../src\controller\buffers\twitter\base.py:578 msgid "Opening item in web browser..." msgstr "ブラウザでアイテムを開いています…" @@ -186,15 +185,15 @@ msgstr "%sへのメンション" msgid "Mention" msgstr "メンション" -#: ../src\controller\buffers\twitter\directMessages.py:133 +#: ../src\controller\buffers\twitter\directMessages.py:127 msgid "{0} new direct messages." msgstr "{0}件の新しいダイレクトメッセージ。" -#: ../src\controller\buffers\twitter\directMessages.py:136 +#: ../src\controller\buffers\twitter\directMessages.py:130 msgid "This action is not supported in the buffer yet." msgstr "この動作は、現在のバッファではサポートされていません。" -#: ../src\controller\buffers\twitter\directMessages.py:146 +#: ../src\controller\buffers\twitter\directMessages.py:140 msgid "" "Getting more items cannot be done in this buffer. Use the direct messages " "buffer instead." @@ -202,11 +201,11 @@ msgstr "" "このバッファでは、さらにアイテムを取得することはできません。代わりにダイレク" "トメッセージバッファを使用してください。" -#: ../src\controller\buffers\twitter\people.py:253 +#: ../src\controller\buffers\twitter\people.py:247 msgid "{0} new followers." msgstr "{0}人の新しいフォロワー。" -#: ../src\controller\buffers\twitter\trends.py:146 +#: ../src\controller\buffers\twitter\trends.py:150 msgid "This action is not supported in the buffer, yet." msgstr "この動作は、現在のバッファではサポートされていません。" @@ -224,7 +223,7 @@ msgstr "タイムライン" #: ../src\controller\mainController.py:359 #: ../src\controller\mainController.py:883 -#: ../src\controller\mainController.py:1585 +#: ../src\controller\mainController.py:1582 msgid "Timeline for {}" msgstr "「{}」のタイムライン" @@ -234,7 +233,7 @@ msgstr "ほかのユーザーのいいね一覧" #: ../src\controller\mainController.py:363 #: ../src\controller\mainController.py:902 -#: ../src\controller\mainController.py:1587 +#: ../src\controller\mainController.py:1584 msgid "Likes for {}" msgstr "{}のいいね一覧" @@ -244,7 +243,7 @@ msgstr "フォロワー一覧" #: ../src\controller\mainController.py:367 #: ../src\controller\mainController.py:921 -#: ../src\controller\mainController.py:1589 +#: ../src\controller\mainController.py:1586 msgid "Followers for {}" msgstr "{}をフォローしているユーザー" @@ -254,7 +253,7 @@ msgstr "フォロー一覧" #: ../src\controller\mainController.py:371 #: ../src\controller\mainController.py:940 -#: ../src\controller\mainController.py:1591 +#: ../src\controller\mainController.py:1588 msgid "Friends for {}" msgstr "{}がフォローしているユーザー" @@ -279,7 +278,7 @@ msgstr "「{}」の検索結果" #: ../src\controller\mainController.py:381 #: ../src\controller\mainController.py:982 -#: ../src\controller\mainController.py:1593 +#: ../src\controller\mainController.py:1590 msgid "Trending topics for %s" msgstr "%s のトレンド" @@ -322,7 +321,7 @@ msgstr "ユーザーエイリアスを追加" msgid "Alias has been set correctly for {}." msgstr "{}のエイリアスが正しく設定されています。" -#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 +#: ../src\controller\mainController.py:829 ../src\controller\messages.py:327 msgid "MMM D, YYYY. H:m" msgstr "YYYY年MMMMD日 H時m分" @@ -411,72 +410,52 @@ msgstr "このバッファのミュートを設定" msgid "Buffer mute off" msgstr "このバッファのミュートを解除" -#: ../src\controller\mainController.py:1545 +#: ../src\controller\mainController.py:1542 msgid "Copied" msgstr "コピーしました" -#: ../src\controller\mainController.py:1575 +#: ../src\controller\mainController.py:1572 msgid "Unable to update this buffer." msgstr "このバッファを更新できません。" -#: ../src\controller\mainController.py:1578 +#: ../src\controller\mainController.py:1575 msgid "Updating buffer..." msgstr "バッファを更新中…" -#: ../src\controller\mainController.py:1581 +#: ../src\controller\mainController.py:1578 msgid "{0} items retrieved" msgstr "{0}個のアイテムを取得しました" -#: ../src\controller\mainController.py:1600 -#: ../src\controller\mainController.py:1620 +#: ../src\controller\mainController.py:1597 +#: ../src\controller\mainController.py:1617 msgid "Invalid buffer" msgstr "無効なバッファ" -#: ../src\controller\mainController.py:1611 +#: ../src\controller\mainController.py:1608 msgid "Picture {0}" msgstr "画像{0}" -#: ../src\controller\mainController.py:1612 +#: ../src\controller\mainController.py:1609 msgid "Select the picture" msgstr "画像を選択" -#: ../src\controller\mainController.py:1631 +#: ../src\controller\mainController.py:1628 msgid "Unable to extract text" msgstr "テキストを抽出できません" -#: ../src\controller\messages.py:56 +#: ../src\controller\messages.py:49 msgid "Translated" msgstr "翻訳完了" -#: ../src\controller\messages.py:63 -msgid "There's no URL to be shortened" -msgstr "短縮されたURLは、ありません" - -#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 -msgid "URL shortened" -msgstr "URLを短縮しました" - -#: ../src\controller\messages.py:82 -msgid "There's no URL to be expanded" -msgstr "短縮を解除するURLはありません" - -#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 -msgid "URL expanded" -msgstr "URLの短縮を解除しました" - -#: ../src\controller\messages.py:108 +#: ../src\controller\messages.py:56 msgid "%s - %s of %d characters" msgstr "%s - %s/%d" -#: ../src\controller\messages.py:112 -msgid "%s - %s characters" -msgstr "%s - %s文字" - -#: ../src\controller\messages.py:272 +#: ../src\controller\messages.py:354 msgid "View item" msgstr "アイテムを見る" -#: ../src\controller\messages.py:301 +#: ../src\controller\messages.py:379 msgid "Link copied to clipboard." msgstr "リンクをクリップボードへコピーしました。" @@ -667,7 +646,7 @@ msgstr "停止" msgid "&Record" msgstr "録音(&R)" -#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 +#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:147 msgid "Playing..." msgstr "再生中…" @@ -719,6 +698,9 @@ msgid "%s seconds" msgstr "%s秒" #: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:36 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:173 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:258 msgid "File" msgstr "ファイル" @@ -1558,7 +1540,7 @@ msgid "New tweet" msgstr "新規ツイート" #: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 -#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 +#: ../src\wxUI\commonMessageDialogs.py:10 msgid "Retweet" msgstr "リツイート" @@ -1996,15 +1978,17 @@ msgid "public" msgstr "公式" #: ../src\sessions\twitter\session.py:211 +#: ../src\sessions\twitter\session.py:238 msgid "%s failed. Reason: %s" msgstr "%s が失敗しました。理由: %s" #: ../src\sessions\twitter\session.py:217 +#: ../src\sessions\twitter\session.py:241 msgid "%s succeeded." msgstr "%sに成功しました。" -#: ../src\sessions\twitter\session.py:426 -#: ../src\sessions\twitter\session.py:504 +#: ../src\sessions\twitter\session.py:450 +#: ../src\sessions\twitter\session.py:528 msgid "Deleted account" msgstr "削除されたアカウント" @@ -2032,7 +2016,7 @@ msgstr "アカウントを連携中…" msgid "Enter your PIN code here" msgstr "PINコードを入力" -#: ../src\sound.py:161 +#: ../src\sound.py:160 msgid "Stopped." msgstr "停止。" @@ -2086,10 +2070,6 @@ msgstr "" msgid "Client" msgstr "クライアント" -#: ../src\wxUI\buffers\base.py:12 -msgid "Text" -msgstr "内容" - #: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 msgid "Date" msgstr "日時" @@ -2101,6 +2081,11 @@ msgstr "日時" msgid "User" msgstr "ユーザー" +#: ../src\wxUI\buffers\base.py:12 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:48 +msgid "Text" +msgstr "内容" + #: ../src\wxUI\buffers\base.py:28 msgid "Direct message" msgstr "ダイレクトメッセージ" @@ -2357,55 +2342,6 @@ msgstr "" "{0}は、前回の実行時に予期せず終了しました。問題が解決しない場合は、{0}開発者" "に報告してください。" -#: ../src\wxUI\dialogs\attach.py:10 -msgid "Add an attachment" -msgstr "添付ファイルを追加" - -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Attachments" -msgstr "添付ファイル" - -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Title" -msgstr "タイトル" - -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Type" -msgstr "形式" - -#: ../src\wxUI\dialogs\attach.py:19 -msgid "Add attachments" -msgstr "添付ファイルを追加" - -#: ../src\wxUI\dialogs\attach.py:20 -msgid "&Photo" -msgstr "画像(&P)" - -#: ../src\wxUI\dialogs\attach.py:21 -msgid "Remove attachment" -msgstr "添付ファイルを削除" - -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "画像ファイル (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" - -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Select the picture to be uploaded" -msgstr "アップロードする画像を選択" - -#: ../src\wxUI\dialogs\attach.py:44 -msgid "please provide a description" -msgstr "説明を入力" - -#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 -#: ../src\wxUI\dialogs\lists.py:70 -msgid "Description" -msgstr "説明" - #: ../src\wxUI\dialogs\configuration.py:15 msgid "Language" msgstr "言語" @@ -2791,6 +2727,14 @@ msgstr "所有者" msgid "mode" msgstr "モード" +#: ../src\wxUI\dialogs\lists.py:14 ../src\wxUI\dialogs\lists.py:70 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:38 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:127 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:175 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:260 +msgid "Description" +msgstr "説明" + #: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 msgid "Create a new list" msgstr "新しいリストを作成" @@ -2847,103 +2791,6 @@ msgstr "ユーザーを削除するには、リストを選択" msgid "Do you really want to delete this list?" msgstr "本当に、このリストを削除しますか?" -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "ツイートを短縮して投稿(&L)" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "画像をアップロード(&U)" - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 -msgid "Check &spelling..." -msgstr "スペルチェック(&S)" - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "音声を添付(&A)" - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "URLを短縮(&O)" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 -msgid "&Expand URL" -msgstr "URLを元に戻す(&E)" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 -msgid "&Translate..." -msgstr "翻訳(&T)..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "ユーザーを自動保管(&C)" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "送信(&D)" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 -msgid "C&lose" -msgstr "閉じる(&C)" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "送信先(&R)" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "全員にリプライ(&M)" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "ツイート - %i文字" - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "画像の説明" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "リツイート: " - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "いいね: " - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "ソース: " - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 -msgid "Date: " -msgstr "日付: " - -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 -msgid "Copy link to clipboard" -msgstr "リンクをクリップボードへコピー" - -#: ../src\wxUI\dialogs\message.py:408 -msgid "View" -msgstr "ツイート" - -#: ../src\wxUI\dialogs\message.py:410 -msgid "Item" -msgstr "アイテム" - #: ../src\wxUI\dialogs\search.py:12 msgid "Search on Twitter" msgstr "ツイッターを検索" @@ -3025,6 +2872,225 @@ msgstr "都市" msgid "&Location" msgstr "場所(&L)" +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:33 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:49 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:170 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:255 +msgid "Attachments" +msgstr "添付ファイル" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:37 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:174 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:259 +msgid "Type" +msgstr "形式" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:40 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:177 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:262 +msgid "Delete attachment" +msgstr "添付ファイルを削除" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:45 +msgid "Added Tweets" +msgstr "ツイートを追加" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:52 +msgid "Delete tweet" +msgstr "ツイートを削除" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:57 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:192 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:267 +msgid "A&dd..." +msgstr "追加(&D)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:59 +msgid "Add t&weet" +msgstr "ツイートを追加(&W)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:62 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:194 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:269 +msgid "&Attach audio..." +msgstr "音声を添付(&A)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:66 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:198 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:237 +msgid "Auto&complete users" +msgstr "ユーザーを自動保管(&C)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:68 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:200 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:273 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:367 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:440 +msgid "Check &spelling..." +msgstr "スペルチェック(&S)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:70 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:202 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:275 +msgid "&Translate" +msgstr "翻訳(&T)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:74 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:206 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:279 +msgid "Sen&d" +msgstr "送信(&D)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:118 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:220 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:299 +msgid "Image" +msgstr "画像" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:120 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:222 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:301 +msgid "Video" +msgstr "動画" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:122 +msgid "Poll" +msgstr "投票" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:127 +msgid "please provide a description" +msgstr "説明を入力" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:134 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:292 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" +msgstr "画像ファイル (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:134 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:292 +#: ../src\wxUI\dialogs\update_profile.py:82 +msgid "Select the picture to be uploaded" +msgstr "アップロードする画像を選択" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:141 +msgid "Select the video to be uploaded" +msgstr "アップロードする動画を選択" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:141 +msgid "Video files (*.mp4)|*.mp4" +msgstr "動画ファイル (*.mp4)|*.mp4" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:147 +msgid "Error adding attachment" +msgstr "添付ファイルの追加中にエラーが発生しました" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:147 +msgid "" +"It is not possible to add more attachments. Please make sure your tweet " +"complies with Twitter'S attachment rules. You can add only one video or GIF " +"in every tweet, and a maximum of 4 photos." +msgstr "" +"これ以上添付ファイルを追加することはできません。ツイートがTwitterの添付ルール" +"に準拠していることを確認してください。すべてのツイートに追加できるビデオまた" +"はGIFは1つだけで、最大4枚の写真を追加できます。" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:182 +msgid "&Mention to all" +msgstr "全員にリプライ(&M)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:235 +msgid "&Recipient" +msgstr "送信先(&R)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:307 +msgid "Tweet - %i characters " +msgstr "ツイート - %i文字" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:324 +msgid "Image description" +msgstr "画像の説明" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:335 +msgid "Retweets: " +msgstr "リツイート: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:340 +msgid "Likes: " +msgstr "いいね: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:345 +msgid "Source: " +msgstr "ソース: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:350 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:428 +msgid "Date: " +msgstr "日付: " + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:365 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:438 +msgid "Copy link to clipboard" +msgstr "リンクをクリップボードへコピー" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:368 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:443 +msgid "&Translate..." +msgstr "翻訳(&T)..." + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:369 +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:444 +msgid "C&lose" +msgstr "閉じる(&C)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:413 +msgid "View" +msgstr "ツイート" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:415 +msgid "Item" +msgstr "アイテム" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:441 +msgid "&Expand URL" +msgstr "URLを元に戻す(&E)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:480 +msgid "Add a poll" +msgstr "投票を追加" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:484 +msgid "Participation time (in days)" +msgstr "投票期間(日数)" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:491 +msgid "Choices" +msgstr "選択肢" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:495 +msgid "Option 1" +msgstr "オプション1" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:501 +msgid "Option 2" +msgstr "オプション2" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:507 +msgid "Option 3" +msgstr "オプション3" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:513 +msgid "Option 4" +msgstr "オプション4" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:540 +msgid "Not enough information" +msgstr "十分な情報がありません" + +#: ../src\wxUI\dialogs\twitterDialogs\tweetDialogs.py:540 +msgid "Please make sure you have provided at least two options for the poll." +msgstr "投票に少なくとも2つのオプションを提供していることを確認してください。" + #: ../src\wxUI\dialogs\update_profile.py:10 msgid "Update your profile" msgstr "プロフィールを更新" From f264f3807fa3985ccc06622d386ef5f4774d5f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Fri, 12 Nov 2021 09:08:50 +0100 Subject: [PATCH 239/245] Updated Windows dependencies --- windows-dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows-dependencies b/windows-dependencies index 27a7c419..1ee41752 160000 --- a/windows-dependencies +++ b/windows-dependencies @@ -1 +1 @@ -Subproject commit 27a7c419835c5fed4ba77bc31d0e1aff50a78f2a +Subproject commit 1ee4175276e8dcb04c23cd0b76ff516d5986c698 From 3ccb3a5be5295ebb2466eedcc02cfaafcfb4747d Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 12 Nov 2021 13:33:54 -0600 Subject: [PATCH 240/245] Updated Spanish locale --- .../es/LC_MESSAGES/twblue-changelog.mo | Bin 67651 -> 73092 bytes .../es/LC_MESSAGES/twblue-changelog.po | 565 +- src/locales/es/LC_MESSAGES/twblue.mo | Bin 54968 -> 56939 bytes src/locales/es/LC_MESSAGES/twblue.po | 5308 +++++++++-------- src/locales/fr/LC_MESSAGES/twblue.mo | Bin 56563 -> 57445 bytes src/locales/fr/LC_MESSAGES/twblue.po | 2 +- 6 files changed, 3082 insertions(+), 2793 deletions(-) diff --git a/doc/locales/es/LC_MESSAGES/twblue-changelog.mo b/doc/locales/es/LC_MESSAGES/twblue-changelog.mo index 5ec37f0df226da8ceb9fac1b713bf929238b459a..82dbe54fb0451a70a178fe67e3e052bca381eae2 100644 GIT binary patch delta 9018 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

    H>=P;eDhkK-&N1F!(qgUZp4U04um zRh(nl1wYYC#HO@_A{xLqC z{Hq>S@qz5fhFR=Qe1^4Xqc_EvkwNdV)oeYtm+({K$xNtPBd%FGLv!#Raq~Hxj`##s zJ3ScgaP(mw)xngEs$TV6^3Q^o*c|;b*^Fv#u3-RX%;OZpV%&jl^Y!99h*88oxgwwA zG*r8zHLWwPG8R=m2b$4;p?>g0R2jR8JVG8VB>(EhWTZ?gurW@_)7v8+TN4*xAt_yt zF^#xJ{_YdcS*&-DC10O}&u{|w4=m8Dy%?j2TQAiekHHe+gLoOI**;*TG!(?1`I3T( z%k+MCTh59mj={m$vyk%}Gtn3A=#O8a58icNmlgUxAE!~M?wjh2mpI+#)K=#FP>G)0 zXjrK$c%ynyH2wu=VmGYE&U83nmEOlASL=gjFTSKalAF~CBiHE6{D=%za@TSya=pnq zeZrnAYRHgHlGn3Jxo{i3aM1>RvTb4I#ZmDlhGFWjr` zWCO{~&HCLj;3NH3tifYU-JiB_o%{NKqRtx|H*I6ysqp4@MvESFKb0HeaR~8+9lHGW zoq82d#=Den$MM{kUn)W}q+*xe*J-=;+wo^y$n{jV%4n|Fe5Q9(-#z+WaTE9Rd>Ok} z@ZtgeKDAxsT;i<1@^Gxh z1-R!Me$h^k<4hwTP4sdrwk+d&BJROWTu(WvPsZk_^$B|5G>=W?hE8YnH<*-rniBvhFkYP+FV>q)dz5J=Ug5cZf44J<=7lHCSF!&@w?k)h%5hDWG665H6&kbxF_3CJQ&#~l0#hhbb3 zLqo=QVz@5_(M=8dj7OD;dQ=tOZ)RwC8$L%h1>$OG_>(Na)!@i(Yjv>)c&xK;@+@}v zcC<8cl)PaGbv&6+J*5&&tV2PMVQvJW*;44l;+B_!Zv6 zILeZiWlb>-O3%o&&I`1=7y8*F3xoZ}nFeK8Et$#bX{N!JOlt&Hg3Ttg*%V|pn!_T@ z;ijOlpdfonp{J`V36BUe+gBEjY!_j)&TjseB`qn-l4LcFvszLkjCR|KZuW\n" "Language-Team: \n" "Language: es\n" @@ -22,12 +22,90 @@ msgstr "" msgid "TWBlue Changelog" msgstr "Lista de cambios de TWBlue" -#: changelog.py:5 changelog.py:7 +#: changelog.py:5 msgid "## changes in this version" msgstr "## Cambios en esta versión" +#: changelog.py:7 +msgid "" +"* Now it is possible to create a tweet from a trending topics buffer again." +msgstr "" +"* De nuevo es posible crear un tweet desde un buffer de Tendencias.* Es " +"posible añadir tuits al buffer de me gusta desde la barra de menú otra vez." + +#: changelog.py:8 +msgid "" +"* TWBlue now includes a completely new set of dialogs to handle tweeting, " +"replying and sending direct messages that takes advantage of more Twitter " +"features." +msgstr "" +"* TWBlue incluye ahora un conjunto completamente nuevo de diálogos para " +"gestionar los tweets, las respuestas y el envío de mensajes directos que " +"aprovechan más funciones de la API de Twitter." + #: changelog.py:9 msgid "" +" * It is possible to add videos in tweets and direct messages by using " +"the new \"add\" button, located in every dialog where media can be added. " +"Twitter suggests to add videos from 5 seconds up to 2 minutes lenght, in mp4 " +"format (video Codec H.264 and audio codec AAC). Currently, TWBlue does not " +"check if the uploaded video complies with Twitter media requirements. You " +"can add only a video in a tweet or direct message. No other kind of media " +"can be added after a video is in a tweet. If the video was unable to be " +"uploaded successfully, the tweet or direct message won't be created." +msgstr "" +" * Ahora ya es posible añadir vídeos en los tweets y mensajes directos " +"utilizando el nuevo botón \"añadir\", situado en todos los diálogos donde se " +"pueden añadir medios. Twitter sugiere añadir vídeos de entre 5 segundos y 2 " +"minutos de duración, en formato mp4 (códec de vídeo H.264 y códec de audio " +"AAC). Actualmente, TWBlue no comprueba si el vídeo subido cumple con los " +"requisitos de los medios de comunicación de Twitter. Sólo se puede añadir un " +"vídeo en un tweet o mensaje directo. No se puede añadir ningún otro tipo de " +"medio después de que un vídeo esté en un tweet. Si el vídeo no se ha podido " +"subir con éxito, el tuit o el mensaje directo no se creará." + +#: changelog.py:10 +msgid "" +" * Now you can add a poll to tweets. Polls can have up to 4 different " +"options and allow voting up to 7 days after being created. Take into " +"account, though, that currently TWBlue does not support reading polls in " +"tweets." +msgstr "" +" * Ahora puedes añadir una encuesta a los tweets. Las encuestas pueden " +"tener hasta 4 opciones diferentes y permiten votar hasta 7 días después de " +"ser creadas. Ten en cuenta, sin embargo, que actualmente TWBlue no soporta " +"la lectura de encuestas en los tweets." + +#: changelog.py:11 +msgid "" +" * TWBlue now support threads while creating a new tweet. There is a new " +"button, called add tweet which will add the current tweet to the thread and " +"will allow you to write another tweet in the thread. Every tweet might " +"include media (up to 4 photos, or one GIF image or a video) or up to one " +"poll." +msgstr "" +" * TWBlue ahora soporta hilos mientras se crea un nuevo tweet. Hay un " +"nuevo botón, llamado añadir tweet, que añadirá el tweet actual al hilo y te " +"permitirá escribir otro tweet en el hilo. Cada tweet puede incluir medios " +"(hasta 4 fotos, o una imagen GIF o un video) y una encuesta." + +#: changelog.py:12 +msgid "" +" * Some functionality was removed from tweet dialogs within TWBlue. " +"Particularly, URL shorteners and long tweets via Twishort. You still can " +"read long tweets posted via Twishort, though." +msgstr "" +" * Se han eliminado algunas características de los diálogos de tweets en " +"TWBlue. En particular, los acortadores de URL y los tweets largos a través " +"de Twishort. Sin embargo, todavía se pueden leer los tweets largos " +"publicados a través de Twishort." + +#: changelog.py:14 +msgid "## Changes in version 2021.11.07" +msgstr "## Cambios en la versión 2021.11.07" + +#: changelog.py:16 +msgid "" "* TWBlue should retrieve tweets from threads and conversations in a more " "reliable way. Tweets in the same thread (made by the same author) will be " "sorted correctly, although replies to the thread (made by different people) " @@ -40,7 +118,29 @@ msgstr "" "mostrar en un orden diferente al que se muestra en las aplicaciones de " "Twitter. ([#417](https://github.com/manuelcortez/TWBlue/issues/417))" -#: changelog.py:10 +#: changelog.py:17 +msgid "" +"* When creating a filter, TWBlue will show an error if user has not provided " +"a name for the filter. Before, unnamed filters were a cause of config breaks " +"in the application." +msgstr "" +"* Al crear un filtro, TWBlue mostrará un error si el usuario no ha " +"proporcionado un nombre para el filtro. Antes, los filtros sin nombre se " +"guardaban en la configuración y causaban errores al iniciar la aplicación." + +#: changelog.py:18 +#, fuzzy +#| msgid "" +#| "* It is possible to add a tweet to the likes buffer from the menu bar " +#| "again." +msgid "" +"* It is again possible to read the changelog for TWBlue from the help menu " +"in the menu bar." +msgstr "" +"* Es posible añadir tuits al buffer de me gusta desde la barra de menú otra " +"vez." + +#: changelog.py:19 msgid "" "* fixed a bug when clearing the direct messages buffer. ([#418](https://" "github.com/manuelcortez/TWBlue/issues/418))" @@ -50,7 +150,7 @@ msgstr "" "problema en el Streaming API que causaba que TWBlue desconectara el " "Streaming. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" -#: changelog.py:11 +#: changelog.py:20 msgid "" "* fixed an issue that was making TWBlue to show incorrectly titles for " "trending topic buffers upon startup. ([#421](https://github.com/manuelcortez/" @@ -60,11 +160,26 @@ msgstr "" "incorrecta los títulos de los buffers de trending topics al iniciarse. " "([#421](https://github.com/manuelcortez/TWBlue/issues/421))" -#: changelog.py:13 +#: changelog.py:21 +msgid "" +"* fixed an issue that was making users of the graphical user interface to " +"delete a buffer if a trends buffer was opened in the same session." +msgstr "" +"* Se ha solucionado un problema que hacía que los usuarios de la interfaz " +"gráfica no pudieran borrar algunos buffers si se abría un buffer de " +"tendencias en la misma sesión." + +#: changelog.py:22 +#, fuzzy +#| msgid "* Updated romanian translation." +msgid "* Updated Spanish, Japanese and french translations." +msgstr "* Actualizada la traducción al rumano." + +#: changelog.py:24 msgid "## Changes in Version 2021.10.30" msgstr "## Cambios en la versión 2021.10.30" -#: changelog.py:15 +#: changelog.py:26 msgid "" "* Fixed many errors in the way we compile TWBlue, so users of 64 bits " "systems and particularly windows 7 users would be able to install TWBlue " @@ -84,7 +199,7 @@ msgstr "" "próximos 23 meses.([#416,](https://github.com/manuelcortez/TWBlue/" "issues/416), [#415,](https://github.com/manuelcortez/TWBlue/issues/415))" -#: changelog.py:16 +#: changelog.py:27 msgid "" "* fixed an issue that was making impossible to manually add an user to the " "autocomplete users database." @@ -92,7 +207,7 @@ msgstr "" "* Corregido un error que causaba que fuera imposible añadir manualmente un " "usuario a la base de datos de autocompletado." -#: changelog.py:17 +#: changelog.py:28 msgid "" "* Started to improve support to conversations by searching for " "conversation_id." @@ -100,11 +215,11 @@ msgstr "" "* Se ha comenzado a mejorar el soporte a las conversaciones e hilos buscando " "por el parámetro conversation_id en Twitter." -#: changelog.py:19 +#: changelog.py:30 msgid "## changes in version 2021.10.27" msgstr "## Cambios en la versión 2021.10.27" -#: changelog.py:21 +#: changelog.py:32 msgid "" "* Added an user alias manager, located in the application menu in the menu " "bar. From this dialog, it is possible to review, add, edit or remove user " @@ -116,7 +231,7 @@ msgstr "" "editar y eliminar el alias para los usuarios de la cuenta seleccionada. " "([#401](https://github.com/manuelcortez/TWBlue/issues/401))" -#: changelog.py:22 +#: changelog.py:33 msgid "" "* TWBlue now closes the VLC player window automatically when a video reaches " "its end. ([#399](https://github.com/manuelcortez/TWBlue/issues/399))" @@ -125,7 +240,7 @@ msgstr "" "reproducción de un video. ([#399](https://github.com/manuelcortez/TWBlue/" "issues/399))" -#: changelog.py:23 +#: changelog.py:34 msgid "" "* After a lot of time, TWBlue now uses a new default Soundpack, called " "FreakyBlue. This soundpack will be set by default in all new sessions " @@ -139,7 +254,7 @@ msgstr "" "por tomarse el trabajo de diseñar el paquete de sonidos para TWBlue. ([#247]" "(https://github.com/manuelcortez/TWBlue/issues/247))" -#: changelog.py:24 +#: changelog.py:35 msgid "" "* When reading a tweet, if the tweet contains more than 2 consecutive " "mentions, TWBlue will announce how many more users the tweet includes, as " @@ -153,7 +268,7 @@ msgstr "" "conjunto de usuarios mencionados en el tweet utilizando el diálogo de ver " "tweets." -#: changelog.py:25 +#: changelog.py:36 msgid "" "* In the tweet displayer, It is possible to copy a link to the current tweet " "or person by pressing a button called \"copy link to clipboard\"." @@ -162,7 +277,7 @@ msgstr "" "directo al tweet o usuario seleccionando el botón llamado \"copiar vínculo " "al portapapeles\"." -#: changelog.py:26 +#: changelog.py:37 msgid "" "* Added a keymap capable to work under Windows 11. ([#391](https://github." "com/manuelcortez/TWBlue/pull/391))" @@ -170,7 +285,7 @@ msgstr "" "* Se ha añadido un mapa de teclado capaz de funcionar correctamente en " "Windows 11. ([#391](https://github.com/manuelcortez/TWBlue/pull/391))" -#: changelog.py:27 +#: changelog.py:38 msgid "" "* Added user aliases to TWBlue. This feature allows you to rename user's " "display names on Twitter, so the next time you'll read an user it will be " @@ -192,11 +307,11 @@ msgstr "" "a ninguna combinación de teclado por defecto. ([#389](https://github.com/" "manuelcortez/TWBlue/pull/389))" -#: changelog.py:28 +#: changelog.py:39 msgid "* There are some changes to the autocomplete users feature:" msgstr "* Hemos introducido algunos cambios al autocompletado de usuarios:" -#: changelog.py:29 +#: changelog.py:40 msgid "" " * Now users can search for twitter screen names or display names in the " "database." @@ -204,7 +319,7 @@ msgstr "" " * Ahora, es posible buscar utilizando los nombres de pantalla o nombres " "para mostrar de los usuarios de Twitter." -#: changelog.py:30 +#: changelog.py:41 msgid "" "* It is possible to undefine keystrokes in the current keymap in TWBlue. " "This allows you, for example, to redefine keystrokes completely." @@ -213,7 +328,7 @@ msgstr "" "uso en TWBlue. Esto permite, por ejemplo, desasignar combinaciones de " "teclado para utilizarlas en otras funciones." -#: changelog.py:31 +#: changelog.py:42 msgid "" "* We have changed our Geocoding service to the Nominatim API from " "OpenStreetMap. Addresses present in tweets are going to be determined by " @@ -226,7 +341,7 @@ msgstr "" "ahora una clave API de pago. ([#390](https://github.com/manuelcortez/TWBlue/" "issues/390))" -#: changelog.py:32 +#: changelog.py:43 msgid "" "* Added a limited version of the Twitter's Streaming API: The Streaming API " "will work only for tweets, and will receive tweets only by people you " @@ -243,7 +358,7 @@ msgstr "" "debería ser capaz de detectar este problema y reconectar el stream de nuevo. " "([#385](https://github.com/manuelcortez/TWBlue/pull/385))" -#: changelog.py:33 +#: changelog.py:44 msgid "" "* Fixed an issue that made TWBlue to not show a dialog when attempting to " "show a profile for a suspended user. ([#387](https://github.com/manuelcortez/" @@ -253,7 +368,7 @@ msgstr "" "mostrar nada al intentar ver el perfil de un usuario suspendido. ([#387]" "(https://github.com/manuelcortez/TWBlue/issues/387))" -#: changelog.py:34 +#: changelog.py:45 msgid "" "* Added support for Twitter audio and videos: Tweets which contains audio or " "videos will be detected as audio items, and you can playback those with the " @@ -265,7 +380,7 @@ msgstr "" "reproducirlos con el comando habitual para reproducir audios. ([#384,]" "(https://github.com/manuelcortez/TWBlue/pull/384))" -#: changelog.py:35 +#: changelog.py:46 msgid "" "* We just implemented some changes in the way TWBlue handles tweets in order " "to reduce its RAM memory usage [#380](https://github.com/manuelcortez/TWBlue/" @@ -275,7 +390,7 @@ msgstr "" "los tweets, con el objetivo de mejorar el consumo de memoria y CPU. [#380]" "(https://github.com/manuelcortez/TWBlue/pull/380):" -#: changelog.py:36 +#: changelog.py:47 msgid "" " * We reduced the tweets size by storing only the tweet fields we " "currently use. This should reduce tweet's size in memory for every object up " @@ -285,7 +400,7 @@ msgstr "" "campos de información que usamos actualmente. Esto debería reducir el tamaño " "del tweet en la memoria para cada objeto hasta un 75%." -#: changelog.py:37 +#: changelog.py:48 msgid "" " * When using the cache database to store your tweets, there is a new " "setting present in the account settings dialog, in the general tab. This " @@ -297,7 +412,7 @@ msgstr "" "pestaña general. Este ajuste te permite controlar si TWBlue cargará toda la " "base de datos en la memoria RAM (Opción predeterminada) o no." -#: changelog.py:38 +#: changelog.py:49 msgid "" " * Loading the whole database into memory has the advantage of being " "extremely fast to access any element (for example when moving through tweets " @@ -314,7 +429,7 @@ msgstr "" "los objetos de tweets. Si tienes una máquina con suficiente memoria, esta " "debería ser una buena opción para ti." -#: changelog.py:39 +#: changelog.py:50 msgid "" " * If you uncheck this setting, TWBlue will read the whole database " "from disk. This is significantly slower, but the advantage of this setting " @@ -333,7 +448,7 @@ msgstr "" "sugiere para ordenadores con poca memoria o para aquellas personas que no " "quieran mantener una cantidad realmente grande de tweets almacenados." -#: changelog.py:40 +#: changelog.py:51 msgid "" "* Changed the label in the direct message's text control so it will indicate " "that the user needs to write the text there, without referring to any " @@ -344,7 +459,7 @@ msgstr "" "de un mensaje directo. Ahora en dicho campo no se especifica ningún nombre " "de usuario. ([#366,](https://github.com/manuelcortez/TWBlue/issues/366))" -#: changelog.py:41 +#: changelog.py:52 msgid "" "* TWBlue will take Shift+F10 again as the contextual menu key in the list of " "items in a buffer. This stopped working after we have migrated to WX 4.1. " @@ -353,7 +468,7 @@ msgstr "" "* TWBlue puede volver a usar la combinación de teclado Shift+F10 como la " "tecla de menú contextual." -#: changelog.py:42 +#: changelog.py:53 msgid "" "* TWBlue should render correctly retweets of quoted tweets. ([#365,](https://" "github.com/manuelcortez/TWBlue/issues/365))" @@ -361,7 +476,7 @@ msgstr "" "* TWBlue debería mostrar apropiadamente los retweets de un tweet citado. " "([#365,](https://github.com/manuelcortez/TWBlue/issues/365))" -#: changelog.py:43 +#: changelog.py:54 msgid "" "* Fixed an error that was causing TWBlue to be unable to output to screen " "readers at times. ([#369,](https://github.com/manuelcortez/TWBlue/" @@ -371,7 +486,7 @@ msgstr "" "enviar texto a los lectores de pantalla. ([#369,](https://github.com/" "manuelcortez/TWBlue/issues/369))" -#: changelog.py:44 +#: changelog.py:55 msgid "" "* Fixed autocomplete users feature. ([#367,](https://github.com/manuelcortez/" "TWBlue/issues/367))" @@ -379,7 +494,7 @@ msgstr "" "* Corregida la característica de autocompletado de usuarios. ([#367,]" "(https://github.com/manuelcortez/TWBlue/issues/367))" -#: changelog.py:45 +#: changelog.py:56 msgid "" "* Fixed error when displaying an URL at the end of a line, when the tweet or " "direct message contained multiple lines. Now the URL should be displayed " @@ -391,7 +506,7 @@ msgstr "" "todas las direcciones. ([#305,](https://github.com/manuelcortez/TWBlue/" "issues/305) [#272,](https://github.com/manuelcortez/TWBlue/issues/272))" -#: changelog.py:46 +#: changelog.py:57 msgid "" "* TWBlue has been migrated completely to Python 3 (currently, the software " "builds with Python 3.8)." @@ -399,7 +514,7 @@ msgstr "" "* TWBlue ha sido migrado completamente a Python 3 (actualmente, el software " "se construye con Python 3.8)." -#: changelog.py:47 +#: changelog.py:58 msgid "" "* TWBlue should be restarted gracefully. Before, the application was " "alerting users of not being closed properly every time the application " @@ -409,7 +524,7 @@ msgstr "" "los usuarios de que no se cerraba correctamente cada vez que debía efectuar " "un reinicio." -#: changelog.py:48 +#: changelog.py:59 msgid "" "* If TWBlue attemps to load an account with invalid tokens (this happens " "when reactivating a previously deactivated account, or when access to the ap " @@ -423,7 +538,7 @@ msgstr "" "sesión. Antes, la aplicación no podía iniciarse debido a un error crítico. " "([#328,](https://github.com/manuelcortez/TWBlue/issues/328))" -#: changelog.py:49 +#: changelog.py:60 msgid "" "* When sending a direct message, the title of the window will change " "appropiately when the recipient is edited. ([#276,](https://github.com/" @@ -433,7 +548,7 @@ msgstr "" "apropiadamente cada vez que el recipiente es editado. ([#276,](https://" "github.com/manuelcortez/TWBlue/issues/276))" -#: changelog.py:50 +#: changelog.py:61 msgid "" "* URL'S in user profiles are expanded automatically. ([#275,](https://github." "com/manuelcortez/TWBlue/issues/275))" @@ -441,7 +556,7 @@ msgstr "" "* Las direcciones URL de los perfiles de usuario estarán expandidas " "automáticamente. ([#275,](https://github.com/manuelcortez/TWBlue/issues/275))" -#: changelog.py:51 +#: changelog.py:62 msgid "" "* TWBlue now uses [Tweepy,](https://github.com/tweepy/tweepy) to connect " "with Twitter. We have adopted this change in order to support Twitter'S API " @@ -454,7 +569,7 @@ msgstr "" "de Twitter en un futuro cercano. ([#333,](https://github.com/manuelcortez/" "TWBlue/issues/337) [#347](https://github.com/manuelcortez/TWBlue/pull/347))" -#: changelog.py:52 +#: changelog.py:63 msgid "" "* TWBlue can upload images in Tweets and replies again. ([#240,](https://" "github.com/manuelcortez/TWBlue/issues/240))" @@ -462,7 +577,7 @@ msgstr "" "* TWBlue puede subir imágenes en tweets y respuestas de nuevo. ([#240,]" "(https://github.com/manuelcortez/TWBlue/issues/240))" -#: changelog.py:53 +#: changelog.py:64 msgid "" "* Fixed the way we use to count characters in Twitter. The new methods in " "TWBlue take into account special characters and URLS as documented in " @@ -474,11 +589,11 @@ msgstr "" "especificaciones de Twitter. ([#199,](https://github.com/manuelcortez/TWBlue/" "issues/199) [#315](https://github.com/manuelcortez/TWBlue/issues/315))" -#: changelog.py:54 +#: changelog.py:65 msgid "* Proxy support now works as expected." msgstr "* El soporte Proxy ahora debería funcionar como es debido." -#: changelog.py:55 +#: changelog.py:66 msgid "" "* Changed translation service from yandex.translate to Google Translator. " "([#355,](https://github.com/manuelcortez/TWBlue/issues/355))" @@ -486,7 +601,7 @@ msgstr "" "* Hemos cambiado el servicio de traducción de yandex.translate a Google " "Translate. ([#355,](https://github.com/manuelcortez/TWBlue/issues/355))" -#: changelog.py:56 +#: changelog.py:67 msgid "" "* Improved method to load direct messages in the buffers. Now it should be " "faster due to less calls to Twitter API performed from the client." @@ -495,16 +610,16 @@ msgstr "" "Ahora debería ser más rápido debido a que se realizan menos llamadas a la " "API de Twitter desde el cliente." -#: changelog.py:57 +#: changelog.py:68 msgid "" "* And more. ([#352,](https://github.com/manuelcortez/TWBlue/issues/352))" msgstr "* Y más ([#352,](https://github.com/manuelcortez/TWBlue/issues/352))" -#: changelog.py:59 +#: changelog.py:70 msgid "## Changes in version 0.95" msgstr "## Cambios en la versión 0.95" -#: changelog.py:61 +#: changelog.py:72 msgid "" "* TWBlue can open a Tweet or user directly in Twitter. There is a new option " "in the context menu for people and tweet buffers, and also, the shortcut " @@ -515,12 +630,12 @@ msgstr "" "también el atajo control+win+alt+enter para abrir en Twitter el elemento con " "el foco." -#: changelog.py:62 +#: changelog.py:73 msgid "* Some keystrokes were remapped in the Windows 10 Keymap:" msgstr "" "* Cambiados algunos atajos de teclado en el mapa de teclado de Windows 10:" -#: changelog.py:63 +#: changelog.py:74 msgid "" " * Read location of a tweet: Ctrl+Win+G. ([#177](https://github.com/" "manuelcortez/TWBlue/pull/177))" @@ -528,17 +643,17 @@ msgstr "" " * Leer ubicación de un tuit: CTRL+Win+G. ([#177](https://github.com/" "manuelcortez/TWBlue/pull/177))" -#: changelog.py:64 +#: changelog.py:75 msgid " * Open global settings dialogue: Ctrl+Win+Alt+O." msgstr " * Abrir diálogo de configuración global: Ctrl+Win+Alt+O." -#: changelog.py:65 +#: changelog.py:76 msgid " * Mute/unmute current session: Control + Windows + Alt + M." msgstr "" " * Silenciar / desactivar silencio en la sesión actual: Control + Windows " "+ Alt + M." -#: changelog.py:66 +#: changelog.py:77 msgid "" "* Fixed an error that was preventing TWBlue to load the direct messages " "buffer if an user who sent a message has been deleted." @@ -546,7 +661,7 @@ msgstr "" "* Corregido un error que impedía a TWBlue cargar el buffer de mensajes " "directos si se ha eliminado un usuario que envió un mensaje." -#: changelog.py:67 +#: changelog.py:78 msgid "" "* Added support for playing audios posted in [AnyAudio.net](http://anyaudio." "net) directly from TWBlue. Thanks to [Sam Tupy](http://www.samtupy.com/)" @@ -555,7 +670,7 @@ msgstr "" "(http://anyaudio.net) directamente desde TWBlue. Gracias a [Sam Tupy](http://" "www.samtupy.com/)" -#: changelog.py:68 +#: changelog.py:79 msgid "" "* Custom buffer ordering will not be reset every time the application " "restarts after an account setting has been modified." @@ -563,7 +678,7 @@ msgstr "" "* El orden personalizado de buffers no se restablecerá cada vez que la " "aplicación se reinicie tras modificar un ajuste de la cuenta." -#: changelog.py:69 +#: changelog.py:80 msgid "" "* When adding or removing an user from a list, it is possible to press enter " "in the focused list instead of having to search for the \"add\" or \"delete" @@ -573,7 +688,7 @@ msgstr "" "la lista con el foco en vez de tener que buscar los botones \"Añadir\" o " "\"Eliminar\"." -#: changelog.py:70 +#: changelog.py:81 msgid "" "* Quoted and long tweets are displayed properly in the sent tweets buffer " "after being send. ([#253](https://github.com/manuelcortez/TWBlue/issues/253))" @@ -582,7 +697,7 @@ msgstr "" "enviados después de enviarse. ([#253](https://github.com/manuelcortez/TWBlue/" "issues/253))" -#: changelog.py:71 +#: changelog.py:82 msgid "" "* Fixed an issue that was making the list manager keystroke unable to be " "shown in the keystroke editor. Now the keystroke is listed properly. ([#260]" @@ -593,7 +708,7 @@ msgstr "" "se lista adecuadamente. ([#260](https://github.com/manuelcortez/TWBlue/" "issues/260))" -#: changelog.py:72 +#: changelog.py:83 msgid "" "* The volume slider, located in the account settings of TWBlue, now should " "decrease and increase value properly when up and down arrows are pressed. " @@ -605,7 +720,7 @@ msgstr "" "arriba y abajo. Antes lo hacía en orden inverso. ([#261](https://github.com/" "manuelcortez/TWBlue/issues/261))" -#: changelog.py:73 +#: changelog.py:84 msgid "" "* autoreading has been redesigned to work in a similar way for almost all " "buffers. Needs testing. ([#221](https://github.com/manuelcortez/TWBlue/" @@ -615,7 +730,7 @@ msgstr "" "casi todos los buffers. Necesita pruebas. ([#221](https://github.com/" "manuelcortez/TWBlue/issues/221))" -#: changelog.py:74 +#: changelog.py:85 msgid "" "* When displaying tweets or direct messages, a new field has been added to " "show the date when the item has been posted to Twitter." @@ -623,7 +738,7 @@ msgstr "" "* Al mostrar tuits o mensajes directos, ahora hay un nuevo campo que muestra " "la fecha en la que se publicó ese elemento en Twitter." -#: changelog.py:75 +#: changelog.py:86 msgid "" "* Added support for deleting direct messages by using the new Twitter API " "methods." @@ -631,14 +746,14 @@ msgstr "" "* Se ha añadido soporte para eliminar mensajes directos usando los nuevos " "métodos de la API de Twitter." -#: changelog.py:76 +#: changelog.py:87 msgid "" "* When quoting a retweet, the quote will be made to the original tweet " "instead of the retweet." msgstr "" "* Al citar un retuit, la cita apuntará al tuit original en vez del retuit." -#: changelog.py:77 +#: changelog.py:88 msgid "" "* If the sent direct messages buffer is hidden, TWBlue should keep loading " "everything as expected. ([#246](https://github.com/manuelcortez/TWBlue/" @@ -648,7 +763,7 @@ msgstr "" "cargar todo como se espera. ([#246](https://github.com/manuelcortez/TWBlue/" "issues/246))" -#: changelog.py:78 +#: changelog.py:89 msgid "" "* There is a new soundpack, called FreakyBlue (Thanks to [Andre Louis]" "(https://twitter.com/FreakyFwoof)) as a new option in TWBlue. This pack can " @@ -662,7 +777,7 @@ msgstr "" "que los usuarios deberían echar un vistazo y dar su opinión en las " "snapshots. ([#247](https://github.com/manuelcortez/TWBlue/issues/247))" -#: changelog.py:79 +#: changelog.py:90 msgid "" "* There is a new option in the help menu that allows you to visit the " "soundpacks section in the TWBlue website. ([#247](https://github.com/" @@ -672,7 +787,7 @@ msgstr "" "paquetes de sonidos en el sitio web de TWBlue. ([#247](https://github.com/" "manuelcortez/TWBlue/issues/247))" -#: changelog.py:80 +#: changelog.py:91 msgid "" "* When reading location of a geotagged tweet, it will be translated for " "users of other languages. ([#251](https://github.com/manuelcortez/TWBlue/" @@ -682,7 +797,7 @@ msgstr "" "usuarios de otros idiomas. ([#251](https://github.com/manuelcortez/TWBlue/" "pull/251))" -#: changelog.py:81 +#: changelog.py:92 msgid "" "* When there are no more items to retrieve in direct messages and people " "buffers, a message will announce it." @@ -690,7 +805,7 @@ msgstr "" "* Cuando no haya más elementos que recuperar en los buffers de mensajes " "directos y personas, un mensaje lo indicará." -#: changelog.py:82 +#: changelog.py:93 msgid "" "* Fixed an issue reported by some users that was making them unable to load " "more items in their direct messages." @@ -698,14 +813,14 @@ msgstr "" "* Corregido un problema reportado por algunos usuarios que les impedía " "cargar más elementos en sus mensajes directos." -#: changelog.py:83 +#: changelog.py:94 msgid "" "* It is possible to add a tweet to the likes buffer from the menu bar again." msgstr "" "* Es posible añadir tuits al buffer de me gusta desde la barra de menú otra " "vez." -#: changelog.py:84 +#: changelog.py:95 msgid "" "* Tweets, replies and retweets will be added to sent tweets right after " "being posted in Twitter." @@ -713,16 +828,16 @@ msgstr "" "* Los tuits, respuestas y retuits se añadirán a los tuits enviados justo al " "publicarse en Twitter." -#: changelog.py:85 +#: changelog.py:96 msgid "* Extended Tweets should be displayed properly in list buffers." msgstr "" "* Los tuits largos deberían mostrarse correctamente en los buffers de listas." -#: changelog.py:87 +#: changelog.py:98 msgid "## Changes in version 0.94" msgstr "## Cambios en la versión 0.94" -#: changelog.py:89 +#: changelog.py:100 msgid "" "* Added an option in the global settings dialog to disable the Streaming " "features of TWBlue. TWBlue will remove all Streaming features after August " @@ -736,7 +851,7 @@ msgstr "" "permite saber cómo se comportará la aplicación al llegar ese día. ([#219]" "(https://github.com/manuelcortez/TWBlue/issues/219))" -#: changelog.py:90 +#: changelog.py:101 msgid "" "* Due to Twitter API changes, Switched authorisation method to Pin-code " "based authorisation. When you add new accounts to TWBlue, you will be " @@ -749,7 +864,7 @@ msgstr "" "autorizar recibirás un número que deberás pegar en la ventana de TWBlue para " "poder continuar. ([#216](https://github.com/manuelcortez/TWBlue/issues/216))" -#: changelog.py:91 +#: changelog.py:102 msgid "" "* In order to comply with latest Twitter changes, TWBlue has switched to the " "new method used to send and receive direct messages, according to issue " @@ -760,7 +875,7 @@ msgstr "" "directos, de acuerdo con lo dispuesto en el issue [#215.](https://github.com/" "manuelcortez/twblue/issues/215)" -#: changelog.py:92 +#: changelog.py:103 msgid "" " * The new method does not allow direct messages to be processed in real " "time. Direct messages will be updated periodically." @@ -769,7 +884,7 @@ msgstr "" "tiempo real. Los mensajes directos se actualizarán periódicamente, pero no " "en tiempo real." -#: changelog.py:93 +#: changelog.py:104 msgid "" "* After august 16 or when streaming is disabled, the events buffer will no " "longer be created in TWBlue." @@ -777,7 +892,7 @@ msgstr "" "* Luego del 16 de agosto o si las características en tiempo real han sido " "desactivadas, el buffer de eventos dejará de ser utilizado en TWBlue." -#: changelog.py:94 +#: changelog.py:105 msgid "" "* You can configure frequency for buffer updates in TWBlue. By default, " "TWBlue will update all buffers every 2 minutes, but you can change this " @@ -789,7 +904,7 @@ msgstr "" "esto puede cambiarse desde el diálogo de opciones globales. ([#223](https://" "github.com/manuelcortez/TWBlue/issues/223))" -#: changelog.py:95 +#: changelog.py:106 msgid "" "* Added a new tab called feedback, in the account settings dialog. This tab " "allows you to control whether automatic speech or Braille feedbak in certain " @@ -806,7 +921,7 @@ msgstr "" "salida automática. ([#203](https://github.com/manuelcortez/TWBlue/" "issues/203))" -#: changelog.py:96 +#: changelog.py:107 msgid "" "* The spell checking dialog now has access keys defined for the most " "important actions. ([#211](https://github.com/manuelcortez/TWBlue/" @@ -816,7 +931,7 @@ msgstr "" "para las acciones más importantes. ([#211](https://github.com/manuelcortez/" "TWBlue/issues/211))" -#: changelog.py:97 +#: changelog.py:108 msgid "" "* TWBlue now Uses WXPython 4.0.1. This will allow us to migrate all " "important components to Python 3 in the future. ([#207](https://github.com/" @@ -826,7 +941,7 @@ msgstr "" "componentes importantes a Python 3 en el futuro. ([#207](https://github.com/" "manuelcortez/TWBlue/issues/207))" -#: changelog.py:98 +#: changelog.py:109 msgid "" "* When you quote a Tweet, if the original tweet was posted with Twishort, " "TWBlue should display properly the quoted tweet. Before it was displaying " @@ -837,7 +952,7 @@ msgstr "" "debería mostrar correctamente el tuit citado. Antes sólo mostraba el tuit " "original. ([#206](https://github.com/manuelcortez/TWBlue/issues/206))" -#: changelog.py:99 +#: changelog.py:110 msgid "" "* It is possible to filter by retweets, quotes and replies when creating a " "new filter." @@ -845,7 +960,7 @@ msgstr "" "* Es posible filtrar por retuits, tuits citados y respuestas al crear nuevos " "filtros." -#: changelog.py:100 +#: changelog.py:111 msgid "" "* Added support for playing youtube Links directly from the client. ([#94]" "(https://github.com/manuelcortez/TWBlue/issues/94))" @@ -853,11 +968,11 @@ msgstr "" "* Se ha añadido soporte para reproducir enlaces de Youtube directamente " "desde el cliente. ([#94](https://github.com/manuelcortez/TWBlue/issues/94))" -#: changelog.py:101 +#: changelog.py:112 msgid "* Replaced Bass with libVLC for playing URL streams." msgstr "* Se ha reemplazado bass por LibVlc para reproducir audio desde URLS." -#: changelog.py:102 +#: changelog.py:113 msgid "" "* the checkbox for indicating whether TWBlue will include everyone in a " "reply or not, will be unchecked by default." @@ -865,7 +980,7 @@ msgstr "" "* La casilla que indica si TWBlue debe incluir a todos los participantes en " "una respuesta estará desmarcada por defecto." -#: changelog.py:103 +#: changelog.py:114 msgid "" "* You can request TWBlue to save the state for two checkboxes: Long tweet " "and mention all, from the global settings dialogue." @@ -873,7 +988,7 @@ msgstr "" "* Puedes pedir a TWBlue que guarde el estado de dos casillas: tuit largo y " "mencionar a todos, desde el diálogo de opciones globales." -#: changelog.py:104 +#: changelog.py:115 msgid "" "* For windows 10 users, some keystrokes in the invisible user interface have " "been changed or merged:" @@ -881,7 +996,7 @@ msgstr "" "* Para usuarios de Windows 10, algunas combinaciones de teclado en el modo " "invisible han sufrido cambios o han sido combinadas:" -#: changelog.py:105 +#: changelog.py:116 msgid "" " * control+Windows+alt+F will be used for toggling between adding and " "removing a tweet to user's likes. This function will execute the needed " @@ -891,22 +1006,22 @@ msgstr "" "un tuit a los tuits que le gustan a un usuario. Esta función ejecutará la " "acción necesaria basándose en el estado actual del tuit con el foco." -#: changelog.py:106 +#: changelog.py:117 msgid "* TWBlue will show an error if something goes wrong in an audio upload." msgstr "" "* TWBlue mostrará un error si algo sale mal durante la carga de un archivo " "de audio." -#: changelog.py:107 +#: changelog.py:118 msgid "" "* And more. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " msgstr "* Y más. ([#171,](https://github.com/manuelcortez/TWBlue/issues/171) " -#: changelog.py:109 +#: changelog.py:120 msgid "## Changes in version 0.93" msgstr "## Cambios en la versión 0.93" -#: changelog.py:111 +#: changelog.py:122 msgid "" "* A new soundpack has been added to TWBlue. Thanks to [@ValeriaK305](https://" "twitter.com/ValeriaK305)" @@ -914,7 +1029,7 @@ msgstr "" "* Se ha añadido un nuevo paquete de sonidos a la instalación predeterminada " "de TWBlue, gracias a [@ValeriaK305](https://twitter.com/ValeriaK305)" -#: changelog.py:112 +#: changelog.py:123 msgid "" "* In the Windows 10 keymap, we have changed some default keystrokes as " "windows now uses some previously assigned shortcuts:" @@ -923,16 +1038,16 @@ msgstr "" "de teclado, ya que Windows ahora utiliza algunos de los atajos que utilizaba " "TWBlue:" -#: changelog.py:113 +#: changelog.py:124 msgid " * For liking a tweet, press Control+Windows+alt+f" msgstr "" " * Para marcar como me gusta un tweet, presiona control+windows+alt+f" -#: changelog.py:114 +#: changelog.py:125 msgid " * for opening a trends buffer, press control+Windows+T" msgstr " * Para abrir un buffer de tendencias, presiona Control+Windows+T" -#: changelog.py:115 +#: changelog.py:126 msgid "" "* TWBlue has received improvements in some functions for handling extended " "tweets, long tweets and quoted retweets. It should render some tweets in a " @@ -942,7 +1057,7 @@ msgstr "" "extendidos y retuits citados. Debería ser capaz de mostrar mejor algunos " "tuits." -#: changelog.py:116 +#: changelog.py:127 msgid "" "* In the spell checker module, there is a new button that will allow you to " "add your own words to your personal dictionary so the module won't mark them " @@ -952,7 +1067,7 @@ msgstr "" "la palabra a tu diccionario. De esta forma,en un futuro esa palabra no " "aparecerá marcada como mal escrita." -#: changelog.py:117 +#: changelog.py:128 msgid "" "* Added filtering capabilities to TWBlue. ([#102](https://github.com/" "manuelcortez/TWBlue/issues/102))" @@ -960,7 +1075,7 @@ msgstr "" "* Se han añadido filtros a TWBlue. ([#102](https://github.com/manuelcortez/" "TWBlue/issues/102))" -#: changelog.py:118 +#: changelog.py:129 msgid "" " * You can create a filter for the current buffer from the buffer menu in " "the menu bar. At this moment, invisible interface does not have any shorcut " @@ -970,11 +1085,11 @@ msgstr "" "ubicado en la barra de menú. Por el momento, la interfaz invisible no cuenta " "con un atajo para esta acción." -#: changelog.py:119 +#: changelog.py:130 msgid " * You can create filters by word or languages." msgstr " * Puedes crear filtros de palabras o de idiomas en el tuit." -#: changelog.py:120 +#: changelog.py:131 msgid "" " * For deleting already created filters, you can go to the filter manager " "in the buffer menu and delete the filters you won't need." @@ -982,7 +1097,7 @@ msgstr "" " * Para eliminar filtros previamente creados, puedes acceder al gestor de " "filtros en el menú buffer, y eliminar desde ahí los que ya no necesites." -#: changelog.py:121 +#: changelog.py:132 msgid "" "* Links should be opened properly in quoted tweets ([#167,](https://github." "com/manuelcortez/TWBlue/issues/167) [#184](https://github.com/manuelcortez/" @@ -992,14 +1107,14 @@ msgstr "" "(https://github.com/manuelcortez/TWBlue/issues/167) [#184](https://github." "com/manuelcortez/TWBlue/issues/184))" -#: changelog.py:122 +#: changelog.py:133 msgid "" "* Increased display name limit up to 50 characters in update profile dialog." msgstr "" "* Se ha aumentado el número de caracteres permitidos en los nombres para " "mostrar en Twitter a 50 caracteres." -#: changelog.py:123 +#: changelog.py:134 msgid "" "* When authorising an account, you will see a dialogue with a cancel button, " "in case you want to abort the process. Also, NVDA will not be blocked when " @@ -1011,7 +1126,7 @@ msgstr "" "autorización para la cuenta. ([#101](https://github.com/manuelcortez/TWBlue/" "issues/101))" -#: changelog.py:124 +#: changelog.py:135 msgid "" "* In the translator module, the list of available languages is fetched " "automatically from the provider. That means all of these languages will work " @@ -1026,7 +1141,7 @@ msgstr "" "determina de forma automática por el API de Yandex. ([#153](https://github." "com/manuelcortez/TWBlue/issues/153))" -#: changelog.py:125 +#: changelog.py:136 msgid "" "* Trending topics, searches and conversation buffers will use mute settings " "set for the session in wich they were opened. ([#157](https://github.com/" @@ -1036,7 +1151,7 @@ msgstr "" "opciones de silencio en la sesión de TWBlue donde fueron creados. ([#157]" "(https://github.com/manuelcortez/TWBlue/issues/157))" -#: changelog.py:126 +#: changelog.py:137 msgid "" "* The Tweet limit is now 280 characters lenght instead 140. It means you can " "tweet longer tweets. ([#172](https://github.com/manuelcortez/TWBlue/" @@ -1046,7 +1161,7 @@ msgstr "" "significa que se pueden escribir tuits más largos. [#172](https://github.com/" "manuelcortez/TWBlue/issues/172))" -#: changelog.py:127 +#: changelog.py:138 msgid "" "* Per popular request, Status for mention to all and long tweet checkboxes " "will not be saved in settings. ([#170](https://github.com/manuelcortez/" @@ -1056,7 +1171,7 @@ msgstr "" "escribir un tuit largo y responder a todos. ([#170](https://github.com/" "manuelcortez/TWBlue/issues/170))" -#: changelog.py:128 +#: changelog.py:139 msgid "" "* Fixed a problem that was making TWBlue unable to start if it was being ran " "in Windows with Serbian language. ([#175](https://github.com/manuelcortez/" @@ -1066,11 +1181,11 @@ msgstr "" "el equipo se detectaba el idioma serbio. ([#175](https://github.com/" "manuelcortez/TWBlue/issues/175))" -#: changelog.py:129 +#: changelog.py:140 msgid "* Added Danish translation." msgstr "* Se ha añadido la traducción al Danés." -#: changelog.py:130 +#: changelog.py:141 msgid "" "* And more. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) " "[#163,](https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://" @@ -1085,11 +1200,11 @@ msgstr "" "TWBlue/issues/173) [#174,](https://github.com/manuelcortez/TWBlue/" "issues/174) [#176,](https://github.com/manuelcortez/TWBlue/issues/176))" -#: changelog.py:132 +#: changelog.py:143 msgid "## changes in version 0.91 and 0.92" msgstr "## Cambios en las versiones 0.91 y 0.92" -#: changelog.py:134 +#: changelog.py:145 msgid "" "* Fixed incorrect unicode handling when copying tweet to clipboard. ([#150]" "(https://github.com/manuelcortez/TWBlue/issues/150))" @@ -1097,7 +1212,7 @@ msgstr "" "* Se ha corregido un error de Unicode al copiar tuits al portapapeles. " "([#150](https://github.com/manuelcortez/TWBlue/issues/150))" -#: changelog.py:135 +#: changelog.py:146 msgid "" "* TWBlue will show an error when trying to open a timeline for a suspended " "user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))" @@ -1106,7 +1221,7 @@ msgstr "" "usuario suspendido. ([#128](https://github.com/manuelcortez/TWBlue/" "issues/128))" -#: changelog.py:136 +#: changelog.py:147 msgid "" "* Removed TwUp as service as it no longer exists. ([#112](https://github.com/" "manuelcortez/TWBlue/issues/112))" @@ -1114,7 +1229,7 @@ msgstr "" "* Se ha removido el servicio de audio TWUp, debido a que ya no existe. " "([#112](https://github.com/manuelcortez/TWBlue/issues/112))" -#: changelog.py:137 +#: changelog.py:148 msgid "" "* Release audio files after uploading them. ([#130](https://github.com/" "manuelcortez/TWBlue/issues/130))" @@ -1123,7 +1238,7 @@ msgstr "" "luego de haber sido subidos a algún servicio de audio. ([#130](https://" "github.com/manuelcortez/TWBlue/issues/130))" -#: changelog.py:138 +#: changelog.py:149 msgid "" "* Now TWBlue will use Yandex's translation services instead microsoft " "translator. ([#132](https://github.com/manuelcortez/TWBlue/issues/132))" @@ -1132,7 +1247,7 @@ msgstr "" "Microsoft Translator. ([#132](https://github.com/manuelcortez/TWBlue/" "issues/132))" -#: changelog.py:139 +#: changelog.py:150 msgid "" "* SndUp users will be able to upload audio in their account by using their " "API Key again. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" @@ -1140,7 +1255,7 @@ msgstr "" "* Los usuarios con cuenta de SNDUp podrán subir audios utilizando su clave " "de API de nuevo. ([#134](https://github.com/manuelcortez/TWBlue/issues/134))" -#: changelog.py:140 +#: changelog.py:151 msgid "" "* old tweets shouldn't be added as new items in buffers. ([#116,](https://" "github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" @@ -1150,7 +1265,7 @@ msgstr "" "github.com/manuelcortez/TWBlue/issues/116)) ([#133](https://github.com/" "manuelcortez/TWBlue/issues/133))" -#: changelog.py:141 +#: changelog.py:152 msgid "" "* All mentionned users should be displayed correctly in Twishort's long " "tweets. ([#116,](https://github.com/manuelcortez/TWBlue/issues/116)) ([#135]" @@ -1160,7 +1275,7 @@ msgstr "" "hechos mediante Twishort. ([#116,](https://github.com/manuelcortez/TWBlue/" "issues/116)) ([#135](https://github.com/manuelcortez/TWBlue/issues/135))" -#: changelog.py:142 +#: changelog.py:153 msgid "" "* It is possible to select a language for OCR service from the extras panel, " "in the account settings dialogue. You can, however, set this to detect " @@ -1175,7 +1290,7 @@ msgstr "" "especiales o símbolos que no forman parte del alfabeto inglés. ([#107]" "(https://github.com/manuelcortez/TWBlue/issues/107))" -#: changelog.py:143 +#: changelog.py:154 msgid "" "* Fixed a problem with JAWS for Windows and TWBlue. Now JAWS will work " "normally in this update. [#100](https://github.com/manuelcortez/twblue/" @@ -1185,15 +1300,15 @@ msgstr "" "funcionar de forma correcta con este lector de pantalla. [#100](https://" "github.com/manuelcortez/twblue/issues/100)" -#: changelog.py:144 +#: changelog.py:155 msgid "* And more ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" msgstr "* Y más ([#136,](https://github.com/manuelcortez/TWBlue/issues/136))" -#: changelog.py:146 +#: changelog.py:157 msgid "## Changes in version 0.90" msgstr "## Cambios en la versión 0.90" -#: changelog.py:148 +#: changelog.py:159 msgid "" "* Fixed a bug in long tweet parsing that was making TWBlue to disconnect the " "streaming API. ([#103](https://github.com/manuelcortez/TWBlue/issues/103))" @@ -1202,7 +1317,7 @@ msgstr "" "desconectara el Streaming. ([#103](https://github.com/manuelcortez/TWBlue/" "issues/103))" -#: changelog.py:149 +#: changelog.py:160 msgid "" "* Now OCR will work in images from retweets. It fixes a bug where TWBlue was " "detecting images but couldn't apply OCR on them. ([#105](https://github.com/" @@ -1213,7 +1328,7 @@ msgstr "" "pudiera aplicar OCR en ellas. ([#105](https://github.com/manuelcortez/TWBlue/" "issues/105))" -#: changelog.py:150 +#: changelog.py:161 msgid "" "* TWBlue won't try to load tweets already deleted, made with Twishort. " "Before, if someone posted a long tweet but deleted it in the Twishort's " @@ -1226,7 +1341,7 @@ msgstr "" "problemas en todo el cliente. ([#113](https://github.com/manuelcortez/TWBlue/" "issues/113))" -#: changelog.py:151 +#: changelog.py:162 msgid "" "* TWBlue shows an error message when you try to view the profile of an user " "that does not exist or has been suspended. ([#114,](https://github.com/" @@ -1238,7 +1353,7 @@ msgstr "" "manuelcortez/TWBlue/issues/114) [#115](https://github.com/manuelcortez/" "TWBlue/issues/115))" -#: changelog.py:152 +#: changelog.py:163 msgid "" "* The spellchecker module should select the right language when is set to " "\"user default\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" @@ -1247,7 +1362,7 @@ msgstr "" "apropiado cuando el idioma del cliente se establece en \"Idioma " "predeterminado\". ([#117](https://github.com/manuelcortez/TWBlue/issues/117))" -#: changelog.py:153 +#: changelog.py:164 msgid "" "* Image description will be displayed in retweets too. ([#119](https://" "github.com/manuelcortez/TWBlue/issues/119))" @@ -1255,7 +1370,7 @@ msgstr "" "* La descripción de imágenes se mostrará en retuits también. ([#119](https://" "github.com/manuelcortez/TWBlue/issues/119))" -#: changelog.py:154 +#: changelog.py:165 msgid "" "* When reading a long tweet, you shouldn't read strange entities anymore. " "([#118](https://github.com/manuelcortez/twblue/issues/118))" @@ -1263,7 +1378,7 @@ msgstr "" "* cuando se lea un tuit largo, no deberían aparecer símbolos extraños. " "([#118](https://github.com/manuelcortez/twblue/issues/118))" -#: changelog.py:155 +#: changelog.py:166 msgid "" "* TWBlue will not try to load timelines if the user is blocking you. ([#125]" "(https://github.com/manuelcortez/twblue/issues/125))" @@ -1272,28 +1387,28 @@ msgstr "" "a la cuenta actual. ([#125](https://github.com/manuelcortez/twblue/" "issues/125))" -#: changelog.py:157 +#: changelog.py:168 msgid "## Changes in version 0.88 and 0.89" msgstr "## Cambios en las versiones 0.88 y 0.89" -#: changelog.py:159 +#: changelog.py:170 msgid "* Fixed more issues with streams and reconnections." msgstr "* Corregidos más problemas con los streams y la reconexión." -#: changelog.py:160 +#: changelog.py:171 msgid "* newer updates will indicate the release date in the updater." msgstr "" "* Las actualizaciones más nuevas indicarán la fecha de lanzamiento en el " "módulo de actualización." -#: changelog.py:161 +#: changelog.py:172 msgid "" "* Changes to keystrokes are reflected in keystroke editor automatically." msgstr "" "* Los cambios en las combinaciones de teclado se reflejarán automáticamente " "en el editor de combinaciones de teclado." -#: changelog.py:162 +#: changelog.py:173 msgid "" "* In replies with multiple users, if the mention to all checkbox is " "unchecked, you will see a checkbox per user so you will be able to control " @@ -1303,7 +1418,7 @@ msgstr "" "todos no está marcada, verás una casilla para cada usuario, lo que te " "permitirá seleccionar a los usuarios que serán mencionados en la respuesta." -#: changelog.py:163 +#: changelog.py:174 msgid "" "* Fixed a bug that caused duplicated user mentions in replies when the tweet " "was made with Twishort." @@ -1311,7 +1426,7 @@ msgstr "" "* Corregido un error que causaba que TWBlue mostrara menciones duplicadas si " "el tuit había sido enviado mediante Twishort." -#: changelog.py:164 +#: changelog.py:175 msgid "" "* Retweets should be displayed normally again when the originating tweet is " "a Twishort's long tweet." @@ -1319,7 +1434,7 @@ msgstr "" "* Los Retuits deben mostrarse correctamente si el tuit original había sido " "enviado mediante Twishort." -#: changelog.py:165 +#: changelog.py:176 msgid "" "* Changed the way TWBlue saves user timelines in configuration. Now it uses " "user IDS instead usernames. With user IDS, if an user changes the username, " @@ -1332,7 +1447,7 @@ msgstr "" "cambia su nombre de usuario TWBlue todavía será capaz de crear la línea " "temporal. Esto no era posible anteriormente." -#: changelog.py:166 +#: changelog.py:177 msgid "" "* Added a new setting in the account settings dialogue that makes TWBlue to " "show twitter usernames instead the full name." @@ -1340,7 +1455,7 @@ msgstr "" "* Añadida una opción en el diálogo de opciones de cuenta que hace que TWBlue " "muestre el nombre de pantalla del usuario en lugar del nombre completo." -#: changelog.py:167 +#: changelog.py:178 msgid "" "* Added OCR in twitter pictures. There is a new item in the tweet menu that " "allows you to extract and display text in images. Also the keystroke alt+Win" @@ -1351,18 +1466,18 @@ msgstr "" "imagen del tuit seleccionado. También se ha añadido la combinación Alt + " "Windows +O para el mismo propósito en la interfaz invisible." -#: changelog.py:168 +#: changelog.py:179 msgid "* Now TWBlue will play a sound when the focused tweet contains images." msgstr "" "* Ahora TWBlue reproducirá un sonido cuando el tuit seleccionado contenga " "imágenes." -#: changelog.py:169 +#: changelog.py:180 msgid "" "* Your own quoted tweets will not appear in the mentions buffer anymore." msgstr "* Tus tuits citados dejarán de mostrarse en el buffer de menciones." -#: changelog.py:170 +#: changelog.py:181 msgid "" "* The config file is saved in a different way, it should fix the bug where " "TWBlue needs to be restarted after the config folder is deleted." @@ -1371,13 +1486,13 @@ msgstr "" "solucionar el error que requería borrar el directorio de configuraciones y " "reiniciar TWBlue." -#: changelog.py:171 +#: changelog.py:182 msgid "* Mentioning people from friends or followers buffers works again." msgstr "" "* Es posible de nuevo mencionar usuarios desde los buffers de seguidores y " "amigos." -#: changelog.py:172 +#: changelog.py:183 msgid "" "* Support for proxy servers has been improved. Now TWBlue supports http, " "https, socks4 and socks5 proxies, with and without autentication." @@ -1385,15 +1500,15 @@ msgstr "" "* Se ha mejorado el soporte para servidores proxy. Ahora TWBlue soporta " "proxys http, https, socks4 y socks5, con o sin autenticación." -#: changelog.py:174 +#: changelog.py:185 msgid "## Changes in version 0.87" msgstr "## Cambios en la versión 0.87" -#: changelog.py:176 +#: changelog.py:187 msgid "* Fixed stream connection errors." msgstr "* Arreglados errores en la conexión de los streams." -#: changelog.py:177 +#: changelog.py:188 msgid "" "* Now TWBlue can handle properly a reply to the sender without including all " "other mentioned users." @@ -1401,11 +1516,11 @@ msgstr "" "* Ahora TWBlue puede manejar correctamente las respuestas sin incluir a " "todos los usuarios del tuit original." -#: changelog.py:178 +#: changelog.py:189 msgid "* Updated translations." msgstr "* Traducciones actualizadas." -#: changelog.py:179 +#: changelog.py:190 msgid "" "* The status of the mention to all checkbox will be remembered the next time " "you reply to multiple users." @@ -1413,11 +1528,11 @@ msgstr "" "* El estado de la casilla para mencionar a todos se recordará la próxima vez " "que escribas una respuesta." -#: changelog.py:181 +#: changelog.py:192 msgid "## Changes in version 0.86" msgstr "## Cambios en la versión 0.86" -#: changelog.py:183 +#: changelog.py:194 msgid "" "* Fixed a very important security issue. Now TWBlue will send tweets to " "twishort without using any other server." @@ -1425,7 +1540,7 @@ msgstr "" "* Arreglado un error de seguridad muy importante. Ahora TWBlue enviará tuits " "hacia Twishort sin utilizar un servidor intermedio." -#: changelog.py:184 +#: changelog.py:195 msgid "" "* When you add a comment to a tweet, it will be sent as a quoted tweet, even " "if your reply plus the original tweet is not exceeding 140 characters." @@ -1434,7 +1549,7 @@ msgstr "" "citado, incluso si el comentario más el tuit original no supera los 140 " "caracteres." -#: changelog.py:185 +#: changelog.py:196 msgid "" "* Updated windows 10 keymap for reflecting changes made in the last windows " "10 build." @@ -1442,11 +1557,11 @@ msgstr "" "* Actualizado el mapa de teclado de Windows 10 debido a los cambios de la " "última build." -#: changelog.py:186 +#: changelog.py:197 msgid "* Added last changes in the twitter API." msgstr "* Añadidos los últimos cambios en el API de Twitter." -#: changelog.py:187 +#: changelog.py:198 msgid "" "* When replying, it will not show the twitter username in the text box. When " "you send the tweet, the username will be added automatically." @@ -1455,7 +1570,7 @@ msgstr "" "campo de texto. El nombre de usuario será añadido de forma automática al " "enviar el tuit." -#: changelog.py:188 +#: changelog.py:199 msgid "" "* When replying to multiple users, you'll have a checkbox instead a button " "for mentioning all people. If this is checked, twitter usernames will be " @@ -1465,44 +1580,44 @@ msgstr "" "lugar de un botón para mencionar a todos. Si es marcada, los nombres de " "usuario de Twitter se añadirán automáticamente al enviar el tuit." -#: changelog.py:190 +#: changelog.py:201 msgid "## Changes in version 0.85" msgstr "## Cambios en la versión 0.85" -#: changelog.py:192 +#: changelog.py:203 msgid "* Long and quoted tweets should be displayed properly In lists." msgstr "" "* Los tuits largos y citados deberían mostrarse correctamente en las listas." -#: changelog.py:193 +#: changelog.py:204 msgid "* The connection should be more stable." msgstr "* La conexión debería ser más estable." -#: changelog.py:194 +#: changelog.py:205 msgid "* Added an autostart option in the global settings dialogue." msgstr "" "* Se ha añadido la opción para iniciar después de iniciar sesión en Windows " "en el diálogo de opciones globales." -#: changelog.py:195 +#: changelog.py:206 msgid "* Updated translation." msgstr "* Se han actualizado las traducciones." -#: changelog.py:196 +#: changelog.py:207 msgid "* Updated russian documentation." msgstr "* Actualizada la documentación en ruso." -#: changelog.py:197 +#: changelog.py:208 msgid "* Tweets in cached database should be loaded properly." msgstr "* Se deben cargar correctamente los tuits en la base de datos." -#: changelog.py:198 +#: changelog.py:209 msgid "* Added some missed dictionaries for spelling correction." msgstr "" "* Se han añadido algunos nuevos diccionarios en el módulo de corrección " "ortográfica." -#: changelog.py:199 +#: changelog.py:210 msgid "" "* Timelines, lists and other buffer should be created in the right order at " "startup." @@ -1510,15 +1625,15 @@ msgstr "" "* Líneas temporales, listas y otros buffers deberían ser creados en el orden " "correcto al iniciar TWBlue." -#: changelog.py:201 +#: changelog.py:212 msgid "## Changes in version 0.84 " msgstr "## Cambios en la versión 0.84 " -#: changelog.py:203 +#: changelog.py:214 msgid "* More improvements in quoted and long tweets." msgstr "* Más mejoras en los tuits largos y citados." -#: changelog.py:204 +#: changelog.py:215 msgid "" "* Updated translations: Russian, Italian, French, Romanian, Galician and " "Finnish." @@ -1526,7 +1641,7 @@ msgstr "" "* Actualizadas las siguientes traducciones: Ruso, italiano, francés, rumano, " "gallego y finlandés." -#: changelog.py:205 +#: changelog.py:216 msgid "" "* Improvements in the audio uploader module: Now it can handle audio with " "non-english characters." @@ -1534,7 +1649,7 @@ msgstr "" "* Mejoras en el módulo de carga de archivos de audio: Ahora es capaz de " "manejar archivos de audio con caracteres especiales." -#: changelog.py:206 +#: changelog.py:217 msgid "" "* the title of the window should be updated properly when spellcheck, " "translate or shorten/unshorten URL buttons are pressed." @@ -1542,7 +1657,7 @@ msgstr "" "* El título de la ventana debe actualizarse correctamente cuando se utilizan " "funciones como corrección ortográfica, traducción o acortar / expandir URL." -#: changelog.py:207 +#: changelog.py:218 msgid "" "* the bug that changes the selected tweet in the home timeline shouldn't be " "happening so often." @@ -1550,11 +1665,11 @@ msgstr "" "* El error que hacía que el tuit seleccionado cambiara en la interfaz " "visible debería estar parcialmente corregido." -#: changelog.py:209 +#: changelog.py:220 msgid "## Changes in version 0.82 and 0.83" msgstr "## Cambios en las versiones 0.82 y 0.83" -#: changelog.py:211 +#: changelog.py:222 msgid "" "* If the tweet source (client) is an application with unicode characters " "(example: российская газета) it will not break the tweet displayer." @@ -1563,7 +1678,7 @@ msgstr "" "caracteres Unicode en su nombre (por ejemplo: российская газета), el " "visualizador de tuits lo podrá mostrar adecuadamente." -#: changelog.py:212 +#: changelog.py:223 msgid "" "* Added a new field for image description in tweet displayer. When " "available, it will show description for images posted in tweets." @@ -1572,7 +1687,7 @@ msgstr "" "tuits. Cuando estén disponibles, se mostrarán descripciones para las " "imágenes en el tuit." -#: changelog.py:213 +#: changelog.py:224 msgid "" "* users can add image descriptions to their photos. When uploading an image, " "a dialog will show for asking a description." @@ -1580,15 +1695,15 @@ msgstr "" "* Los usuarios ahora pueden añadir descripción a sus fotos. Al subir la " "imagen, aparecerá un diálogo para que se proporcione una descripción." -#: changelog.py:214 +#: changelog.py:225 msgid "* Redesigned upload image dialog." msgstr "* El diálogo para subir imágenes ha sido rediseñado." -#: changelog.py:215 +#: changelog.py:226 msgid "* Fixed photo uploads when posting tweets." msgstr "* Se ha corregido la carga de imágenes al publicar tuits." -#: changelog.py:216 +#: changelog.py:227 msgid "" "* When getting tweets for a conversation, ignores deleted tweets or some " "errors, now TWBlue will try to get as much tweets as possible, even if some " @@ -1598,23 +1713,23 @@ msgstr "" "los tuits eliminados y algunos errores comunes. TWBlue cargará la mayor " "cantidad de tuits posible." -#: changelog.py:217 +#: changelog.py:228 msgid "* Added audio playback from soundcloud." msgstr "* Añadida la reproducción de audio desde Soundcloud." -#: changelog.py:218 +#: changelog.py:229 msgid "* Now the session mute option don't makes the screen reader speaks." msgstr "" "* Al silenciar una sesión, el lector de pantalla ya no anunciará ningún " "contenido automáticamente." -#: changelog.py:219 +#: changelog.py:230 msgid "* Fixed the direct message dialog. Now it should be displayed properly." msgstr "" "* Corregido el diálogo de mensaje directo. Ahora debería mostrarse " "correctamente." -#: changelog.py:220 +#: changelog.py:231 msgid "" "* when a tweet is deleted in twitter, TWBlue should reflect this change and " "delete that tweet in every buffer it is displayed." @@ -1622,7 +1737,7 @@ msgstr "" "* Cuando se elimina un tuit, TWBlue debería reflejar el cambio y eliminar el " "tuit de todos los buffers donde se muestra." -#: changelog.py:221 +#: changelog.py:232 msgid "" "* If your session is broken, TWBlue will be able to remove it automatically " "instead just crashing." @@ -1630,12 +1745,12 @@ msgstr "" "* Si la configuración de una sesión ha sido dañada, TWBlue debería ser capaz " "de eliminarla y continuar en lugar de no abrirse." -#: changelog.py:222 +#: changelog.py:233 msgid "* audio uploader should display the current progress." msgstr "" "* El diálogo de carga de archivos de audio ahora muestra el progreso actual." -#: changelog.py:223 +#: changelog.py:234 msgid "" "* users can disable the check for updates feature at startup from the " "general tab, in the global settings dialogue." @@ -1643,7 +1758,7 @@ msgstr "" "* Es posible desactivar la comprobación automática de actualizaciones en el " "diálogo de opciones globales, en la pestaña General." -#: changelog.py:224 +#: changelog.py:235 msgid "" "* The invisible interface and the window should be synchronized when the " "client reconnects." @@ -1651,12 +1766,12 @@ msgstr "" "* La interfaz invisible y la ventana gráfica deben estar sincronizadas " "cuando el cliente se reconecta." -#: changelog.py:225 +#: changelog.py:236 msgid "* The documentation option in the systray icon should be enabled." msgstr "" "* La opción de documentación en la bandeja del sistema se encuentra activa." -#: changelog.py:226 +#: changelog.py:237 msgid "" "* In trending buffers, you can press enter for posting a tweet about the " "focused trend." @@ -1664,7 +1779,7 @@ msgstr "" "* En buffers de tendencias, puedes pulsar enter sobre cada tendencia para " "publicar un tuit acerca de ella." -#: changelog.py:227 +#: changelog.py:238 msgid "" "* Updated russian documentation and main program interface (thanks to " "Natalia Hedlund (Наталья Хедлунд), [@lifestar_n](https://twitter.com/" @@ -1673,19 +1788,19 @@ msgstr "" "* Actualizada la documentación e interfaz en ruso (gracias a Natalia Hedlund " "(Наталья Хедлунд), [@lifestar_n](https://twitter.com/lifestar_n) en twitter)" -#: changelog.py:228 +#: changelog.py:239 msgid "* updated translations." msgstr "* Actualizadas algunas traducciones." -#: changelog.py:230 +#: changelog.py:241 msgid "## Changes in Version 0.81" msgstr "## Cambios en la versión 0.81" -#: changelog.py:232 +#: changelog.py:243 msgid "* Updated translations" msgstr "* Traducciones actualizadas" -#: changelog.py:233 +#: changelog.py:244 msgid "" "* The updater module has received some improvements. Now it includes a " "Mirror URL for checking updates if the main URL is not available at the " @@ -1696,24 +1811,24 @@ msgstr "" "una URL con información de actualizaciones de respaldo por si la dirección " "principal no funciona." -#: changelog.py:234 +#: changelog.py:245 msgid "* some GUI elements now use keyboard shortcuts for common actions." msgstr "" "* Algunos elementos de la interfaz gráfica ahora utilizan atajos de teclado " "para acciones comunes." -#: changelog.py:235 +#: changelog.py:246 msgid "* fixed a bug in the geolocation dialog." msgstr "" "* Corregido un error en el diálogo para mostrar la información geográfica en " "Tuits." -#: changelog.py:236 +#: changelog.py:247 msgid "* the chicken nugget keymap should work properly." msgstr "" "* El mapa de teclado de chicken Nugget debería funcionar correctamente." -#: changelog.py:237 +#: changelog.py:248 msgid "" "* Added a new soundpack to the default installation of TWBlue, thanks to " "[@Deng90](https://twitter.com/deng90)" @@ -1721,11 +1836,11 @@ msgstr "" "* Se ha añadido un nuevo paquete de sonidos a la instalación predeterminada " "de TWBlue, gracias a [@Deng90](https://twitter.com/deng90)" -#: changelog.py:238 +#: changelog.py:249 msgid "* Now the changelog is written in an html File." msgstr "* La lista de cambios ahora está escrita en un archivo HTML." -#: changelog.py:239 +#: changelog.py:250 msgid "" "* Added some missed dictionaries in last version for the spell checking " "feature." @@ -1733,7 +1848,7 @@ msgstr "" "* Se han añadido algunos diccionarios al módulo de corrección ortográfica " "que no habían sido añadidos en la última versión." -#: changelog.py:240 +#: changelog.py:251 msgid "" "* Trimmed the beginnings of the sounds in the default soundpack. Thanks to " "[@masonasons](https://github.com/masonasons)" @@ -1742,7 +1857,7 @@ msgstr "" "de sonidos predeterminado. Gracias a [@masonasons](https://github.com/" "masonasons)" -#: changelog.py:241 +#: changelog.py:252 msgid "" "* Added Opus support for sound playback in TWBlue. Thanks to [@masonasons]" "(https://github.com/masonasons)" @@ -1750,7 +1865,7 @@ msgstr "" "* Añadido soporte al códec Opus en TWBlue. Gracias a [@masonasons](https://" "github.com/masonasons)" -#: changelog.py:242 +#: changelog.py:253 msgid "" "* Added a source field in view tweet dialogue. Thanks to [@masonasons]" "(https://github.com/masonasons)" @@ -1759,14 +1874,14 @@ msgstr "" "el visualizador de tuits. Gracias a [@masonasons](https://github.com/" "masonasons)" -#: changelog.py:243 +#: changelog.py:254 msgid "" "* You can load previous items in followers and friend buffers for others." msgstr "" "* Se pueden cargar más elementos en los buffers de seguidores y amigos de " "otros usuarios." -#: changelog.py:244 +#: changelog.py:255 msgid "" "* The Spell Checker dialogue should not display an error message when you " "have set \"default language\" in the global settings dialogue if your " @@ -1777,20 +1892,20 @@ msgstr "" "tu idioma se encuentra soportado. [#168](http://twblue.es/bugs/view.php?" "id=168)" -#: changelog.py:245 +#: changelog.py:256 msgid "* Updated romanian translation." msgstr "* Actualizada la traducción al rumano." -#: changelog.py:246 +#: changelog.py:257 msgid "* Some code cleanups." msgstr "* Limpieza del código." -#: changelog.py:247 +#: changelog.py:258 msgid "* The bug reports feature is fully operational again." msgstr "" "* El sistema de reporte de errores es completamente operativo de nuevo." -#: changelog.py:248 +#: changelog.py:259 msgid "" "* TWBlue should work again for users that contains special characters in " "windows usernames." @@ -1798,24 +1913,24 @@ msgstr "" "* TWBlue debería funcionar de nuevo para usuarios que contienen caracteres " "especiales en sus nombres de usuario de Windows." -#: changelog.py:249 +#: changelog.py:260 msgid "* Added more options for the tweet searches." msgstr "* Añadidas más opciones para las búsquedas en Twitter." -#: changelog.py:250 +#: changelog.py:261 msgid "* Added play_audio to the keymap editor." msgstr "* Añadida la función play_audio al editor de mapas de teclado." -#: changelog.py:251 +#: changelog.py:262 msgid "* Windows key is no longer required in the keymap editor" msgstr "" "* La tecla Windows ya no es obligatoria en el editor de mapas de teclado" -#: changelog.py:252 +#: changelog.py:263 msgid "* Switched to the Microsoft translator." msgstr "* hemos pasado a usar el servicio Microsoft translator." -#: changelog.py:253 +#: changelog.py:264 msgid "" "* You can update the current buffer by pressing ctrl+win+shift+u in the " "default keymap or in the buffer menu." @@ -1823,21 +1938,23 @@ msgstr "" "* Puedes actualizar el buffer actual pulsando ctrl+win+shift+u en la " "interfaz invisible o desde el menú buffer." -#: changelog.py:254 +#: changelog.py:265 msgid "* Changed some keystrokes in the windows 10 default keymap" msgstr "" "* Cambiados algunos atajos de teclado en el mapa de teclado de Windows 10" -#: changelog.py:255 +#: changelog.py:266 msgid "* New followers and friends buffer for user timelines." msgstr "* Nuevos buffers de amigos y seguidores para otros usuarios." -#: changelog.py:257 +#: changelog.py:268 msgid "---" msgstr "---" -#: changelog.py:258 -msgid "Copyright © 2014-2017, Manuel Cortez." +#: changelog.py:269 +#, fuzzy +#| msgid "Copyright © 2014-2017, Manuel Cortez." +msgid "Copyright © 2014-2021, Manuel Cortez." msgstr "Copyright © 2014-2017, Manuel Cortéz." #~ msgid "" diff --git a/src/locales/es/LC_MESSAGES/twblue.mo b/src/locales/es/LC_MESSAGES/twblue.mo index 6a57f84e650ac26c3934f0a4a884f79bd6af5c08..41660d8d59c96d760f0f2d4bdfc1dd408d1143f9 100644 GIT binary patch delta 19359 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 delta 17412 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 D&n251 diff --git a/src/locales/es/LC_MESSAGES/twblue.po b/src/locales/es/LC_MESSAGES/twblue.po index 452cd695..55b892fd 100644 --- a/src/locales/es/LC_MESSAGES/twblue.po +++ b/src/locales/es/LC_MESSAGES/twblue.po @@ -1,8 +1,9 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.84\n" -"POT-Creation-Date: 2021-11-01 05:25-0600\n" -"PO-Revision-Date: 2021-11-01 05:44-0600\n" +"Report-Msgid-Bugs-To: manuel@manuelcortez.net\n" +"POT-Creation-Date: 2021-11-12 13:22-0600\n" +"PO-Revision-Date: 2021-11-12 13:29-0600\n" "Last-Translator: Manuel Cortez \n" "Language-Team: Manuel Cortez \n" "Language: es\n" @@ -15,1839 +16,90 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: ../src\controller\attach.py:25 -msgid "Photo" -msgstr "Imagen" - -#: ../src\controller\buffers\base\base.py:91 -msgid "This action is not supported for this buffer" -msgstr "Esta acción no se encuentra soportada para este buffer" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:337 ../src\controller\settings.py:286 -msgid "Home" -msgstr "Inicio" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:339 ../src\controller\settings.py:287 -msgid "Mentions" -msgstr "Menciones" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:341 -msgid "Direct messages" -msgstr "Mensajes directos" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:343 ../src\controller\settings.py:289 -msgid "Sent direct messages" -msgstr "Mensajes directos enviados" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:345 ../src\controller\settings.py:290 -msgid "Sent tweets" -msgstr "Tuits enviados" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:347 -#: ../src\controller\mainController.py:1390 ../src\controller\settings.py:291 -msgid "Likes" -msgstr "Tuits marcados como me gusta" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:349 -#: ../src\controller\mainController.py:1395 ../src\controller\settings.py:292 -msgid "Followers" -msgstr "Seguidores" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:353 -#: ../src\controller\mainController.py:1405 ../src\controller\settings.py:294 -msgid "Blocked users" -msgstr "Usuarios bloqueados" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:355 -#: ../src\controller\mainController.py:1410 ../src\controller\settings.py:295 -msgid "Muted users" -msgstr "Usuarios silenciados" - -#: ../src\controller\buffers\twitter\base.py:70 -#: ../src\controller\mainController.py:1400 ../src\controller\settings.py:293 -msgid "Friends" -msgstr "Amigos" - -#: ../src\controller\buffers\twitter\base.py:76 -msgid "{username}'s timeline" -msgstr "Línea temporal de {username}" - -#: ../src\controller\buffers\twitter\base.py:78 -msgid "{username}'s likes" -msgstr "Tuits que le gustan a {username}" - -#: ../src\controller\buffers\twitter\base.py:80 -msgid "{username}'s followers" -msgstr "Seguidores de {username}" - -#: ../src\controller\buffers\twitter\base.py:82 -msgid "{username}'s friends" -msgstr "Amigos de {username}" - -#: ../src\controller\buffers\twitter\base.py:84 -msgid "Unknown buffer" -msgstr "Buffer desconocido" - -#: ../src\controller\buffers\twitter\base.py:88 -#: ../src\controller\buffers\twitter\trends.py:122 -#: ../src\controller\messages.py:214 ../src\wxUI\buffers\base.py:25 -#: ../src\wxUI\buffers\events.py:15 ../src\wxUI\buffers\trends.py:18 -#: ../src\wxUI\dialogs\message.py:304 ../src\wxUI\sysTrayIcon.py:35 -msgid "Tweet" -msgstr "Tuit" - -#: ../src\controller\buffers\twitter\base.py:89 -#: ../src\controller\buffers\twitter\trends.py:123 -msgid "Write the tweet here" -msgstr "Escribe el tuit aquí" - -#: ../src\controller\buffers\twitter\base.py:219 -msgid "New tweet in {0}" -msgstr "Nuevo tuit en {0}" - -#: ../src\controller\buffers\twitter\base.py:222 -msgid "{0} new tweets in {1}." -msgstr "{0} nuevos tuits en {1}." - -#: ../src\controller\buffers\twitter\base.py:261 -#: ../src\controller\buffers\twitter\directMessages.py:88 -#: ../src\controller\buffers\twitter\people.py:180 -msgid "%s items retrieved" -msgstr "%s elementos recuperados" - -#: ../src\controller\buffers\twitter\base.py:293 -#: ../src\controller\buffers\twitter\people.py:80 -msgid "This buffer is not a timeline; it can't be deleted." -msgstr "Este buffer no es una línea temporal. No se puede eliminar." - -#: ../src\controller\buffers\twitter\base.py:430 -msgid "Reply to {arg0}" -msgstr "Responder a {arg0}" - -#: ../src\controller\buffers\twitter\base.py:432 -#: ../src\keystrokeEditor\constants.py:11 ../src\wxUI\buffers\base.py:27 -msgid "Reply" -msgstr "Responder" - -#: ../src\controller\buffers\twitter\base.py:433 -msgid "Reply to %s" -msgstr "Responder a %s" - -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\buffers\twitter\directMessages.py:130 -msgid "New direct message" -msgstr "Nuevo mensaje directo" - -#: ../src\controller\buffers\twitter\base.py:480 -#: ../src\controller\messages.py:200 -msgid "Direct message to %s" -msgstr "Mensaje directo a %s" - -#: ../src\controller\buffers\twitter\base.py:520 -msgid "Add your comment to the tweet" -msgstr "Añade tu comentario al tuit" - -#: ../src\controller\buffers\twitter\base.py:520 -msgid "Quote" -msgstr "Citar" - -#: ../src\controller\buffers\twitter\base.py:596 -msgid "Opening URL..." -msgstr "Abriendo URL..." - -#: ../src\controller\buffers\twitter\base.py:633 -msgid "User details" -msgstr "Detalles del usuario" - -#: ../src\controller\buffers\twitter\base.py:654 -msgid "Opening item in web browser..." -msgstr "Abriendo elemento en el navegador..." - -#: ../src\controller\buffers\twitter\directMessages.py:93 -#: ../src\controller\buffers\twitter\people.py:95 -msgid "Mention to %s" -msgstr "Mencionar a %s" - -#: ../src\controller\buffers\twitter\directMessages.py:93 -#: ../src\controller\buffers\twitter\people.py:95 -#: ../src\wxUI\buffers\people.py:17 -msgid "Mention" -msgstr "Mención" - -#: ../src\controller\buffers\twitter\directMessages.py:133 -msgid "{0} new direct messages." -msgstr "{0} mensajes directos nuevos." - -#: ../src\controller\buffers\twitter\directMessages.py:136 -msgid "This action is not supported in the buffer yet." -msgstr "Esta acción todavía no se soporta en este buffer." - -#: ../src\controller\buffers\twitter\directMessages.py:146 -msgid "" -"Getting more items cannot be done in this buffer. Use the direct messages " -"buffer instead." -msgstr "" -"No se pueden obtener más elementos en este buffer. Usa el buffer de mensajes " -"directos en su lugar." - -#: ../src\controller\buffers\twitter\people.py:253 -msgid "{0} new followers." -msgstr "{0} nuevos seguidores." - -#: ../src\controller\buffers\twitter\trends.py:146 -msgid "This action is not supported in the buffer, yet." -msgstr "Esta acción todavía no se soporta en este buffer." - -#: ../src\controller\mainController.py:277 -msgid "Ready" -msgstr "Listo" - -#: ../src\controller\mainController.py:351 -msgid "Following" -msgstr "Siguiendo" - -#: ../src\controller\mainController.py:356 -msgid "Timelines" -msgstr "Líneas temporales" - -#: ../src\controller\mainController.py:359 -#: ../src\controller\mainController.py:883 -#: ../src\controller\mainController.py:1585 -msgid "Timeline for {}" -msgstr "Línea temporal de {0}" - -#: ../src\controller\mainController.py:360 -msgid "Likes timelines" -msgstr "Líneas temporales de tuits marcados con me gusta" - -#: ../src\controller\mainController.py:363 -#: ../src\controller\mainController.py:902 -#: ../src\controller\mainController.py:1587 -msgid "Likes for {}" -msgstr "Tuits que le gustan a {0}" - -#: ../src\controller\mainController.py:364 -msgid "Followers timelines" -msgstr "Líneas temporales de seguidores" - -#: ../src\controller\mainController.py:367 -#: ../src\controller\mainController.py:921 -#: ../src\controller\mainController.py:1589 -msgid "Followers for {}" -msgstr "Seguidores de {0}" - -#: ../src\controller\mainController.py:368 -msgid "Following timelines" -msgstr "Líneas temporales de siguiendo" - -#: ../src\controller\mainController.py:371 -#: ../src\controller\mainController.py:940 -#: ../src\controller\mainController.py:1591 -msgid "Friends for {}" -msgstr "Amigos de {0}" - -#: ../src\controller\mainController.py:372 ../src\wxUI\dialogs\lists.py:13 -msgid "Lists" -msgstr "Listas" - -#: ../src\controller\mainController.py:375 -#: ../src\controller\mainController.py:1422 -msgid "List for {}" -msgstr "Lista {0}" - -#: ../src\controller\mainController.py:376 -msgid "Searches" -msgstr "Búsquedas" - -#: ../src\controller\mainController.py:379 -#: ../src\controller\mainController.py:426 -#: ../src\controller\mainController.py:431 -msgid "Search for {}" -msgstr "Buscar {0}" - -#: ../src\controller\mainController.py:381 -#: ../src\controller\mainController.py:982 -#: ../src\controller\mainController.py:1593 -msgid "Trending topics for %s" -msgstr "Tendencias para %s" - -#: ../src\controller\mainController.py:448 -#: ../src\controller\mainController.py:464 -#: ../src\controller\mainController.py:1080 -#: ../src\controller\mainController.py:1099 -#: ../src\controller\mainController.py:1118 -#: ../src\controller\mainController.py:1137 -msgid "" -"No session is currently in focus. Focus a session with the next or previous " -"session shortcut." -msgstr "No estás en ninguna sesión. Cambia a una sesión activa." - -#: ../src\controller\mainController.py:452 -msgid "Empty buffer." -msgstr "Buffer vacío." - -#: ../src\controller\mainController.py:459 -msgid "{0} not found." -msgstr "{0} no encontrado." - -#: ../src\controller\mainController.py:469 -msgid "Filters cannot be applied on this buffer" -msgstr "No pueden aplicarse filtros sobre este buffer" - -#: ../src\controller\mainController.py:522 -#: ../src\controller\mainController.py:539 -#: ../src\controller\mainController.py:568 -msgid "Select the user" -msgstr "Selecciona un usuario" - -#: ../src\controller\mainController.py:753 -msgid "Add an user alias" -msgstr "Añadir alias de usuario" - -#: ../src\controller\mainController.py:761 -msgid "Alias has been set correctly for {}." -msgstr "Añadido el alias para {}" - -#: ../src\controller\mainController.py:829 ../src\controller\messages.py:245 -msgid "MMM D, YYYY. H:m" -msgstr "D MMM, YYYY. H:m" - -#: ../src\controller\mainController.py:957 -msgid "Conversation with {0}" -msgstr "Conversación con {0}" - -#: ../src\controller\mainController.py:998 -#: ../src\controller\mainController.py:1015 -msgid "There are no coordinates in this tweet" -msgstr "No hay coordenadas en este tuit" - -#: ../src\controller\mainController.py:1000 -#: ../src\controller\mainController.py:1019 -msgid "Error decoding coordinates. Try again later." -msgstr "Error decodificando las coordenadas. Inténtalo nuevamente más tarde." - -#: ../src\controller\mainController.py:1004 -msgid "Unable to find address in OpenStreetMap." -msgstr "Imposible encontrar dirección en Open Street Map." - -#: ../src\controller\mainController.py:1017 -msgid "There are no results for the coordinates in this tweet" -msgstr "No hay resultados para las coordenadas en este tuit" - -#: ../src\controller\mainController.py:1128 -#: ../src\controller\mainController.py:1147 -msgid "%s, %s of %s" -msgstr "%s, %s de %s" - -#: ../src\controller\mainController.py:1130 -#: ../src\controller\mainController.py:1149 -#: ../src\controller\mainController.py:1174 -#: ../src\controller\mainController.py:1199 -msgid "%s. Empty" -msgstr "%s. Vacío" - -#: ../src\controller\mainController.py:1162 -#: ../src\controller\mainController.py:1166 -#: ../src\controller\mainController.py:1187 -msgid "{0}: This account is not logged into Twitter." -msgstr "{0}: No has iniciado sesión con esta cuenta en Twitter." - -#: ../src\controller\mainController.py:1172 -#: ../src\controller\mainController.py:1197 -msgid "%s. %s, %s of %s" -msgstr "%s. %s, %s de %s" - -#: ../src\controller\mainController.py:1191 -msgid "{0}: This account is not logged into twitter." -msgstr "{0}: No has iniciado sesión con esta cuenta en Twitter." - -#: ../src\controller\mainController.py:1416 -msgid "This list is already opened" -msgstr "Esta lista ya ha sido abierta" - -#: ../src\controller\mainController.py:1446 -#: ../src\controller\mainController.py:1462 -msgid "" -"An error happened while trying to connect to the server. Please try later." -msgstr "" -"Ha ocurrido un error al intentar conectarse al servidor. Por favor, " -"inténtalo más tarde." - -#: ../src\controller\mainController.py:1498 -msgid "The auto-reading of new tweets is enabled for this buffer" -msgstr "La lectura automática de nuevos tuits para este buffer está activada" - -#: ../src\controller\mainController.py:1501 -msgid "The auto-reading of new tweets is disabled for this buffer" -msgstr "" -"La lectura automática de nuevos tuits para este buffer está desactivada" - -#: ../src\controller\mainController.py:1508 -msgid "Session mute on" -msgstr "Silencio de sesión activo" - -#: ../src\controller\mainController.py:1511 -msgid "Session mute off" -msgstr "Silencio de sesión desactivado" - -#: ../src\controller\mainController.py:1519 -msgid "Buffer mute on" -msgstr "Silenciar buffer, activado" - -#: ../src\controller\mainController.py:1522 -msgid "Buffer mute off" -msgstr "Silenciar buffer, desactivado" - -#: ../src\controller\mainController.py:1545 -msgid "Copied" -msgstr "Copiado" - -#: ../src\controller\mainController.py:1575 -msgid "Unable to update this buffer." -msgstr "Imposible actualizar este buffer." - -#: ../src\controller\mainController.py:1578 -msgid "Updating buffer..." -msgstr "Actualizando buffer..." - -#: ../src\controller\mainController.py:1581 -msgid "{0} items retrieved" -msgstr "{0} elementos descargados" - -#: ../src\controller\mainController.py:1600 -#: ../src\controller\mainController.py:1620 -msgid "Invalid buffer" -msgstr "Buffer inválido" - -#: ../src\controller\mainController.py:1611 -msgid "Picture {0}" -msgstr "Foto {0}" - -#: ../src\controller\mainController.py:1612 -msgid "Select the picture" -msgstr "Selecciona la foto" - -#: ../src\controller\mainController.py:1631 -msgid "Unable to extract text" -msgstr "Imposible extraer texto" - -#: ../src\controller\messages.py:56 -msgid "Translated" -msgstr "Traducido" - -#: ../src\controller\messages.py:63 -msgid "There's no URL to be shortened" -msgstr "No hay ninguna URL para acortar" - -#: ../src\controller\messages.py:67 ../src\controller\messages.py:75 -msgid "URL shortened" -msgstr "URL Acortada" - -#: ../src\controller\messages.py:82 -msgid "There's no URL to be expanded" -msgstr "No hay ninguna URL para expandir" - -#: ../src\controller\messages.py:86 ../src\controller\messages.py:94 -msgid "URL expanded" -msgstr "URL expandida" - -#: ../src\controller\messages.py:108 -msgid "%s - %s of %d characters" -msgstr "%s - %s de %d caracteres" - -#: ../src\controller\messages.py:112 -msgid "%s - %s characters" -msgstr "%s - %s caracteres" - -#: ../src\controller\messages.py:272 -msgid "View item" -msgstr "Ver elemento" - -#: ../src\controller\messages.py:301 -msgid "Link copied to clipboard." -msgstr "Enlace copiado al portapapeles" - -#: ../src\controller\settings.py:74 -msgid "HTTP" -msgstr "HTTP" - -#: ../src\controller\settings.py:74 -msgid "SOCKS v4" -msgstr "SOCKS v4" - -#: ../src\controller\settings.py:74 -msgid "SOCKS v4 with DNS support" -msgstr "SOCKS v4 con soporte DNS" - -#: ../src\controller\settings.py:74 -msgid "SOCKS v5" -msgstr "SOCKS v5" - -#: ../src\controller\settings.py:74 -msgid "SOCKS v5 with DNS support" -msgstr "SOCKS v5 con soporte DNS" - -#: ../src\controller\settings.py:74 -msgid "System default" -msgstr "Predeterminado del sistema" - -#: ../src\controller\settings.py:145 ../src\controller\settings.py:211 -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Ask" -msgstr "Preguntar" - -#: ../src\controller\settings.py:147 ../src\controller\settings.py:213 -#: ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet without comments" -msgstr "Retuitear sin comentario" - -#: ../src\controller\settings.py:149 ../src\wxUI\dialogs\configuration.py:116 -msgid "Retweet with comments" -msgstr "Retuitear añadiendo un comentario" - -#: ../src\controller\settings.py:185 -msgid "Account settings for %s" -msgstr "Opciones de la cuenta de %s" - -#: ../src\controller\settings.py:288 -msgid "Direct Messages" -msgstr "Mensajes directos" - -#: ../src\controller\user.py:29 ../src\controller\user.py:31 -#: ../src\extra\SpellChecker\wx_ui.py:80 ../src\issueReporter\wx_ui.py:84 -#: ../src\issueReporter\wx_ui.py:87 ../src\wxUI\commonMessageDialogs.py:39 -#: ../src\wxUI\commonMessageDialogs.py:51 -#: ../src\wxUI\commonMessageDialogs.py:58 -#: ../src\wxUI\commonMessageDialogs.py:61 -#: ../src\wxUI\commonMessageDialogs.py:64 -#: ../src\wxUI\commonMessageDialogs.py:67 -#: ../src\wxUI\commonMessageDialogs.py:77 -#: ../src\wxUI\commonMessageDialogs.py:80 -#: ../src\wxUI\commonMessageDialogs.py:83 -#: ../src\wxUI\commonMessageDialogs.py:89 -#: ../src\wxUI\commonMessageDialogs.py:92 -msgid "Error" -msgstr "Error" - -#: ../src\controller\user.py:29 ../src\wxUI\commonMessageDialogs.py:39 -msgid "That user does not exist" -msgstr "El usuario no existe" - -#: ../src\controller\user.py:31 -msgid "User has been suspended" -msgstr "El usuario ha sido suspendido" - -#: ../src\controller\user.py:37 -msgid "Information for %s" -msgstr "Detalles para %s" - -#: ../src\controller\user.py:67 ../src\extra\AudioUploader\audioUploader.py:127 -msgid "Discarded" -msgstr "Descartado" - -#: ../src\controller\user.py:95 -msgid "Username: @%s\n" -msgstr "Nombre de usuario: @%s\n" - -#: ../src\controller\user.py:96 -msgid "Name: %s\n" -msgstr "Nombre: %s\n" - -#: ../src\controller\user.py:98 -msgid "Location: %s\n" -msgstr "Ubicación: %s\n" - -#: ../src\controller\user.py:100 -msgid "URL: %s\n" -msgstr "URL: %s\n" - -#: ../src\controller\user.py:104 -msgid "Bio: %s\n" -msgstr "Descripción: %s\n" - -#: ../src\controller\user.py:105 ../src\controller\user.py:120 -msgid "Yes" -msgstr "Sí" - -#: ../src\controller\user.py:106 ../src\controller\user.py:121 -msgid "No" -msgstr "No" - -#: ../src\controller\user.py:107 -msgid "Protected: %s\n" -msgstr "Protegido: %s\n" - -#: ../src\controller\user.py:112 -msgid "You follow {0}. " -msgstr "Sigues a {0}. " - -#: ../src\controller\user.py:115 -msgid "{0} is following you." -msgstr "{0} te sigue." - -#: ../src\controller\user.py:119 -msgid "" -"Followers: %s\n" -" Friends: %s\n" -msgstr "" -"Seguidores: %s\n" -" Amigos: %s\n" - -#: ../src\controller\user.py:122 -msgid "Verified: %s\n" -msgstr "Verificado: %s\n" - -#: ../src\controller\user.py:123 -msgid "Tweets: %s\n" -msgstr "Tuits: %s\n" - -#: ../src\controller\user.py:124 -msgid "Likes: %s" -msgstr "Me gusta: %s" - -#: ../src\controller\userActionsController.py:74 -msgid "You can't ignore direct messages" -msgstr "No puedes ignorar los mensajes directos" - -#: ../src\controller\userAliasController.py:32 -msgid "Edit alias for {}" -msgstr "Editar alias para {}" - -#: ../src\extra\AudioUploader\audioUploader.py:57 -msgid "Attaching..." -msgstr "Adjuntando..." - -#: ../src\extra\AudioUploader\audioUploader.py:74 -msgid "Pause" -msgstr "Pausa" - -#: ../src\extra\AudioUploader\audioUploader.py:76 -msgid "&Resume" -msgstr "&Reanudar" - -#: ../src\extra\AudioUploader\audioUploader.py:77 -msgid "Resume" -msgstr "Reanudar" - -#: ../src\extra\AudioUploader\audioUploader.py:79 -#: ../src\extra\AudioUploader\audioUploader.py:106 -#: ../src\extra\AudioUploader\wx_ui.py:37 -msgid "&Pause" -msgstr "&Pausa" - -#: ../src\extra\AudioUploader\audioUploader.py:94 -#: ../src\extra\AudioUploader\audioUploader.py:140 -msgid "&Stop" -msgstr "&Detener" - -#: ../src\extra\AudioUploader\audioUploader.py:95 -msgid "Recording" -msgstr "Grabando" - -#: ../src\extra\AudioUploader\audioUploader.py:100 -#: ../src\extra\AudioUploader\audioUploader.py:151 -msgid "Stopped" -msgstr "Stopped" - -#: ../src\extra\AudioUploader\audioUploader.py:102 -#: ../src\extra\AudioUploader\wx_ui.py:39 -msgid "&Record" -msgstr "&Grabar" - -#: ../src\extra\AudioUploader\audioUploader.py:136 ../src\sound.py:148 -msgid "Playing..." -msgstr "Reproduciendo..." - -#: ../src\extra\AudioUploader\audioUploader.py:144 -#: ../src\extra\AudioUploader\audioUploader.py:154 -#: ../src\extra\AudioUploader\wx_ui.py:35 -msgid "&Play" -msgstr "&Reproducir" - -#: ../src\extra\AudioUploader\audioUploader.py:159 -msgid "Recoding audio..." -msgstr "Recodificando audio..." - -#: ../src\extra\AudioUploader\transfer.py:82 -#: ../src\extra\AudioUploader\transfer.py:88 -msgid "Error in file upload: {0}" -msgstr "Error al subir el archivo: {0}" - -#: ../src\extra\AudioUploader\utils.py:29 ../src\update\utils.py:29 -msgid "%d day, " -msgstr "%d día, " - -#: ../src\extra\AudioUploader\utils.py:31 ../src\update\utils.py:31 -msgid "%d days, " -msgstr "%d días, " - -#: ../src\extra\AudioUploader\utils.py:33 ../src\update\utils.py:33 -msgid "%d hour, " -msgstr "%d hora, " - -#: ../src\extra\AudioUploader\utils.py:35 ../src\update\utils.py:35 -msgid "%d hours, " -msgstr "%d horas, " - -#: ../src\extra\AudioUploader\utils.py:37 ../src\update\utils.py:37 -msgid "%d minute, " -msgstr "%d minuto, " - -#: ../src\extra\AudioUploader\utils.py:39 ../src\update\utils.py:39 -msgid "%d minutes, " -msgstr "%d minutos, " - -#: ../src\extra\AudioUploader\utils.py:41 ../src\update\utils.py:41 -msgid "%s second" -msgstr "%s segundo" - -#: ../src\extra\AudioUploader\utils.py:43 ../src\update\utils.py:43 -msgid "%s seconds" -msgstr "%s segundos" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:15 -msgid "File" -msgstr "Archivo" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:21 -msgid "Transferred" -msgstr "Transferido" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:26 -msgid "Total file size" -msgstr "Tamaño total del archivo" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:31 -msgid "Transfer rate" -msgstr "Velocidad de transferencia" - -#: ../src\extra\AudioUploader\wx_transfer_dialogs.py:36 -msgid "Time left" -msgstr "Tiempo restante" - -#: ../src\extra\AudioUploader\wx_ui.py:29 -msgid "Attach audio" -msgstr "Adjuntar audio" - -#: ../src\extra\AudioUploader\wx_ui.py:41 -msgid "&Add an existing file" -msgstr "&Añadir un archivo existente" - -#: ../src\extra\AudioUploader\wx_ui.py:42 -msgid "&Discard" -msgstr "&Descartar" - -#: ../src\extra\AudioUploader\wx_ui.py:44 -msgid "Upload to" -msgstr "Subir a" - -#: ../src\extra\AudioUploader\wx_ui.py:49 -msgid "Attach" -msgstr "Adjuntar" - -#: ../src\extra\AudioUploader\wx_ui.py:51 -msgid "&Cancel" -msgstr "&Cancelar" - -#: ../src\extra\AudioUploader\wx_ui.py:76 -msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" -msgstr "Archivos de audio (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" - -#: ../src\extra\AudioUploader\wx_ui.py:76 -msgid "Select the audio file to be uploaded" -msgstr "Selecciona el archivo de audio que deseas subir" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:7 -msgid "Audio tweet." -msgstr "Tuit con audio." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:8 -msgid "User timeline buffer created." -msgstr "Línea temporal de un usuario creada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:9 -msgid "Buffer destroied." -msgstr "Buffer eliminado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:10 -msgid "Direct message received." -msgstr "Mensaje directo recibido." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:11 -msgid "Direct message sent." -msgstr "Mensaje directo enviado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:12 -msgid "Error." -msgstr "Error." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:13 -msgid "Tweet liked." -msgstr "Tuit marcado como me gusta." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:14 -msgid "Likes buffer updated." -msgstr "Un Buffer de tuits marcados como me gusta se ha actualizado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:15 -msgid "Geotweet." -msgstr "Tuit con información geográfica." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:16 -msgid "Tweet contains one or more images" -msgstr "El tuit contiene una o más imágenes" - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:17 -msgid "Boundary reached." -msgstr "No hay más elementos en el buffer." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:18 -msgid "List updated." -msgstr "Lista actualizada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:19 -msgid "Too many characters." -msgstr "Demasiados caracteres." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:20 -msgid "Mention received." -msgstr "Mención recibida." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:21 -msgid "New event." -msgstr "Nuevo evento." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:22 -msgid "{0} is ready." -msgstr "{0} está listo." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:23 -msgid "Mention sent." -msgstr "Mención enviada." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:24 -msgid "Tweet retweeted." -msgstr "Tuit retuiteado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:25 -msgid "Search buffer updated." -msgstr "Buffer de búsqueda actualizado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:26 -msgid "Tweet received." -msgstr "Tuit recibido." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:27 -msgid "Tweet sent." -msgstr "Tuit enviado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:28 -msgid "Trending topics buffer updated." -msgstr "Buffer de trending topics actualizado." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:29 -msgid "New tweet in user timeline buffer." -msgstr "Nuevo tuit en línea temporal de un usuario." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:30 -msgid "New follower." -msgstr "Nuevo seguidor." - -#: ../src\extra\SoundsTutorial\soundsTutorial_constants.py:31 -msgid "Volume changed." -msgstr "Volumen modificado." - -#: ../src\extra\SoundsTutorial\wx_ui.py:9 -msgid "Sounds tutorial" -msgstr "Tutorial de sonidos" - -#: ../src\extra\SoundsTutorial\wx_ui.py:12 -msgid "Press enter to listen to the sound for the selected event" -msgstr "Pulsa enter para escuchar el sonido para el evento seleccionado" - -#: ../src\extra\SpellChecker\spellchecker.py:60 -msgid "Misspelled word: %s" -msgstr "Palabra mal escrita: %s" - -#: ../src\extra\SpellChecker\wx_ui.py:28 -msgid "Misspelled word" -msgstr "Palabra mal escrita" - -#: ../src\extra\SpellChecker\wx_ui.py:33 -msgid "Context" -msgstr "Contexto" - -#: ../src\extra\SpellChecker\wx_ui.py:38 -msgid "Suggestions" -msgstr "Sugerencias" - -#: ../src\extra\SpellChecker\wx_ui.py:43 -msgid "&Ignore" -msgstr "&Ignorar" - -#: ../src\extra\SpellChecker\wx_ui.py:44 -msgid "I&gnore all" -msgstr "Ignorar &todo" - -#: ../src\extra\SpellChecker\wx_ui.py:45 -msgid "&Replace" -msgstr "&Reemplazar" - -#: ../src\extra\SpellChecker\wx_ui.py:46 -msgid "R&eplace all" -msgstr "R&eemplazar todo" - -#: ../src\extra\SpellChecker\wx_ui.py:47 -msgid "&Add to personal dictionary" -msgstr "Añadir al &diccionario" - -#: ../src\extra\SpellChecker\wx_ui.py:80 -msgid "" -"An error has occurred. There are no dictionaries available for the selected " -"language in {0}" -msgstr "" -"Ha ocurrido un error. No se encuentran diccionarios disponibles para el " -"idioma seleccionado en {0}." - -#: ../src\extra\SpellChecker\wx_ui.py:83 -msgid "Spell check complete." -msgstr "Corrección ortográfica finalizada." - -#: ../src\extra\autocompletionUsers\completion.py:20 -#: ../src\extra\autocompletionUsers\completion.py:38 -msgid "You have to start writing" -msgstr "Tienes que empezar a escribir" - -#: ../src\extra\autocompletionUsers\completion.py:30 -#: ../src\extra\autocompletionUsers\completion.py:47 -msgid "There are no results in your users database" -msgstr "No hay resultados en tu base de datos de usuarios" - -#: ../src\extra\autocompletionUsers\completion.py:32 -msgid "Autocompletion only works for users." -msgstr "El autocompletado solo funciona con usuarios." - -#: ../src\extra\autocompletionUsers\settings.py:25 -msgid "" -"Updating database... You can close this window now. A message will tell you " -"when the process finishes." -msgstr "" -"Actualizando base de datos... Puedes cerrar esta ventana ahora. Un mensaje " -"te informará cuando el proceso haya terminado." - -#: ../src\extra\autocompletionUsers\wx_manage.py:9 -msgid "Manage Autocompletion database" -msgstr "Gestionar la base de datos del autocompletado de usuarios" - -#: ../src\extra\autocompletionUsers\wx_manage.py:12 -msgid "Editing {0} users database" -msgstr "Editando la base de datos de usuarios de {0}" - -#: ../src\extra\autocompletionUsers\wx_manage.py:13 -msgid "Username" -msgstr "Nombre de usuario" - -#: ../src\extra\autocompletionUsers\wx_manage.py:13 -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Name" -msgstr "Nombre" - -#: ../src\extra\autocompletionUsers\wx_manage.py:16 -msgid "Add user" -msgstr "Añadir usuario" - -#: ../src\extra\autocompletionUsers\wx_manage.py:17 -msgid "Remove user" -msgstr "Quitar usuario" - -#: ../src\extra\autocompletionUsers\wx_manage.py:38 -msgid "Add user to database" -msgstr "Añadir usuario a la base de datos" - -#: ../src\extra\autocompletionUsers\wx_manage.py:38 -msgid "Twitter username" -msgstr "Nombre de usuario de Twitter" - -#: ../src\extra\autocompletionUsers\wx_manage.py:44 -msgid "The user does not exist" -msgstr "El usuario no existe" - -#: ../src\extra\autocompletionUsers\wx_manage.py:44 -#: ../src\wxUI\commonMessageDialogs.py:45 -msgid "Error!" -msgstr "¡Error!" - -#: ../src\extra\autocompletionUsers\wx_settings.py:8 -msgid "Autocomplete users' settings" -msgstr "Opciones de autocompletado de usuarios" - -#: ../src\extra\autocompletionUsers\wx_settings.py:11 -msgid "Add users from followers buffer" -msgstr "Añadir usuarios desde el buffer de seguidores" - -#: ../src\extra\autocompletionUsers\wx_settings.py:12 -msgid "Add users from friends buffer" -msgstr "Añadir usuarios desde el buffer de amigos" - -#: ../src\extra\autocompletionUsers\wx_settings.py:15 -msgid "Manage database..." -msgstr "Administrar base de datos..." - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "Done" -msgstr "¡Hecho" - -#: ../src\extra\autocompletionUsers\wx_settings.py:27 -msgid "{0}'s database of users has been updated." -msgstr "La base de datos de usuarios de {0} ha sido actualizada." - -#: ../src\extra\ocr\OCRSpace.py:7 -msgid "Detect automatically" -msgstr "Detectar automáticamente" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:41 -msgid "Danish" -msgstr "Danés" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:43 -msgid "Dutch" -msgstr "Holandés" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:44 -msgid "English" -msgstr "Inglés" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:48 -msgid "Finnish" -msgstr "Finés" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:49 -msgid "French" -msgstr "Francés" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:52 -msgid "German" -msgstr "Alemán" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:58 -msgid "Hungarian" -msgstr "Húngaro" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:63 -msgid "Italian" -msgstr "Italiano" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:64 -msgid "Japanese" -msgstr "Japonés" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:68 -msgid "Korean" -msgstr "Coreano" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:85 -msgid "Polish" -msgstr "Polaco" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:86 -msgid "Portuguese" -msgstr "Portugués" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:89 -msgid "Russian" -msgstr "Ruso" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:96 -msgid "Spanish" -msgstr "Español" - -#: ../src\extra\ocr\OCRSpace.py:7 ../src\extra\translator\translator.py:105 -msgid "Turkish" -msgstr "Turco" - -#: ../src\extra\translator\translator.py:22 -msgid "Afrikaans" -msgstr "Africano" - -#: ../src\extra\translator\translator.py:23 -msgid "Albanian" -msgstr "Albanés" - -#: ../src\extra\translator\translator.py:24 +#: languageHandler.py:61 +msgctxt "languageName" msgid "Amharic" msgstr "Amárico" -#: ../src\extra\translator\translator.py:25 -msgid "Arabic" -msgstr "Árabe" +#: languageHandler.py:62 +msgctxt "languageName" +msgid "Aragonese" +msgstr "Aragonés" -#: ../src\extra\translator\translator.py:26 -msgid "Armenian" -msgstr "Armenio" +#: languageHandler.py:63 +msgctxt "languageName" +msgid "Spanish" +msgstr "Español" -#: ../src\extra\translator\translator.py:27 -msgid "Azerbaijani" -msgstr "Acerí" +#: languageHandler.py:64 +msgctxt "languageName" +msgid "Portuguese" +msgstr "Portugués" -#: ../src\extra\translator\translator.py:28 -msgid "Basque" -msgstr "Vasco" +#: languageHandler.py:65 +msgctxt "languageName" +msgid "Russian" +msgstr "Ruso" -#: ../src\extra\translator\translator.py:29 -msgid "Belarusian" -msgstr "Bielorruso" +#: languageHandler.py:66 +msgctxt "languageName" +msgid "italian" +msgstr "Italiano" -#: ../src\extra\translator\translator.py:30 -msgid "Bengali" -msgstr "Bengalí" +#: languageHandler.py:67 +msgctxt "languageName" +msgid "Turkey" +msgstr "Turco" -#: ../src\extra\translator\translator.py:31 -msgid "Bihari" -msgstr "Bihari" - -#: ../src\extra\translator\translator.py:32 -msgid "Bulgarian" -msgstr "Búlgaro" - -#: ../src\extra\translator\translator.py:33 -msgid "Burmese" -msgstr "Birmano" - -#: ../src\extra\translator\translator.py:34 -msgid "Catalan" -msgstr "Catalán" - -#: ../src\extra\translator\translator.py:35 -msgid "Cherokee" -msgstr "Cheroqui" - -#: ../src\extra\translator\translator.py:36 -msgid "Chinese" -msgstr "Chino" - -#: ../src\extra\translator\translator.py:37 -msgid "Chinese_simplified" -msgstr "Chino simplificado" - -#: ../src\extra\translator\translator.py:38 -msgid "Chinese_traditional" -msgstr "Chino tradicional" - -#: ../src\extra\translator\translator.py:39 -msgid "Croatian" -msgstr "Croata" - -#: ../src\extra\translator\translator.py:40 -msgid "Czech" -msgstr "Checo" - -#: ../src\extra\translator\translator.py:42 -msgid "Dhivehi" -msgstr "Dhivehi" - -#: ../src\extra\translator\translator.py:45 -msgid "Esperanto" -msgstr "Esperanto" - -#: ../src\extra\translator\translator.py:46 -msgid "Estonian" -msgstr "Estonio" - -#: ../src\extra\translator\translator.py:47 -msgid "Filipino" -msgstr "Filipino" - -#: ../src\extra\translator\translator.py:50 +#: languageHandler.py:68 +msgctxt "languageName" msgid "Galician" msgstr "Gallego" -#: ../src\extra\translator\translator.py:51 -msgid "Georgian" -msgstr "Georgiano" +#: languageHandler.py:69 +msgctxt "languageName" +msgid "Catala" +msgstr "Catalán" -#: ../src\extra\translator\translator.py:53 -msgid "Greek" -msgstr "Griego" +#: languageHandler.py:70 +msgctxt "languageName" +msgid "Vasque" +msgstr "Vasco" -#: ../src\extra\translator\translator.py:54 -msgid "Guarani" -msgstr "Guaraní" +#: languageHandler.py:71 +msgctxt "languageName" +msgid "polish" +msgstr "Polaco" -#: ../src\extra\translator\translator.py:55 -msgid "Gujarati" -msgstr "Guyaratí" +#: languageHandler.py:72 +msgctxt "languageName" +msgid "Arabic" +msgstr "Árabe" -#: ../src\extra\translator\translator.py:56 -msgid "Hebrew" -msgstr "Hebreo" - -#: ../src\extra\translator\translator.py:57 -msgid "Hindi" -msgstr "Hindi" - -#: ../src\extra\translator\translator.py:59 -msgid "Icelandic" -msgstr "Islandés" - -#: ../src\extra\translator\translator.py:60 -msgid "Indonesian" -msgstr "Indonesio" - -#: ../src\extra\translator\translator.py:61 -msgid "Inuktitut" -msgstr "Inuktitut" - -#: ../src\extra\translator\translator.py:62 -msgid "Irish" -msgstr "Irlandés" - -#: ../src\extra\translator\translator.py:65 -msgid "Kannada" -msgstr "Canarés" - -#: ../src\extra\translator\translator.py:66 -msgid "Kazakh" -msgstr "Kazajo" - -#: ../src\extra\translator\translator.py:67 -msgid "Khmer" -msgstr "Camboyano" - -#: ../src\extra\translator\translator.py:69 -msgid "Kurdish" -msgstr "Kurdo" - -#: ../src\extra\translator\translator.py:70 -msgid "Kyrgyz" -msgstr "Kirguís" - -#: ../src\extra\translator\translator.py:71 -msgid "Laothian" -msgstr "Lao" - -#: ../src\extra\translator\translator.py:72 -msgid "Latvian" -msgstr "Letón" - -#: ../src\extra\translator\translator.py:73 -msgid "Lithuanian" -msgstr "Lituano" - -#: ../src\extra\translator\translator.py:74 -msgid "Macedonian" -msgstr "Macedonio" - -#: ../src\extra\translator\translator.py:75 -msgid "Malay" -msgstr "Malayo" - -#: ../src\extra\translator\translator.py:76 -msgid "Malayalam" -msgstr "Malayalam" - -#: ../src\extra\translator\translator.py:77 -msgid "Maltese" -msgstr "Maltés" - -#: ../src\extra\translator\translator.py:78 -msgid "Marathi" -msgstr "Maratí" - -#: ../src\extra\translator\translator.py:79 -msgid "Mongolian" -msgstr "Mongol" - -#: ../src\extra\translator\translator.py:80 +#: languageHandler.py:73 +msgctxt "languageName" msgid "Nepali" msgstr "Nepalí" -#: ../src\extra\translator\translator.py:81 -msgid "Norwegian" -msgstr "Noruego" - -#: ../src\extra\translator\translator.py:82 -msgid "Oriya" -msgstr "Oriya" - -#: ../src\extra\translator\translator.py:83 -msgid "Pashto" -msgstr "Pastú" - -#: ../src\extra\translator\translator.py:84 -msgid "Persian" -msgstr "Persa" - -#: ../src\extra\translator\translator.py:87 -msgid "Punjabi" -msgstr "Panyabí" - -#: ../src\extra\translator\translator.py:88 -msgid "Romanian" -msgstr "Rumano" - -#: ../src\extra\translator\translator.py:90 -msgid "Sanskrit" -msgstr "Sánscrito" - -#: ../src\extra\translator\translator.py:91 -msgid "Serbian" +#: languageHandler.py:74 +msgctxt "languageName" +msgid "Serbian (Latin)" msgstr "Serbio" -#: ../src\extra\translator\translator.py:92 -msgid "Sindhi" -msgstr "Sindhi" +#: languageHandler.py:75 +msgctxt "languageName" +msgid "Japanese" +msgstr "Japonés" -#: ../src\extra\translator\translator.py:93 -msgid "Sinhalese" -msgstr "Cingalés" - -#: ../src\extra\translator\translator.py:94 -msgid "Slovak" -msgstr "Eslovaco" - -#: ../src\extra\translator\translator.py:95 -msgid "Slovenian" -msgstr "Esloveno" - -#: ../src\extra\translator\translator.py:97 -msgid "Swahili" -msgstr "Suajili" - -#: ../src\extra\translator\translator.py:98 -msgid "Swedish" -msgstr "Sueco" - -#: ../src\extra\translator\translator.py:99 -msgid "Tajik" -msgstr "Tayiko" - -#: ../src\extra\translator\translator.py:100 -msgid "Tamil" -msgstr "Tamil" - -#: ../src\extra\translator\translator.py:101 -msgid "Tagalog" -msgstr "Tagalo" - -#: ../src\extra\translator\translator.py:102 -msgid "Telugu" -msgstr "Telugú" - -#: ../src\extra\translator\translator.py:103 -msgid "Thai" -msgstr "Tailandés" - -#: ../src\extra\translator\translator.py:104 -msgid "Tibetan" -msgstr "Tibetano" - -#: ../src\extra\translator\translator.py:106 -msgid "Ukrainian" -msgstr "Ucraniano" - -#: ../src\extra\translator\translator.py:107 -msgid "Urdu" -msgstr "Urdu" - -#: ../src\extra\translator\translator.py:108 -msgid "Uzbek" -msgstr "Uzbeco" - -#: ../src\extra\translator\translator.py:109 -msgid "Uighur" -msgstr "Uigur" - -#: ../src\extra\translator\translator.py:110 -msgid "Vietnamese" -msgstr "Vietnamita" - -#: ../src\extra\translator\translator.py:111 -msgid "Welsh" -msgstr "Galés" - -#: ../src\extra\translator\translator.py:112 -msgid "Yiddish" -msgstr "Yídish" - -#: ../src\extra\translator\wx_ui.py:29 -msgid "Translate message" -msgstr "Traducir mensaje" - -#: ../src\extra\translator\wx_ui.py:32 -msgid "Target language" -msgstr "Idioma de destino" - -#: ../src\issueReporter\issueReporter.py:32 -#: ../src\wxUI\dialogs\configuration.py:359 -#: ../src\wxUI\dialogs\configuration.py:368 -msgid "General" -msgstr "General" - -#: ../src\issueReporter\issueReporter.py:33 -msgid "always" -msgstr "siempre" - -#: ../src\issueReporter\issueReporter.py:33 -msgid "have not tried" -msgstr "no se ha intentado" - -#: ../src\issueReporter\issueReporter.py:33 -msgid "random" -msgstr "aleatoriamente" - -#: ../src\issueReporter\issueReporter.py:33 -msgid "sometimes" -msgstr "a veces" - -#: ../src\issueReporter\issueReporter.py:33 -msgid "unable to duplicate" -msgstr "imposible de reproducir" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "block" -msgstr "bloqueo" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "crash" -msgstr "fallo" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "feature" -msgstr "característica" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "major" -msgstr "mayor" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "minor" -msgstr "menor" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "text" -msgstr "texto" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "trivial" -msgstr "trivial" - -#: ../src\issueReporter\issueReporter.py:34 -msgid "tweak" -msgstr "ajuste" - -#: ../src\issueReporter\wx_ui.py:26 -msgid "Report an error" -msgstr "Reportar un error" - -#: ../src\issueReporter\wx_ui.py:29 -msgid "Select a category" -msgstr "Selecciona una categoría" - -#: ../src\issueReporter\wx_ui.py:37 -msgid "" -"Briefly describe what happened. You will be able to thoroughly explain it " -"later" -msgstr "" -"Describe en pocas palabras lo que ha pasado (después podrás profundizar)" - -#: ../src\issueReporter\wx_ui.py:46 -msgid "Here, you can describe the bug in detail" -msgstr "Aquí puedes describir el error en detalle" - -#: ../src\issueReporter\wx_ui.py:56 -msgid "how often does this bug happen?" -msgstr "¿Qué tan a menudo ocurre este error?" - -#: ../src\issueReporter\wx_ui.py:63 -msgid "Select the importance that you think this bug has" -msgstr "Selecciona la importancia que consideras que tiene este error" - -#: ../src\issueReporter\wx_ui.py:70 -msgid "" -"I know that the {0} bug system will get my Twitter username to contact me " -"and fix the bug quickly" -msgstr "" -"Sé que el sistema de errores de {0} obtendrá mi nombre de usuario de Twitter " -"para contactarme y resolver el error rápidamente" - -#: ../src\issueReporter\wx_ui.py:73 -msgid "Send report" -msgstr "Enviar reporte" - -#: ../src\issueReporter\wx_ui.py:75 ../src\wxUI\dialogs\filterDialogs.py:84 -#: ../src\wxUI\dialogs\find.py:23 -msgid "Cancel" -msgstr "Cancelar" - -#: ../src\issueReporter\wx_ui.py:84 -msgid "You must fill out both fields" -msgstr "Debes llenar ambos campos" - -#: ../src\issueReporter\wx_ui.py:87 -msgid "" -"You need to mark the checkbox to provide us your twitter username to contact " -"you if it is necessary." -msgstr "" -"Debes marcar la casilla para proporcionarnos tu nombre de usuario de Twitter " -"para poder contactarte si es necesario." - -#: ../src\issueReporter\wx_ui.py:90 -msgid "" -"Thanks for reporting this bug! In future versions, you may be able to find " -"it in the changes list. You've reported the bug number %i" -msgstr "" -"¡Gracias por reportar este error! Quizá puedas verlo entre la lista de " -"cambios de próximas versiones. Has reportado el error número %i" - -#: ../src\issueReporter\wx_ui.py:90 -msgid "reported" -msgstr "reportado" - -#: ../src\issueReporter\wx_ui.py:94 -msgid "Error while reporting" -msgstr "Error al reportar" - -#: ../src\issueReporter\wx_ui.py:94 -msgid "" -"Something unexpected occurred while trying to report the bug. Please, try " -"again later" -msgstr "" -"Algo inesperado ocurrió mientras intentábamos reportar tu error. Por favor, " -"vuelve a intentarlo más tarde" - -#: ../src\keystrokeEditor\constants.py:3 -msgid "Go up in the current buffer" -msgstr "Va arriba en la lista actual" - -#: ../src\keystrokeEditor\constants.py:4 -msgid "Go down in the current buffer" -msgstr "Va abajo en la lista actual" - -#: ../src\keystrokeEditor\constants.py:5 -msgid "Go to the previous buffer" -msgstr "Va al buffer anterior" - -#: ../src\keystrokeEditor\constants.py:6 -msgid "Go to the next buffer" -msgstr "Va al buffer siguiente" - -#: ../src\keystrokeEditor\constants.py:7 -msgid "Focus the next session" -msgstr "Ir a la siguiente sesión" - -#: ../src\keystrokeEditor\constants.py:8 -msgid "Focus the previous session" -msgstr "Va a la sesión anterior" - -#: ../src\keystrokeEditor\constants.py:9 -msgid "Show or hide the GUI" -msgstr "Muestra o esconde la interfaz gráfica" - -#: ../src\keystrokeEditor\constants.py:10 -msgid "New tweet" -msgstr "Nuevo tuit" - -#: ../src\keystrokeEditor\constants.py:12 ../src\wxUI\buffers\base.py:26 -#: ../src\wxUI\commonMessageDialogs.py:10 ../src\wxUI\dialogs\message.py:126 -msgid "Retweet" -msgstr "Retuit" - -#: ../src\keystrokeEditor\constants.py:13 -msgid "Send direct message" -msgstr "Enviar mensaje directo" - -#: ../src\keystrokeEditor\constants.py:14 -msgid "Like a tweet" -msgstr "Marcar tuit como me gusta" - -#: ../src\keystrokeEditor\constants.py:15 -msgid "Like/unlike a tweet" -msgstr "Marcar o remover tuit como me gusta" - -#: ../src\keystrokeEditor\constants.py:16 -msgid "Unlike a tweet" -msgstr "Marcar tuit como ya no me gusta" - -#: ../src\keystrokeEditor\constants.py:17 -msgid "Open the user actions dialogue" -msgstr "Abrir el diálogo de acciones" - -#: ../src\keystrokeEditor\constants.py:18 -msgid "See user details" -msgstr "Ver detalles del usuario" - -#: ../src\keystrokeEditor\constants.py:19 -msgid "Show tweet" -msgstr "Ver tuit" - -#: ../src\keystrokeEditor\constants.py:20 -msgid "Quit" -msgstr "Salir" - -#: ../src\keystrokeEditor\constants.py:21 -msgid "Open user timeline" -msgstr "Abrir línea temporal" - -#: ../src\keystrokeEditor\constants.py:22 -msgid "Destroy buffer" -msgstr "Eliminar buffer" - -#: ../src\keystrokeEditor\constants.py:23 -msgid "Interact with the currently focused tweet." -msgstr "Interactuar con el tuit que tiene el foco." - -#: ../src\keystrokeEditor\constants.py:24 -msgid "Open URL" -msgstr "Abrir URL" - -#: ../src\keystrokeEditor\constants.py:25 -msgid "View in Twitter" -msgstr "Ver en Twitter" - -#: ../src\keystrokeEditor\constants.py:26 -msgid "Increase volume by 5%" -msgstr "Subir volumen en un 5%" - -#: ../src\keystrokeEditor\constants.py:27 -msgid "Decrease volume by 5%" -msgstr "Bajar volumen en un 5%" - -#: ../src\keystrokeEditor\constants.py:28 -msgid "Jump to the first element of a buffer" -msgstr "Ir al primer elemento del buffer" - -#: ../src\keystrokeEditor\constants.py:29 -msgid "Jump to the last element of the current buffer" -msgstr "Ir al último elemento del buffer" - -#: ../src\keystrokeEditor\constants.py:30 -msgid "Jump 20 elements up in the current buffer" -msgstr "Moverse 20 elementos hacia arriba en el buffer actual" - -#: ../src\keystrokeEditor\constants.py:31 -msgid "Jump 20 elements down in the current buffer" -msgstr "Moverse 20 elementos hacia abajo en el buffer actual" - -#: ../src\keystrokeEditor\constants.py:32 -msgid "Edit profile" -msgstr "Editar perfil" - -#: ../src\keystrokeEditor\constants.py:33 -msgid "Delete a tweet or direct message" -msgstr "Eliminar tuit o mensaje directo" - -#: ../src\keystrokeEditor\constants.py:34 -msgid "Empty the current buffer" -msgstr "Vaciar buffer" - -#: ../src\keystrokeEditor\constants.py:35 -msgid "Repeat last item" -msgstr "Repetir último elemento" - -#: ../src\keystrokeEditor\constants.py:36 -msgid "Copy to clipboard" -msgstr "Copiar al portapapeles" - -#: ../src\keystrokeEditor\constants.py:37 -msgid "Add to list" -msgstr "Añadir a lista" - -#: ../src\keystrokeEditor\constants.py:38 -msgid "Remove from list" -msgstr "Quitar de lista" - -#: ../src\keystrokeEditor\constants.py:39 -msgid "Mute/unmute the active buffer" -msgstr "Silenciar o des-silenciar el buffer activo" - -#: ../src\keystrokeEditor\constants.py:40 -msgid "Mute/unmute the current session" -msgstr "Activar o desactivar el silencio para la sesión activa" - -#: ../src\keystrokeEditor\constants.py:41 -msgid "toggle the automatic reading of incoming tweets in the active buffer" -msgstr "" -"conmutar entre la lectura automática de nuevos tuits para el buffer actual" - -#: ../src\keystrokeEditor\constants.py:42 -msgid "Search on twitter" -msgstr "Buscar en Twitter" - -#: ../src\keystrokeEditor\constants.py:43 -msgid "Find a string in the currently focused buffer" -msgstr "Buscar un término en el buffer actual" - -#: ../src\keystrokeEditor\constants.py:44 -msgid "Show the keystroke editor" -msgstr "Mostrar el editor de combinaciones de teclado" - -#: ../src\keystrokeEditor\constants.py:45 -msgid "Show lists for a specified user" -msgstr "Mostrar listas para un usuario específico" - -#: ../src\keystrokeEditor\constants.py:46 -msgid "load previous items" -msgstr "cargar elementos anteriores" - -#: ../src\keystrokeEditor\constants.py:47 -msgid "Get geolocation" -msgstr "Obtener ubicación" - -#: ../src\keystrokeEditor\constants.py:48 -msgid "Display the tweet's geolocation in a dialog" -msgstr "Mostrar la ubicación del tuit en un diálogo" - -#: ../src\keystrokeEditor\constants.py:49 -msgid "Create a trending topics buffer" -msgstr "Crear un buffer de tendencias" - -#: ../src\keystrokeEditor\constants.py:50 -msgid "View conversation" -msgstr "Ver conversación" - -#: ../src\keystrokeEditor\constants.py:51 -msgid "Check and download updates" -msgstr "&Comprobar y descargar actualizaciones" - -#: ../src\keystrokeEditor\constants.py:52 -msgid "" -"Opens the list manager, which allows you to create, edit, delete and open " -"lists in buffers." -msgstr "" -"Abre el gestor de listas, que permite crear, editar, eliminar y abrir listas " -"como buffers." - -#: ../src\keystrokeEditor\constants.py:53 -msgid "Opens the global settings dialogue" -msgstr "Abre el diálogo de opciones globales" - -#: ../src\keystrokeEditor\constants.py:54 -msgid "Opens the list manager" -msgstr "Abre el gestor de listas" - -#: ../src\keystrokeEditor\constants.py:55 -msgid "Opens the account settings dialogue" -msgstr "Abre el diálogo de opciones de cuenta" - -#: ../src\keystrokeEditor\constants.py:56 -msgid "Try to play an audio file" -msgstr "Intentar reproducir audio" - -#: ../src\keystrokeEditor\constants.py:57 -msgid "Updates the buffer and retrieves possible lost items there." -msgstr "Actualiza el buffer e intenta descargar los elementos perdidos." - -#: ../src\keystrokeEditor\constants.py:58 -msgid "Extracts the text from a picture and displays the result in a dialog." -msgstr "Extrae el texto de una foto y muestra el resultado en un diálogo." - -#: ../src\keystrokeEditor\constants.py:59 -msgid "Adds an alias to an user" -msgstr "Añade un alias a un usuario específico." - -#: ../src\keystrokeEditor\wx_ui.py:8 -msgid "Keystroke editor" -msgstr "Editor de combinaciones de teclado" - -#: ../src\keystrokeEditor\wx_ui.py:12 -msgid "Select a keystroke to edit" -msgstr "Selecciona una combinación de teclado para editarla" - -#: ../src\keystrokeEditor\wx_ui.py:13 -msgid "Keystroke" -msgstr "Combinación de teclado" - -#: ../src\keystrokeEditor\wx_ui.py:13 ../src\wxUI\dialogs\userActions.py:10 -#: ../src\wxUI\dialogs\userActions.py:19 ../src\wxUI\dialogs\userActions.py:20 -msgid "Action" -msgstr "Acción" - -#: ../src\keystrokeEditor\wx_ui.py:18 ../src\wxUI\dialogs\filterDialogs.py:131 -#: ../src\wxUI\dialogs\lists.py:20 ../src\wxUI\dialogs\userAliasDialogs.py:53 -msgid "Edit" -msgstr "Editar" - -#: ../src\keystrokeEditor\wx_ui.py:20 ../src\keystrokeEditor\wx_ui.py:50 -msgid "Undefine keystroke" -msgstr "Desasignar combinación de teclas" - -#: ../src\keystrokeEditor\wx_ui.py:21 -msgid "Execute action" -msgstr "Ejecutar acción" - -#: ../src\keystrokeEditor\wx_ui.py:22 ../src\wxUI\dialogs\configuration.py:396 -#: ../src\wxUI\dialogs\userAliasDialogs.py:25 ../src\wxUI\dialogs\utils.py:39 -msgid "Close" -msgstr "Cerrar" - -#: ../src\keystrokeEditor\wx_ui.py:42 -msgid "Undefined" -msgstr "Sin definir" - -#: ../src\keystrokeEditor\wx_ui.py:50 -msgid "Are you sure you want to undefine this keystroke?" -msgstr "¿Seguro que deseas desasignar esta combinación de teclado?" - -#: ../src\keystrokeEditor\wx_ui.py:54 -msgid "Editing keystroke" -msgstr "Editando combinación de teclas" - -#: ../src\keystrokeEditor\wx_ui.py:57 -msgid "Control" -msgstr "Control" - -#: ../src\keystrokeEditor\wx_ui.py:58 -msgid "Alt" -msgstr "Alt" - -#: ../src\keystrokeEditor\wx_ui.py:59 -msgid "Shift" -msgstr "Shift" - -#: ../src\keystrokeEditor\wx_ui.py:60 -msgid "Windows" -msgstr "Windows" - -#: ../src\keystrokeEditor\wx_ui.py:66 -msgid "Key" -msgstr "Tecla" - -#: ../src\keystrokeEditor\wx_ui.py:71 ../src\wxUI\dialogs\filterDialogs.py:82 -#: ../src\wxUI\dialogs\find.py:21 ../src\wxUI\dialogs\userAliasDialogs.py:23 -#: ../src\wxUI\dialogs\utils.py:36 -msgid "OK" -msgstr "Aceptar" - -#: ../src\keystrokeEditor\wx_ui.py:84 -msgid "You need to use the Windows key" -msgstr "Necesitas usar la tecla de windows" - -#: ../src\keystrokeEditor\wx_ui.py:84 ../src\keystrokeEditor\wx_ui.py:87 -msgid "Invalid keystroke" -msgstr "Combinación de teclado inválida" - -#: ../src\keystrokeEditor\wx_ui.py:87 -msgid "You must provide a character for the keystroke" -msgstr "Debes proporcionar una letra para el atajo de teclado" - -#: ../src\languageHandler.py:99 +#: languageHandler.py:99 msgid "User default" msgstr "Idioma predeterminado" -#: ../src\main.py:120 +#: main.py:120 msgid "https://twblue.es/donate" msgstr "https://twblue.es/donate" -#: ../src\main.py:137 +#: main.py:137 msgid "" "{0} is already running. Close the other instance before starting this one. " "If you're sure that {0} isn't running, try deleting the file at {1}. If " @@ -1858,43 +110,1839 @@ msgstr "" "archivo que se encuentra en {1}. Si no sabes cómo hacerlo con seguridad, " "contacta con los desarrolladores de {0}." -#: ../src\sessionmanager\wxUI.py:9 +#: extra/AudioUploader/audioUploader.py:136 sound.py:147 +msgid "Playing..." +msgstr "Reproduciendo..." + +#: sound.py:160 +msgid "Stopped." +msgstr "Detenido." + +#: controller/mainController.py:277 +msgid "Ready" +msgstr "Listo" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:337 +#: controller/settings.py:286 +msgid "Home" +msgstr "Inicio" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:339 +#: controller/settings.py:287 +msgid "Mentions" +msgstr "Menciones" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:341 +msgid "Direct messages" +msgstr "Mensajes directos" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:343 +#: controller/settings.py:289 +msgid "Sent direct messages" +msgstr "Mensajes directos enviados" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:345 +#: controller/settings.py:290 +msgid "Sent tweets" +msgstr "Tuits enviados" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:347 +#: controller/mainController.py:1390 controller/settings.py:291 +msgid "Likes" +msgstr "Tuits marcados como me gusta" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:349 +#: controller/mainController.py:1395 controller/settings.py:292 +msgid "Followers" +msgstr "Seguidores" + +#: controller/mainController.py:351 +msgid "Following" +msgstr "Siguiendo" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:353 +#: controller/mainController.py:1405 controller/settings.py:294 +msgid "Blocked users" +msgstr "Usuarios bloqueados" + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:355 +#: controller/mainController.py:1410 controller/settings.py:295 +msgid "Muted users" +msgstr "Usuarios silenciados" + +#: controller/mainController.py:356 +msgid "Timelines" +msgstr "Líneas temporales" + +#: controller/mainController.py:359 controller/mainController.py:883 +#: controller/mainController.py:1582 +msgid "Timeline for {}" +msgstr "Línea temporal de {0}" + +#: controller/mainController.py:360 +msgid "Likes timelines" +msgstr "Líneas temporales de tuits marcados con me gusta" + +#: controller/mainController.py:363 controller/mainController.py:902 +#: controller/mainController.py:1584 +msgid "Likes for {}" +msgstr "Tuits que le gustan a {0}" + +#: controller/mainController.py:364 +msgid "Followers timelines" +msgstr "Líneas temporales de seguidores" + +#: controller/mainController.py:367 controller/mainController.py:921 +#: controller/mainController.py:1586 +msgid "Followers for {}" +msgstr "Seguidores de {0}" + +#: controller/mainController.py:368 +msgid "Following timelines" +msgstr "Líneas temporales de siguiendo" + +#: controller/mainController.py:371 controller/mainController.py:940 +#: controller/mainController.py:1588 +msgid "Friends for {}" +msgstr "Amigos de {0}" + +#: controller/mainController.py:372 wxUI/dialogs/lists.py:13 +msgid "Lists" +msgstr "Listas" + +#: controller/mainController.py:375 controller/mainController.py:1422 +msgid "List for {}" +msgstr "Lista {0}" + +#: controller/mainController.py:376 +msgid "Searches" +msgstr "Búsquedas" + +#: controller/mainController.py:379 controller/mainController.py:426 +#: controller/mainController.py:431 +msgid "Search for {}" +msgstr "Buscar {0}" + +#: controller/mainController.py:381 controller/mainController.py:982 +#: controller/mainController.py:1590 +#, python-format +msgid "Trending topics for %s" +msgstr "Tendencias para %s" + +#: controller/mainController.py:448 controller/mainController.py:464 +#: controller/mainController.py:1080 controller/mainController.py:1099 +#: controller/mainController.py:1118 controller/mainController.py:1137 +msgid "" +"No session is currently in focus. Focus a session with the next or previous " +"session shortcut." +msgstr "No estás en ninguna sesión. Cambia a una sesión activa." + +#: controller/mainController.py:452 +msgid "Empty buffer." +msgstr "Buffer vacío." + +#: controller/mainController.py:459 +msgid "{0} not found." +msgstr "{0} no encontrado." + +#: controller/mainController.py:469 +msgid "Filters cannot be applied on this buffer" +msgstr "No pueden aplicarse filtros sobre este buffer" + +#: controller/mainController.py:522 controller/mainController.py:539 +#: controller/mainController.py:568 +msgid "Select the user" +msgstr "Selecciona un usuario" + +#: controller/mainController.py:753 +msgid "Add an user alias" +msgstr "Añadir alias de usuario" + +#: controller/mainController.py:761 +msgid "Alias has been set correctly for {}." +msgstr "Añadido el alias para {}" + +#: controller/mainController.py:829 controller/messages.py:327 +msgid "MMM D, YYYY. H:m" +msgstr "D MMM, YYYY. H:m" + +#: controller/mainController.py:957 +msgid "Conversation with {0}" +msgstr "Conversación con {0}" + +#: controller/mainController.py:998 controller/mainController.py:1015 +msgid "There are no coordinates in this tweet" +msgstr "No hay coordenadas en este tuit" + +#: controller/mainController.py:1000 controller/mainController.py:1019 +msgid "Error decoding coordinates. Try again later." +msgstr "Error decodificando las coordenadas. Inténtalo nuevamente más tarde." + +#: controller/mainController.py:1004 +msgid "Unable to find address in OpenStreetMap." +msgstr "Imposible encontrar dirección en Open Street Map." + +#: controller/mainController.py:1017 +msgid "There are no results for the coordinates in this tweet" +msgstr "No hay resultados para las coordenadas en este tuit" + +#: controller/mainController.py:1128 controller/mainController.py:1147 +#, python-format +msgid "%s, %s of %s" +msgstr "%s, %s de %s" + +#: controller/mainController.py:1130 controller/mainController.py:1149 +#: controller/mainController.py:1174 controller/mainController.py:1199 +#, python-format +msgid "%s. Empty" +msgstr "%s. Vacío" + +#: controller/mainController.py:1162 controller/mainController.py:1166 +#: controller/mainController.py:1187 +msgid "{0}: This account is not logged into Twitter." +msgstr "{0}: No has iniciado sesión con esta cuenta en Twitter." + +#: controller/mainController.py:1172 controller/mainController.py:1197 +#, python-format +msgid "%s. %s, %s of %s" +msgstr "%s. %s, %s de %s" + +#: controller/mainController.py:1191 +msgid "{0}: This account is not logged into twitter." +msgstr "{0}: No has iniciado sesión con esta cuenta en Twitter." + +#: controller/buffers/twitter/base.py:70 controller/mainController.py:1400 +#: controller/settings.py:293 +msgid "Friends" +msgstr "Amigos" + +#: controller/mainController.py:1416 +msgid "This list is already opened" +msgstr "Esta lista ya ha sido abierta" + +#: controller/mainController.py:1446 controller/mainController.py:1462 +msgid "" +"An error happened while trying to connect to the server. Please try later." +msgstr "" +"Ha ocurrido un error al intentar conectarse al servidor. Por favor, " +"inténtalo más tarde." + +#: controller/mainController.py:1498 +msgid "The auto-reading of new tweets is enabled for this buffer" +msgstr "La lectura automática de nuevos tuits para este buffer está activada" + +#: controller/mainController.py:1501 +msgid "The auto-reading of new tweets is disabled for this buffer" +msgstr "" +"La lectura automática de nuevos tuits para este buffer está desactivada" + +#: controller/mainController.py:1508 +msgid "Session mute on" +msgstr "Silencio de sesión activo" + +#: controller/mainController.py:1511 +msgid "Session mute off" +msgstr "Silencio de sesión desactivado" + +#: controller/mainController.py:1519 +msgid "Buffer mute on" +msgstr "Silenciar buffer, activado" + +#: controller/mainController.py:1522 +msgid "Buffer mute off" +msgstr "Silenciar buffer, desactivado" + +#: controller/mainController.py:1542 +msgid "Copied" +msgstr "Copiado" + +#: controller/mainController.py:1572 +msgid "Unable to update this buffer." +msgstr "Imposible actualizar este buffer." + +#: controller/mainController.py:1575 +msgid "Updating buffer..." +msgstr "Actualizando buffer..." + +#: controller/mainController.py:1578 +msgid "{0} items retrieved" +msgstr "{0} elementos descargados" + +#: controller/mainController.py:1597 controller/mainController.py:1617 +msgid "Invalid buffer" +msgstr "Buffer inválido" + +#: controller/mainController.py:1608 +msgid "Picture {0}" +msgstr "Foto {0}" + +#: controller/mainController.py:1609 +msgid "Select the picture" +msgstr "Selecciona la foto" + +#: controller/mainController.py:1628 +msgid "Unable to extract text" +msgstr "Imposible extraer texto" + +#: controller/messages.py:49 +msgid "Translated" +msgstr "Traducido" + +#: controller/messages.py:56 +#, python-format +msgid "%s - %s of %d characters" +msgstr "%s - %s de %d caracteres" + +#: controller/buffers/twitter/base.py:428 controller/messages.py:268 +#, python-format +msgid "Direct message to %s" +msgstr "Mensaje directo a %s" + +#: controller/buffers/twitter/base.py:87 +#: controller/buffers/twitter/trends.py:43 +#: controller/buffers/twitter/trends.py:134 controller/messages.py:296 +#: wxUI/buffers/base.py:25 wxUI/buffers/events.py:15 wxUI/buffers/trends.py:18 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:309 wxUI/sysTrayIcon.py:35 +msgid "Tweet" +msgstr "Tuit" + +#: controller/messages.py:354 +msgid "View item" +msgstr "Ver elemento" + +#: controller/messages.py:379 +msgid "Link copied to clipboard." +msgstr "Enlace copiado al portapapeles" + +#: controller/settings.py:74 +msgid "System default" +msgstr "Predeterminado del sistema" + +#: controller/settings.py:74 +msgid "HTTP" +msgstr "HTTP" + +#: controller/settings.py:74 +msgid "SOCKS v4" +msgstr "SOCKS v4" + +#: controller/settings.py:74 +msgid "SOCKS v4 with DNS support" +msgstr "SOCKS v4 con soporte DNS" + +#: controller/settings.py:74 +msgid "SOCKS v5" +msgstr "SOCKS v5" + +#: controller/settings.py:74 +msgid "SOCKS v5 with DNS support" +msgstr "SOCKS v5 con soporte DNS" + +#: controller/settings.py:145 controller/settings.py:211 +#: wxUI/dialogs/configuration.py:116 +msgid "Ask" +msgstr "Preguntar" + +#: controller/settings.py:147 controller/settings.py:213 +#: wxUI/dialogs/configuration.py:116 +msgid "Retweet without comments" +msgstr "Retuitear sin comentario" + +#: controller/settings.py:149 wxUI/dialogs/configuration.py:116 +msgid "Retweet with comments" +msgstr "Retuitear añadiendo un comentario" + +#: controller/settings.py:185 +#, python-format +msgid "Account settings for %s" +msgstr "Opciones de la cuenta de %s" + +#: controller/settings.py:288 +msgid "Direct Messages" +msgstr "Mensajes directos" + +#: controller/user.py:29 wxUI/commonMessageDialogs.py:39 +msgid "That user does not exist" +msgstr "El usuario no existe" + +#: controller/user.py:29 controller/user.py:31 extra/SpellChecker/wx_ui.py:80 +#: issueReporter/wx_ui.py:84 issueReporter/wx_ui.py:87 +#: wxUI/commonMessageDialogs.py:39 wxUI/commonMessageDialogs.py:51 +#: wxUI/commonMessageDialogs.py:58 wxUI/commonMessageDialogs.py:61 +#: wxUI/commonMessageDialogs.py:64 wxUI/commonMessageDialogs.py:67 +#: wxUI/commonMessageDialogs.py:77 wxUI/commonMessageDialogs.py:80 +#: wxUI/commonMessageDialogs.py:83 wxUI/commonMessageDialogs.py:89 +#: wxUI/commonMessageDialogs.py:92 +msgid "Error" +msgstr "Error" + +#: controller/user.py:31 +msgid "User has been suspended" +msgstr "El usuario ha sido suspendido" + +#: controller/user.py:37 +#, python-format +msgid "Information for %s" +msgstr "Detalles para %s" + +#: controller/user.py:67 extra/AudioUploader/audioUploader.py:127 +msgid "Discarded" +msgstr "Descartado" + +#: controller/user.py:95 +#, python-format +msgid "Username: @%s\n" +msgstr "Nombre de usuario: @%s\n" + +#: controller/user.py:96 +#, python-format +msgid "Name: %s\n" +msgstr "Nombre: %s\n" + +#: controller/user.py:98 +#, python-format +msgid "Location: %s\n" +msgstr "Ubicación: %s\n" + +#: controller/user.py:100 +#, python-format +msgid "URL: %s\n" +msgstr "URL: %s\n" + +#: controller/user.py:104 +#, python-format +msgid "Bio: %s\n" +msgstr "Descripción: %s\n" + +#: controller/user.py:105 controller/user.py:120 +msgid "Yes" +msgstr "Sí" + +#: controller/user.py:106 controller/user.py:121 +msgid "No" +msgstr "No" + +#: controller/user.py:107 +#, python-format +msgid "Protected: %s\n" +msgstr "Protegido: %s\n" + +#: controller/user.py:112 +msgid "You follow {0}. " +msgstr "Sigues a {0}. " + +#: controller/user.py:115 +msgid "{0} is following you." +msgstr "{0} te sigue." + +#: controller/user.py:119 +#, python-format +msgid "" +"Followers: %s\n" +" Friends: %s\n" +msgstr "" +"Seguidores: %s\n" +" Amigos: %s\n" + +#: controller/user.py:122 +#, python-format +msgid "Verified: %s\n" +msgstr "Verificado: %s\n" + +#: controller/user.py:123 +#, python-format +msgid "Tweets: %s\n" +msgstr "Tuits: %s\n" + +#: controller/user.py:124 +#, python-format +msgid "Likes: %s" +msgstr "Me gusta: %s" + +#: controller/userActionsController.py:74 +msgid "You can't ignore direct messages" +msgstr "No puedes ignorar los mensajes directos" + +#: controller/userAliasController.py:32 +msgid "Edit alias for {}" +msgstr "Editar alias para {}" + +#: controller/buffers/base/base.py:91 +msgid "This action is not supported for this buffer" +msgstr "Esta acción no se encuentra soportada para este buffer" + +#: controller/buffers/twitter/base.py:76 +msgid "{username}'s timeline" +msgstr "Línea temporal de {username}" + +#: controller/buffers/twitter/base.py:78 +msgid "{username}'s likes" +msgstr "Tuits que le gustan a {username}" + +#: controller/buffers/twitter/base.py:80 +msgid "{username}'s followers" +msgstr "Seguidores de {username}" + +#: controller/buffers/twitter/base.py:82 +msgid "{username}'s friends" +msgstr "Amigos de {username}" + +#: controller/buffers/twitter/base.py:84 +msgid "Unknown buffer" +msgstr "Buffer desconocido" + +#: controller/buffers/twitter/base.py:88 +#: controller/buffers/twitter/trends.py:44 +#: controller/buffers/twitter/trends.py:135 +msgid "Write the tweet here" +msgstr "Escribe el tuit aquí" + +#: controller/buffers/twitter/base.py:192 +msgid "New tweet in {0}" +msgstr "Nuevo tuit en {0}" + +#: controller/buffers/twitter/base.py:195 +msgid "{0} new tweets in {1}." +msgstr "{0} nuevos tuits en {1}." + +#: controller/buffers/twitter/base.py:234 +#: controller/buffers/twitter/directMessages.py:88 +#: controller/buffers/twitter/people.py:174 +#, python-format +msgid "%s items retrieved" +msgstr "%s elementos recuperados" + +#: controller/buffers/twitter/base.py:266 +#: controller/buffers/twitter/people.py:80 +msgid "This buffer is not a timeline; it can't be deleted." +msgstr "Este buffer no es una línea temporal. No se puede eliminar." + +#: controller/buffers/twitter/base.py:402 +msgid "Reply to {arg0}" +msgstr "Responder a {arg0}" + +#: controller/buffers/twitter/base.py:404 keystrokeEditor/constants.py:11 +#: wxUI/buffers/base.py:27 +msgid "Reply" +msgstr "Responder" + +#: controller/buffers/twitter/base.py:405 +#, python-format +msgid "Reply to %s" +msgstr "Responder a %s" + +#: controller/buffers/twitter/base.py:428 +#: controller/buffers/twitter/directMessages.py:124 +msgid "New direct message" +msgstr "Nuevo mensaje directo" + +#: controller/buffers/twitter/base.py:459 +msgid "Quote" +msgstr "Citar" + +#: controller/buffers/twitter/base.py:459 +msgid "Add your comment to the tweet" +msgstr "Añade tu comentario al tuit" + +#: controller/buffers/twitter/base.py:520 +msgid "Opening URL..." +msgstr "Abriendo URL..." + +#: controller/buffers/twitter/base.py:557 +msgid "User details" +msgstr "Detalles del usuario" + +#: controller/buffers/twitter/base.py:578 +msgid "Opening item in web browser..." +msgstr "Abriendo elemento en el navegador..." + +#: controller/buffers/twitter/directMessages.py:93 +#: controller/buffers/twitter/people.py:95 wxUI/buffers/people.py:17 +msgid "Mention" +msgstr "Mención" + +#: controller/buffers/twitter/directMessages.py:93 +#: controller/buffers/twitter/people.py:95 +#, python-format +msgid "Mention to %s" +msgstr "Mencionar a %s" + +#: controller/buffers/twitter/directMessages.py:127 +msgid "{0} new direct messages." +msgstr "{0} mensajes directos nuevos." + +#: controller/buffers/twitter/directMessages.py:130 +msgid "This action is not supported in the buffer yet." +msgstr "Esta acción todavía no se soporta en este buffer." + +#: controller/buffers/twitter/directMessages.py:140 +msgid "" +"Getting more items cannot be done in this buffer. Use the direct messages " +"buffer instead." +msgstr "" +"No se pueden obtener más elementos en este buffer. Usa el buffer de mensajes " +"directos en su lugar." + +#: controller/buffers/twitter/people.py:247 +msgid "{0} new followers." +msgstr "{0} nuevos seguidores." + +#: controller/buffers/twitter/trends.py:150 +msgid "This action is not supported in the buffer, yet." +msgstr "Esta acción todavía no se soporta en este buffer." + +#: extra/AudioUploader/audioUploader.py:57 +msgid "Attaching..." +msgstr "Adjuntando..." + +#: extra/AudioUploader/audioUploader.py:74 +msgid "Pause" +msgstr "Pausa" + +#: extra/AudioUploader/audioUploader.py:76 +msgid "&Resume" +msgstr "&Reanudar" + +#: extra/AudioUploader/audioUploader.py:77 +msgid "Resume" +msgstr "Reanudar" + +#: extra/AudioUploader/audioUploader.py:79 +#: extra/AudioUploader/audioUploader.py:106 extra/AudioUploader/wx_ui.py:37 +msgid "&Pause" +msgstr "&Pausa" + +#: extra/AudioUploader/audioUploader.py:94 +#: extra/AudioUploader/audioUploader.py:140 +msgid "&Stop" +msgstr "&Detener" + +#: extra/AudioUploader/audioUploader.py:95 +msgid "Recording" +msgstr "Grabando" + +#: extra/AudioUploader/audioUploader.py:100 +#: extra/AudioUploader/audioUploader.py:151 +msgid "Stopped" +msgstr "Stopped" + +#: extra/AudioUploader/audioUploader.py:102 extra/AudioUploader/wx_ui.py:39 +msgid "&Record" +msgstr "&Grabar" + +#: extra/AudioUploader/audioUploader.py:144 +#: extra/AudioUploader/audioUploader.py:154 extra/AudioUploader/wx_ui.py:35 +msgid "&Play" +msgstr "&Reproducir" + +#: extra/AudioUploader/audioUploader.py:159 +msgid "Recoding audio..." +msgstr "Recodificando audio..." + +#: extra/AudioUploader/transfer.py:82 extra/AudioUploader/transfer.py:88 +msgid "Error in file upload: {0}" +msgstr "Error al subir el archivo: {0}" + +#: extra/AudioUploader/utils.py:29 update/utils.py:29 +#, python-format +msgid "%d day, " +msgstr "%d día, " + +#: extra/AudioUploader/utils.py:31 update/utils.py:31 +#, python-format +msgid "%d days, " +msgstr "%d días, " + +#: extra/AudioUploader/utils.py:33 update/utils.py:33 +#, python-format +msgid "%d hour, " +msgstr "%d hora, " + +#: extra/AudioUploader/utils.py:35 update/utils.py:35 +#, python-format +msgid "%d hours, " +msgstr "%d horas, " + +#: extra/AudioUploader/utils.py:37 update/utils.py:37 +#, python-format +msgid "%d minute, " +msgstr "%d minuto, " + +#: extra/AudioUploader/utils.py:39 update/utils.py:39 +#, python-format +msgid "%d minutes, " +msgstr "%d minutos, " + +#: extra/AudioUploader/utils.py:41 update/utils.py:41 +#, python-format +msgid "%s second" +msgstr "%s segundo" + +#: extra/AudioUploader/utils.py:43 update/utils.py:43 +#, python-format +msgid "%s seconds" +msgstr "%s segundos" + +#: extra/AudioUploader/wx_transfer_dialogs.py:15 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:35 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:171 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:255 +msgid "File" +msgstr "Archivo" + +#: extra/AudioUploader/wx_transfer_dialogs.py:21 +msgid "Transferred" +msgstr "Transferido" + +#: extra/AudioUploader/wx_transfer_dialogs.py:26 +msgid "Total file size" +msgstr "Tamaño total del archivo" + +#: extra/AudioUploader/wx_transfer_dialogs.py:31 +msgid "Transfer rate" +msgstr "Velocidad de transferencia" + +#: extra/AudioUploader/wx_transfer_dialogs.py:36 +msgid "Time left" +msgstr "Tiempo restante" + +#: extra/AudioUploader/wx_ui.py:29 +msgid "Attach audio" +msgstr "Adjuntar audio" + +#: extra/AudioUploader/wx_ui.py:41 +msgid "&Add an existing file" +msgstr "&Añadir un archivo existente" + +#: extra/AudioUploader/wx_ui.py:42 +msgid "&Discard" +msgstr "&Descartar" + +#: extra/AudioUploader/wx_ui.py:44 +msgid "Upload to" +msgstr "Subir a" + +#: extra/AudioUploader/wx_ui.py:49 +msgid "Attach" +msgstr "Adjuntar" + +#: extra/AudioUploader/wx_ui.py:51 +msgid "&Cancel" +msgstr "&Cancelar" + +#: extra/AudioUploader/wx_ui.py:76 +msgid "Select the audio file to be uploaded" +msgstr "Selecciona el archivo de audio que deseas subir" + +#: extra/AudioUploader/wx_ui.py:76 +msgid "Audio Files (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" +msgstr "Archivos de audio (*.mp3, *.ogg, *.wav)|*.mp3; *.ogg; *.wav" + +#: extra/SoundsTutorial/soundsTutorial_constants.py:7 +msgid "Audio tweet." +msgstr "Tuit con audio." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:8 +msgid "User timeline buffer created." +msgstr "Línea temporal de un usuario creada." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:9 +msgid "Buffer destroied." +msgstr "Buffer eliminado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:10 +msgid "Direct message received." +msgstr "Mensaje directo recibido." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:11 +msgid "Direct message sent." +msgstr "Mensaje directo enviado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:12 +msgid "Error." +msgstr "Error." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:13 +msgid "Tweet liked." +msgstr "Tuit marcado como me gusta." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:14 +msgid "Likes buffer updated." +msgstr "Un Buffer de tuits marcados como me gusta se ha actualizado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:15 +msgid "Geotweet." +msgstr "Tuit con información geográfica." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:16 +msgid "Tweet contains one or more images" +msgstr "El tuit contiene una o más imágenes" + +#: extra/SoundsTutorial/soundsTutorial_constants.py:17 +msgid "Boundary reached." +msgstr "No hay más elementos en el buffer." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:18 +msgid "List updated." +msgstr "Lista actualizada." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:19 +msgid "Too many characters." +msgstr "Demasiados caracteres." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:20 +msgid "Mention received." +msgstr "Mención recibida." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:21 +msgid "New event." +msgstr "Nuevo evento." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:22 +msgid "{0} is ready." +msgstr "{0} está listo." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:23 +msgid "Mention sent." +msgstr "Mención enviada." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:24 +msgid "Tweet retweeted." +msgstr "Tuit retuiteado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:25 +msgid "Search buffer updated." +msgstr "Buffer de búsqueda actualizado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:26 +msgid "Tweet received." +msgstr "Tuit recibido." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:27 +msgid "Tweet sent." +msgstr "Tuit enviado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:28 +msgid "Trending topics buffer updated." +msgstr "Buffer de trending topics actualizado." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:29 +msgid "New tweet in user timeline buffer." +msgstr "Nuevo tuit en línea temporal de un usuario." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:30 +msgid "New follower." +msgstr "Nuevo seguidor." + +#: extra/SoundsTutorial/soundsTutorial_constants.py:31 +msgid "Volume changed." +msgstr "Volumen modificado." + +#: extra/SoundsTutorial/wx_ui.py:9 +msgid "Sounds tutorial" +msgstr "Tutorial de sonidos" + +#: extra/SoundsTutorial/wx_ui.py:12 +msgid "Press enter to listen to the sound for the selected event" +msgstr "Pulsa enter para escuchar el sonido para el evento seleccionado" + +#: extra/SpellChecker/spellchecker.py:60 +#, python-format +msgid "Misspelled word: %s" +msgstr "Palabra mal escrita: %s" + +#: extra/SpellChecker/wx_ui.py:28 +msgid "Misspelled word" +msgstr "Palabra mal escrita" + +#: extra/SpellChecker/wx_ui.py:33 +msgid "Context" +msgstr "Contexto" + +#: extra/SpellChecker/wx_ui.py:38 +msgid "Suggestions" +msgstr "Sugerencias" + +#: extra/SpellChecker/wx_ui.py:43 +msgid "&Ignore" +msgstr "&Ignorar" + +#: extra/SpellChecker/wx_ui.py:44 +msgid "I&gnore all" +msgstr "Ignorar &todo" + +#: extra/SpellChecker/wx_ui.py:45 +msgid "&Replace" +msgstr "&Reemplazar" + +#: extra/SpellChecker/wx_ui.py:46 +msgid "R&eplace all" +msgstr "R&eemplazar todo" + +#: extra/SpellChecker/wx_ui.py:47 +msgid "&Add to personal dictionary" +msgstr "Añadir al &diccionario" + +#: extra/SpellChecker/wx_ui.py:80 +msgid "" +"An error has occurred. There are no dictionaries available for the selected " +"language in {0}" +msgstr "" +"Ha ocurrido un error. No se encuentran diccionarios disponibles para el " +"idioma seleccionado en {0}." + +#: extra/SpellChecker/wx_ui.py:83 +msgid "Spell check complete." +msgstr "Corrección ortográfica finalizada." + +#: extra/autocompletionUsers/completion.py:20 +#: extra/autocompletionUsers/completion.py:38 +msgid "You have to start writing" +msgstr "Tienes que empezar a escribir" + +#: extra/autocompletionUsers/completion.py:30 +#: extra/autocompletionUsers/completion.py:47 +msgid "There are no results in your users database" +msgstr "No hay resultados en tu base de datos de usuarios" + +#: extra/autocompletionUsers/completion.py:32 +msgid "Autocompletion only works for users." +msgstr "El autocompletado solo funciona con usuarios." + +#: extra/autocompletionUsers/settings.py:25 +msgid "" +"Updating database... You can close this window now. A message will tell you " +"when the process finishes." +msgstr "" +"Actualizando base de datos... Puedes cerrar esta ventana ahora. Un mensaje " +"te informará cuando el proceso haya terminado." + +#: extra/autocompletionUsers/wx_manage.py:9 +msgid "Manage Autocompletion database" +msgstr "Gestionar la base de datos del autocompletado de usuarios" + +#: extra/autocompletionUsers/wx_manage.py:12 +msgid "Editing {0} users database" +msgstr "Editando la base de datos de usuarios de {0}" + +#: extra/autocompletionUsers/wx_manage.py:13 +msgid "Username" +msgstr "Nombre de usuario" + +#: extra/autocompletionUsers/wx_manage.py:13 wxUI/dialogs/configuration.py:144 +msgid "Name" +msgstr "Nombre" + +#: extra/autocompletionUsers/wx_manage.py:16 +msgid "Add user" +msgstr "Añadir usuario" + +#: extra/autocompletionUsers/wx_manage.py:17 +msgid "Remove user" +msgstr "Quitar usuario" + +#: extra/autocompletionUsers/wx_manage.py:38 +msgid "Twitter username" +msgstr "Nombre de usuario de Twitter" + +#: extra/autocompletionUsers/wx_manage.py:38 +msgid "Add user to database" +msgstr "Añadir usuario a la base de datos" + +#: extra/autocompletionUsers/wx_manage.py:44 +msgid "The user does not exist" +msgstr "El usuario no existe" + +#: extra/autocompletionUsers/wx_manage.py:44 wxUI/commonMessageDialogs.py:45 +msgid "Error!" +msgstr "¡Error!" + +#: extra/autocompletionUsers/wx_settings.py:8 +msgid "Autocomplete users' settings" +msgstr "Opciones de autocompletado de usuarios" + +#: extra/autocompletionUsers/wx_settings.py:11 +msgid "Add users from followers buffer" +msgstr "Añadir usuarios desde el buffer de seguidores" + +#: extra/autocompletionUsers/wx_settings.py:12 +msgid "Add users from friends buffer" +msgstr "Añadir usuarios desde el buffer de amigos" + +#: extra/autocompletionUsers/wx_settings.py:15 +msgid "Manage database..." +msgstr "Administrar base de datos..." + +#: extra/autocompletionUsers/wx_settings.py:27 +msgid "{0}'s database of users has been updated." +msgstr "La base de datos de usuarios de {0} ha sido actualizada." + +#: extra/autocompletionUsers/wx_settings.py:27 +msgid "Done" +msgstr "¡Hecho" + +#: extra/ocr/OCRSpace.py:7 +msgid "Detect automatically" +msgstr "Detectar automáticamente" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:41 +msgid "Danish" +msgstr "Danés" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:43 +msgid "Dutch" +msgstr "Holandés" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:44 +msgid "English" +msgstr "Inglés" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:48 +msgid "Finnish" +msgstr "Finés" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:49 +msgid "French" +msgstr "Francés" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:52 +msgid "German" +msgstr "Alemán" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:58 +msgid "Hungarian" +msgstr "Húngaro" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:68 +msgid "Korean" +msgstr "Coreano" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:63 +msgid "Italian" +msgstr "Italiano" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:64 +msgid "Japanese" +msgstr "Japonés" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:85 +msgid "Polish" +msgstr "Polaco" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:86 +msgid "Portuguese" +msgstr "Portugués" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:89 +msgid "Russian" +msgstr "Ruso" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:96 +msgid "Spanish" +msgstr "Español" + +#: extra/ocr/OCRSpace.py:7 extra/translator/translator.py:105 +msgid "Turkish" +msgstr "Turco" + +#: extra/translator/translator.py:22 +msgid "Afrikaans" +msgstr "Africano" + +#: extra/translator/translator.py:23 +msgid "Albanian" +msgstr "Albanés" + +#: extra/translator/translator.py:24 +msgid "Amharic" +msgstr "Amárico" + +#: extra/translator/translator.py:25 +msgid "Arabic" +msgstr "Árabe" + +#: extra/translator/translator.py:26 +msgid "Armenian" +msgstr "Armenio" + +#: extra/translator/translator.py:27 +msgid "Azerbaijani" +msgstr "Acerí" + +#: extra/translator/translator.py:28 +msgid "Basque" +msgstr "Vasco" + +#: extra/translator/translator.py:29 +msgid "Belarusian" +msgstr "Bielorruso" + +#: extra/translator/translator.py:30 +msgid "Bengali" +msgstr "Bengalí" + +#: extra/translator/translator.py:31 +msgid "Bihari" +msgstr "Bihari" + +#: extra/translator/translator.py:32 +msgid "Bulgarian" +msgstr "Búlgaro" + +#: extra/translator/translator.py:33 +msgid "Burmese" +msgstr "Birmano" + +#: extra/translator/translator.py:34 +msgid "Catalan" +msgstr "Catalán" + +#: extra/translator/translator.py:35 +msgid "Cherokee" +msgstr "Cheroqui" + +#: extra/translator/translator.py:36 +msgid "Chinese" +msgstr "Chino" + +#: extra/translator/translator.py:37 +msgid "Chinese_simplified" +msgstr "Chino simplificado" + +#: extra/translator/translator.py:38 +msgid "Chinese_traditional" +msgstr "Chino tradicional" + +#: extra/translator/translator.py:39 +msgid "Croatian" +msgstr "Croata" + +#: extra/translator/translator.py:40 +msgid "Czech" +msgstr "Checo" + +#: extra/translator/translator.py:42 +msgid "Dhivehi" +msgstr "Dhivehi" + +#: extra/translator/translator.py:45 +msgid "Esperanto" +msgstr "Esperanto" + +#: extra/translator/translator.py:46 +msgid "Estonian" +msgstr "Estonio" + +#: extra/translator/translator.py:47 +msgid "Filipino" +msgstr "Filipino" + +#: extra/translator/translator.py:50 +msgid "Galician" +msgstr "Gallego" + +#: extra/translator/translator.py:51 +msgid "Georgian" +msgstr "Georgiano" + +#: extra/translator/translator.py:53 +msgid "Greek" +msgstr "Griego" + +#: extra/translator/translator.py:54 +msgid "Guarani" +msgstr "Guaraní" + +#: extra/translator/translator.py:55 +msgid "Gujarati" +msgstr "Guyaratí" + +#: extra/translator/translator.py:56 +msgid "Hebrew" +msgstr "Hebreo" + +#: extra/translator/translator.py:57 +msgid "Hindi" +msgstr "Hindi" + +#: extra/translator/translator.py:59 +msgid "Icelandic" +msgstr "Islandés" + +#: extra/translator/translator.py:60 +msgid "Indonesian" +msgstr "Indonesio" + +#: extra/translator/translator.py:61 +msgid "Inuktitut" +msgstr "Inuktitut" + +#: extra/translator/translator.py:62 +msgid "Irish" +msgstr "Irlandés" + +#: extra/translator/translator.py:65 +msgid "Kannada" +msgstr "Canarés" + +#: extra/translator/translator.py:66 +msgid "Kazakh" +msgstr "Kazajo" + +#: extra/translator/translator.py:67 +msgid "Khmer" +msgstr "Camboyano" + +#: extra/translator/translator.py:69 +msgid "Kurdish" +msgstr "Kurdo" + +#: extra/translator/translator.py:70 +msgid "Kyrgyz" +msgstr "Kirguís" + +#: extra/translator/translator.py:71 +msgid "Laothian" +msgstr "Lao" + +#: extra/translator/translator.py:72 +msgid "Latvian" +msgstr "Letón" + +#: extra/translator/translator.py:73 +msgid "Lithuanian" +msgstr "Lituano" + +#: extra/translator/translator.py:74 +msgid "Macedonian" +msgstr "Macedonio" + +#: extra/translator/translator.py:75 +msgid "Malay" +msgstr "Malayo" + +#: extra/translator/translator.py:76 +msgid "Malayalam" +msgstr "Malayalam" + +#: extra/translator/translator.py:77 +msgid "Maltese" +msgstr "Maltés" + +#: extra/translator/translator.py:78 +msgid "Marathi" +msgstr "Maratí" + +#: extra/translator/translator.py:79 +msgid "Mongolian" +msgstr "Mongol" + +#: extra/translator/translator.py:80 +msgid "Nepali" +msgstr "Nepalí" + +#: extra/translator/translator.py:81 +msgid "Norwegian" +msgstr "Noruego" + +#: extra/translator/translator.py:82 +msgid "Oriya" +msgstr "Oriya" + +#: extra/translator/translator.py:83 +msgid "Pashto" +msgstr "Pastú" + +#: extra/translator/translator.py:84 +msgid "Persian" +msgstr "Persa" + +#: extra/translator/translator.py:87 +msgid "Punjabi" +msgstr "Panyabí" + +#: extra/translator/translator.py:88 +msgid "Romanian" +msgstr "Rumano" + +#: extra/translator/translator.py:90 +msgid "Sanskrit" +msgstr "Sánscrito" + +#: extra/translator/translator.py:91 +msgid "Serbian" +msgstr "Serbio" + +#: extra/translator/translator.py:92 +msgid "Sindhi" +msgstr "Sindhi" + +#: extra/translator/translator.py:93 +msgid "Sinhalese" +msgstr "Cingalés" + +#: extra/translator/translator.py:94 +msgid "Slovak" +msgstr "Eslovaco" + +#: extra/translator/translator.py:95 +msgid "Slovenian" +msgstr "Esloveno" + +#: extra/translator/translator.py:97 +msgid "Swahili" +msgstr "Suajili" + +#: extra/translator/translator.py:98 +msgid "Swedish" +msgstr "Sueco" + +#: extra/translator/translator.py:99 +msgid "Tajik" +msgstr "Tayiko" + +#: extra/translator/translator.py:100 +msgid "Tamil" +msgstr "Tamil" + +#: extra/translator/translator.py:101 +msgid "Tagalog" +msgstr "Tagalo" + +#: extra/translator/translator.py:102 +msgid "Telugu" +msgstr "Telugú" + +#: extra/translator/translator.py:103 +msgid "Thai" +msgstr "Tailandés" + +#: extra/translator/translator.py:104 +msgid "Tibetan" +msgstr "Tibetano" + +#: extra/translator/translator.py:106 +msgid "Ukrainian" +msgstr "Ucraniano" + +#: extra/translator/translator.py:107 +msgid "Urdu" +msgstr "Urdu" + +#: extra/translator/translator.py:108 +msgid "Uzbek" +msgstr "Uzbeco" + +#: extra/translator/translator.py:109 +msgid "Uighur" +msgstr "Uigur" + +#: extra/translator/translator.py:110 +msgid "Vietnamese" +msgstr "Vietnamita" + +#: extra/translator/translator.py:111 +msgid "Welsh" +msgstr "Galés" + +#: extra/translator/translator.py:112 +msgid "Yiddish" +msgstr "Yídish" + +#: extra/translator/wx_ui.py:29 +msgid "Translate message" +msgstr "Traducir mensaje" + +#: extra/translator/wx_ui.py:32 +msgid "Target language" +msgstr "Idioma de destino" + +#: issueReporter/issueReporter.py:32 wxUI/dialogs/configuration.py:359 +#: wxUI/dialogs/configuration.py:368 +msgid "General" +msgstr "General" + +#: issueReporter/issueReporter.py:33 +msgid "always" +msgstr "siempre" + +#: issueReporter/issueReporter.py:33 +msgid "sometimes" +msgstr "a veces" + +#: issueReporter/issueReporter.py:33 +msgid "random" +msgstr "aleatoriamente" + +#: issueReporter/issueReporter.py:33 +msgid "have not tried" +msgstr "no se ha intentado" + +#: issueReporter/issueReporter.py:33 +msgid "unable to duplicate" +msgstr "imposible de reproducir" + +#: issueReporter/issueReporter.py:34 +msgid "block" +msgstr "bloqueo" + +#: issueReporter/issueReporter.py:34 +msgid "crash" +msgstr "fallo" + +#: issueReporter/issueReporter.py:34 +msgid "major" +msgstr "mayor" + +#: issueReporter/issueReporter.py:34 +msgid "minor" +msgstr "menor" + +#: issueReporter/issueReporter.py:34 +msgid "tweak" +msgstr "ajuste" + +#: issueReporter/issueReporter.py:34 +msgid "text" +msgstr "texto" + +#: issueReporter/issueReporter.py:34 +msgid "trivial" +msgstr "trivial" + +#: issueReporter/issueReporter.py:34 +msgid "feature" +msgstr "característica" + +#: issueReporter/wx_ui.py:26 +msgid "Report an error" +msgstr "Reportar un error" + +#: issueReporter/wx_ui.py:29 +msgid "Select a category" +msgstr "Selecciona una categoría" + +#: issueReporter/wx_ui.py:37 +msgid "" +"Briefly describe what happened. You will be able to thoroughly explain it " +"later" +msgstr "" +"Describe en pocas palabras lo que ha pasado (después podrás profundizar)" + +#: issueReporter/wx_ui.py:46 +msgid "Here, you can describe the bug in detail" +msgstr "Aquí puedes describir el error en detalle" + +#: issueReporter/wx_ui.py:56 +msgid "how often does this bug happen?" +msgstr "¿Qué tan a menudo ocurre este error?" + +#: issueReporter/wx_ui.py:63 +msgid "Select the importance that you think this bug has" +msgstr "Selecciona la importancia que consideras que tiene este error" + +#: issueReporter/wx_ui.py:70 +msgid "" +"I know that the {0} bug system will get my Twitter username to contact me " +"and fix the bug quickly" +msgstr "" +"Sé que el sistema de errores de {0} obtendrá mi nombre de usuario de Twitter " +"para contactarme y resolver el error rápidamente" + +#: issueReporter/wx_ui.py:73 +msgid "Send report" +msgstr "Enviar reporte" + +#: issueReporter/wx_ui.py:75 wxUI/dialogs/filterDialogs.py:83 +#: wxUI/dialogs/find.py:23 +msgid "Cancel" +msgstr "Cancelar" + +#: issueReporter/wx_ui.py:84 +msgid "You must fill out both fields" +msgstr "Debes llenar ambos campos" + +#: issueReporter/wx_ui.py:87 +msgid "" +"You need to mark the checkbox to provide us your twitter username to contact " +"you if it is necessary." +msgstr "" +"Debes marcar la casilla para proporcionarnos tu nombre de usuario de Twitter " +"para poder contactarte si es necesario." + +#: issueReporter/wx_ui.py:90 +#, python-format +msgid "" +"Thanks for reporting this bug! In future versions, you may be able to find " +"it in the changes list. You've reported the bug number %i" +msgstr "" +"¡Gracias por reportar este error! Quizá puedas verlo entre la lista de " +"cambios de próximas versiones. Has reportado el error número %i" + +#: issueReporter/wx_ui.py:90 +msgid "reported" +msgstr "reportado" + +#: issueReporter/wx_ui.py:94 +msgid "" +"Something unexpected occurred while trying to report the bug. Please, try " +"again later" +msgstr "" +"Algo inesperado ocurrió mientras intentábamos reportar tu error. Por favor, " +"vuelve a intentarlo más tarde" + +#: issueReporter/wx_ui.py:94 +msgid "Error while reporting" +msgstr "Error al reportar" + +#: keystrokeEditor/constants.py:3 +msgid "Go up in the current buffer" +msgstr "Va arriba en la lista actual" + +#: keystrokeEditor/constants.py:4 +msgid "Go down in the current buffer" +msgstr "Va abajo en la lista actual" + +#: keystrokeEditor/constants.py:5 +msgid "Go to the previous buffer" +msgstr "Va al buffer anterior" + +#: keystrokeEditor/constants.py:6 +msgid "Go to the next buffer" +msgstr "Va al buffer siguiente" + +#: keystrokeEditor/constants.py:7 +msgid "Focus the next session" +msgstr "Ir a la siguiente sesión" + +#: keystrokeEditor/constants.py:8 +msgid "Focus the previous session" +msgstr "Va a la sesión anterior" + +#: keystrokeEditor/constants.py:9 +msgid "Show or hide the GUI" +msgstr "Muestra o esconde la interfaz gráfica" + +#: keystrokeEditor/constants.py:10 +msgid "New tweet" +msgstr "Nuevo tuit" + +#: keystrokeEditor/constants.py:12 wxUI/buffers/base.py:26 +#: wxUI/commonMessageDialogs.py:10 +msgid "Retweet" +msgstr "Retuit" + +#: keystrokeEditor/constants.py:13 +msgid "Send direct message" +msgstr "Enviar mensaje directo" + +#: keystrokeEditor/constants.py:14 +msgid "Like a tweet" +msgstr "Marcar tuit como me gusta" + +#: keystrokeEditor/constants.py:15 +msgid "Like/unlike a tweet" +msgstr "Marcar o remover tuit como me gusta" + +#: keystrokeEditor/constants.py:16 +msgid "Unlike a tweet" +msgstr "Marcar tuit como ya no me gusta" + +#: keystrokeEditor/constants.py:17 +msgid "Open the user actions dialogue" +msgstr "Abrir el diálogo de acciones" + +#: keystrokeEditor/constants.py:18 +msgid "See user details" +msgstr "Ver detalles del usuario" + +#: keystrokeEditor/constants.py:19 +msgid "Show tweet" +msgstr "Ver tuit" + +#: keystrokeEditor/constants.py:20 +msgid "Quit" +msgstr "Salir" + +#: keystrokeEditor/constants.py:21 +msgid "Open user timeline" +msgstr "Abrir línea temporal" + +#: keystrokeEditor/constants.py:22 +msgid "Destroy buffer" +msgstr "Eliminar buffer" + +#: keystrokeEditor/constants.py:23 +msgid "Interact with the currently focused tweet." +msgstr "Interactuar con el tuit que tiene el foco." + +#: keystrokeEditor/constants.py:24 +msgid "Open URL" +msgstr "Abrir URL" + +#: keystrokeEditor/constants.py:25 +msgid "View in Twitter" +msgstr "Ver en Twitter" + +#: keystrokeEditor/constants.py:26 +msgid "Increase volume by 5%" +msgstr "Subir volumen en un 5%" + +#: keystrokeEditor/constants.py:27 +msgid "Decrease volume by 5%" +msgstr "Bajar volumen en un 5%" + +#: keystrokeEditor/constants.py:28 +msgid "Jump to the first element of a buffer" +msgstr "Ir al primer elemento del buffer" + +#: keystrokeEditor/constants.py:29 +msgid "Jump to the last element of the current buffer" +msgstr "Ir al último elemento del buffer" + +#: keystrokeEditor/constants.py:30 +msgid "Jump 20 elements up in the current buffer" +msgstr "Moverse 20 elementos hacia arriba en el buffer actual" + +#: keystrokeEditor/constants.py:31 +msgid "Jump 20 elements down in the current buffer" +msgstr "Moverse 20 elementos hacia abajo en el buffer actual" + +#: keystrokeEditor/constants.py:32 +msgid "Edit profile" +msgstr "Editar perfil" + +#: keystrokeEditor/constants.py:33 +msgid "Delete a tweet or direct message" +msgstr "Eliminar tuit o mensaje directo" + +#: keystrokeEditor/constants.py:34 +msgid "Empty the current buffer" +msgstr "Vaciar buffer" + +#: keystrokeEditor/constants.py:35 +msgid "Repeat last item" +msgstr "Repetir último elemento" + +#: keystrokeEditor/constants.py:36 +msgid "Copy to clipboard" +msgstr "Copiar al portapapeles" + +#: keystrokeEditor/constants.py:37 +msgid "Add to list" +msgstr "Añadir a lista" + +#: keystrokeEditor/constants.py:38 +msgid "Remove from list" +msgstr "Quitar de lista" + +#: keystrokeEditor/constants.py:39 +msgid "Mute/unmute the active buffer" +msgstr "Silenciar o des-silenciar el buffer activo" + +#: keystrokeEditor/constants.py:40 +msgid "Mute/unmute the current session" +msgstr "Activar o desactivar el silencio para la sesión activa" + +#: keystrokeEditor/constants.py:41 +msgid "toggle the automatic reading of incoming tweets in the active buffer" +msgstr "" +"conmutar entre la lectura automática de nuevos tuits para el buffer actual" + +#: keystrokeEditor/constants.py:42 +msgid "Search on twitter" +msgstr "Buscar en Twitter" + +#: keystrokeEditor/constants.py:43 +msgid "Find a string in the currently focused buffer" +msgstr "Buscar un término en el buffer actual" + +#: keystrokeEditor/constants.py:44 +msgid "Show the keystroke editor" +msgstr "Mostrar el editor de combinaciones de teclado" + +#: keystrokeEditor/constants.py:45 +msgid "Show lists for a specified user" +msgstr "Mostrar listas para un usuario específico" + +#: keystrokeEditor/constants.py:46 +msgid "load previous items" +msgstr "cargar elementos anteriores" + +#: keystrokeEditor/constants.py:47 +msgid "Get geolocation" +msgstr "Obtener ubicación" + +#: keystrokeEditor/constants.py:48 +msgid "Display the tweet's geolocation in a dialog" +msgstr "Mostrar la ubicación del tuit en un diálogo" + +#: keystrokeEditor/constants.py:49 +msgid "Create a trending topics buffer" +msgstr "Crear un buffer de tendencias" + +#: keystrokeEditor/constants.py:50 +msgid "View conversation" +msgstr "Ver conversación" + +#: keystrokeEditor/constants.py:51 +msgid "Check and download updates" +msgstr "&Comprobar y descargar actualizaciones" + +#: keystrokeEditor/constants.py:52 +msgid "" +"Opens the list manager, which allows you to create, edit, delete and open " +"lists in buffers." +msgstr "" +"Abre el gestor de listas, que permite crear, editar, eliminar y abrir listas " +"como buffers." + +#: keystrokeEditor/constants.py:53 +msgid "Opens the global settings dialogue" +msgstr "Abre el diálogo de opciones globales" + +#: keystrokeEditor/constants.py:54 +msgid "Opens the list manager" +msgstr "Abre el gestor de listas" + +#: keystrokeEditor/constants.py:55 +msgid "Opens the account settings dialogue" +msgstr "Abre el diálogo de opciones de cuenta" + +#: keystrokeEditor/constants.py:56 +msgid "Try to play an audio file" +msgstr "Intentar reproducir audio" + +#: keystrokeEditor/constants.py:57 +msgid "Updates the buffer and retrieves possible lost items there." +msgstr "Actualiza el buffer e intenta descargar los elementos perdidos." + +#: keystrokeEditor/constants.py:58 +msgid "Extracts the text from a picture and displays the result in a dialog." +msgstr "Extrae el texto de una foto y muestra el resultado en un diálogo." + +#: keystrokeEditor/constants.py:59 +msgid "Adds an alias to an user" +msgstr "Añade un alias a un usuario específico." + +#: keystrokeEditor/wx_ui.py:8 +msgid "Keystroke editor" +msgstr "Editor de combinaciones de teclado" + +#: keystrokeEditor/wx_ui.py:12 +msgid "Select a keystroke to edit" +msgstr "Selecciona una combinación de teclado para editarla" + +#: keystrokeEditor/wx_ui.py:13 wxUI/dialogs/userActions.py:10 +#: wxUI/dialogs/userActions.py:19 wxUI/dialogs/userActions.py:20 +msgid "Action" +msgstr "Acción" + +#: keystrokeEditor/wx_ui.py:13 +msgid "Keystroke" +msgstr "Combinación de teclado" + +#: keystrokeEditor/wx_ui.py:18 wxUI/dialogs/filterDialogs.py:135 +#: wxUI/dialogs/lists.py:20 wxUI/dialogs/userAliasDialogs.py:53 +msgid "Edit" +msgstr "Editar" + +#: keystrokeEditor/wx_ui.py:20 keystrokeEditor/wx_ui.py:50 +msgid "Undefine keystroke" +msgstr "Desasignar combinación de teclas" + +#: keystrokeEditor/wx_ui.py:21 +msgid "Execute action" +msgstr "Ejecutar acción" + +#: keystrokeEditor/wx_ui.py:22 wxUI/dialogs/configuration.py:396 +#: wxUI/dialogs/userAliasDialogs.py:25 wxUI/dialogs/utils.py:39 +msgid "Close" +msgstr "Cerrar" + +#: keystrokeEditor/wx_ui.py:42 +msgid "Undefined" +msgstr "Sin definir" + +#: keystrokeEditor/wx_ui.py:50 +msgid "Are you sure you want to undefine this keystroke?" +msgstr "¿Seguro que deseas desasignar esta combinación de teclado?" + +#: keystrokeEditor/wx_ui.py:54 +msgid "Editing keystroke" +msgstr "Editando combinación de teclas" + +#: keystrokeEditor/wx_ui.py:57 +msgid "Control" +msgstr "Control" + +#: keystrokeEditor/wx_ui.py:58 +msgid "Alt" +msgstr "Alt" + +#: keystrokeEditor/wx_ui.py:59 +msgid "Shift" +msgstr "Shift" + +#: keystrokeEditor/wx_ui.py:60 +msgid "Windows" +msgstr "Windows" + +#: keystrokeEditor/wx_ui.py:66 +msgid "Key" +msgstr "Tecla" + +#: keystrokeEditor/wx_ui.py:71 wxUI/dialogs/filterDialogs.py:80 +#: wxUI/dialogs/find.py:21 wxUI/dialogs/userAliasDialogs.py:23 +#: wxUI/dialogs/utils.py:36 +msgid "OK" +msgstr "Aceptar" + +#: keystrokeEditor/wx_ui.py:84 +msgid "You need to use the Windows key" +msgstr "Necesitas usar la tecla de windows" + +#: keystrokeEditor/wx_ui.py:84 keystrokeEditor/wx_ui.py:87 +msgid "Invalid keystroke" +msgstr "Combinación de teclado inválida" + +#: keystrokeEditor/wx_ui.py:87 +msgid "You must provide a character for the keystroke" +msgstr "Debes proporcionar una letra para el atajo de teclado" + +#: sessionmanager/wxUI.py:9 msgid "Session manager" msgstr "Gestor de sesiones" -#: ../src\sessionmanager\wxUI.py:12 +#: sessionmanager/wxUI.py:12 msgid "Accounts list" msgstr "Lista de cuentas" -#: ../src\sessionmanager\wxUI.py:14 +#: sessionmanager/wxUI.py:14 msgid "Account" msgstr "Cuenta" -#: ../src\sessionmanager\wxUI.py:18 +#: sessionmanager/wxUI.py:18 msgid "New account" msgstr "Nueva cuenta" -#: ../src\sessionmanager\wxUI.py:19 ../src\sessionmanager\wxUI.py:65 +#: sessionmanager/wxUI.py:19 sessionmanager/wxUI.py:65 msgid "Remove account" msgstr "Eliminar cuenta" -#: ../src\sessionmanager\wxUI.py:20 +#: sessionmanager/wxUI.py:20 msgid "Global Settings" msgstr "Opciones globales" -#: ../src\sessionmanager\wxUI.py:43 -msgid "Account Error" -msgstr "Error en la cuenta" - -#: ../src\sessionmanager\wxUI.py:43 +#: sessionmanager/wxUI.py:43 msgid "You need to configure an account." msgstr "Necesitas configurar una cuenta." -#: ../src\sessionmanager\wxUI.py:49 -msgid "Authorization" -msgstr "Autorización" +#: sessionmanager/wxUI.py:43 +msgid "Account Error" +msgstr "Error en la cuenta" -#: ../src\sessionmanager\wxUI.py:49 +#: sessionmanager/wxUI.py:49 msgid "" "The request to authorize your Twitter account will be opened in your " "browser. You only need to do this once. Would you like to continue?" @@ -1902,15 +1950,16 @@ msgstr "" "La solicitud de autorización de Twitter será abierta en tu navegador. Esto " "es necesario hacerlo solo una vez. ¿Quieres continuar?" -#: ../src\sessionmanager\wxUI.py:53 +#: sessionmanager/wxUI.py:49 +msgid "Authorization" +msgstr "Autorización" + +#: sessionmanager/wxUI.py:53 +#, python-format msgid "Authorized account %d" msgstr "Cuenta autorizada %d" -#: ../src\sessionmanager\wxUI.py:59 -msgid "Invalid user token" -msgstr "Código de acceso inválido" - -#: ../src\sessionmanager\wxUI.py:59 +#: sessionmanager/wxUI.py:59 msgid "" "Your access token is invalid or the authorization has failed. Please try " "again." @@ -1918,15 +1967,15 @@ msgstr "" "El código de autorización es inválido o el proceso ha fallado. Por favor " "inténtalo de nuevo más tarde." -#: ../src\sessionmanager\wxUI.py:65 +#: sessionmanager/wxUI.py:59 +msgid "Invalid user token" +msgstr "Código de acceso inválido" + +#: sessionmanager/wxUI.py:65 msgid "Do you really want to delete this account?" msgstr "¿Realmente deseas eliminar esta cuenta?" -#: ../src\sessionmanager\wxUI.py:81 -msgid "Authentication error for session {}" -msgstr "Error de autenticación en la sesión {}" - -#: ../src\sessionmanager\wxUI.py:81 +#: sessionmanager/wxUI.py:81 msgid "" "TWBlue is unable to authenticate the account for {} in Twitter. It might be " "due to an invalid or expired token, revoqued access to the application, or " @@ -1939,7 +1988,11 @@ msgstr "" "favor, elimina esta cuenta manualmente desde tus sesiones de Twitter en la " "aplicación para dejar de ver este mensaje." -#: ../src\sessions\base.py:113 +#: sessionmanager/wxUI.py:81 +msgid "Authentication error for session {}" +msgstr "Error de autenticación en la sesión {}" + +#: sessions/base.py:113 msgid "" "An exception occurred while saving the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1949,7 +2002,7 @@ msgstr "" "será creada desde cero automáticamente. Si este error persiste, contacta con " "los desarrolladores de {app} para obtener ayuda." -#: ../src\sessions\base.py:153 +#: sessions/base.py:153 msgid "" "An exception occurred while loading the {app} database. It will be deleted " "and rebuilt automatically. If this error persists, send the error log to the " @@ -1959,26 +2012,46 @@ msgstr "" "de datos nueva automáticamente. Si este error persiste, contacta con los " "desarrolladores de {app} para obtener ayuda." -#: ../src\sessions\twitter\compose.py:38 ../src\sessions\twitter\compose.py:81 -#: ../src\sessions\twitter\compose.py:146 -#: ../src\sessions\twitter\compose.py:155 +#: sessions/session_utils.py:231 sessions/twitter/utils.py:231 +msgid "Sorry, you are not authorised to see this status." +msgstr "Lo sentimos, no estás autorizado para ver este tuit." + +#: sessions/session_utils.py:233 sessions/twitter/utils.py:233 +msgid "No status found with that ID" +msgstr "No existe un tuit con este ID" + +#: sessions/session_utils.py:235 +msgid "Error code {0}" +msgstr "Código de error {0}" + +#: sessions/session_utils.py:262 sessions/twitter/utils.py:262 +msgid "{user_1}, {user_2} and {all_users} more: {text}" +msgstr "{user_1}, {user_2} y {all_users} más: {text}" + +#: sessions/twitter/compose.py:38 sessions/twitter/compose.py:81 +#: sessions/twitter/compose.py:146 sessions/twitter/compose.py:155 +#: sessions/twitter/templates.py:38 sessions/twitter/templates.py:81 +#: sessions/twitter/templates.py:146 sessions/twitter/templates.py:155 msgid "dddd, MMMM D, YYYY H:m:s" msgstr "dddd, MMMM D, YYYY H:m:s" -#: ../src\sessions\twitter\compose.py:89 ../src\sessions\twitter\compose.py:91 +#: sessions/twitter/compose.py:89 sessions/twitter/compose.py:91 +#: sessions/twitter/templates.py:89 sessions/twitter/templates.py:91 +#, python-format msgid "Dm to %s " msgstr "Dm a %s " -#: ../src\sessions\twitter\compose.py:130 +#: sessions/twitter/compose.py:130 sessions/twitter/templates.py:130 msgid "{0}. Quoted tweet from @{1}: {2}" msgstr "{0} citó el tuit de {1}: {2}" -#: ../src\sessions\twitter\compose.py:157 -#: ../src\sessions\twitter\compose.py:159 +#: sessions/twitter/compose.py:157 sessions/twitter/compose.py:159 +#: sessions/twitter/templates.py:157 sessions/twitter/templates.py:159 msgid "Unavailable" msgstr "No disponible" -#: ../src\sessions\twitter\compose.py:160 +#: sessions/twitter/compose.py:160 sessions/twitter/templates.py:160 +#, python-format msgid "" "%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined " "Twitter %s" @@ -1986,64 +2059,46 @@ msgstr "" "%s (@%s). %s seguidores, %s amigos, %s tuits. Último tuit %s. Se unió a " "Twitter %s" -#: ../src\sessions\twitter\compose.py:164 +#: sessions/twitter/compose.py:164 sessions/twitter/templates.py:164 msgid "No description available" msgstr "No hay una descripción disponible" -#: ../src\sessions\twitter\compose.py:168 +#: sessions/twitter/compose.py:168 sessions/twitter/templates.py:168 msgid "private" msgstr "privado" -#: ../src\sessions\twitter\compose.py:169 +#: sessions/twitter/compose.py:169 sessions/twitter/templates.py:169 msgid "public" msgstr "público" -#: ../src\sessions\twitter\session.py:211 +#: sessions/twitter/session.py:211 sessions/twitter/session.py:238 +#, python-format msgid "%s failed. Reason: %s" msgstr "%s falló. Razón: %s" -#: ../src\sessions\twitter\session.py:217 +#: sessions/twitter/session.py:217 sessions/twitter/session.py:241 +#, python-format msgid "%s succeeded." msgstr "%s con éxito." -#: ../src\sessions\twitter\session.py:426 -#: ../src\sessions\twitter\session.py:504 +#: sessions/twitter/session.py:450 sessions/twitter/session.py:528 msgid "Deleted account" msgstr "Cuenta eliminada" -#: ../src\sessions\twitter\utils.py:231 -msgid "Sorry, you are not authorised to see this status." -msgstr "Lo sentimos, no estás autorizado para ver este tuit." - -#: ../src\sessions\twitter\utils.py:233 -msgid "No status found with that ID" -msgstr "No existe un tuit con este ID" - -#: ../src\sessions\twitter\utils.py:235 +#: sessions/twitter/utils.py:235 msgid "Error {0}" msgstr "Código de error {0}" -#: ../src\sessions\twitter\utils.py:262 -msgid "{user_1}, {user_2} and {all_users} more: {text}" -msgstr "{user_1}, {user_2} y {all_users} más: {text}" - -#: ../src\sessions\twitter\wxUI.py:7 +#: sessions/twitter/wxUI.py:7 msgid "Authorising account..." msgstr "Autorizando cuenta..." -#: ../src\sessions\twitter\wxUI.py:10 +#: sessions/twitter/wxUI.py:10 msgid "Enter your PIN code here" msgstr "Introduce el código PIN aquí" -#: ../src\sound.py:161 -msgid "Stopped." -msgstr "Detenido." - -#: ../src\update\wxUpdater.py:14 -msgid "New version for %s" -msgstr "Nueva versión de %s" - -#: ../src\update\wxUpdater.py:14 +#: update/wxUpdater.py:14 +#, python-format msgid "" "There's a new %s version available, released on %s. Would you like to " "download it now?\n" @@ -2060,23 +2115,25 @@ msgstr "" "Novedades:\n" "%s" -#: ../src\update\wxUpdater.py:22 +#: update/wxUpdater.py:14 +#, python-format +msgid "New version for %s" +msgstr "Nueva versión de %s" + +#: update/wxUpdater.py:22 msgid "Download in Progress" msgstr "Descarga en progreso" -#: ../src\update\wxUpdater.py:22 +#: update/wxUpdater.py:22 msgid "Downloading the new version..." msgstr "Descargando la nueva versión..." -#: ../src\update\wxUpdater.py:32 +#: update/wxUpdater.py:32 +#, python-format msgid "Updating... %s of %s" msgstr "Actualizando... %s de %s" -#: ../src\update\wxUpdater.py:35 -msgid "Done!" -msgstr "¡Hecho!" - -#: ../src\update\wxUpdater.py:35 +#: update/wxUpdater.py:35 msgid "" "The update has been downloaded and installed successfully. Press OK to " "continue." @@ -2084,62 +2141,11 @@ msgstr "" "La actualización ha sido descargada e instalada. Presiona aceptar para " "iniciar la aplicación." -#: ../src\wxUI\buffers\base.py:12 -msgid "Client" -msgstr "Cliente" +#: update/wxUpdater.py:35 +msgid "Done!" +msgstr "¡Hecho!" -#: ../src\wxUI\buffers\base.py:12 -msgid "Text" -msgstr "Texto" - -#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\events.py:14 -msgid "Date" -msgstr "Fecha" - -#: ../src\wxUI\buffers\base.py:12 ../src\wxUI\buffers\people.py:12 -#: ../src\wxUI\buffers\user_searches.py:11 -#: ../src\wxUI\dialogs\userAliasDialogs.py:14 -#: ../src\wxUI\dialogs\userSelection.py:11 ../src\wxUI\dialogs\utils.py:32 -msgid "User" -msgstr "Usuario" - -#: ../src\wxUI\buffers\base.py:28 -msgid "Direct message" -msgstr "Mensaje directo" - -#: ../src\wxUI\buffers\events.py:14 -msgid "Event" -msgstr "Evento" - -#: ../src\wxUI\buffers\events.py:16 -msgid "Remove event" -msgstr "Eliminar evento" - -#: ../src\wxUI\buffers\panels.py:12 ../src\wxUI\buffers\panels.py:20 -msgid "Login" -msgstr "Iniciar sesión" - -#: ../src\wxUI\buffers\panels.py:14 -msgid "Log in automatically" -msgstr "Iniciar sesión automáticamente" - -#: ../src\wxUI\buffers\panels.py:22 -msgid "Logout" -msgstr "Cerrar sesión" - -#: ../src\wxUI\buffers\trends.py:9 -msgid "Trending topic" -msgstr "Tendencia" - -#: ../src\wxUI\buffers\trends.py:19 -msgid "Tweet about this trend" -msgstr "Tuitear sobre esta tendencia" - -#: ../src\wxUI\buffers\trends.py:20 ../src\wxUI\menus.py:97 -msgid "Search topic" -msgstr "Buscar tema" - -#: ../src\wxUI\commonMessageDialogs.py:7 +#: wxUI/commonMessageDialogs.py:7 msgid "" "This retweet is over 140 characters. Would you like to post it as a mention " "to the poster with your comments and a link to the original tweet?" @@ -2148,38 +2154,38 @@ msgstr "" "comentarios con una mención al usuario que publicó el tuit original y un " "enlace al mismo?" -#: ../src\wxUI\commonMessageDialogs.py:10 +#: wxUI/commonMessageDialogs.py:10 msgid "Would you like to add a comment to this tweet?" msgstr "¿Te gustaría añadir un comentario a este tuit?" -#: ../src\wxUI\commonMessageDialogs.py:13 +#: wxUI/commonMessageDialogs.py:13 msgid "" "Do you really want to delete this tweet? It will be deleted from Twitter as " "well." msgstr "" "¿Realmente quieres borrar este mensaje? También se eliminará de Twitter." -#: ../src\wxUI\commonMessageDialogs.py:13 ../src\wxUI\dialogs\lists.py:149 +#: wxUI/commonMessageDialogs.py:13 wxUI/dialogs/lists.py:149 msgid "Delete" msgstr "Eliminar" -#: ../src\wxUI\commonMessageDialogs.py:16 +#: wxUI/commonMessageDialogs.py:16 msgid "Do you really want to close {0}?" msgstr "¿Realmente deseas salir de {0}?" -#: ../src\wxUI\commonMessageDialogs.py:16 +#: wxUI/commonMessageDialogs.py:16 msgid "Exit" msgstr "Salir" -#: ../src\wxUI\commonMessageDialogs.py:20 +#: wxUI/commonMessageDialogs.py:20 msgid " {0} must be restarted for these changes to take effect." msgstr " Debes reiniciar {0} para que estos cambios tengan efecto." -#: ../src\wxUI\commonMessageDialogs.py:20 +#: wxUI/commonMessageDialogs.py:20 msgid "Restart {0} " msgstr "Reiniciar {0} " -#: ../src\wxUI\commonMessageDialogs.py:23 +#: wxUI/commonMessageDialogs.py:23 msgid "" "Are you sure you want to delete this user from the database? This user will " "not appear in autocomplete results anymore." @@ -2187,20 +2193,19 @@ msgstr "" "¿Estás seguro de querer eliminar este usuario de la base de datos? Este ya " "no aparecerá en los resultados del autocompletado." -#: ../src\wxUI\commonMessageDialogs.py:23 +#: wxUI/commonMessageDialogs.py:23 msgid "Confirm" msgstr "Confirmar" -#: ../src\wxUI\commonMessageDialogs.py:26 +#: wxUI/commonMessageDialogs.py:26 msgid "Enter the name of the client : " msgstr "Introduce el nombre del cliente: " -#: ../src\wxUI\commonMessageDialogs.py:26 -#: ../src\wxUI\dialogs\configuration.py:246 +#: wxUI/commonMessageDialogs.py:26 wxUI/dialogs/configuration.py:246 msgid "Add client" msgstr "Añadir cliente" -#: ../src\wxUI\commonMessageDialogs.py:32 +#: wxUI/commonMessageDialogs.py:32 msgid "" "Do you really want to empty this buffer? It's items will be removed from " "the list but not from Twitter" @@ -2208,32 +2213,31 @@ msgstr "" "¿Realmente quieres vaciar el contenido de este buffer? Los tweets serán " "eliminados de la lista, pero no de Twitter" -#: ../src\wxUI\commonMessageDialogs.py:32 +#: wxUI/commonMessageDialogs.py:32 msgid "Empty buffer" msgstr "Vaciar buffer" -#: ../src\wxUI\commonMessageDialogs.py:36 +#: wxUI/commonMessageDialogs.py:36 msgid "Do you really want to destroy this buffer?" msgstr "¿Realmente deseas eliminar este buffer?" -#: ../src\wxUI\commonMessageDialogs.py:36 -#: ../src\wxUI\commonMessageDialogs.py:86 +#: wxUI/commonMessageDialogs.py:36 wxUI/commonMessageDialogs.py:86 msgid "Attention" msgstr "Atención" -#: ../src\wxUI\commonMessageDialogs.py:42 +#: wxUI/commonMessageDialogs.py:42 msgid "A timeline for this user already exists. You can't open another" msgstr "Ya hay una línea temporal para este usuario. No se puede abrir otra" -#: ../src\wxUI\commonMessageDialogs.py:42 +#: wxUI/commonMessageDialogs.py:42 msgid "Existing timeline" msgstr "Línea temporal existente" -#: ../src\wxUI\commonMessageDialogs.py:45 +#: wxUI/commonMessageDialogs.py:45 msgid "This user has no tweets, so you can't open a timeline for them." msgstr "Este usuario no tiene tuits. No puedes abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:48 +#: wxUI/commonMessageDialogs.py:48 msgid "" "This is a protected Twitter user, which means you can't open a timeline " "using the Streaming API. The user's tweets will not update due to a twitter " @@ -2244,12 +2248,11 @@ msgstr "" "este usuario no se actualizarán debido a una política de Twitter. ¿Deseas " "continuar?" -#: ../src\wxUI\commonMessageDialogs.py:48 -#: ../src\wxUI\commonMessageDialogs.py:95 +#: wxUI/commonMessageDialogs.py:48 wxUI/commonMessageDialogs.py:95 msgid "Warning" msgstr "Atención" -#: ../src\wxUI\commonMessageDialogs.py:51 +#: wxUI/commonMessageDialogs.py:51 msgid "" "This is a protected user account, you need to follow this user to view their " "tweets or likes." @@ -2257,7 +2260,7 @@ msgstr "" "Esta es una cuenta protegida, debes seguir al usuario para poder ver sus " "tuits y los tuits marcados con me gusta." -#: ../src\wxUI\commonMessageDialogs.py:54 +#: wxUI/commonMessageDialogs.py:54 msgid "" "If you like {0} we need your help to keep it going. Help us by donating to " "the project. This will help us pay for the server, the domain and some other " @@ -2272,42 +2275,38 @@ msgstr "" "permitirá seguir escribiendo características para {0} y que estas sean " "libres en {0}. ¿Te gustaría donar ahora?" -#: ../src\wxUI\commonMessageDialogs.py:54 +#: wxUI/commonMessageDialogs.py:54 msgid "We need your help" msgstr "Necesitamos tu ayuda" -#: ../src\wxUI\commonMessageDialogs.py:58 +#: wxUI/commonMessageDialogs.py:58 msgid "This user has no tweets. {0} can't create a timeline." msgstr "Este usuario no tiene tuits. {0} no puede abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:61 +#: wxUI/commonMessageDialogs.py:61 msgid "This user has no favorited tweets. {0} can't create a timeline." msgstr "" "Este usuario no tiene tuits favoritos. {0} no puede abrirle una línea " "temporal." -#: ../src\wxUI\commonMessageDialogs.py:64 +#: wxUI/commonMessageDialogs.py:64 msgid "This user has no followers. {0} can't create a timeline." msgstr "" "Este usuario no tiene seguidores. {0} no puede abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:67 +#: wxUI/commonMessageDialogs.py:67 msgid "This user has no friends. {0} can't create a timeline." msgstr "Este usuario no tiene amigos. {0} no puede abrirle una línea temporal." -#: ../src\wxUI\commonMessageDialogs.py:71 -msgid "Geo data for this tweet" -msgstr "Información geográfica para este tweet" - -#: ../src\wxUI\commonMessageDialogs.py:71 +#: wxUI/commonMessageDialogs.py:71 msgid "Geolocation data: {0}" msgstr "Datos de ubicación: {0}" -#: ../src\wxUI\commonMessageDialogs.py:74 -msgid "Information" -msgstr "Información" +#: wxUI/commonMessageDialogs.py:71 +msgid "Geo data for this tweet" +msgstr "Información geográfica para este tweet" -#: ../src\wxUI\commonMessageDialogs.py:74 +#: wxUI/commonMessageDialogs.py:74 msgid "" "TWBlue has detected that you're running windows 10 and has changed the " "default keymap to the Windows 10 keymap. It means that some keyboard " @@ -2320,11 +2319,15 @@ msgstr "" "el editor de combinaciones de teclado y ver todas las combinaciones " "disponibles en este mapa de teclado." -#: ../src\wxUI\commonMessageDialogs.py:77 +#: wxUI/commonMessageDialogs.py:74 +msgid "Information" +msgstr "Información" + +#: wxUI/commonMessageDialogs.py:77 msgid "You have been blocked from viewing this content" msgstr "Te han bloqueado y no puedes ver este contenido" -#: ../src\wxUI\commonMessageDialogs.py:80 +#: wxUI/commonMessageDialogs.py:80 msgid "" "You have been blocked from viewing someone's content. In order to avoid " "conflicts with the full session, TWBlue will remove the affected timeline." @@ -2332,7 +2335,7 @@ msgstr "" "Alguien te ha bloqueado y no puedes ver su contenido. Para evitar conflictos " "en la sesión entera, TWBlue quitará el hilo temporal afectado." -#: ../src\wxUI\commonMessageDialogs.py:83 +#: wxUI/commonMessageDialogs.py:83 msgid "" "TWBlue cannot load this timeline because the user has been suspended from " "Twitter." @@ -2340,15 +2343,15 @@ msgstr "" "TWBlue no puede cargar este hilo temporal porque el usuario ha sido " "suspendido por Twitter." -#: ../src\wxUI\commonMessageDialogs.py:86 +#: wxUI/commonMessageDialogs.py:86 msgid "Do you really want to delete this filter?" msgstr "¿Realmente deseas eliminar este filtro?" -#: ../src\wxUI\commonMessageDialogs.py:89 +#: wxUI/commonMessageDialogs.py:89 msgid "This filter already exists. Please use a different title" msgstr "Este filtro ya existe, por favor utiliza un título diferente" -#: ../src\wxUI\commonMessageDialogs.py:95 +#: wxUI/commonMessageDialogs.py:95 msgid "" "{0} quit unexpectedly the last time it was run. If the problem persists, " "please report it to the {0} developers." @@ -2356,146 +2359,441 @@ msgstr "" "{0} se cerró de forma inesperada la última vez que se usó. Si el problema " "persiste, por favor informa de él a los desarrolladores de {0}." -#: ../src\wxUI\dialogs\attach.py:10 -msgid "Add an attachment" -msgstr "Adjuntar un archivo" +#: wxUI/menus.py:8 wxUI/view.py:33 +msgid "&Retweet" +msgstr "&Retuit" -#: ../src\wxUI\dialogs\attach.py:13 -msgid "Attachments" -msgstr "Adjuntos" +#: wxUI/menus.py:10 wxUI/menus.py:34 wxUI/view.py:32 +msgid "Re&ply" +msgstr "Res&ponder" -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Title" -msgstr "Título" +#: wxUI/menus.py:12 wxUI/view.py:34 +msgid "&Like" +msgstr "Me &gusta" -#: ../src\wxUI\dialogs\attach.py:14 -msgid "Type" -msgstr "Tipo" +#: wxUI/menus.py:14 wxUI/view.py:35 +msgid "&Unlike" +msgstr "&Ya no me gusta" -#: ../src\wxUI\dialogs\attach.py:19 -msgid "Add attachments" -msgstr "Añadir adjuntos" +#: wxUI/menus.py:16 wxUI/menus.py:36 wxUI/menus.py:52 +msgid "&Open URL" +msgstr "&Abrir URL" -#: ../src\wxUI\dialogs\attach.py:20 -msgid "&Photo" -msgstr "&Foto" +#: wxUI/menus.py:18 wxUI/menus.py:54 wxUI/menus.py:87 +msgid "&Open in Twitter" +msgstr "&Abrir en Twitter" -#: ../src\wxUI\dialogs\attach.py:21 -msgid "Remove attachment" -msgstr "Remover archivo" +#: wxUI/menus.py:20 wxUI/menus.py:38 wxUI/menus.py:56 +msgid "&Play audio" +msgstr "&Reproducir audio" -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" -msgstr "Archivos de imagen (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" +#: wxUI/menus.py:22 wxUI/menus.py:58 wxUI/view.py:36 +msgid "&Show tweet" +msgstr "&Ver tuit" -#: ../src\wxUI\dialogs\attach.py:37 ../src\wxUI\dialogs\message.py:116 -#: ../src\wxUI\dialogs\message.py:175 ../src\wxUI\dialogs\message.py:235 -#: ../src\wxUI\dialogs\update_profile.py:82 -msgid "Select the picture to be uploaded" -msgstr "Selecciona una foto para subir" +#: wxUI/menus.py:24 wxUI/menus.py:42 wxUI/menus.py:60 wxUI/menus.py:70 +#: wxUI/menus.py:89 wxUI/menus.py:103 +msgid "&Copy to clipboard" +msgstr "&Copiar al portapapeles" -#: ../src\wxUI\dialogs\attach.py:44 -msgid "please provide a description" -msgstr "por favor proporciona una descripción" +#: wxUI/menus.py:26 wxUI/menus.py:44 wxUI/menus.py:62 wxUI/menus.py:72 +#: wxUI/view.py:40 +msgid "&Delete" +msgstr "&Eliminar" -#: ../src\wxUI\dialogs\attach.py:44 ../src\wxUI\dialogs\lists.py:14 -#: ../src\wxUI\dialogs\lists.py:70 -msgid "Description" -msgstr "Descripción" +#: wxUI/menus.py:28 wxUI/menus.py:46 wxUI/menus.py:91 +msgid "&User actions..." +msgstr "&Acciones de usuario..." -#: ../src\wxUI\dialogs\configuration.py:15 +#: wxUI/menus.py:40 +msgid "&Show direct message" +msgstr "&Mostrar mensaje directo" + +#: wxUI/menus.py:68 +msgid "&Show event" +msgstr "&Mostrar evento" + +#: wxUI/menus.py:78 +msgid "Direct &message" +msgstr "Mensaje &directo" + +#: wxUI/menus.py:80 wxUI/view.py:50 +msgid "&View lists" +msgstr "&Ver listas" + +#: wxUI/menus.py:83 wxUI/view.py:51 +msgid "Show user &profile" +msgstr "Ve&r perfil del usuario" + +#: wxUI/menus.py:85 +msgid "&Show user" +msgstr "&Mostrar usuario" + +#: wxUI/buffers/trends.py:20 wxUI/menus.py:97 +msgid "Search topic" +msgstr "Buscar tema" + +#: wxUI/menus.py:99 +msgid "&Tweet about this trend" +msgstr "&Tuitear sobre esta tendencia" + +#: wxUI/menus.py:101 +msgid "&Show item" +msgstr "&Ver tuit" + +#: wxUI/sysTrayIcon.py:36 wxUI/view.py:26 +msgid "&Global settings" +msgstr "Opciones &globales" + +#: wxUI/sysTrayIcon.py:37 wxUI/view.py:25 +msgid "Account se&ttings" +msgstr "Opciones de &cuenta" + +#: wxUI/sysTrayIcon.py:38 +msgid "Update &profile" +msgstr "Actualizar &perfil" + +#: wxUI/sysTrayIcon.py:39 +msgid "&Show / hide" +msgstr "&Mostrar / esconder" + +#: wxUI/sysTrayIcon.py:40 wxUI/view.py:75 +msgid "&Documentation" +msgstr "&Documentación" + +#: wxUI/sysTrayIcon.py:41 +msgid "Check for &updates" +msgstr "Comprobar &actualizaciones" + +#: wxUI/sysTrayIcon.py:42 +msgid "&Exit" +msgstr "&Salir" + +#: wxUI/view.py:18 +msgid "&Manage accounts" +msgstr "Gestionar &cuentas" + +#: wxUI/dialogs/update_profile.py:35 wxUI/view.py:19 +msgid "&Update profile" +msgstr "Actuali&zar perfil" + +#: wxUI/view.py:20 +msgid "&Hide window" +msgstr "Esconder &ventana" + +#: wxUI/dialogs/search.py:13 wxUI/view.py:21 +msgid "&Search" +msgstr "&Buscar" + +#: wxUI/view.py:22 +msgid "&Lists manager" +msgstr "Gestor de &listas" + +#: wxUI/view.py:23 +msgid "Manage user aliases" +msgstr "Gestionar alias de usuario" + +#: wxUI/view.py:24 +msgid "&Edit keystrokes" +msgstr "Editar combinaciones de &teclas" + +#: wxUI/view.py:27 +msgid "E&xit" +msgstr "S&alir" + +#: wxUI/view.py:31 wxUI/view.py:86 +msgid "&Tweet" +msgstr "&Tuit" + +#: wxUI/view.py:37 +msgid "View &address" +msgstr "Ver &dirección" + +#: wxUI/view.py:38 +msgid "View conversa&tion" +msgstr "Ver conversa&ción" + +#: wxUI/view.py:39 +msgid "Read text in picture" +msgstr "Leer texto en imágenes" + +#: wxUI/view.py:44 +msgid "&Actions..." +msgstr "&Acciones..." + +#: wxUI/view.py:45 +msgid "&View timeline..." +msgstr "&Ver línea temporal..." + +#: wxUI/view.py:46 +msgid "Direct me&ssage" +msgstr "&Mensaje directo" + +#: wxUI/view.py:47 +msgid "Add a&lias" +msgstr "Añadir alias" + +#: wxUI/view.py:48 +msgid "&Add to list" +msgstr "&Añadir a lista" + +#: wxUI/view.py:49 +msgid "R&emove from list" +msgstr "&Quitar de lista" + +#: wxUI/view.py:52 +msgid "V&iew likes" +msgstr "&Ver tuits marcados con me gusta" + +#: wxUI/view.py:56 +msgid "&Update buffer" +msgstr "&actualizar buffer" + +#: wxUI/view.py:57 +msgid "New &trending topics buffer..." +msgstr "Nuevo buffer de &tendencias..." + +#: wxUI/view.py:58 +msgid "Create a &filter" +msgstr "Crear &filtro" + +#: wxUI/view.py:59 +msgid "&Manage filters" +msgstr "Gestionar &filtros" + +#: wxUI/view.py:60 +msgid "Find a string in the currently focused buffer..." +msgstr "Buscar término en el buffer actual..." + +#: wxUI/view.py:61 +msgid "&Load previous items" +msgstr "&Cargar elementos anteriores" + +#: wxUI/dialogs/userActions.py:22 wxUI/view.py:63 +msgid "&Mute" +msgstr "S&ilenciar" + +#: wxUI/view.py:64 +msgid "&Autoread" +msgstr "&lectura automática" + +#: wxUI/view.py:65 +msgid "&Clear buffer" +msgstr "&Vaciar buffer" + +#: wxUI/view.py:66 +msgid "&Destroy" +msgstr "&Eliminar" + +#: wxUI/view.py:70 +msgid "&Seek back 5 seconds" +msgstr "&Retroceder 5 segundos" + +#: wxUI/view.py:71 +msgid "&Seek forward 5 seconds" +msgstr "A&vanzar 5 segundos" + +#: wxUI/view.py:76 +msgid "Sounds &tutorial" +msgstr "Tutorial de &sonidos" + +#: wxUI/view.py:77 +msgid "&What's new in this version?" +msgstr "¿&Qué hay de nuevo en esta versión?" + +#: wxUI/view.py:78 +msgid "&Check for updates" +msgstr "&Comprobar actualizaciones" + +#: wxUI/view.py:79 +msgid "&Report an error" +msgstr "&Reportar un error" + +#: wxUI/view.py:80 +msgid "{0}'s &website" +msgstr "Sitio &web de {0}" + +#: wxUI/view.py:81 +msgid "Get soundpacks for TWBlue" +msgstr "Obtener paquetes de sonidos para TWBlue" + +#: wxUI/view.py:82 +msgid "About &{0}" +msgstr "Sobre &{0}" + +#: wxUI/view.py:85 +msgid "&Application" +msgstr "&Aplicación" + +#: wxUI/dialogs/userActions.py:11 wxUI/view.py:87 +msgid "&User" +msgstr "&Usuario" + +#: wxUI/view.py:88 +msgid "&Buffer" +msgstr "&Buffer" + +#: wxUI/view.py:89 +msgid "&Audio" +msgstr "&Audio" + +#: wxUI/view.py:90 +msgid "&Help" +msgstr "Ay&uda" + +#: wxUI/view.py:176 +msgid "Address" +msgstr "Dirección" + +#: wxUI/view.py:207 +msgid "Your {0} version is up to date" +msgstr "Tu versión de {0} está actualizada" + +#: wxUI/view.py:207 +msgid "Update" +msgstr "Actualización" + +#: wxUI/buffers/base.py:12 wxUI/buffers/people.py:12 +#: wxUI/buffers/user_searches.py:11 wxUI/dialogs/userAliasDialogs.py:14 +#: wxUI/dialogs/userSelection.py:11 wxUI/dialogs/utils.py:32 +msgid "User" +msgstr "Usuario" + +#: wxUI/buffers/base.py:12 wxUI/dialogs/twitterDialogs/tweetDialogs.py:47 +msgid "Text" +msgstr "Texto" + +#: wxUI/buffers/base.py:12 wxUI/buffers/events.py:14 +msgid "Date" +msgstr "Fecha" + +#: wxUI/buffers/base.py:12 +msgid "Client" +msgstr "Cliente" + +#: wxUI/buffers/base.py:28 +msgid "Direct message" +msgstr "Mensaje directo" + +#: wxUI/buffers/events.py:14 +msgid "Event" +msgstr "Evento" + +#: wxUI/buffers/events.py:16 +msgid "Remove event" +msgstr "Eliminar evento" + +#: wxUI/buffers/panels.py:12 wxUI/buffers/panels.py:20 +msgid "Login" +msgstr "Iniciar sesión" + +#: wxUI/buffers/panels.py:14 +msgid "Log in automatically" +msgstr "Iniciar sesión automáticamente" + +#: wxUI/buffers/panels.py:22 +msgid "Logout" +msgstr "Cerrar sesión" + +#: wxUI/buffers/trends.py:9 +msgid "Trending topic" +msgstr "Tendencia" + +#: wxUI/buffers/trends.py:19 +msgid "Tweet about this trend" +msgstr "Tuitear sobre esta tendencia" + +#: wxUI/dialogs/configuration.py:15 msgid "Language" msgstr "Idioma" -#: ../src\wxUI\dialogs\configuration.py:22 +#: wxUI/dialogs/configuration.py:22 msgid "Run {0} at Windows startup" msgstr "Ejecutar {0} al iniciar Windows" -#: ../src\wxUI\dialogs\configuration.py:23 +#: wxUI/dialogs/configuration.py:23 msgid "ask before exiting {0}" msgstr "preguntar antes de salir de {0}" -#: ../src\wxUI\dialogs\configuration.py:26 +#: wxUI/dialogs/configuration.py:26 msgid "Disable Streaming functions" msgstr "Desactivar funciones en tiempo real" -#: ../src\wxUI\dialogs\configuration.py:29 +#: wxUI/dialogs/configuration.py:29 msgid "Buffer update interval, in minutes" msgstr "Intervalo de actualización de los buffers, en minutos" -#: ../src\wxUI\dialogs\configuration.py:35 +#: wxUI/dialogs/configuration.py:35 msgid "Play a sound when {0} launches" msgstr "Reproducir un sonido cuando inicia {0}" -#: ../src\wxUI\dialogs\configuration.py:37 +#: wxUI/dialogs/configuration.py:37 msgid "Speak a message when {0} launches" msgstr "Hablar un mensaje cuando {0} inicie" -#: ../src\wxUI\dialogs\configuration.py:39 +#: wxUI/dialogs/configuration.py:39 msgid "Use invisible interface's keyboard shortcuts while GUI is visible" msgstr "" "Usar los atajos de teclado de la interfaz invisible en la ventana gráfica" -#: ../src\wxUI\dialogs\configuration.py:41 +#: wxUI/dialogs/configuration.py:41 msgid "Activate Sapi5 when any other screen reader is not being run" msgstr "Activar Sapi5 cuando no hay ningún lector de pantalla ejecutándose" -#: ../src\wxUI\dialogs\configuration.py:43 +#: wxUI/dialogs/configuration.py:43 msgid "Hide GUI on launch" msgstr "Esconder interfaz gráfica al iniciar" -#: ../src\wxUI\dialogs\configuration.py:45 +#: wxUI/dialogs/configuration.py:45 msgid "Use Codeofdusk's longtweet handlers (may decrease client performance)" msgstr "" "Lectura completa de Tuits largos (puede disminuir el rendimiento del cliente)" -#: ../src\wxUI\dialogs\configuration.py:47 +#: wxUI/dialogs/configuration.py:47 msgid "Remember state for mention all and long tweet" msgstr "Recordar estado para casillas de mencionar a todos y tweet largos" -#: ../src\wxUI\dialogs\configuration.py:50 +#: wxUI/dialogs/configuration.py:50 msgid "Keymap" msgstr "Mapa de teclado" -#: ../src\wxUI\dialogs\configuration.py:55 +#: wxUI/dialogs/configuration.py:55 msgid "Check for updates when {0} launches" msgstr "Comprobar actualizaciones cuando {0} inicie" -#: ../src\wxUI\dialogs\configuration.py:65 +#: wxUI/dialogs/configuration.py:65 msgid "Proxy type: " msgstr "Tipo de proxy: " -#: ../src\wxUI\dialogs\configuration.py:72 +#: wxUI/dialogs/configuration.py:72 msgid "Proxy server: " msgstr "Servidor proxy: " -#: ../src\wxUI\dialogs\configuration.py:78 +#: wxUI/dialogs/configuration.py:78 msgid "Port: " msgstr "Puerto: " -#: ../src\wxUI\dialogs\configuration.py:84 +#: wxUI/dialogs/configuration.py:84 msgid "User: " msgstr "Usuario: " -#: ../src\wxUI\dialogs\configuration.py:90 +#: wxUI/dialogs/configuration.py:90 msgid "Password: " msgstr "Contraseña: " -#: ../src\wxUI\dialogs\configuration.py:102 +#: wxUI/dialogs/configuration.py:102 msgid "Autocompletion settings..." msgstr "Opciones de autocompletado de usuarios..." -#: ../src\wxUI\dialogs\configuration.py:104 +#: wxUI/dialogs/configuration.py:104 msgid "Relative timestamps" msgstr "Tiempos relativos" -#: ../src\wxUI\dialogs\configuration.py:107 +#: wxUI/dialogs/configuration.py:107 msgid "Items on each API call" msgstr "Elementos por cada llamada a la API" -#: ../src\wxUI\dialogs\configuration.py:113 +#: wxUI/dialogs/configuration.py:113 msgid "" "Inverted buffers: The newest tweets will be shown at the beginning while the " "oldest at the end" @@ -2503,15 +2801,15 @@ msgstr "" "Buffers invertidos: los nuevos tweets se mostrarán al principio de las " "listas y los viejos al final" -#: ../src\wxUI\dialogs\configuration.py:115 +#: wxUI/dialogs/configuration.py:115 msgid "Retweet mode" msgstr "Modo de retuit" -#: ../src\wxUI\dialogs\configuration.py:121 +#: wxUI/dialogs/configuration.py:121 msgid "Show screen names instead of full names" msgstr "Mostrar nombres de pantalla en lugar de nombres completos" -#: ../src\wxUI\dialogs\configuration.py:123 +#: wxUI/dialogs/configuration.py:123 msgid "" "Number of items per buffer to cache in database (0 to disable caching, blank " "for unlimited)" @@ -2520,7 +2818,7 @@ msgstr "" "blanco para guardarlos de forma ilimitada, 0 para desactivar la base de " "datos)" -#: ../src\wxUI\dialogs\configuration.py:127 +#: wxUI/dialogs/configuration.py:127 msgid "" "Load cache for tweets in memory (much faster in big datasets but requires " "more RAM)" @@ -2528,909 +2826,786 @@ msgstr "" "Cargar cache para Tweets en RAM (es más rápido para listas muy grandes de " "elementos, pero requiere más memoria)" -#: ../src\wxUI\dialogs\configuration.py:134 +#: wxUI/dialogs/configuration.py:134 msgid "Enable automatic speech feedback" msgstr "Activar mensajes automáticos hablados" -#: ../src\wxUI\dialogs\configuration.py:136 +#: wxUI/dialogs/configuration.py:136 msgid "Enable automatic Braille feedback" msgstr "Activar mensajes automáticos en Braille" -#: ../src\wxUI\dialogs\configuration.py:144 -msgid "Status" -msgstr "Estado" - -#: ../src\wxUI\dialogs\configuration.py:144 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: wxUI/dialogs/configuration.py:144 wxUI/dialogs/filterDialogs.py:130 msgid "Buffer" msgstr "Buffer" -#: ../src\wxUI\dialogs\configuration.py:147 +#: wxUI/dialogs/configuration.py:144 +msgid "Status" +msgstr "Estado" + +#: wxUI/dialogs/configuration.py:147 msgid "Show/hide" msgstr "Mostrar/ocultar" -#: ../src\wxUI\dialogs\configuration.py:148 +#: wxUI/dialogs/configuration.py:148 msgid "Move up" msgstr "Mover arriba" -#: ../src\wxUI\dialogs\configuration.py:149 +#: wxUI/dialogs/configuration.py:149 msgid "Move down" msgstr "Mover abajo" -#: ../src\wxUI\dialogs\configuration.py:159 -#: ../src\wxUI\dialogs\configuration.py:224 -#: ../src\wxUI\dialogs\configuration.py:227 -#: ../src\wxUI\dialogs\configuration.py:232 +#: wxUI/dialogs/configuration.py:159 wxUI/dialogs/configuration.py:224 +#: wxUI/dialogs/configuration.py:227 wxUI/dialogs/configuration.py:232 msgid "Show" msgstr "Mostrar" -#: ../src\wxUI\dialogs\configuration.py:161 -#: ../src\wxUI\dialogs\configuration.py:171 -#: ../src\wxUI\dialogs\configuration.py:195 -#: ../src\wxUI\dialogs\configuration.py:225 +#: wxUI/dialogs/configuration.py:161 wxUI/dialogs/configuration.py:171 +#: wxUI/dialogs/configuration.py:195 wxUI/dialogs/configuration.py:225 msgid "Hide" msgstr "Ocultar" -#: ../src\wxUI\dialogs\configuration.py:169 -#: ../src\wxUI\dialogs\configuration.py:193 +#: wxUI/dialogs/configuration.py:169 wxUI/dialogs/configuration.py:193 msgid "Select a buffer first." msgstr "Primero selecciona un buffer." -#: ../src\wxUI\dialogs\configuration.py:172 -#: ../src\wxUI\dialogs\configuration.py:196 +#: wxUI/dialogs/configuration.py:172 wxUI/dialogs/configuration.py:196 msgid "The buffer is hidden, show it first." msgstr "El buffer está oculto, muéstralo primero." -#: ../src\wxUI\dialogs\configuration.py:175 +#: wxUI/dialogs/configuration.py:175 msgid "The buffer is already at the top of the list." msgstr "El buffer ya se encuentra al principio de la lista." -#: ../src\wxUI\dialogs\configuration.py:199 +#: wxUI/dialogs/configuration.py:199 msgid "The buffer is already at the bottom of the list." msgstr "El buffer ya se encuentra al final de la lista." -#: ../src\wxUI\dialogs\configuration.py:240 -#: ../src\wxUI\dialogs\configuration.py:381 +#: wxUI/dialogs/configuration.py:240 wxUI/dialogs/configuration.py:381 msgid "Ignored clients" msgstr "Clientes ignorados" -#: ../src\wxUI\dialogs\configuration.py:247 +#: wxUI/dialogs/configuration.py:247 msgid "Remove client" msgstr "Quitar cliente" -#: ../src\wxUI\dialogs\configuration.py:271 +#: wxUI/dialogs/configuration.py:271 msgid "Volume" msgstr "Volumen" -#: ../src\wxUI\dialogs\configuration.py:282 +#: wxUI/dialogs/configuration.py:282 msgid "Session mute" msgstr "Silencio de sesión" -#: ../src\wxUI\dialogs\configuration.py:284 +#: wxUI/dialogs/configuration.py:284 msgid "Output device" msgstr "Dispositivo de salida" -#: ../src\wxUI\dialogs\configuration.py:291 +#: wxUI/dialogs/configuration.py:291 msgid "Input device" msgstr "Dispositivo de entrada" -#: ../src\wxUI\dialogs\configuration.py:299 +#: wxUI/dialogs/configuration.py:299 msgid "Sound pack" msgstr "Paquete de sonidos" -#: ../src\wxUI\dialogs\configuration.py:305 +#: wxUI/dialogs/configuration.py:305 msgid "Indicate audio tweets with sound" msgstr "Reproducir sonido en tuits con audio" -#: ../src\wxUI\dialogs\configuration.py:307 +#: wxUI/dialogs/configuration.py:307 msgid "Indicate geotweets with sound" msgstr "Reproducir sonido en tuits con información geográfica" -#: ../src\wxUI\dialogs\configuration.py:309 +#: wxUI/dialogs/configuration.py:309 msgid "Indicate tweets containing images with sound" msgstr "Reproducir sonido en tuits con imágenes" -#: ../src\wxUI\dialogs\configuration.py:332 +#: wxUI/dialogs/configuration.py:332 msgid "Language for OCR" msgstr "Idioma para el OCR" -#: ../src\wxUI\dialogs\configuration.py:338 +#: wxUI/dialogs/configuration.py:338 msgid "API Key for SndUp" msgstr "Clave de api para SNDUp" -#: ../src\wxUI\dialogs\configuration.py:353 +#: wxUI/dialogs/configuration.py:353 msgid "{0} preferences" msgstr "Preferencias de {0}" -#: ../src\wxUI\dialogs\configuration.py:364 +#: wxUI/dialogs/configuration.py:364 msgid "Proxy" msgstr "Proxy" -#: ../src\wxUI\dialogs\configuration.py:373 +#: wxUI/dialogs/configuration.py:373 msgid "Feedback" msgstr "Retroalimentación" -#: ../src\wxUI\dialogs\configuration.py:377 +#: wxUI/dialogs/configuration.py:377 msgid "Buffers" msgstr "Buffers" -#: ../src\wxUI\dialogs\configuration.py:385 +#: wxUI/dialogs/configuration.py:385 msgid "Sound" msgstr "Sonido" -#: ../src\wxUI\dialogs\configuration.py:389 +#: wxUI/dialogs/configuration.py:389 msgid "Extras" msgstr "Extras" -#: ../src\wxUI\dialogs\configuration.py:394 +#: wxUI/dialogs/configuration.py:394 msgid "Save" msgstr "Guardar" -#: ../src\wxUI\dialogs\filterDialogs.py:16 +#: wxUI/dialogs/filterDialogs.py:13 msgid "Create a filter for this buffer" msgstr "Crear filtro para este buffer" -#: ../src\wxUI\dialogs\filterDialogs.py:17 +#: wxUI/dialogs/filterDialogs.py:14 msgid "Filter title" msgstr "Nombre del filtro" -#: ../src\wxUI\dialogs\filterDialogs.py:26 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: wxUI/dialogs/filterDialogs.py:24 wxUI/dialogs/filterDialogs.py:130 msgid "Filter by word" msgstr "Filtrar por palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:27 +#: wxUI/dialogs/filterDialogs.py:25 msgid "Ignore tweets wich contain the following word" msgstr "Ignorar tuits que contengan la siguiente palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:28 +#: wxUI/dialogs/filterDialogs.py:26 msgid "Ignore tweets without the following word" msgstr "Ignorar tuits que no contengan la siguiente palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:33 +#: wxUI/dialogs/filterDialogs.py:31 msgid "word" msgstr "palabra" -#: ../src\wxUI\dialogs\filterDialogs.py:38 +#: wxUI/dialogs/filterDialogs.py:36 msgid "Allow retweets" msgstr "Permitir retuits" -#: ../src\wxUI\dialogs\filterDialogs.py:39 +#: wxUI/dialogs/filterDialogs.py:37 msgid "Allow quoted tweets" msgstr "Permitir tweets citados" -#: ../src\wxUI\dialogs\filterDialogs.py:40 +#: wxUI/dialogs/filterDialogs.py:38 msgid "Allow replies" msgstr "Permitir respuestas" -#: ../src\wxUI\dialogs\filterDialogs.py:48 +#: wxUI/dialogs/filterDialogs.py:46 msgid "Use this term as a regular expression" msgstr "Usar término como expresión regular" -#: ../src\wxUI\dialogs\filterDialogs.py:50 -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: wxUI/dialogs/filterDialogs.py:48 wxUI/dialogs/filterDialogs.py:130 msgid "Filter by language" msgstr "Filtrar por idioma" -#: ../src\wxUI\dialogs\filterDialogs.py:51 +#: wxUI/dialogs/filterDialogs.py:49 msgid "Load tweets in the following languages" msgstr "Cargar tuits en los siguientes idiomas" -#: ../src\wxUI\dialogs\filterDialogs.py:52 +#: wxUI/dialogs/filterDialogs.py:50 msgid "Ignore tweets in the following languages" msgstr "Ignorar tuits en los siguientes idiomas" -#: ../src\wxUI\dialogs\filterDialogs.py:53 +#: wxUI/dialogs/filterDialogs.py:51 msgid "Don't filter by language" msgstr "No filtrar por idioma" -#: ../src\wxUI\dialogs\filterDialogs.py:64 +#: wxUI/dialogs/filterDialogs.py:62 msgid "Supported languages" msgstr "Idiomas soportados" -#: ../src\wxUI\dialogs\filterDialogs.py:69 +#: wxUI/dialogs/filterDialogs.py:67 msgid "Add selected language to filter" msgstr "Añadir idioma seleccionado al filtro" -#: ../src\wxUI\dialogs\filterDialogs.py:73 +#: wxUI/dialogs/filterDialogs.py:71 msgid "Selected languages" msgstr "Idiomas seleccionados" -#: ../src\wxUI\dialogs\filterDialogs.py:75 -#: ../src\wxUI\dialogs\filterDialogs.py:133 ../src\wxUI\dialogs\lists.py:21 -#: ../src\wxUI\dialogs\lists.py:132 ../src\wxUI\dialogs\userAliasDialogs.py:57 +#: wxUI/dialogs/filterDialogs.py:73 wxUI/dialogs/filterDialogs.py:137 +#: wxUI/dialogs/lists.py:21 wxUI/dialogs/lists.py:132 +#: wxUI/dialogs/userAliasDialogs.py:57 msgid "Remove" msgstr "Borrar" -#: ../src\wxUI\dialogs\filterDialogs.py:123 +#: wxUI/dialogs/filterDialogs.py:120 +msgid "You must define a name for the filter before creating it." +msgstr "Debes definir un título ppara el filtro antes de poder guardarlo." + +#: wxUI/dialogs/filterDialogs.py:120 +msgid "Missing filter name" +msgstr "Título del filtro faltante" + +#: wxUI/dialogs/filterDialogs.py:127 msgid "Manage filters" msgstr "Gestionar filtros" -#: ../src\wxUI\dialogs\filterDialogs.py:125 +#: wxUI/dialogs/filterDialogs.py:129 msgid "Filters" msgstr "Filtros" -#: ../src\wxUI\dialogs\filterDialogs.py:126 +#: wxUI/dialogs/filterDialogs.py:130 msgid "Filter" msgstr "Filtro" -#: ../src\wxUI\dialogs\find.py:13 +#: wxUI/dialogs/find.py:13 msgid "Find in current buffer" msgstr "Buscar en el buffer actual" -#: ../src\wxUI\dialogs\find.py:14 +#: wxUI/dialogs/find.py:14 msgid "String" msgstr "Término" -#: ../src\wxUI\dialogs\lists.py:11 +#: wxUI/dialogs/lists.py:11 msgid "Lists manager" msgstr "Gestor de listas" -#: ../src\wxUI\dialogs\lists.py:14 +#: wxUI/dialogs/lists.py:14 msgid "List" msgstr "Lista" -#: ../src\wxUI\dialogs\lists.py:14 -msgid "Members" -msgstr "Miembros" +#: wxUI/dialogs/lists.py:14 wxUI/dialogs/lists.py:70 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:37 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:126 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:173 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:257 +msgid "Description" +msgstr "Descripción" -#: ../src\wxUI\dialogs\lists.py:14 +#: wxUI/dialogs/lists.py:14 msgid "Owner" msgstr "Propietario" -#: ../src\wxUI\dialogs\lists.py:14 +#: wxUI/dialogs/lists.py:14 +msgid "Members" +msgstr "Miembros" + +#: wxUI/dialogs/lists.py:14 msgid "mode" msgstr "modo" -#: ../src\wxUI\dialogs\lists.py:19 ../src\wxUI\dialogs\lists.py:62 +#: wxUI/dialogs/lists.py:19 wxUI/dialogs/lists.py:62 msgid "Create a new list" msgstr "Crear nueva lista" -#: ../src\wxUI\dialogs\lists.py:22 +#: wxUI/dialogs/lists.py:22 msgid "Open in buffer" msgstr "Abrir en buffer" -#: ../src\wxUI\dialogs\lists.py:52 +#: wxUI/dialogs/lists.py:52 +#, python-format msgid "Viewing lists for %s" msgstr "Viendo las listas de %s" -#: ../src\wxUI\dialogs\lists.py:53 +#: wxUI/dialogs/lists.py:53 msgid "Subscribe" msgstr "Darte de alta" -#: ../src\wxUI\dialogs\lists.py:54 +#: wxUI/dialogs/lists.py:54 msgid "Unsubscribe" msgstr "Darse de baja" -#: ../src\wxUI\dialogs\lists.py:65 +#: wxUI/dialogs/lists.py:65 msgid "Name (20 characters maximun)" msgstr "Nombre (máximo 20 caracteres)" -#: ../src\wxUI\dialogs\lists.py:75 +#: wxUI/dialogs/lists.py:75 msgid "Mode" msgstr "Modo" -#: ../src\wxUI\dialogs\lists.py:76 +#: wxUI/dialogs/lists.py:76 msgid "Public" msgstr "Público" -#: ../src\wxUI\dialogs\lists.py:77 +#: wxUI/dialogs/lists.py:77 msgid "Private" msgstr "Privado" -#: ../src\wxUI\dialogs\lists.py:97 +#: wxUI/dialogs/lists.py:97 +#, python-format msgid "Editing the list %s" msgstr "Editando la lista %s" -#: ../src\wxUI\dialogs\lists.py:108 +#: wxUI/dialogs/lists.py:108 msgid "Select a list to add the user" msgstr "Selecciona una lista para añadir al usuario" -#: ../src\wxUI\dialogs\lists.py:109 +#: wxUI/dialogs/lists.py:109 msgid "Add" msgstr "Añadir" -#: ../src\wxUI\dialogs\lists.py:131 +#: wxUI/dialogs/lists.py:131 msgid "Select a list to remove the user" msgstr "Selecciona una lista para quitar al usuario" -#: ../src\wxUI\dialogs\lists.py:149 +#: wxUI/dialogs/lists.py:149 msgid "Do you really want to delete this list?" msgstr "¿Realmente deseas eliminar esta lista?" -#: ../src\wxUI\dialogs\message.py:73 ../src\wxUI\dialogs\message.py:254 -msgid "&Long tweet" -msgstr "Tuit &largo" - -#: ../src\wxUI\dialogs\message.py:74 ../src\wxUI\dialogs\message.py:133 -#: ../src\wxUI\dialogs\message.py:255 -msgid "&Upload image..." -msgstr "&Subir imagen..." - -#: ../src\wxUI\dialogs\message.py:75 ../src\wxUI\dialogs\message.py:134 -#: ../src\wxUI\dialogs\message.py:194 ../src\wxUI\dialogs\message.py:256 -#: ../src\wxUI\dialogs\message.py:359 ../src\wxUI\dialogs\message.py:435 -msgid "Check &spelling..." -msgstr "Revisar &ortografía..." - -#: ../src\wxUI\dialogs\message.py:76 ../src\wxUI\dialogs\message.py:135 -#: ../src\wxUI\dialogs\message.py:195 ../src\wxUI\dialogs\message.py:257 -msgid "&Attach audio..." -msgstr "&Adjuntar audio..." - -#: ../src\wxUI\dialogs\message.py:77 ../src\wxUI\dialogs\message.py:136 -#: ../src\wxUI\dialogs\message.py:196 ../src\wxUI\dialogs\message.py:258 -msgid "Sh&orten URL" -msgstr "Acortar &URL" - -#: ../src\wxUI\dialogs\message.py:78 ../src\wxUI\dialogs\message.py:137 -#: ../src\wxUI\dialogs\message.py:197 ../src\wxUI\dialogs\message.py:259 -#: ../src\wxUI\dialogs\message.py:360 ../src\wxUI\dialogs\message.py:436 -msgid "&Expand URL" -msgstr "&Expandir URL" - -#: ../src\wxUI\dialogs\message.py:81 ../src\wxUI\dialogs\message.py:140 -#: ../src\wxUI\dialogs\message.py:200 ../src\wxUI\dialogs\message.py:262 -#: ../src\wxUI\dialogs\message.py:362 ../src\wxUI\dialogs\message.py:438 -msgid "&Translate..." -msgstr "&Traducir..." - -#: ../src\wxUI\dialogs\message.py:82 ../src\wxUI\dialogs\message.py:141 -#: ../src\wxUI\dialogs\message.py:186 ../src\wxUI\dialogs\message.py:263 -msgid "Auto&complete users" -msgstr "Auto&completar usuarios" - -#: ../src\wxUI\dialogs\message.py:83 ../src\wxUI\dialogs\message.py:142 -#: ../src\wxUI\dialogs\message.py:201 ../src\wxUI\dialogs\message.py:264 -msgid "Sen&d" -msgstr "En&viar" - -#: ../src\wxUI\dialogs\message.py:85 ../src\wxUI\dialogs\message.py:144 -#: ../src\wxUI\dialogs\message.py:203 ../src\wxUI\dialogs\message.py:266 -#: ../src\wxUI\dialogs\message.py:363 ../src\wxUI\dialogs\message.py:439 -msgid "C&lose" -msgstr "Ce&rrar" - -#: ../src\wxUI\dialogs\message.py:184 -msgid "&Recipient" -msgstr "&Destinatario" - -#: ../src\wxUI\dialogs\message.py:245 -msgid "&Mention to all" -msgstr "&Mencionar a todos" - -#: ../src\wxUI\dialogs\message.py:299 -msgid "Tweet - %i characters " -msgstr "Tuit - %i caracteres " - -#: ../src\wxUI\dialogs\message.py:316 -msgid "Image description" -msgstr "Descripción de la imagen" - -#: ../src\wxUI\dialogs\message.py:327 -msgid "Retweets: " -msgstr "Retuits: " - -#: ../src\wxUI\dialogs\message.py:332 -msgid "Likes: " -msgstr "Me gusta: " - -#: ../src\wxUI\dialogs\message.py:337 -msgid "Source: " -msgstr "Desde: " - -#: ../src\wxUI\dialogs\message.py:342 ../src\wxUI\dialogs\message.py:423 -msgid "Date: " -msgstr "Fecha: " - -#: ../src\wxUI\dialogs\message.py:357 ../src\wxUI\dialogs\message.py:433 -msgid "Copy link to clipboard" -msgstr "Copiar enlace al portapapeles" - -#: ../src\wxUI\dialogs\message.py:408 -msgid "View" -msgstr "Ver" - -#: ../src\wxUI\dialogs\message.py:410 -msgid "Item" -msgstr "Elemento" - -#: ../src\wxUI\dialogs\search.py:12 +#: wxUI/dialogs/search.py:12 msgid "Search on Twitter" msgstr "Buscar en Twitter" -#: ../src\wxUI\dialogs\search.py:13 ../src\wxUI\view.py:21 -msgid "&Search" -msgstr "&Buscar" - -#: ../src\wxUI\dialogs\search.py:21 +#: wxUI/dialogs/search.py:21 msgid "Tweets" msgstr "Tuits" -#: ../src\wxUI\dialogs\search.py:22 ../src\wxUI\dialogs\userAliasDialogs.py:43 +#: wxUI/dialogs/search.py:22 wxUI/dialogs/userAliasDialogs.py:43 msgid "Users" msgstr "Usuarios" -#: ../src\wxUI\dialogs\search.py:29 +#: wxUI/dialogs/search.py:29 msgid "&Language for results: " msgstr "&Idioma para los resultados: " -#: ../src\wxUI\dialogs\search.py:31 ../src\wxUI\dialogs\search.py:55 +#: wxUI/dialogs/search.py:31 wxUI/dialogs/search.py:55 msgid "any" msgstr "cualquiera" -#: ../src\wxUI\dialogs\search.py:37 +#: wxUI/dialogs/search.py:37 msgid "Results &type: " msgstr "&Tipo de resultados: " -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:63 +#: wxUI/dialogs/search.py:38 wxUI/dialogs/search.py:63 msgid "Mixed" msgstr "Mixtos" -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:64 +#: wxUI/dialogs/search.py:38 wxUI/dialogs/search.py:64 msgid "Recent" msgstr "Recientes" -#: ../src\wxUI\dialogs\search.py:38 ../src\wxUI\dialogs\search.py:65 +#: wxUI/dialogs/search.py:38 wxUI/dialogs/search.py:65 msgid "Popular" msgstr "Populares" -#: ../src\wxUI\dialogs\search.py:43 ../src\wxUI\dialogs\trends.py:25 -#: ../src\wxUI\dialogs\userActions.py:41 -#: ../src\wxUI\dialogs\userSelection.py:33 +#: wxUI/dialogs/search.py:43 wxUI/dialogs/trends.py:25 +#: wxUI/dialogs/userActions.py:41 wxUI/dialogs/userSelection.py:33 msgid "&OK" msgstr "&Aceptar" -#: ../src\wxUI\dialogs\search.py:45 ../src\wxUI\dialogs\show_user.py:19 -#: ../src\wxUI\dialogs\trends.py:27 ../src\wxUI\dialogs\update_profile.py:37 -#: ../src\wxUI\dialogs\userActions.py:43 -#: ../src\wxUI\dialogs\userSelection.py:35 +#: wxUI/dialogs/search.py:45 wxUI/dialogs/show_user.py:19 +#: wxUI/dialogs/trends.py:27 wxUI/dialogs/update_profile.py:37 +#: wxUI/dialogs/userActions.py:43 wxUI/dialogs/userSelection.py:35 msgid "&Close" msgstr "Ce&rrar" -#: ../src\wxUI\dialogs\show_user.py:12 +#: wxUI/dialogs/show_user.py:12 msgid "Details" msgstr "Detalles" -#: ../src\wxUI\dialogs\show_user.py:17 +#: wxUI/dialogs/show_user.py:17 msgid "&Go to URL" msgstr "&Ir a URL" -#: ../src\wxUI\dialogs\trends.py:10 +#: wxUI/dialogs/trends.py:10 msgid "View trending topics" msgstr "Ver tendencias" -#: ../src\wxUI\dialogs\trends.py:11 +#: wxUI/dialogs/trends.py:11 msgid "Trending topics by" msgstr "Tendencias por" -#: ../src\wxUI\dialogs\trends.py:12 +#: wxUI/dialogs/trends.py:12 msgid "Country" msgstr "País" -#: ../src\wxUI\dialogs\trends.py:13 +#: wxUI/dialogs/trends.py:13 msgid "City" msgstr "Ciudad" -#: ../src\wxUI\dialogs\trends.py:19 ../src\wxUI\dialogs\update_profile.py:18 +#: wxUI/dialogs/trends.py:19 wxUI/dialogs/update_profile.py:18 msgid "&Location" msgstr "&Ubicación" -#: ../src\wxUI\dialogs\update_profile.py:10 +#: wxUI/dialogs/update_profile.py:10 msgid "Update your profile" msgstr "Actualizar tu perfil" -#: ../src\wxUI\dialogs\update_profile.py:12 +#: wxUI/dialogs/update_profile.py:12 msgid "&Name (50 characters maximum)" msgstr "&Nombre (máximo 50 caracteres)" -#: ../src\wxUI\dialogs\update_profile.py:23 +#: wxUI/dialogs/update_profile.py:23 msgid "&Website" msgstr "Sitio &web" -#: ../src\wxUI\dialogs\update_profile.py:28 +#: wxUI/dialogs/update_profile.py:28 msgid "&Bio (160 characters maximum)" msgstr "&Descripción (máximo 160 caracteres)" -#: ../src\wxUI\dialogs\update_profile.py:34 +#: wxUI/dialogs/update_profile.py:34 msgid "Upload a &picture" msgstr "Subir una &foto" -#: ../src\wxUI\dialogs\update_profile.py:35 ../src\wxUI\view.py:19 -msgid "&Update profile" -msgstr "Actuali&zar perfil" - -#: ../src\wxUI\dialogs\update_profile.py:77 +#: wxUI/dialogs/update_profile.py:77 msgid "Upload a picture" msgstr "Subir una foto" -#: ../src\wxUI\dialogs\update_profile.py:79 +#: wxUI/dialogs/update_profile.py:79 msgid "Discard image" msgstr "Descartar foto" -#: ../src\wxUI\dialogs\urlList.py:6 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:133 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:289 +#: wxUI/dialogs/update_profile.py:82 +msgid "Select the picture to be uploaded" +msgstr "Selecciona una foto para subir" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:133 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:289 +#: wxUI/dialogs/update_profile.py:82 +msgid "Image files (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" +msgstr "Archivos de imagen (*.png, *.jpg, *.gif)|*.png; *.jpg; *.gif" + +#: wxUI/dialogs/urlList.py:6 msgid "Select URL" msgstr "Selecciona la URL" -#: ../src\wxUI\dialogs\userActions.py:11 ../src\wxUI\view.py:87 -msgid "&User" -msgstr "&Usuario" - -#: ../src\wxUI\dialogs\userActions.py:14 -#: ../src\wxUI\dialogs\userAliasDialogs.py:13 -#: ../src\wxUI\dialogs\userSelection.py:14 ../src\wxUI\dialogs\utils.py:31 +#: wxUI/dialogs/userActions.py:14 wxUI/dialogs/userAliasDialogs.py:13 +#: wxUI/dialogs/userSelection.py:14 wxUI/dialogs/utils.py:31 msgid "&Autocomplete users" msgstr "&Autocompletar usuarios" -#: ../src\wxUI\dialogs\userActions.py:20 +#: wxUI/dialogs/userActions.py:20 msgid "&Follow" msgstr "&Seguir" -#: ../src\wxUI\dialogs\userActions.py:21 +#: wxUI/dialogs/userActions.py:21 msgid "U&nfollow" msgstr "&Dejar de seguir" -#: ../src\wxUI\dialogs\userActions.py:22 ../src\wxUI\view.py:63 -msgid "&Mute" -msgstr "S&ilenciar" - -#: ../src\wxUI\dialogs\userActions.py:23 +#: wxUI/dialogs/userActions.py:23 msgid "Unmu&te" msgstr "D&esactivar silencio" -#: ../src\wxUI\dialogs\userActions.py:24 +#: wxUI/dialogs/userActions.py:24 msgid "&Block" msgstr "&Bloquear" -#: ../src\wxUI\dialogs\userActions.py:25 +#: wxUI/dialogs/userActions.py:25 msgid "Unbl&ock" msgstr "Desb&loquear" -#: ../src\wxUI\dialogs\userActions.py:26 +#: wxUI/dialogs/userActions.py:26 msgid "&Report as spam" msgstr "&Reportar como spam" -#: ../src\wxUI\dialogs\userActions.py:27 +#: wxUI/dialogs/userActions.py:27 msgid "&Ignore tweets from this client" msgstr "&Ignorar tuits de este cliente" -#: ../src\wxUI\dialogs\userAliasDialogs.py:18 +#: wxUI/dialogs/userAliasDialogs.py:18 msgid "Alias" msgstr "Alias" -#: ../src\wxUI\dialogs\userAliasDialogs.py:41 +#: wxUI/dialogs/userAliasDialogs.py:41 msgid "Edit user aliases" msgstr "Editar alias de usuarios" -#: ../src\wxUI\dialogs\userAliasDialogs.py:48 +#: wxUI/dialogs/userAliasDialogs.py:48 msgid "Actions" msgstr "Acciones" -#: ../src\wxUI\dialogs\userAliasDialogs.py:50 +#: wxUI/dialogs/userAliasDialogs.py:50 msgid "Add alias" msgstr "Añadir alias" -#: ../src\wxUI\dialogs\userAliasDialogs.py:51 +#: wxUI/dialogs/userAliasDialogs.py:51 msgid "Adds a new user alias" msgstr "Añadir un nuevo alias" -#: ../src\wxUI\dialogs\userAliasDialogs.py:54 +#: wxUI/dialogs/userAliasDialogs.py:54 msgid "Edit the currently focused user Alias." msgstr "Editar alias del usuario seleccionado" -#: ../src\wxUI\dialogs\userAliasDialogs.py:58 +#: wxUI/dialogs/userAliasDialogs.py:58 msgid "Remove the currently focused user alias." msgstr "Eliminar alias del usuario seleccionado." -#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +#: wxUI/dialogs/userAliasDialogs.py:82 msgid "Are you sure you want to delete this user alias?" msgstr "¿Estás seguro que deseas eliminar este alias de usuario?" -#: ../src\wxUI\dialogs\userAliasDialogs.py:82 +#: wxUI/dialogs/userAliasDialogs.py:82 msgid "Remove user alias" msgstr "Eliminar alias de usuario" -#: ../src\wxUI\dialogs\userAliasDialogs.py:93 +#: wxUI/dialogs/userAliasDialogs.py:93 msgid "User alias" msgstr "Alias de usuario" -#: ../src\wxUI\dialogs\userSelection.py:10 +#: wxUI/dialogs/userSelection.py:10 +#, python-format msgid "Timeline for %s" msgstr "Línea temporal de %s" -#: ../src\wxUI\dialogs\userSelection.py:19 +#: wxUI/dialogs/userSelection.py:19 msgid "Buffer type" msgstr "Tipo de buffer" -#: ../src\wxUI\dialogs\userSelection.py:20 +#: wxUI/dialogs/userSelection.py:20 msgid "&Tweets" msgstr "&Tuits" -#: ../src\wxUI\dialogs\userSelection.py:21 +#: wxUI/dialogs/userSelection.py:21 msgid "&Likes" msgstr "Tuits marcados como &me gusta" -#: ../src\wxUI\dialogs\userSelection.py:22 +#: wxUI/dialogs/userSelection.py:22 msgid "&Followers" msgstr "&Seguidores" -#: ../src\wxUI\dialogs\userSelection.py:23 +#: wxUI/dialogs/userSelection.py:23 msgid "F&riends" msgstr "&Amigos" -#: ../src\wxUI\menus.py:8 ../src\wxUI\view.py:33 -msgid "&Retweet" -msgstr "&Retuit" - -#: ../src\wxUI\menus.py:10 ../src\wxUI\menus.py:34 ../src\wxUI\view.py:32 -msgid "Re&ply" -msgstr "Res&ponder" - -#: ../src\wxUI\menus.py:12 ../src\wxUI\view.py:34 -msgid "&Like" -msgstr "Me &gusta" - -#: ../src\wxUI\menus.py:14 ../src\wxUI\view.py:35 -msgid "&Unlike" -msgstr "&Ya no me gusta" - -#: ../src\wxUI\menus.py:16 ../src\wxUI\menus.py:36 ../src\wxUI\menus.py:52 -msgid "&Open URL" -msgstr "&Abrir URL" - -#: ../src\wxUI\menus.py:18 ../src\wxUI\menus.py:54 ../src\wxUI\menus.py:87 -msgid "&Open in Twitter" -msgstr "&Abrir en Twitter" - -#: ../src\wxUI\menus.py:20 ../src\wxUI\menus.py:38 ../src\wxUI\menus.py:56 -msgid "&Play audio" -msgstr "&Reproducir audio" - -#: ../src\wxUI\menus.py:22 ../src\wxUI\menus.py:58 ../src\wxUI\view.py:36 -msgid "&Show tweet" -msgstr "&Ver tuit" - -#: ../src\wxUI\menus.py:24 ../src\wxUI\menus.py:42 ../src\wxUI\menus.py:60 -#: ../src\wxUI\menus.py:70 ../src\wxUI\menus.py:89 ../src\wxUI\menus.py:103 -msgid "&Copy to clipboard" -msgstr "&Copiar al portapapeles" - -#: ../src\wxUI\menus.py:26 ../src\wxUI\menus.py:44 ../src\wxUI\menus.py:62 -#: ../src\wxUI\menus.py:72 ../src\wxUI\view.py:40 -msgid "&Delete" -msgstr "&Eliminar" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:32 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:48 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:168 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:252 +msgid "Attachments" +msgstr "Adjuntos" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:36 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:172 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:256 +msgid "Type" +msgstr "Tipo" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:39 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:175 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:259 +msgid "Delete attachment" +msgstr "Quitar archivo" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:44 +msgid "Added Tweets" +msgstr "Tuits añadidos" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:51 +msgid "Delete tweet" +msgstr "Quitar tuit" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:56 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:190 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:264 +msgid "A&dd..." +msgstr "Añadir..." + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:58 +msgid "Add t&weet" +msgstr "Añadir Tuit" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:61 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:192 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:266 +msgid "&Attach audio..." +msgstr "&Adjuntar audio..." + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:65 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:196 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:235 +msgid "Auto&complete users" +msgstr "Auto&completar usuarios" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:67 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:198 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:270 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:364 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:437 +msgid "Check &spelling..." +msgstr "Revisar &ortografía..." + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:69 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:200 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:272 +msgid "&Translate" +msgstr "&Traducir" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:73 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:204 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:276 +msgid "Sen&d" +msgstr "En&viar" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:117 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:218 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:296 +msgid "Image" +msgstr "Imagen" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:119 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:220 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:298 +msgid "Video" +msgstr "Vídeo" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:121 +msgid "Poll" +msgstr "Encuesta" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:126 +msgid "please provide a description" +msgstr "por favor proporciona una descripción" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:140 +msgid "Select the video to be uploaded" +msgstr "Selecciona un vídeo para subir" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:140 +msgid "Video files (*.mp4)|*.mp4" +msgstr "Archivos de video (*.mp4)|*.mp4" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:146 +msgid "" +"It is not possible to add more attachments. Please make sure your tweet " +"complies with Twitter'S attachment rules. You can add only one video or GIF " +"in every tweet, and a maximum of 4 photos." +msgstr "" +"No es posible añadir más archivos multimedia. Por favor asegúrate que " +"cumples con los requisitos de archivos de Twitter. Solo se puede añadir un " +"video o un GIF en cada tweet, o un máximo de hasta 4 imágenes." + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:146 +msgid "Error adding attachment" +msgstr "Error añadiendo un archivo" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:180 +msgid "&Mention to all" +msgstr "&Mencionar a todos" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:233 +msgid "&Recipient" +msgstr "&Destinatario" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:304 +#, python-format +msgid "Tweet - %i characters " +msgstr "Tuit - %i caracteres " + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:321 +msgid "Image description" +msgstr "Descripción de la imagen" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:332 +msgid "Retweets: " +msgstr "Retuits: " + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:337 +msgid "Likes: " +msgstr "Me gusta: " + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:342 +msgid "Source: " +msgstr "Desde: " + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:347 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:425 +msgid "Date: " +msgstr "Fecha: " + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:362 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:435 +msgid "Copy link to clipboard" +msgstr "Copiar enlace al portapapeles" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:365 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:440 +msgid "&Translate..." +msgstr "&Traducir..." + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:366 +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:441 +msgid "C&lose" +msgstr "Ce&rrar" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:410 +msgid "View" +msgstr "Ver" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:412 +msgid "Item" +msgstr "Elemento" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:438 +msgid "&Expand URL" +msgstr "&Expandir URL" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:477 +msgid "Add a poll" +msgstr "Añadir encuesta" + +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:481 +msgid "Participation time (in days)" +msgstr "Tiempo para participar (en días)" -#: ../src\wxUI\menus.py:28 ../src\wxUI\menus.py:46 ../src\wxUI\menus.py:91 -msgid "&User actions..." -msgstr "&Acciones de usuario..." +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:488 +msgid "Choices" +msgstr "Opciones" -#: ../src\wxUI\menus.py:40 -msgid "&Show direct message" -msgstr "&Mostrar mensaje directo" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:492 +msgid "Option 1" +msgstr "Opción 1" -#: ../src\wxUI\menus.py:68 -msgid "&Show event" -msgstr "&Mostrar evento" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:499 +msgid "Option 2" +msgstr "Opción 2" -#: ../src\wxUI\menus.py:78 -msgid "Direct &message" -msgstr "Mensaje &directo" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:506 +msgid "Option 3" +msgstr "Opción 3" -#: ../src\wxUI\menus.py:80 ../src\wxUI\view.py:50 -msgid "&View lists" -msgstr "&Ver listas" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:513 +msgid "Option 4" +msgstr "Opción 4" -#: ../src\wxUI\menus.py:83 ../src\wxUI\view.py:51 -msgid "Show user &profile" -msgstr "Ve&r perfil del usuario" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:541 +msgid "Please make sure you have provided at least two options for the poll." +msgstr "" +"Por favor asegúrate de haber proporcionado, al menos, dos opciones para la " +"encuesta." -#: ../src\wxUI\menus.py:85 -msgid "&Show user" -msgstr "&Mostrar usuario" +#: wxUI/dialogs/twitterDialogs/tweetDialogs.py:541 +msgid "Not enough information" +msgstr "Información insuficiente" -#: ../src\wxUI\menus.py:99 -msgid "&Tweet about this trend" -msgstr "&Tuitear sobre esta tendencia" +#~ msgid "Photo" +#~ msgstr "Imagen" -#: ../src\wxUI\menus.py:101 -msgid "&Show item" -msgstr "&Ver tuit" +#~ msgid "There's no URL to be shortened" +#~ msgstr "No hay ninguna URL para acortar" -#: ../src\wxUI\sysTrayIcon.py:36 ../src\wxUI\view.py:26 -msgid "&Global settings" -msgstr "Opciones &globales" +#~ msgid "URL shortened" +#~ msgstr "URL Acortada" -#: ../src\wxUI\sysTrayIcon.py:37 ../src\wxUI\view.py:25 -msgid "Account se&ttings" -msgstr "Opciones de &cuenta" +#~ msgid "There's no URL to be expanded" +#~ msgstr "No hay ninguna URL para expandir" -#: ../src\wxUI\sysTrayIcon.py:38 -msgid "Update &profile" -msgstr "Actualizar &perfil" +#~ msgid "URL expanded" +#~ msgstr "URL expandida" -#: ../src\wxUI\sysTrayIcon.py:39 -msgid "&Show / hide" -msgstr "&Mostrar / esconder" +#~ msgid "%s - %s characters" +#~ msgstr "%s - %s caracteres" -#: ../src\wxUI\sysTrayIcon.py:40 ../src\wxUI\view.py:75 -msgid "&Documentation" -msgstr "&Documentación" +#~ msgid "Title" +#~ msgstr "Título" -#: ../src\wxUI\sysTrayIcon.py:41 -msgid "Check for &updates" -msgstr "Comprobar &actualizaciones" +#~ msgid "Add attachments" +#~ msgstr "Añadir adjuntos" -#: ../src\wxUI\sysTrayIcon.py:42 -msgid "&Exit" -msgstr "&Salir" +#~ msgid "&Photo" +#~ msgstr "&Foto" -#: ../src\wxUI\view.py:18 -msgid "&Manage accounts" -msgstr "Gestionar &cuentas" +#~ msgid "&Long tweet" +#~ msgstr "Tuit &largo" -#: ../src\wxUI\view.py:20 -msgid "&Hide window" -msgstr "Esconder &ventana" +#~ msgid "&Upload image..." +#~ msgstr "&Subir imagen..." -#: ../src\wxUI\view.py:22 -msgid "&Lists manager" -msgstr "Gestor de &listas" - -#: ../src\wxUI\view.py:23 -msgid "Manage user aliases" -msgstr "Gestionar alias de usuario" - -#: ../src\wxUI\view.py:24 -msgid "&Edit keystrokes" -msgstr "Editar combinaciones de &teclas" - -#: ../src\wxUI\view.py:27 -msgid "E&xit" -msgstr "S&alir" - -#: ../src\wxUI\view.py:31 ../src\wxUI\view.py:86 -msgid "&Tweet" -msgstr "&Tuit" - -#: ../src\wxUI\view.py:37 -msgid "View &address" -msgstr "Ver &dirección" - -#: ../src\wxUI\view.py:38 -msgid "View conversa&tion" -msgstr "Ver conversa&ción" - -#: ../src\wxUI\view.py:39 -msgid "Read text in picture" -msgstr "Leer texto en imágenes" - -#: ../src\wxUI\view.py:44 -msgid "&Actions..." -msgstr "&Acciones..." - -#: ../src\wxUI\view.py:45 -msgid "&View timeline..." -msgstr "&Ver línea temporal..." - -#: ../src\wxUI\view.py:46 -msgid "Direct me&ssage" -msgstr "&Mensaje directo" - -#: ../src\wxUI\view.py:47 -msgid "Add a&lias" -msgstr "Añadir alias" - -#: ../src\wxUI\view.py:48 -msgid "&Add to list" -msgstr "&Añadir a lista" - -#: ../src\wxUI\view.py:49 -msgid "R&emove from list" -msgstr "&Quitar de lista" - -#: ../src\wxUI\view.py:52 -msgid "V&iew likes" -msgstr "&Ver tuits marcados con me gusta" - -#: ../src\wxUI\view.py:56 -msgid "&Update buffer" -msgstr "&actualizar buffer" - -#: ../src\wxUI\view.py:57 -msgid "New &trending topics buffer..." -msgstr "Nuevo buffer de &tendencias..." - -#: ../src\wxUI\view.py:58 -msgid "Create a &filter" -msgstr "Crear &filtro" - -#: ../src\wxUI\view.py:59 -msgid "&Manage filters" -msgstr "Gestionar &filtros" - -#: ../src\wxUI\view.py:60 -msgid "Find a string in the currently focused buffer..." -msgstr "Buscar término en el buffer actual..." - -#: ../src\wxUI\view.py:61 -msgid "&Load previous items" -msgstr "&Cargar elementos anteriores" - -#: ../src\wxUI\view.py:64 -msgid "&Autoread" -msgstr "&lectura automática" - -#: ../src\wxUI\view.py:65 -msgid "&Clear buffer" -msgstr "&Vaciar buffer" - -#: ../src\wxUI\view.py:66 -msgid "&Destroy" -msgstr "&Eliminar" - -#: ../src\wxUI\view.py:70 -msgid "&Seek back 5 seconds" -msgstr "&Retroceder 5 segundos" - -#: ../src\wxUI\view.py:71 -msgid "&Seek forward 5 seconds" -msgstr "A&vanzar 5 segundos" - -#: ../src\wxUI\view.py:76 -msgid "Sounds &tutorial" -msgstr "Tutorial de &sonidos" - -#: ../src\wxUI\view.py:77 -msgid "&What's new in this version?" -msgstr "¿&Qué hay de nuevo en esta versión?" - -#: ../src\wxUI\view.py:78 -msgid "&Check for updates" -msgstr "&Comprobar actualizaciones" - -#: ../src\wxUI\view.py:79 -msgid "&Report an error" -msgstr "&Reportar un error" - -#: ../src\wxUI\view.py:80 -msgid "{0}'s &website" -msgstr "Sitio &web de {0}" - -#: ../src\wxUI\view.py:81 -msgid "Get soundpacks for TWBlue" -msgstr "Obtener paquetes de sonidos para TWBlue" - -#: ../src\wxUI\view.py:82 -msgid "About &{0}" -msgstr "Sobre &{0}" - -#: ../src\wxUI\view.py:85 -msgid "&Application" -msgstr "&Aplicación" - -#: ../src\wxUI\view.py:88 -msgid "&Buffer" -msgstr "&Buffer" - -#: ../src\wxUI\view.py:89 -msgid "&Audio" -msgstr "&Audio" - -#: ../src\wxUI\view.py:90 -msgid "&Help" -msgstr "Ay&uda" - -#: ../src\wxUI\view.py:176 -msgid "Address" -msgstr "Dirección" - -#: ../src\wxUI\view.py:207 -msgid "Update" -msgstr "Actualización" - -#: ../src\wxUI\view.py:207 -msgid "Your {0} version is up to date" -msgstr "Tu versión de {0} está actualizada" +#~ msgid "Sh&orten URL" +#~ msgstr "Acortar &URL" #~ msgid "Friends' Timelines" #~ msgstr "Líneas temporales de amigos" @@ -3682,9 +3857,6 @@ msgstr "Tu versión de {0} está actualizada" #~ msgid "GIF images" #~ msgstr "Imágenes GIF" -#~ msgid "PNG Images" -#~ msgstr "Imágenes PNG" - #~ msgid "Select an URL" #~ msgstr "Selecciona una URL" diff --git a/src/locales/fr/LC_MESSAGES/twblue.mo b/src/locales/fr/LC_MESSAGES/twblue.mo index 2d8ceb5cd79bfc8523ba19a9b3344d478969ea03..a6de84039f627abb6c7670462284eface51f20bf 100644 GIT binary patch delta 18273 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 TH*FJBADo}%le+Y~BYyt}NNleu diff --git a/src/locales/fr/LC_MESSAGES/twblue.po b/src/locales/fr/LC_MESSAGES/twblue.po index 3842a448..f9587d45 100644 --- a/src/locales/fr/LC_MESSAGES/twblue.po +++ b/src/locales/fr/LC_MESSAGES/twblue.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: TW Blue 0.94\n" "POT-Creation-Date: 2021-11-11 01:00+0100\n" -"PO-Revision-Date: 2021-11-11 01:08+0100\n" +"PO-Revision-Date: 2021-11-12 13:32-0600\n" "Last-Translator: Oreonan \n" "Language-Team: Oreonan \n" "Language: fr\n" From 7bfbadc254604e1b01fb5f88bd53274fe6bf95a5 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 12 Nov 2021 15:01:54 -0600 Subject: [PATCH 241/245] Update write_version_data --- src/write_version_data.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/write_version_data.py b/src/write_version_data.py index a634030f..2136c3a0 100644 --- a/src/write_version_data.py +++ b/src/write_version_data.py @@ -28,11 +28,3 @@ file2 = open("..\\scripts\\twblue.nsi", "w", encoding="utf-8") file2.write(contents) file2.close() print("done") -print("Writing keys to module...") -file3 = open("appkeys.py", "w") -keys = """twitter_api_key = "{}" -twitter_api_secret = "{}" -""".format(os.environ.get("TWITTER_API_KEY"), os.environ.get("TWITTER_API_SECRET")) -file3.write(keys) -file3.close() -print("Wrote set of keys for consumer of {}".format(os.environ.get("TWITTER_API_KEY"))) \ No newline at end of file From 806111c36e87679348a225824fa7081dc5086632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Mon, 15 Nov 2021 13:04:18 +0100 Subject: [PATCH 242/245] Included more dependencies in the setup script --- src/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/setup.py b/src/setup.py index f5bc1f17..b0734eaa 100644 --- a/src/setup.py +++ b/src/setup.py @@ -8,9 +8,9 @@ from requests import certs def get_architecture_files(): if platform.architecture()[0][:2] == "32": - return ["../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", "../windows-dependencies/x86/libvlc.dll", "../windows-dependencies/x86/libvlccore.dll", "../windows-dependencies/x86/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell"], ["../windows-dependencies/x86/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFC", "."]] + return ["../windows-dependencies/x86/oggenc2.exe", "../windows-dependencies/x86/bootstrap.exe", "../windows-dependencies/x86/libvlc.dll", "../windows-dependencies/x86/libvlccore.dll", "../windows-dependencies/x86/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw32/share/enchant/hunspell"], ["../windows-dependencies/x86/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFC", "."], ["../windows-dependencies/x86/Microsoft.VC142.MFCLOC", "."], ["../windows-dependencies/x86/ucrt", "."]] elif platform.architecture()[0][:2] == "64": - return ["../windows-dependencies/x64/oggenc2.exe", "../windows-dependencies/x64/bootstrap.exe", "../windows-dependencies/x64/libvlc.dll", "../windows-dependencies/x64/libvlccore.dll", "../windows-dependencies/x64/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw64/share/enchant/hunspell"], ["../windows-dependencies/x64/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFC", "."]] + return ["../windows-dependencies/x64/oggenc2.exe", "../windows-dependencies/x64/bootstrap.exe", "../windows-dependencies/x64/libvlc.dll", "../windows-dependencies/x64/libvlccore.dll", "../windows-dependencies/x64/plugins", ["../windows-dependencies/dictionaries", "lib/enchant/data/mingw64/share/enchant/hunspell"], ["../windows-dependencies/x64/Microsoft.VC142.CRT", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFC", "."], ["../windows-dependencies/x64/Microsoft.VC142.MFCLOC", "."], ["../windows-dependencies/x64/ucrt", "."]] def find_sound_lib_datafiles(): import os From 78c10b38e5d9cc455eef725deb729f1af275fde2 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 8 Dec 2021 12:49:20 -0600 Subject: [PATCH 243/245] Fixed issue when sending tweets and replies with images --- src/sessions/twitter/session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sessions/twitter/session.py b/src/sessions/twitter/session.py index a311ab42..55373aa7 100644 --- a/src/sessions/twitter/session.py +++ b/src/sessions/twitter/session.py @@ -631,7 +631,7 @@ class Session(base.baseSession): if i["type"] == "photo": self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) - item = self.api_call_v2(call_name="create_tweet", status=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"], quote_tweet_id=obj.get("quote_tweet_id")) + item = self.api_call_v2(call_name="create_tweet", text=obj["text"], _sound="tweet_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, poll_duration_minutes=obj["poll_period"], poll_options=obj["poll_options"], quote_tweet_id=obj.get("quote_tweet_id")) in_reply_to_status_id = item.data["id"] def reply(self, text="", in_reply_to_status_id=None, attachments=[], *args, **kwargs): @@ -644,7 +644,7 @@ class Session(base.baseSession): if i["type"] == "photo": self.api_call(call_name="create_media_metadata", media_id=img.media_id, alt_text=i["description"]) media_ids.append(img.media_id) - item = self.api_call(call_name="update_status", status=text, _sound="reply_send.ogg", tweet_mode="extended", in_reply_to_status_id=in_reply_to_status_id, media_ids=media_ids, *args, **kwargs) + item = self.api_call_v2(call_name="create_tweet", text=text, _sound="reply_send.ogg", in_reply_to_tweet_id=in_reply_to_status_id, media_ids=media_ids, *args, **kwargs) def direct_message(self, text, recipient, attachment=None, *args, **kwargs): if attachment == None: From 86a2eb7c0d8ed7bf2c326a30e615a7ddec9bc3f1 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 9 Dec 2021 10:46:07 -0600 Subject: [PATCH 244/245] Restored conversation and threads support powered by Twitter API V2 --- doc/changelog.md | 5 +++++ src/controller/buffers/twitter/search.py | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/changelog.md b/doc/changelog.md index cc097af8..13d35a74 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,11 @@ TWBlue Changelog ## changes in this version +* We have restored conversation and threads support powered by Twitter API V2 thanks to a set of improvements we have done in the application, as well as more generous limits to Tweet monthly cap by Twitter. +* Fixed issue when uploading attachments (images, videos or gif files) while sending tweets or replies. + +## Changes in version 2021.11.12 + * Now it is possible to create a tweet from a trending topics buffer again. * TWBlue now includes a completely new set of dialogs to handle tweeting, replying and sending direct messages that takes advantage of more Twitter features. * It is possible to add videos in tweets and direct messages by using the new "add" button, located in every dialog where media can be added. Twitter suggests to add videos from 5 seconds up to 2 minutes lenght, in mp4 format (video Codec H.264 and audio codec AAC). Currently, TWBlue does not check if the uploaded video complies with Twitter media requirements. You can add only a video in a tweet or direct message. No other kind of media can be added after a video is in a tweet. If the video was unable to be uploaded successfully, the tweet or direct message won't be created. diff --git a/src/controller/buffers/twitter/search.py b/src/controller/buffers/twitter/search.py index db72fd35..55205069 100644 --- a/src/controller/buffers/twitter/search.py +++ b/src/controller/buffers/twitter/search.py @@ -64,12 +64,16 @@ class SearchPeopleBuffer(people.PeopleBuffer): return False class ConversationBuffer(SearchBuffer): + last_thread_id = None + last_reply_id = None def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False): current_time = time.time() if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True: self.execution_time = current_time - results = self.get_replies_v1(self.tweet) + log.debug("Retrieving conversation. Last thread ID is {}, last reply ID is {}".format(self.last_thread_id, self.last_reply_id)) + results = self.get_replies(self.tweet) + log.debug("Retrieved {} items before filters.".format(len(results))) number_of_items = self.session.order_buffer(self.name, results) log.debug("Number of items retrieved: %d" % (number_of_items,)) self.put_items_on_list(number_of_items) @@ -117,12 +121,12 @@ class ConversationBuffer(SearchBuffer): # find all tweets replying to the original thread only. Those tweets are sent by the same author who originally posted the first tweet. try: term = "conversation_id:{} from:{} to:{}".format(conversation_id, original_tweet.data.author_id, original_tweet.data.author_id) - thread_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) + thread_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=98, since_id=self.last_thread_id, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) if thread_tweets.data != None: thread_results.extend(thread_tweets.data) # Search only replies to conversation_id. term = "conversation_id:{}".format(conversation_id, original_tweet.data.author_id) - reply_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=50, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) + reply_tweets = self.session.twitter_v2.search_recent_tweets(term, user_auth=True, max_results=50, since_id=self.last_reply_id, tweet_fields=["in_reply_to_user_id", "author_id", "conversation_id"]) if reply_tweets.data != None: reply_results.extend(reply_tweets.data) except TweepyException as e: @@ -135,6 +139,7 @@ class ConversationBuffer(SearchBuffer): try: thread_results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended") thread_results.sort(key=lambda x: x.id) + self.last_thread_id = thread_results[-1].id results.extend(thread_results) except TweepyException as e: log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) @@ -144,6 +149,7 @@ class ConversationBuffer(SearchBuffer): try: reply_results = self.session.twitter.lookup_statuses(ids, include_ext_alt_text=True, tweet_mode="extended") reply_results.sort(key=lambda x: x.id) + self.last_reply_id = reply_results[-1].id results.extend(reply_results) except TweepyException as e: log.exception("There was an error attempting to retrieve tweets for Twitter API V1.1, in conversation buffer {}".format(self.name)) From b67fc0ff3822b980a8eaaf9f8ab1761a1876230e Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 10 Dec 2021 09:53:49 -0600 Subject: [PATCH 245/245] Made some cleanup in unneeded imports --- src/sessions/twitter/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sessions/twitter/utils.py b/src/sessions/twitter/utils.py index d44e0e3f..47cef7a7 100644 --- a/src/sessions/twitter/utils.py +++ b/src/sessions/twitter/utils.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- import re import output -import config import logging import requests import time -import sound from tweepy.errors import TweepyException, NotFound, Forbidden log = logging.getLogger("twitter.utils") """ Some utilities for the twitter interface."""