From 9dc50b5c4160f9a657cb25d70518d3e243c2b72f Mon Sep 17 00:00:00 2001 From: ShyPike Date: Sun, 5 Sep 2010 21:35:47 +0200 Subject: [PATCH] Convert to GNU gettext following the Launchpad translation guidelines. Implements blueprints "go-gettext" and "code-gettext". Use tools/extract_pot.py to create new POT files. Use tools/make_mo.py to create MO files, email template translations and patch the NSIS_Installer.nsi script. --- NSIS_Installer.nsi | 859 ++++---- SABnzbd.py | 26 +- SABnzbdDelegate.py | 77 +- email/email-en.tmpl | 41 + email/rss-en.tmpl | 25 + interfaces/Classic/templates/history.tmpl | 4 +- interfaces/Classic/templates/queue.tmpl | 2 +- interfaces/Mobile/language/de-de.txt | 41 - interfaces/Mobile/language/dk-da.txt | 40 - interfaces/Mobile/language/fr-fr.txt | 42 - interfaces/Mobile/language/nl-du.txt | 42 - interfaces/Mobile/language/no-no.txt | 40 - interfaces/Mobile/language/sv-se.txt | 40 - interfaces/Mobile/language/us-en.txt | 42 - interfaces/Plush/language/de-de.txt | 72 - interfaces/Plush/language/dk-da.txt | 70 - interfaces/Plush/language/fr-fr.txt | 70 - interfaces/Plush/language/nl-du.txt | 69 - interfaces/Plush/language/sv-se.txt | 71 - interfaces/Plush/language/us-en.txt | 72 - interfaces/Plush/templates/history.tmpl | 4 +- interfaces/smpl/language/de-de.txt | 46 - interfaces/smpl/language/dk-da.txt | 45 - interfaces/smpl/language/fr-fr.txt | 45 - interfaces/smpl/language/nl-du.txt | 44 - interfaces/smpl/language/no-no.txt | 48 - interfaces/smpl/language/sv-se.txt | 46 - interfaces/smpl/language/us-en.txt | 45 - interfaces/smpl/templates/history.tmpl | 4 +- interfaces/smpl/templates/main.tmpl | 2 +- interfaces/wizard/language/de-de.txt | 61 - interfaces/wizard/language/dk-da.txt | 54 - interfaces/wizard/language/fr-fr.txt | 53 - interfaces/wizard/language/nl-du.txt | 56 - interfaces/wizard/language/no-no.txt | 54 - interfaces/wizard/language/sv-se.txt | 54 - interfaces/wizard/language/us-en.txt | 53 - language/de-de.txt | 920 -------- language/dk-da.txt | 830 -------- language/email-da-dk.tmpl | 43 - language/email-de-de.tmpl | 43 - language/email-fr-fr.tmpl | 42 - language/email-nl-du.tmpl | 41 - language/email-no-no.tmpl | 43 - language/email-sv-se.tmpl | 43 - language/email-us-en.tmpl | 41 - language/fr-fr.txt | 858 -------- language/nl-du.txt | 826 -------- language/no-no.txt | 830 -------- language/rss-de-de.tmpl | 25 - language/rss-fr-fr.tmpl | 25 - language/rss-nl-nl.tmpl | 24 - language/rss-no-no.tmpl | 25 - language/rss-sv-se.tmpl | 25 - language/rss-us-en.tmpl | 25 - language/sv-se.txt | 838 -------- language/us-en.txt | 858 -------- package.py | 12 +- po/email/SABemail.pot | 89 + po/email/da.po | 130 ++ po/email/de.po | 155 ++ po/email/en.po | 153 ++ po/email/fr.po | 154 ++ po/email/nl.po | 152 ++ po/email/no.po | 155 ++ po/email/sv.po | 155 ++ po/main/SABnzbd.pot | 3240 ++++++++++++++++++++++++++++ po/main/da.po | 3241 +++++++++++++++++++++++++++++ po/main/de.po | 3241 +++++++++++++++++++++++++++++ po/main/fr.po | 3241 +++++++++++++++++++++++++++++ po/main/nl.po | 3241 +++++++++++++++++++++++++++++ po/main/no.po | 3241 +++++++++++++++++++++++++++++ po/main/sv.po | 3241 +++++++++++++++++++++++++++++ po/nsis/SABnsis.pot | 67 + po/nsis/da.po | 66 + po/nsis/de.po | 66 + po/nsis/fr.po | 67 + po/nsis/nl.po | 67 + po/nsis/no.po | 66 + po/nsis/sv.po | 66 + sabnzbd/__init__.py | 46 +- sabnzbd/api.py | 35 +- sabnzbd/assembler.py | 9 +- sabnzbd/cfg.py | 7 +- sabnzbd/config.py | 11 +- sabnzbd/constants.py | 5 +- sabnzbd/database.py | 12 +- sabnzbd/decoder.py | 9 +- sabnzbd/dirscanner.py | 11 +- sabnzbd/downloader.py | 37 +- sabnzbd/emailer.py | 36 +- sabnzbd/interface.py | 95 +- sabnzbd/lang.py | 238 +-- sabnzbd/misc.py | 39 +- sabnzbd/newsunpack.py | 141 +- sabnzbd/newswrapper.py | 3 +- sabnzbd/newzbin.py | 25 +- sabnzbd/nzbqueue.py | 11 +- sabnzbd/nzbstuff.py | 19 +- sabnzbd/postproc.py | 45 +- sabnzbd/rss.py | 17 +- sabnzbd/scheduler.py | 9 +- sabnzbd/skintext.py | 725 +++++++ sabnzbd/tvsort.py | 11 +- sabnzbd/urlgrabber.py | 5 +- sabnzbd/utils/osx.py | 1 - sabnzbd/utils/servertests.py | 241 ++- sabnzbd/utils/upload.py | 130 +- sabnzbd/wizard.py | 16 +- tools/extract_pot.py | 143 ++ tools/make_mo.py | 183 ++ 111 files changed, 26518 insertions(+), 8967 deletions(-) create mode 100644 email/email-en.tmpl create mode 100644 email/rss-en.tmpl delete mode 100644 interfaces/Mobile/language/de-de.txt delete mode 100644 interfaces/Mobile/language/dk-da.txt delete mode 100644 interfaces/Mobile/language/fr-fr.txt delete mode 100644 interfaces/Mobile/language/nl-du.txt delete mode 100644 interfaces/Mobile/language/no-no.txt delete mode 100644 interfaces/Mobile/language/sv-se.txt delete mode 100644 interfaces/Mobile/language/us-en.txt delete mode 100644 interfaces/Plush/language/de-de.txt delete mode 100644 interfaces/Plush/language/dk-da.txt delete mode 100644 interfaces/Plush/language/fr-fr.txt delete mode 100644 interfaces/Plush/language/nl-du.txt delete mode 100644 interfaces/Plush/language/sv-se.txt delete mode 100644 interfaces/Plush/language/us-en.txt delete mode 100644 interfaces/smpl/language/de-de.txt delete mode 100644 interfaces/smpl/language/dk-da.txt delete mode 100644 interfaces/smpl/language/fr-fr.txt delete mode 100644 interfaces/smpl/language/nl-du.txt delete mode 100644 interfaces/smpl/language/no-no.txt delete mode 100644 interfaces/smpl/language/sv-se.txt delete mode 100644 interfaces/smpl/language/us-en.txt delete mode 100644 interfaces/wizard/language/de-de.txt delete mode 100644 interfaces/wizard/language/dk-da.txt delete mode 100644 interfaces/wizard/language/fr-fr.txt delete mode 100644 interfaces/wizard/language/nl-du.txt delete mode 100644 interfaces/wizard/language/no-no.txt delete mode 100644 interfaces/wizard/language/sv-se.txt delete mode 100644 interfaces/wizard/language/us-en.txt delete mode 100644 language/de-de.txt delete mode 100644 language/dk-da.txt delete mode 100644 language/email-da-dk.tmpl delete mode 100644 language/email-de-de.tmpl delete mode 100644 language/email-fr-fr.tmpl delete mode 100644 language/email-nl-du.tmpl delete mode 100644 language/email-no-no.tmpl delete mode 100644 language/email-sv-se.tmpl delete mode 100644 language/email-us-en.tmpl delete mode 100644 language/fr-fr.txt delete mode 100644 language/nl-du.txt delete mode 100644 language/no-no.txt delete mode 100644 language/rss-de-de.tmpl delete mode 100644 language/rss-fr-fr.tmpl delete mode 100644 language/rss-nl-nl.tmpl delete mode 100644 language/rss-no-no.tmpl delete mode 100644 language/rss-sv-se.tmpl delete mode 100644 language/rss-us-en.tmpl delete mode 100644 language/sv-se.txt delete mode 100644 language/us-en.txt create mode 100644 po/email/SABemail.pot create mode 100644 po/email/da.po create mode 100644 po/email/de.po create mode 100644 po/email/en.po create mode 100644 po/email/fr.po create mode 100644 po/email/nl.po create mode 100644 po/email/no.po create mode 100644 po/email/sv.po create mode 100644 po/main/SABnzbd.pot create mode 100644 po/main/da.po create mode 100644 po/main/de.po create mode 100644 po/main/fr.po create mode 100644 po/main/nl.po create mode 100644 po/main/no.po create mode 100644 po/main/sv.po create mode 100644 po/nsis/SABnsis.pot create mode 100644 po/nsis/da.po create mode 100644 po/nsis/de.po create mode 100644 po/nsis/fr.po create mode 100644 po/nsis/nl.po create mode 100644 po/nsis/no.po create mode 100644 po/nsis/sv.po create mode 100644 sabnzbd/skintext.py create mode 100644 tools/extract_pot.py create mode 100644 tools/make_mo.py diff --git a/NSIS_Installer.nsi b/NSIS_Installer.nsi index 93c2309..f8c35e3 100644 --- a/NSIS_Installer.nsi +++ b/NSIS_Installer.nsi @@ -1,421 +1,438 @@ -; -*- coding: latin-1 -*- -; -; Copyright 2008-2010 The SABnzbd-Team -; -; 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, write to the Free Software -; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -!addplugindir win\nsis\Plugins -!addincludedir win\nsis\Include - -!include "MUI2.nsh" -!include "registerExtension.nsh" - - -Name "${SAB_PRODUCT}" -OutFile "${SAB_FILE}" - - -; Some default compiler settings (uncomment and change at will): -; SetCompress auto ; (can be off or force) -; SetDatablockOptimize on ; (can be off) -; CRCCheck on ; (can be off) -; AutoCloseWindow false ; (can be true for the window go away automatically at end) -; ShowInstDetails hide ; (can be show to have them shown, or nevershow to disable) -; SetDateSave off ; (can be on to have files restored to their orginal date) -WindowIcon on - -InstallDir "$PROGRAMFILES\SABnzbd" -InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" -;DirText $(MsgSelectDir) - - ;Vista redirects $SMPROGRAMS to all users without this - RequestExecutionLevel admin - FileErrorText "If you have no admin rights, try to install into a user directory." - - -;-------------------------------- -;Variables - - Var MUI_TEMP - Var STARTMENU_FOLDER -;-------------------------------- -;Interface Settings - - !define MUI_ABORTWARNING - - ;Show all languages, despite user's codepage - !define MUI_LANGDLL_ALLLANGUAGES - - !define MUI_ICON "interfaces/Classic/templates/static/images/favicon.ico" - - -;-------------------------------- -;Pages - - !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" - !define MUI_COMPONENTSPAGE_NODESC - !insertmacro MUI_PAGE_COMPONENTS - - !insertmacro MUI_PAGE_DIRECTORY - - ;Start Menu Folder Page Configuration - !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" - !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\SABnzbd" - !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" - !define MUI_STARTMENUPAGE_DEFAULTFOLDER "SABnzbd" - ;Remember the installer language - !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" - !define MUI_LANGDLL_REGISTRY_KEY "Software\SABnzbd" - !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" - - !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER - - - !insertmacro MUI_PAGE_INSTFILES - !define MUI_FINISHPAGE_RUN - !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink" - !define MUI_FINISHPAGE_RUN_TEXT $(MsgStartSab) - !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt" - !define MUI_FINISHPAGE_SHOWREADME_TEXT $(MsgShowRelNote) - ;!define MUI_FINISHPAGE_LINK "View the SABnzbdPlus Wiki" - ;!define MUI_FINISHPAGE_LINK_LOCATION "http://wiki.sabnzbd.org/" - !define MUI_FINISHPAGE_LINK $(MsgSupportUs) - !define MUI_FINISHPAGE_LINK_LOCATION "http://www.sabnzbd.org/contribute/" - - !insertmacro MUI_PAGE_FINISH - - !insertmacro MUI_UNPAGE_CONFIRM - !define MUI_UNPAGE_COMPONENTSPAGE_NODESC - !insertmacro MUI_UNPAGE_COMPONENTS - !insertmacro MUI_UNPAGE_INSTFILES - -;-------------------------------- -;Languages - - ; Set supported languages - !insertmacro MUI_LANGUAGE "English" ;first language is the default language - !insertmacro MUI_LANGUAGE "French" - !insertmacro MUI_LANGUAGE "German" - !insertmacro MUI_LANGUAGE "Dutch" - !insertmacro MUI_LANGUAGE "Swedish" - !insertmacro MUI_LANGUAGE "Danish" - - -;-------------------------------- -;Reserve Files - - ;If you are using solid compression, files that are required before - ;the actual installation should be stored first in the data block, - ;because this will make your installer start faster. - - !insertmacro MUI_RESERVEFILE_LANGDLL - - -Function LaunchLink - ExecShell "" "$INSTDIR\SABnzbd.exe" -FunctionEnd - -;-------------------------------- -Function .onInit - !insertmacro MUI_LANGDLL_DISPLAY - -;make sure sabnzbd.exe isnt running..if so abort - loop: - StrCpy $0 "SABnzbd.exe" - KillProc::FindProcesses - StrCmp $0 "0" endcheck - MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgCloseSab) IDOK loop IDCANCEL exitinstall - exitinstall: - Abort - endcheck: -FunctionEnd - - -Section "SABnzbd" SecDummy -SetOutPath "$INSTDIR" - -IfFileExists $INSTDIR\sabnzbd.exe 0 endWarnExist - IfFileExists $INSTDIR\language\us-en.txt endWarnExist 0 - MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgOldQueue) IDOK endWarnExist IDCANCEL 0 - Abort -endWarnExist: - -; add files / whatever that need to be installed here. -File /r "dist\*" - - -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" "$INSTDIR" -WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayName" "SABnzbd (remove only)" -WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "UninstallString" '"$INSTDIR\uninstall.exe"' -;WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '"$INSTDIR\need-a-.ico"' -; write out uninstaller -WriteUninstaller "$INSTDIR\Uninstall.exe" - - !insertmacro MUI_STARTMENU_WRITE_BEGIN Application - - ;Create shortcuts - CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - SafeMode.lnk" "$INSTDIR\SABnzbd-console.exe" - WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - Documentation.url" "InternetShortcut" "URL" "http://wiki.sabnzbd.org/" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" - - - - !insertmacro MUI_STARTMENU_WRITE_END - - -SectionEnd ; end of default section - -Section /o $(MsgRunAtStart) startup - CreateShortCut "$SMPROGRAMS\Startup\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" "-b0" -SectionEnd ; - -Section $(MsgIcon) desktop - CreateShortCut "$DESKTOP\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" -SectionEnd ; end of desktop icon section - -Section /o $(MsgAssoc) assoc - ${registerExtension} "$INSTDIR\nzb.ico" "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File" - ;${registerExtension} "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File" -SectionEnd ; end of file association section - -; begin uninstall settings/section -UninstallText $(MsgUninstall) - -Section "un.$(MsgDelProgram)" Uninstall -;make sure sabnzbd.exe isnt running..if so shut it down - - StrCpy $0 "sabnzbd.exe" - DetailPrint "Searching for processes called '$0'" - KillProc::FindProcesses - StrCmp $1 "-1" wooops - DetailPrint "-> Found $0 processes" - - StrCmp $0 "0" completed - Sleep 1500 - - StrCpy $0 "sabnzbd.exe" - DetailPrint "Killing all processes called '$0'" - KillProc::KillProcesses - StrCmp $1 "-1" wooops - DetailPrint "-> Killed $0 processes, failed to kill $1 processes" - - Goto completed - - wooops: - DetailPrint "-> Error: Something went wrong :-(" - Abort - - completed: - DetailPrint "Process Killed" - - - ; add delete commands to delete whatever files/registry keys/etc you installed here. - Delete "$INSTDIR\uninstall.exe" - DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" - DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" - - ; Delete installation files are carefully as possible - ; Using just rmdir /r "$instdir" is considered unsafe! - Delete "$INSTDIR\language\email-de-de.tmpl" - Delete "$INSTDIR\language\email-us-en.tmpl" - Delete "$INSTDIR\language\email-nl-du.tmpl" - Delete "$INSTDIR\language\email-fr-fr.tmpl" - Delete "$INSTDIR\language\email-sv-se.tmpl" - Delete "$INSTDIR\language\email-dk-da.tmpl" - Delete "$INSTDIR\language\de-de.txt" - Delete "$INSTDIR\language\us-en.txt" - Delete "$INSTDIR\language\nl-du.txt" - Delete "$INSTDIR\language\fr-fr.txt" - Delete "$INSTDIR\language\sv-se.txt" - Delete "$INSTDIR\language\dk-da.txt" - RMDir "$INSTDIR\language" - RMDir /r "$INSTDIR\interfaces\Classic" - RMDir /r "$INSTDIR\interfaces\Plush" - RMDir /r "$INSTDIR\interfaces\smpl" - RMDir /r "$INSTDIR\interfaces\Mobile" - RMDir /r "$INSTDIR\interfaces\wizard" - RMDir "$INSTDIR\interfaces" - RMDir /r "$INSTDIR\win\par2" - RMDir /r "$INSTDIR\win\unrar" - RMDir /r "$INSTDIR\win\unzip" - RMDir /r "$INSTDIR\win" - Delete "$INSTDIR\licenses\*.txt" - Delete "$INSTDIR\licenses\Python\*.txt" - RMDir "$INSTDIR\licenses\Python" - RMDir "$INSTDIR\licenses" - Delete "$INSTDIR\lib\libeay32.dll" - Delete "$INSTDIR\lib\pywintypes25.dll" - Delete "$INSTDIR\lib\ssleay32.dll" - Delete "$INSTDIR\lib\sabnzbd.zip" - Delete "$INSTDIR\lib\*.pyd" - RMDir /r "$INSTDIR\lib\" - Delete "$INSTDIR\CHANGELOG.txt" - Delete "$INSTDIR\COPYRIGHT.txt" - Delete "$INSTDIR\email.tmpl" - Delete "$INSTDIR\GPL2.txt" - Delete "$INSTDIR\GPL3.txt" - Delete "$INSTDIR\INSTALL.txt" - Delete "$INSTDIR\ISSUES.txt" - Delete "$INSTDIR\LICENSE.txt" - Delete "$INSTDIR\nzbmatrix.txt" - Delete "$INSTDIR\MSVCR71.dll" - Delete "$INSTDIR\nzb.ico" - Delete "$INSTDIR\PKG-INFO" - Delete "$INSTDIR\python25.dll" - Delete "$INSTDIR\python26.dll" - Delete "$INSTDIR\README.txt" - Delete "$INSTDIR\SABnzbd-console.exe" - Delete "$INSTDIR\SABnzbd.exe" - Delete "$INSTDIR\Sample-PostProc.cmd" - Delete "$INSTDIR\Uninstall.exe" - Delete "$INSTDIR\w9xpopen.exe" - RMDir "$INSTDIR" - - !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP - - Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd.lnk" - Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" - Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - SafeMode.lnk" - Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - Documentation.url" - RMDir "$SMPROGRAMS\$MUI_TEMP" - - Delete "$SMPROGRAMS\Startup\SABnzbd.lnk" - - Delete "$DESKTOP\SABnzbd.lnk" - - DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd" - - ${unregisterExtension} ".nzb" "NZB File" - - -SectionEnd ; end of uninstall section - -Section "un.$(MsgDelSettings)" DelSettings - Delete "$LOCALAPPDATA\sabnzbd\sabnzbd.ini" - RMDir /r "$LOCALAPPDATA\sabnzbd\admin" -SectionEnd - - -Section "un.$(MsgDelLogs)" DelLogs - RMDir /r "$LOCALAPPDATA\sabnzbd\logs" -SectionEnd - - -Section "un.$(MsgDelCache)" DelCache - RMDir /r "$LOCALAPPDATA\sabnzbd\cache" - RMDir "$LOCALAPPDATA\sabnzbd" -SectionEnd - -; eof - -;-------------------------------- -;Language strings -; MsgWarnRunning 'Please close "SABnzbd.exe" first' - LangString MsgStartSab ${LANG_ENGLISH} "Start SABnzbd (hidden)" - LangString MsgStartSab ${LANG_DUTCH} "Start SABnzbd (verborgen)" - LangString MsgStartSab ${LANG_FRENCH} "Lancer SABnzbd (caché)" - LangString MsgStartSab ${LANG_GERMAN} "SABnzbd starten (unsichtbar)" - LangString MsgStartSab ${LANG_SWEDISH} "Starta SABnzbd (dold)" - LangString MsgStartSab ${LANG_DANISH} "Start SABnzbd (hidden)" - - LangString MsgShowRelNote ${LANG_ENGLISH} "Show Release Notes" - LangString MsgShowRelNote ${LANG_DUTCH} "Toon Vrijgave Bericht (Engels)" - LangString MsgShowRelNote ${LANG_FRENCH} "Afficher les notes de version" - LangString MsgShowRelNote ${LANG_GERMAN} "Versionshinweise anzeigen" - LangString MsgShowRelNote ${LANG_SWEDISH} "Visa release noteringar" - LangString MsgShowRelNote ${LANG_DANISH} "Show Release Notes" - - LangString MsgSupportUs ${LANG_ENGLISH} "Support the project, Donate!" - LangString MsgSupportUs ${LANG_DUTCH} "Steun het project, Doneer!" - LangString MsgSupportUs ${LANG_FRENCH} "Supportez le projet, faites un don !" - LangString MsgSupportUs ${LANG_GERMAN} "Bitte unterstützen Sie das Projekt durch eine Spende!" - LangString MsgSupportUs ${LANG_SWEDISH} "Donera och stöd detta projekt!" - LangString MsgSupportUs ${LANG_DANISH} "Support the project, Donate!" - - LangString MsgCloseSab ${LANG_ENGLISH} "Please close $\"SABnzbd.exe$\" first" - LangString MsgCloseSab ${LANG_DUTCH} "Sluit $\"SABnzbd.exe$\" eerst af" - LangString MsgCloseSab ${LANG_FRENCH} "Quittez $\"SABnzbd.exe$\" avant l\'installation, SVP" - LangString MsgCloseSab ${LANG_GERMAN} "Schliessen Sie bitte zuerst $\"SABnzbd.exe$\"." - LangString MsgCloseSab ${LANG_SWEDISH} "Var vänlig stäng $\"SABnzbd.exe$\" först" - LangString MsgCloseSab ${LANG_DANISH} "Please close $\"SABnzbd.exe$\" first" - - LangString MsgOldQueue ${LANG_ENGLISH} " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" - LangString MsgOldQueue ${LANG_DUTCH} " >>>> WAARSCHUWING <<<<$\r$\n$\r$\nIndien niet leeg, download eerst de gehele huidige wachtrij met het oude programma.$\r$\nHet nieuwe programma zal je huidige wachtrij negeren!" - LangString MsgOldQueue ${LANG_FRENCH} " >>>> ATTENTION <<<<$\r$\n$\r$\nsi votre file d'attente de téléchargement n'est pas vide, terminez la avec la version précédente du programme.$\r$\nLa nouvelle version l'ignorera!" - LangString MsgOldQueue ${LANG_GERMAN} " >>>> ACHTUNG <<<<$\r$\n$\r$\nWarten Sie, bis das alte Programm alle Downloads fertiggestellt hat.$\r$\nDas neue Programm wird die noch ausstehenden Downloads ignorieren!" - LangString MsgOldQueue ${LANG_SWEDISH} " >>>> VARNING <<<<$\r$\n$\r$\nOm kön inte är tom, hämta din nuvarande kö med det gamla programmet.$\r$\nDet nya programmet kommer att ignorera din nuvarande kö!" - LangString MsgOldQueue ${LANG_DANISH} " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" - - LangString MsgUninstall ${LANG_ENGLISH} "This will uninstall SABnzbd from your system" - LangString MsgUninstall ${LANG_DUTCH} "Dit verwijdert SABnzbd van je systeem" - LangString MsgUninstall ${LANG_FRENCH} "Ceci désinstallera SABnzbd de votre système" - LangString MsgUninstall ${LANG_GERMAN} "Dies entfernt SABnzbd von Ihrem System" - LangString MsgUninstall ${LANG_SWEDISH} "Detta kommer att avinstallera SABnzbd från systemet" - LangString MsgUninstall ${LANG_DANISH} "This will uninstall SABnzbd from your system" - - LangString MsgRunAtStart ${LANG_ENGLISH} "Run at startup" - LangString MsgRunAtStart ${LANG_DUTCH} "Opstarten bij systeem start" - LangString MsgRunAtStart ${LANG_FRENCH} "Lancer au démarrage" - LangString MsgRunAtStart ${LANG_GERMAN} "Beim Systemstart ausführen" - LangString MsgRunAtStart ${LANG_SWEDISH} "Kör vid uppstart" - LangString MsgRunAtStart ${LANG_DANISH} "Run at startup" - - LangString MsgIcon ${LANG_ENGLISH} "Desktop Icon" - LangString MsgIcon ${LANG_DUTCH} "Pictogram op bureaublad" - LangString MsgIcon ${LANG_FRENCH} "Icône sur le Bureau" - LangString MsgIcon ${LANG_GERMAN} "Desktop-Symbol" - LangString MsgIcon ${LANG_SWEDISH} "Skrivbordsikon" - LangString MsgIcon ${LANG_DANISH} "Desktop Icon" - - LangString MsgAssoc ${LANG_ENGLISH} "NZB File association" - LangString MsgAssoc ${LANG_DUTCH} "NZB bestanden koppelen aan SABnzbd" - LangString MsgAssoc ${LANG_FRENCH} "Association des fichiers NZB" - LangString MsgAssoc ${LANG_GERMAN} "Mit NZB-Dateien verknüpfen" - LangString MsgAssoc ${LANG_SWEDISH} "NZB Filassosication" - LangString MsgAssoc ${LANG_DANISH} "NZB File association" - - LangString MsgDelProgram ${LANG_ENGLISH} "Delete Program" - LangString MsgDelProgram ${LANG_DUTCH} "Verwijder programma" - LangString MsgDelProgram ${LANG_FRENCH} "Supprimer le programme" - LangString MsgDelProgram ${LANG_GERMAN} "Programm löschen" - LangString MsgDelProgram ${LANG_SWEDISH} "Ta bort programmet" - LangString MsgDelProgram ${LANG_DANISH} "Delete Program" - - LangString MsgDelSettings ${LANG_ENGLISH} "Delete Settings" - LangString MsgDelSettings ${LANG_DUTCH} "Verwijder instellingen" - LangString MsgDelSettings ${LANG_FRENCH} "Supprimer Paramètres" - LangString MsgDelSettings ${LANG_GERMAN} "Einstellungen löschen" - LangString MsgDelSettings ${LANG_SWEDISH} "Ta bort inställningar" - LangString MsgDelSettings ${LANG_DANISH} "Delete Settings" - - LangString MsgDelLogs ${LANG_ENGLISH} "Delete Logs" - LangString MsgDelLogs ${LANG_DUTCH} "Verwijder logging" - LangString MsgDelLogs ${LANG_FRENCH} "Supprimer les logs" - LangString MsgDelLogs ${LANG_GERMAN} "Protokoll löschen" - LangString MsgDelLogs ${LANG_SWEDISH} "Ta bort logg" - LangString MsgDelLogs ${LANG_DANISH} "Delete Logs" - - LangString MsgDelCache ${LANG_ENGLISH} "Delete Cache" - LangString MsgDelCache ${LANG_DUTCH} "Verwijder Cache" - LangString MsgDelCache ${LANG_FRENCH} "Supprimer le cache" - LangString MsgDelCache ${LANG_GERMAN} "Cache löschen" - LangString MsgDelCache ${LANG_SWEDISH} "Ta bort temporär-mapp" - LangString MsgDelCache ${LANG_DANISH} "Delete Cache" - -Function un.onInit - !insertmacro MUI_UNGETLANGUAGE -FunctionEnd +; -*- coding: latin-1 -*- +; +; Copyright 2008-2010 The SABnzbd-Team +; +; 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, write to the Free Software +; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +!addplugindir win\nsis\Plugins +!addincludedir win\nsis\Include + +!include "MUI2.nsh" +!include "registerExtension.nsh" + + +Name "${SAB_PRODUCT}" +OutFile "${SAB_FILE}" + + +; Some default compiler settings (uncomment and change at will): +; SetCompress auto ; (can be off or force) +; SetDatablockOptimize on ; (can be off) +; CRCCheck on ; (can be off) +; AutoCloseWindow false ; (can be true for the window go away automatically at end) +; ShowInstDetails hide ; (can be show to have them shown, or nevershow to disable) +; SetDateSave off ; (can be on to have files restored to their orginal date) +WindowIcon on + +InstallDir "$PROGRAMFILES\SABnzbd" +InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" +;DirText $(MsgSelectDir) + + ;Vista redirects $SMPROGRAMS to all users without this + RequestExecutionLevel admin + FileErrorText "If you have no admin rights, try to install into a user directory." + + +;-------------------------------- +;Variables + + Var MUI_TEMP + Var STARTMENU_FOLDER +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + + ;Show all languages, despite user's codepage + !define MUI_LANGDLL_ALLLANGUAGES + + !define MUI_ICON "interfaces/Classic/templates/static/images/favicon.ico" + + +;-------------------------------- +;Pages + + !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" + !define MUI_COMPONENTSPAGE_NODESC + !insertmacro MUI_PAGE_COMPONENTS + + !insertmacro MUI_PAGE_DIRECTORY + + ;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\SABnzbd" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "SABnzbd" + ;Remember the installer language + !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" + !define MUI_LANGDLL_REGISTRY_KEY "Software\SABnzbd" + !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" + + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + + + !insertmacro MUI_PAGE_INSTFILES + !define MUI_FINISHPAGE_RUN + !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink" + !define MUI_FINISHPAGE_RUN_TEXT $(MsgStartSab) + !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt" + !define MUI_FINISHPAGE_SHOWREADME_TEXT $(MsgShowRelNote) + ;!define MUI_FINISHPAGE_LINK "View the SABnzbdPlus Wiki" + ;!define MUI_FINISHPAGE_LINK_LOCATION "http://wiki.sabnzbd.org/" + !define MUI_FINISHPAGE_LINK $(MsgSupportUs) + !define MUI_FINISHPAGE_LINK_LOCATION "http://www.sabnzbd.org/contribute/" + + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !define MUI_UNPAGE_COMPONENTSPAGE_NODESC + !insertmacro MUI_UNPAGE_COMPONENTS + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + ; Set supported languages + !insertmacro MUI_LANGUAGE "English" ;first language is the default language + !insertmacro MUI_LANGUAGE "French" + !insertmacro MUI_LANGUAGE "German" + !insertmacro MUI_LANGUAGE "Dutch" + !insertmacro MUI_LANGUAGE "Swedish" + !insertmacro MUI_LANGUAGE "Danish" + !insertmacro MUI_LANGUAGE "Norse" + + +;-------------------------------- +;Reserve Files + + ;If you are using solid compression, files that are required before + ;the actual installation should be stored first in the data block, + ;because this will make your installer start faster. + + !insertmacro MUI_RESERVEFILE_LANGDLL + + +Function LaunchLink + ExecShell "" "$INSTDIR\SABnzbd.exe" +FunctionEnd + +;-------------------------------- +Function .onInit + !insertmacro MUI_LANGDLL_DISPLAY + +;make sure sabnzbd.exe isnt running..if so abort + loop: + StrCpy $0 "SABnzbd.exe" + KillProc::FindProcesses + StrCmp $0 "0" endcheck + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgCloseSab) IDOK loop IDCANCEL exitinstall + exitinstall: + Abort + endcheck: +FunctionEnd + + +Section "SABnzbd" SecDummy +SetOutPath "$INSTDIR" + +IfFileExists $INSTDIR\sabnzbd.exe 0 endWarnExist + IfFileExists $INSTDIR\language\us-en.txt endWarnExist 0 + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgOldQueue) IDOK endWarnExist IDCANCEL 0 + Abort +endWarnExist: + +; add files / whatever that need to be installed here. +File /r "dist\*" + + +WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" "$INSTDIR" +WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayName" "SABnzbd (remove only)" +WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "UninstallString" '"$INSTDIR\uninstall.exe"' +;WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '"$INSTDIR\need-a-.ico"' +; write out uninstaller +WriteUninstaller "$INSTDIR\Uninstall.exe" + + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - SafeMode.lnk" "$INSTDIR\SABnzbd-console.exe" + WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - Documentation.url" "InternetShortcut" "URL" "http://wiki.sabnzbd.org/" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + + + + !insertmacro MUI_STARTMENU_WRITE_END + + +SectionEnd ; end of default section + +Section /o $(MsgRunAtStart) startup + CreateShortCut "$SMPROGRAMS\Startup\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" "-b0" +SectionEnd ; + +Section $(MsgIcon) desktop + CreateShortCut "$DESKTOP\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" +SectionEnd ; end of desktop icon section + +Section /o $(MsgAssoc) assoc + ${registerExtension} "$INSTDIR\nzb.ico" "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File" + ;${registerExtension} "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File" +SectionEnd ; end of file association section + +; begin uninstall settings/section +UninstallText $(MsgUninstall) + +Section "un.$(MsgDelProgram)" Uninstall +;make sure sabnzbd.exe isnt running..if so shut it down + + StrCpy $0 "sabnzbd.exe" + DetailPrint "Searching for processes called '$0'" + KillProc::FindProcesses + StrCmp $1 "-1" wooops + DetailPrint "-> Found $0 processes" + + StrCmp $0 "0" completed + Sleep 1500 + + StrCpy $0 "sabnzbd.exe" + DetailPrint "Killing all processes called '$0'" + KillProc::KillProcesses + StrCmp $1 "-1" wooops + DetailPrint "-> Killed $0 processes, failed to kill $1 processes" + + Goto completed + + wooops: + DetailPrint "-> Error: Something went wrong :-(" + Abort + + completed: + DetailPrint "Process Killed" + + + ; add delete commands to delete whatever files/registry keys/etc you installed here. + Delete "$INSTDIR\uninstall.exe" + DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" + DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" + + ; Delete installation files are carefully as possible + ; Using just rmdir /r "$instdir" is considered unsafe! + Delete "$INSTDIR\email\email-de.tmpl" + Delete "$INSTDIR\email\email-en.tmpl" + Delete "$INSTDIR\email\email-nl.tmpl" + Delete "$INSTDIR\email\email-fr.tmpl" + Delete "$INSTDIR\email\email-sv.tmpl" + Delete "$INSTDIR\email\email-da.tmpl" + Delete "$INSTDIR\email\email-no.tmpl" + Delete "$INSTDIR\email\rss-de.tmpl" + Delete "$INSTDIR\email\rss-en.tmpl" + Delete "$INSTDIR\email\rss-nl.tmpl" + Delete "$INSTDIR\email\rss-fr.tmpl" + Delete "$INSTDIR\email\rss-sv.tmpl" + Delete "$INSTDIR\email\rss-da.tmpl" + Delete "$INSTDIR\email\rss-no.tmpl" + RMDir "$INSTDIR\email" + RMDir /r "$INSTDIR\locale" + RMDir /r "$INSTDIR\interfaces\Classic" + RMDir /r "$INSTDIR\interfaces\Plush" + RMDir /r "$INSTDIR\interfaces\smpl" + RMDir /r "$INSTDIR\interfaces\Mobile" + RMDir /r "$INSTDIR\interfaces\wizard" + RMDir "$INSTDIR\interfaces" + RMDir /r "$INSTDIR\win\par2" + RMDir /r "$INSTDIR\win\unrar" + RMDir /r "$INSTDIR\win\unzip" + RMDir /r "$INSTDIR\win" + Delete "$INSTDIR\licenses\*.txt" + Delete "$INSTDIR\licenses\Python\*.txt" + RMDir "$INSTDIR\licenses\Python" + RMDir "$INSTDIR\licenses" + Delete "$INSTDIR\lib\libeay32.dll" + Delete "$INSTDIR\lib\pywintypes25.dll" + Delete "$INSTDIR\lib\ssleay32.dll" + Delete "$INSTDIR\lib\sabnzbd.zip" + Delete "$INSTDIR\lib\*.pyd" + RMDir /r "$INSTDIR\lib\" + Delete "$INSTDIR\CHANGELOG.txt" + Delete "$INSTDIR\COPYRIGHT.txt" + Delete "$INSTDIR\email.tmpl" + Delete "$INSTDIR\GPL2.txt" + Delete "$INSTDIR\GPL3.txt" + Delete "$INSTDIR\INSTALL.txt" + Delete "$INSTDIR\ISSUES.txt" + Delete "$INSTDIR\LICENSE.txt" + Delete "$INSTDIR\nzbmatrix.txt" + Delete "$INSTDIR\MSVCR71.dll" + Delete "$INSTDIR\nzb.ico" + Delete "$INSTDIR\PKG-INFO" + Delete "$INSTDIR\python25.dll" + Delete "$INSTDIR\python26.dll" + Delete "$INSTDIR\README.txt" + Delete "$INSTDIR\SABnzbd-console.exe" + Delete "$INSTDIR\SABnzbd.exe" + Delete "$INSTDIR\Sample-PostProc.cmd" + Delete "$INSTDIR\Uninstall.exe" + Delete "$INSTDIR\w9xpopen.exe" + RMDir "$INSTDIR" + + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + + Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - SafeMode.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - Documentation.url" + RMDir "$SMPROGRAMS\$MUI_TEMP" + + Delete "$SMPROGRAMS\Startup\SABnzbd.lnk" + + Delete "$DESKTOP\SABnzbd.lnk" + + DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd" + + ${unregisterExtension} ".nzb" "NZB File" + + +SectionEnd ; end of uninstall section + +Section "un.$(MsgDelSettings)" DelSettings + Delete "$LOCALAPPDATA\sabnzbd\sabnzbd.ini" + RMDir /r "$LOCALAPPDATA\sabnzbd\admin" +SectionEnd + + +Section "un.$(MsgDelLogs)" DelLogs + RMDir /r "$LOCALAPPDATA\sabnzbd\logs" +SectionEnd + + +Section "un.$(MsgDelCache)" DelCache + RMDir /r "$LOCALAPPDATA\sabnzbd\cache" + RMDir "$LOCALAPPDATA\sabnzbd" +SectionEnd + +; eof + +;-------------------------------- +;Language strings +; MsgWarnRunning 'Please close "SABnzbd.exe" first' + LangString MsgStartSab ${LANG_ENGLISH} "Start SABnzbd (hidden)" + LangString MsgStartSab ${LANG_DANISH "Start SABnzbd (hidden)" + LangString MsgStartSab ${LANG_GERMAN "SABnzbd starten (unsichtbar)" + LangString MsgStartSab ${LANG_FRENCH "Lancer SABnzbd (caché)" + LangString MsgStartSab ${LANG_DUTCH "Start SABnzbd (verborgen)" + LangString MsgStartSab ${LANG_NORSE "Start SABnzbd (hidden)" + LangString MsgStartSab ${LANG_SWEDISH "Starta SABnzbd (dold)" + + LangString MsgShowRelNote ${LANG_ENGLISH} "Show Release Notes" + LangString MsgShowRelNote ${LANG_DANISH "Show Release Notes" + LangString MsgShowRelNote ${LANG_GERMAN "Versionshinweise anzeigen" + LangString MsgShowRelNote ${LANG_FRENCH "Afficher les notes de version" + LangString MsgShowRelNote ${LANG_DUTCH "Toon Vrijgave Bericht (Engels)" + LangString MsgShowRelNote ${LANG_NORSE "Show Release Notes" + LangString MsgShowRelNote ${LANG_SWEDISH "Visa release noteringar" + + LangString MsgSupportUs ${LANG_ENGLISH} "Support the project, Donate!" + LangString MsgSupportUs ${LANG_DANISH "Support the project, Donate!" + LangString MsgSupportUs ${LANG_GERMAN "Bitte unterstützen Sie das Projekt durch eine Spende!" + LangString MsgSupportUs ${LANG_FRENCH "Supportez le projet, faites un don !" + LangString MsgSupportUs ${LANG_DUTCH "Steun het project, Doneer!" + LangString MsgSupportUs ${LANG_NORSE "Support the project, Donate!" + LangString MsgSupportUs ${LANG_SWEDISH "Donera och stöd detta projekt!" + + LangString MsgCloseSab ${LANG_ENGLISH} "Please close $\"SABnzbd.exe$\" first" + LangString MsgCloseSab ${LANG_DANISH "Please close $\"SABnzbd.exe$\" first" + LangString MsgCloseSab ${LANG_GERMAN "Schliessen Sie bitte zuerst $\"SABnzbd.exe$\"." + LangString MsgCloseSab ${LANG_FRENCH "Quittez $\"SABnzbd.exe$\" avant l'installation, SVP" + LangString MsgCloseSab ${LANG_DUTCH "Sluit $\"SABnzbd.exe$\" eerst af" + LangString MsgCloseSab ${LANG_NORSE "Please close $\"SABnzbd.exe$\" first" + LangString MsgCloseSab ${LANG_SWEDISH "Var vänlig stäng $\"SABnzbd.exe$\" först" + + LangString MsgOldQueue ${LANG_ENGLISH} " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + LangString MsgOldQueue ${LANG_DANISH " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + LangString MsgOldQueue ${LANG_GERMAN " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + LangString MsgOldQueue ${LANG_FRENCH " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + LangString MsgOldQueue ${LANG_DUTCH " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + LangString MsgOldQueue ${LANG_NORSE " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + LangString MsgOldQueue ${LANG_SWEDISH " >>>> WARNING <<<<$\r$\n$\r$\nIf not empty, download your current queue with the old program.$\r$\nThe new program will ignore your current queue!" + + LangString MsgUninstall ${LANG_ENGLISH} "This will uninstall SABnzbd from your system" + LangString MsgUninstall ${LANG_DANISH "This will uninstall SABnzbd from your system" + LangString MsgUninstall ${LANG_GERMAN "Dies entfernt SABnzbd von Ihrem System" + LangString MsgUninstall ${LANG_FRENCH "Ceci désinstallera SABnzbd de votre système" + LangString MsgUninstall ${LANG_DUTCH "Dit verwijdert SABnzbd van je systeem" + LangString MsgUninstall ${LANG_NORSE "This will uninstall SABnzbd from your system" + LangString MsgUninstall ${LANG_SWEDISH "Detta kommer att avinstallera SABnzbd från systemet" + + LangString MsgRunAtStart ${LANG_ENGLISH} "Run at startup" + LangString MsgRunAtStart ${LANG_DANISH "Run at startup" + LangString MsgRunAtStart ${LANG_GERMAN "Beim Systemstart ausführen" + LangString MsgRunAtStart ${LANG_FRENCH "Lancer au démarrage" + LangString MsgRunAtStart ${LANG_DUTCH "Opstarten bij systeem start" + LangString MsgRunAtStart ${LANG_NORSE "Run at startup" + LangString MsgRunAtStart ${LANG_SWEDISH "Kör vid uppstart" + + LangString MsgIcon ${LANG_ENGLISH} "Desktop Icon" + LangString MsgIcon ${LANG_DANISH "Desktop Icon" + LangString MsgIcon ${LANG_GERMAN "Desktop-Symbol" + LangString MsgIcon ${LANG_FRENCH "Icône sur le Bureau" + LangString MsgIcon ${LANG_DUTCH "Pictogram op bureaublad" + LangString MsgIcon ${LANG_NORSE "Desktop Icon" + LangString MsgIcon ${LANG_SWEDISH "Skrivbordsikon" + + LangString MsgAssoc ${LANG_ENGLISH} "NZB File association" + LangString MsgAssoc ${LANG_DANISH "NZB File association" + LangString MsgAssoc ${LANG_GERMAN "Mit NZB-Dateien verknüpfen" + LangString MsgAssoc ${LANG_FRENCH "Association des fichiers NZB" + LangString MsgAssoc ${LANG_DUTCH "NZB bestanden koppelen aan SABnzbd" + LangString MsgAssoc ${LANG_NORSE "NZB File association" + LangString MsgAssoc ${LANG_SWEDISH "NZB Filassosication" + + LangString MsgDelProgram ${LANG_ENGLISH} "Delete Program" + LangString MsgDelProgram ${LANG_DANISH "Delete Program" + LangString MsgDelProgram ${LANG_GERMAN "Programm löschen" + LangString MsgDelProgram ${LANG_FRENCH "Supprimer le programme" + LangString MsgDelProgram ${LANG_DUTCH "Verwijder programma" + LangString MsgDelProgram ${LANG_NORSE "Delete Program" + LangString MsgDelProgram ${LANG_SWEDISH "Ta bort programmet" + + LangString MsgDelSettings ${LANG_ENGLISH} "Delete Settings" + LangString MsgDelSettings ${LANG_DANISH "Delete Settings" + LangString MsgDelSettings ${LANG_GERMAN "Einstellungen löschen" + LangString MsgDelSettings ${LANG_FRENCH "Supprimer Paramètres" + LangString MsgDelSettings ${LANG_DUTCH "Verwijder instellingen" + LangString MsgDelSettings ${LANG_NORSE "Delete Settings" + LangString MsgDelSettings ${LANG_SWEDISH "Ta bort inställningar" + + LangString MsgDelLogs ${LANG_ENGLISH} "Delete Logs" + LangString MsgDelLogs ${LANG_DANISH "Delete Logs" + LangString MsgDelLogs ${LANG_GERMAN "Protokoll löschen" + LangString MsgDelLogs ${LANG_FRENCH "Supprimer les logs" + LangString MsgDelLogs ${LANG_DUTCH "Verwijder logging" + LangString MsgDelLogs ${LANG_NORSE "Delete Logs" + LangString MsgDelLogs ${LANG_SWEDISH "Ta bort logg" + + LangString MsgDelCache ${LANG_ENGLISH} "Delete Cache" + LangString MsgDelCache ${LANG_DANISH "Delete Cache" + LangString MsgDelCache ${LANG_GERMAN "Cache löschen" + LangString MsgDelCache ${LANG_FRENCH "Supprimer le cache" + LangString MsgDelCache ${LANG_DUTCH "Verwijder Cache" + LangString MsgDelCache ${LANG_NORSE "Delete Cache" + LangString MsgDelCache ${LANG_SWEDISH "Ta bort temporär-mapp" + +Function un.onInit + !insertmacro MUI_UNGETLANGUAGE +FunctionEnd diff --git a/SABnzbd.py b/SABnzbd.py index 1f49e59..dbbd96f 100755 --- a/SABnzbd.py +++ b/SABnzbd.py @@ -62,6 +62,7 @@ except: else: SQLITE_DLL = False +import sabnzbd.lang import sabnzbd import sabnzbd.interface from sabnzbd.constants import * @@ -75,7 +76,6 @@ import sabnzbd.config as config import sabnzbd.cfg import sabnzbd.downloader as downloader from sabnzbd.encoding import unicoder -from sabnzbd.lang import T, Ta from sabnzbd.utils import osx from threading import Thread @@ -292,7 +292,7 @@ def daemonize(): def Bail_Out(browserhost, cherryport, access=False): """Abort program because of CherryPy troubles """ - logging.error(Ta('error-noWebUi')) + logging.error(Ta('Failed to start web-interface'), Ta('Cannot find web template: %s, trying standard template')) if access: panic_xport(browserhost, cherryport) else: @@ -322,7 +322,7 @@ def Web_Template(key, defweb, wdir): logging.info("Web dir is %s", full_dir) if not os.path.exists(full_main): - logging.warning(Ta('warn-noSkin@1'), full_main) + logging.warning(Ta('Cannot find web template: %s, trying standard template'), full_main) full_dir = real_path(sabnzbd.DIR_INTERFACES, DEF_STDINTF) full_main = real_path(full_dir, DEF_MAIN_TMPL) if not os.path.exists(full_main): @@ -330,7 +330,7 @@ def Web_Template(key, defweb, wdir): panic_tmpl(full_dir) exit_sab(1) - sabnzbd.lang.install_language(real_path(full_dir, DEF_INT_LANGUAGE), sabnzbd.cfg.language(), wdir) + #sabnzbd.lang.install_language(real_path(full_dir, DEF_INT_LANGUAGE), sabnzbd.cfg.language(), wdir) return real_path(full_dir, "templates") @@ -443,14 +443,14 @@ def print_modules(): logging.info("_yenc module... found!") else: if hasattr(sys, "frozen"): - logging.error(Ta('error-noYEnc')) + logging.error(Ta('_yenc module... NOT found!')) else: logging.info("_yenc module... NOT found!") if sabnzbd.newsunpack.PAR2_COMMAND: logging.info("par2 binary... found (%s)", sabnzbd.newsunpack.PAR2_COMMAND) else: - logging.error(Ta('error-noPar2')) + logging.error(Ta('par2 binary... NOT found!')) if sabnzbd.newsunpack.PAR2C_COMMAND: logging.info("par2-classic binary... found (%s)", sabnzbd.newsunpack.PAR2C_COMMAND) @@ -458,12 +458,12 @@ def print_modules(): if sabnzbd.newsunpack.RAR_COMMAND: logging.info("unrar binary... found (%s)", sabnzbd.newsunpack.RAR_COMMAND) else: - logging.warning(Ta('warn-noUnrar')) + logging.warning(Ta('unrar binary... NOT found')) if sabnzbd.newsunpack.ZIP_COMMAND: logging.info("unzip binary... found (%s)", sabnzbd.newsunpack.ZIP_COMMAND) else: - logging.warning(Ta('warn-noUnzip')) + logging.warning(Ta('unzip binary... NOT found!')) if not sabnzbd.WIN32: if sabnzbd.newsunpack.NICE_COMMAND: @@ -567,7 +567,7 @@ def get_webhost(cherryhost, cherryport, https_port): logging.info("IPV6 has priority on this system, potential Firefox issue") if ipv6 and ipv4 and cherryhost == '' and sabnzbd.WIN32: - logging.warning(Ta('warn-0000')) + logging.warning(Ta('Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access')) if cherryhost == 'localhost' and not sabnzbd.WIN32 and not sabnzbd.DARWIN: # On the Ubuntu family, localhost leads to problems for CherryPy @@ -597,7 +597,7 @@ def get_webhost(cherryhost, cherryport, https_port): if cherryport == https_port: sabnzbd.cfg.enable_https.set(False) # Should have a translated message, but that's not available yet - #logging.error(Ta('error-sameHTTP-HTTPS')) + #logging.error(Ta('HTTP and HTTPS ports cannot be the same')) logging.error('HTTP and HTTPS ports cannot be the same') return cherryhost, cherryport, browserhost, https_port @@ -1159,7 +1159,7 @@ def main(): web_dir2 = Web_Template(sabnzbd.cfg.web_dir2, '', fix_webname(web_dir2)) wizard_dir = os.path.join(sabnzbd.DIR_INTERFACES, 'wizard') - sabnzbd.lang.install_language(os.path.join(wizard_dir, DEF_INT_LANGUAGE), sabnzbd.cfg.language(), 'wizard') + #sabnzbd.lang.install_language(os.path.join(wizard_dir, DEF_INT_LANGUAGE), sabnzbd.cfg.language(), 'wizard') sabnzbd.WEB_DIR = web_dir sabnzbd.WEB_DIR2 = web_dir2 @@ -1231,7 +1231,7 @@ def main(): create_https_certificates(https_cert, https_key) if https_port and not (os.path.exists(https_cert) or os.path.exists(https_key)): - logging.warning(Ta('warn-noCertKey')) + logging.warning(Ta('Disabled HTTPS because of missing CERT and KEY files')) https_port = False if https_port: @@ -1406,7 +1406,7 @@ def main(): if sabnzbd.WIN_SERVICE and mail: mail.send('stop') notify("SAB_Shutdown", None) - osx.sendGrowlMsg('SABnzbd',T('grwl-shutdown-end-msg'),osx.NOTIFICATION['startup']) + osx.sendGrowlMsg('SABnzbd',T('SABnzbd shutdown finished'),osx.NOTIFICATION['startup']) logging.info('Leaving SABnzbd') sys.stderr.flush() sys.stdout.flush() diff --git a/SABnzbdDelegate.py b/SABnzbdDelegate.py index 74e1b2b..11ad800 100755 --- a/SABnzbdDelegate.py +++ b/SABnzbdDelegate.py @@ -36,7 +36,6 @@ import sabnzbd.cfg from sabnzbd.constants import * from sabnzbd.misc import launch_a_browser,get_filename,get_ext,diskfree -from sabnzbd.lang import T from sabnzbd.utils import osx import sabnzbd.nzbqueue as nzbqueue @@ -86,12 +85,12 @@ class SABnzbdDelegate(NSObject): #Wait for SABnzbd Initialisation #cherrypy.engine.wait(cherrypy.process.wspbus.states.STARTED) - - if (debug == 1) : NSLog("[osx] yes=%s" % (T('yes'))) - while T('yes')[0:1]=="#": + if (debug == 1) : NSLog("[osx] yes=%s" % (T('Yes'))) + + while T('Yes')[0:1]=="#": time.sleep(0.5) - if (debug == 1) : NSLog("[osx] yes=%s" % (T('yes'))) + if (debug == 1) : NSLog("[osx] yes=%s" % (T('Yes'))) if (debug == 1) : NSLog("[osx] language file not loaded, waiting") #Variables @@ -115,7 +114,7 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 3 construction") #Warnings Item - self.warnings_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-warnings'), 'openBrowserAction:', '') + self.warnings_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Warnings'), 'openBrowserAction:', '') if self.isLeopard: self.warnings_menu_item.setHidden_(YES) else: @@ -126,14 +125,14 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 4 warning added") #State Item - self.state_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-status-idle'), 'openBrowserAction:', '') + self.state_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Idle'), 'openBrowserAction:', '') self.state_menu_item.setRepresentedObject_("") self.menu.addItem_(self.state_menu_item) if (debug == 1) : NSLog("[osx] menu 5 state added") #Config Item - menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-config'), 'openBrowserAction:', '') + menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Configuration'), 'openBrowserAction:', '') menu_item.setRepresentedObject_("config/general/") menu_item.setAlternate_(YES) menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) @@ -142,14 +141,14 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 6 config added") #Queue Item - self.queue_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-queue'), 'openBrowserAction:', '') + self.queue_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Queue'), 'openBrowserAction:', '') self.queue_menu_item.setRepresentedObject_("") self.menu.addItem_(self.queue_menu_item) if (debug == 1) : NSLog("[osx] menu 7 queue added") #Purge Queue Item - self.purgequeue_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-purgequeue'), 'purgeAction:', '') + self.purgequeue_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Purge Queue'), 'purgeAction:', '') self.purgequeue_menu_item.setRepresentedObject_("queue") self.purgequeue_menu_item.setAlternate_(YES) self.purgequeue_menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) @@ -158,14 +157,14 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 8 purge queue added") #History Item - self.history_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-history'), 'openBrowserAction:', '') + self.history_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('History'), 'openBrowserAction:', '') self.history_menu_item.setRepresentedObject_("") self.menu.addItem_(self.history_menu_item) if (debug == 1) : NSLog("[osx] menu 9 history added") #Purge History Item - self.purgehistory_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-purgehistory'), 'purgeAction:', '') + self.purgehistory_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Purge History'), 'purgeAction:', '') self.purgehistory_menu_item.setRepresentedObject_("history") self.purgehistory_menu_item.setAlternate_(YES) self.purgehistory_menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) @@ -177,11 +176,11 @@ class SABnzbdDelegate(NSObject): self.menu.addItem_(self.separator_menu_item) #Limit Speed Item & Submenu - self.speed_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-speedlimit'), '', '') + self.speed_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Limit Speed'), '', '') self.menu_speed = NSMenu.alloc().init() - speeds ={ 0 : T('osx-menu-none'), 50 :'50 KB/s' , 100 : '100 KB/s', 200 : '200 KB/s' , 300 : '300 KB/s' , + speeds ={ 0 : T('None'), 50 :'50 KB/s' , 100 : '100 KB/s', 200 : '200 KB/s' , 300 : '300 KB/s' , 400 : '400 KB/s', 500 :'500 KB/s' , 600 : '600 KB/s', 700 : '700 KB/s' , 800 : '800 KB/s' , 900 : '900 KB/s', 1000 :'1000 KB/s' , 1500 : '1500 KB/s', 2000 : '2000 KB/s' , 3000 : '3000 KB/s' } @@ -197,13 +196,13 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 11 limit speed added") #Pause Item & Submenu - self.pause_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-pause'), 'pauseAction:', '') + self.pause_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Pause'), 'pauseAction:', '') self.pause_menu_item.setRepresentedObject_('0') self.menu_pause = NSMenu.alloc().init() for i in range(6): - menu_pause_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("%s %s" % ((i+1)*10,T('osx-menu-min')), 'pauseAction:', '') + menu_pause_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("%s %s" % ((i+1)*10,T('min.')), 'pauseAction:', '') menu_pause_item.setRepresentedObject_("%s" % ((i+1)*10)) self.menu_pause.addItem_(menu_pause_item) @@ -213,7 +212,7 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 12 pause added") #Resume Item - self.resume_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-resume'), 'resumeAction:', '') + self.resume_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Resume'), 'resumeAction:', '') if self.isLeopard: self.resume_menu_item.setHidden_(YES) else: @@ -223,7 +222,7 @@ class SABnzbdDelegate(NSObject): if (debug == 1) : NSLog("[osx] menu 13 resume added") #Newzbin Item - self.newzbin_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-getnewzbinbm'), 'getNewzbinBookmarksAction:', '') + self.newzbin_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Get Newzbin Bookmarks'), 'getNewzbinBookmarksAction:', '') if self.isLeopard: self.newzbin_menu_item.setHidden_(YES) else: @@ -234,14 +233,14 @@ class SABnzbdDelegate(NSObject): self.menu.addItem_(self.separator2_menu_item) if (debug == 1) : NSLog("[osx] menu 14 newzbin added") - + #Complete Folder Item - self.completefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-complete'), 'openFolderAction:', '') + self.completefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Complete Folder '), 'openFolderAction:', '') self.completefolder_menu_item.setRepresentedObject_(sabnzbd.cfg.complete_dir.get_path()) self.menu.addItem_(self.completefolder_menu_item) #Incomplete Folder Item - self.incompletefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-incomplete'), 'openFolderAction:', '') + self.incompletefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Incomplete Folder '), 'openFolderAction:', '') self.incompletefolder_menu_item.setRepresentedObject_(sabnzbd.cfg.download_dir.get_path()) self.menu.addItem_(self.incompletefolder_menu_item) @@ -254,13 +253,13 @@ class SABnzbdDelegate(NSObject): #self.menu.addItem_(menu_item) #Quit Item - menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-quit'), 'terminate:', '') + menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Quit'), 'terminate:', '') self.menu.addItem_(menu_item) if (debug == 1) : NSLog("[osx] menu 16 quit added") #Restart Item - menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-restart'), 'restartAction:', '') + menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Restart'), 'restartAction:', '') menu_item.setAlternate_(YES) menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) self.menu.addItem_(menu_item) @@ -317,7 +316,7 @@ class SABnzbdDelegate(NSObject): if len(pnfo_list): - menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-queuelimit'), '', '') + menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Queue First 10 Items'), '', '') self.menu_queue.addItem_(menu_queue_item) self.menu_queue.addItem_(NSMenuItem.separatorItem()) @@ -341,7 +340,7 @@ class SABnzbdDelegate(NSObject): self.info = "%d nzb(s)\t( %d / %d MB )" % (len(pnfo_list),(qnfo[QNFO_BYTES_LEFT_FIELD] / MEBI), (qnfo[QNFO_BYTES_FIELD] / MEBI)) else: - menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-empty'), '', '') + menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Empty'), '', '') self.menu_queue.addItem_(menu_queue_item) self.queue_menu_item.setSubmenu_(self.menu_queue) @@ -358,7 +357,7 @@ class SABnzbdDelegate(NSObject): self.menu_history = NSMenu.alloc().init() self.failedAttributes = { NSForegroundColorAttributeName:NSColor.redColor(), NSFontAttributeName:NSFont.menuFontOfSize_(14.0) } - menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-historylimit'), '', '') + menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('History Last 10 Items'), '', '') self.menu_history.addItem_(menu_history_item) self.menu_history.addItem_(NSMenuItem.separatorItem()) @@ -382,7 +381,7 @@ class SABnzbdDelegate(NSObject): menu_history_item.setRepresentedObject_("%s" % (path)) self.menu_history.addItem_(menu_history_item) else: - menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('osx-menu-empty'), '', '') + menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Empty'), '', '') self.menu_history.addItem_(menu_history_item) self.history_menu_item.setSubmenu_(self.menu_history) @@ -398,7 +397,7 @@ class SABnzbdDelegate(NSObject): NSFontAttributeName: NSFont.menuFontOfSize_(14.0) } - warningsTitle = NSAttributedString.alloc().initWithString_attributes_( "%s : %s" % (T('osx-menu-warnings'),warnings), warningsAttributes) + warningsTitle = NSAttributedString.alloc().initWithString_attributes_( "%s : %s" % (T('Warnings'),warnings), warningsAttributes) self.warnings_menu_item.setAttributedTitle_(warningsTitle) if self.isLeopard: @@ -406,7 +405,7 @@ class SABnzbdDelegate(NSObject): else: self.warnings_menu_item.setEnabled_(YES) else: - self.warnings_menu_item.setTitle_("%s : 0" % (T('osx-menu-warnings'))) + self.warnings_menu_item.setTitle_("%s : 0" % (T('Warnings'))) if self.isLeopard: self.warnings_menu_item.setHidden_(YES) else: @@ -419,7 +418,7 @@ class SABnzbdDelegate(NSObject): qnfo = sabnzbd.nzbqueue.queue_info() bpsnow = BPSMeter.do.get_bps() if downloader.paused(): - self.state = T('osx-menu-status-paused') + self.state = T('Paused') if sabnzbd.scheduler.pause_int() != "0": self.setMenuTitle("\n\n%s\n" % (sabnzbd.scheduler.pause_int())) else: @@ -440,7 +439,7 @@ class SABnzbdDelegate(NSObject): self.setMenuTitle(statusbarText) else: - self.state = T('osx-menu-status-idle') + self.state = T('Idle') self.setMenuTitle("") if self.state != "" and self.info != "": @@ -501,7 +500,7 @@ class SABnzbdDelegate(NSObject): if sabnzbd.NEW_VERSION and self.version_notify: #logging.info("[osx] New Version : %s" % (sabnzbd.NEW_VERSION)) new_release, new_rel_url = sabnzbd.NEW_VERSION.split(';') - osx.sendGrowlMsg("SABnzbd","%s : %s" % (T('grwl-newversion-msg'),new_release),osx.NOTIFICATION['other']) + osx.sendGrowlMsg("SABnzbd","%s : %s" % (T('New release available'),new_release),osx.NOTIFICATION['other']) self.version_notify = 0 except : logging.info("[osx] versionUpdate Exception %s" % (sys.exc_info()[0])) @@ -525,7 +524,7 @@ class SABnzbdDelegate(NSObject): def serverUpdate(self): try: if not config.get_servers(): - self.state_menu_item.setTitle_(T('osx-menu-wizard')) + self.state_menu_item.setTitle_(T('Go to wizard')) hide=YES alternate=NO value=0 @@ -571,8 +570,8 @@ class SABnzbdDelegate(NSObject): def diskspaceUpdate(self): try: - self.completefolder_menu_item.setTitle_("%s%.2f GB" % (T('osx-menu-complete'),diskfree(sabnzbd.cfg.complete_dir.get_path()))) - self.incompletefolder_menu_item.setTitle_("%s%.2f GB" % (T('osx-menu-incomplete'),diskfree(sabnzbd.cfg.download_dir.get_path()))) + self.completefolder_menu_item.setTitle_("%s%.2f GB" % (T('Complete Folder '),diskfree(sabnzbd.cfg.complete_dir.get_path()))) + self.incompletefolder_menu_item.setTitle_("%s%.2f GB" % (T('Incomplete Folder '),diskfree(sabnzbd.cfg.download_dir.get_path()))) except : logging.info("[osx] diskspaceUpdate Exception %s" % (sys.exc_info()[0])) @@ -693,10 +692,10 @@ class SABnzbdDelegate(NSObject): # app.orderFrontStandardAboutPanel_(nil) def restartAction_(self, sender): - self.setMenuTitle("\n\n%s\n"% (T('osx-menu-shutdowning'))) + self.setMenuTitle("\n\n%s\n"% (T('Stopping...'))) sabnzbd.halt() cherrypy.engine.restart() - self.setMenuTitle("\n\n%s\n"% (T('osx-menu-shutdowning'))) + self.setMenuTitle("\n\n%s\n"% (T('Stopping...'))) def application_openFiles_(self, nsapp, filenames): #logging.info('[osx] file open') @@ -721,14 +720,14 @@ class SABnzbdDelegate(NSObject): def applicationShouldTerminate_(self, sender): logging.info('[osx] application terminating') - self.setMenuTitle("\n\n%s\n"% (T('osx-menu-shutdowning'))) + self.setMenuTitle("\n\n%s\n"% (T('Stopping...'))) self.status_item.setHighlightMode_(NO) sabnzbd.OSX_ICON = 0 logging.info('[osx] application stopping daemon') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True - osx.sendGrowlMsg('SABnzbd',T('grwl-shutdown-end-msg'),osx.NOTIFICATION['other']) + osx.sendGrowlMsg('SABnzbd',T('SABnzbd shutdown finished'),osx.NOTIFICATION['other']) logging.info('Leaving SABnzbd') sys.stderr.flush() sys.stdout.flush() diff --git a/email/email-en.tmpl b/email/email-en.tmpl new file mode 100644 index 0000000..ff8137f --- /dev/null +++ b/email/email-en.tmpl @@ -0,0 +1,41 @@ +## +## Default Email template for SABnzbd +## This a Cheetah template +## Documentation: http://sabnzbd.wikidot.com/email-templates +## +## Newlines and whitespace are significant! +## +## These are the email headers +to: $to +from: $from +date: $date +subject: SABnzbd has job $name +X-priority: 5 +X-MS-priority: 5 +## After this comes the body, the empty line is required! + +Hi, + +SABnzbd has downloaded "$name" + +SABnzbd has failed to download "$name" + +Finished at $end_time +Downloaded $size + +Results of the job: + +Stage $stage + + $result + + + +Output from user script "$script" (Exit code = $script_ret): +$script_output + + +Enjoy! + +Sorry! + diff --git a/email/rss-en.tmpl b/email/rss-en.tmpl new file mode 100644 index 0000000..727a2bf --- /dev/null +++ b/email/rss-en.tmpl @@ -0,0 +1,25 @@ +## +## RSS Email template for SABnzbd +## This a Cheetah template +## Documentation: http://sabnzbd.wikidot.com/email-templates +## +## Newlines and whitespace are significant! +## +## These are the email headers +to: $to +from: $from +date: $date +subject: SABnzbd has added $amount jobs to the queue +X-priority: 5 +X-MS-priority: 5 +## After this comes the body, the empty line is required! + +Hi, + +SABnzbd has added $amount job(s) to the queue. +They are from RSS feed "$feed". + + $job + + +Bye diff --git a/interfaces/Classic/templates/history.tmpl b/interfaces/Classic/templates/history.tmpl index 027e0fb..d03f48a 100644 --- a/interfaces/Classic/templates/history.tmpl +++ b/interfaces/Classic/templates/history.tmpl @@ -35,7 +35,7 @@ compl = datetime.datetime.fromtimestamp(float(line['completed'])).strftime('%Y-% $compl $line.name - $line.action_line - $line.fail_message - $line.size$T('post-'+$line.status) + $line.size$Tx('post-'+$line.status) @@ -63,7 +63,7 @@ compl = datetime.datetime.fromtimestamp(float(line['completed'])).strftime('%Y-%
-
$T('stage-'+$stage.name.title.lower())
+
$Tx('stage-'+$stage.name.title.lower())
$action
diff --git a/interfaces/Classic/templates/queue.tmpl b/interfaces/Classic/templates/queue.tmpl index f840fe6..084f857 100644 --- a/interfaces/Classic/templates/queue.tmpl +++ b/interfaces/Classic/templates/queue.tmpl @@ -89,7 +89,7 @@ $T('onQueueFinish'):
-''' % (sabnzbd.__version__, T('error'), T('badParm'), unicoder(msg), T('button-back')) +''' % (sabnzbd.__version__, T('ERROR:'), T('Incorrect parameter'), unicoder(msg), T('Back')) def ShowFile(name, path): """Return a html page listing a file and a 'back' button @@ -2192,7 +2193,7 @@ def ShowFile(name, path):

-''' % (name, T('button-back'), name, escape(msg)) +''' % (name, T('Back'), name, escape(msg)) def ShowString(name, string): """Return a html page listing a file and a 'back' button @@ -2216,7 +2217,7 @@ def ShowString(name, string):

-''' % (xml_name(name), T('button-back'), xml_name(name), escape(unicoder(msg))) +''' % (xml_name(name), T('Back'), xml_name(name), escape(unicoder(msg))) def ShowOK(url): @@ -2233,7 +2234,7 @@ def ShowOK(url):

-''' % (escape(url), T('button-back'), T('msg-reAdded@1') % escape(url)) +''' % (escape(url), T('Back'), T('Job "%s" was re-added to the queue') % escape(url)) def _make_link(qfeed, job): @@ -2271,7 +2272,7 @@ def _make_link(qfeed, job): star = ' *' * int(status.endswith('*')) if rule < 0: - rule = ' %s!' % T('msg-duplicate') + rule = ' %s!' % T('duplicate') else: rule = ' #%s' % str(rule) @@ -2281,7 +2282,7 @@ def _make_link(qfeed, job): title = xml_name(title) return '%s   %s%s%s
' % \ - (cfg.api_key() ,qfeed, name, cat, pp, script, prio, nzbname, T('link-download'), title, star, rule) + (cfg.api_key() ,qfeed, name, cat, pp, script, prio, nzbname, T('Download'), title, star, rule) @@ -2362,8 +2363,8 @@ def ShowRssLog(feed, all):
-''' % (escape(feed), T('button-back'), escape(feed), T('explain-rssStar'), T('rss-matched'), \ - ''.join(goodStr), T('rss-notMatched'), ''.join(badStr), T('rss-done'), ''.join(doneStr)) +''' % (escape(feed), T('Back'), escape(feed), T('Jobs marked with a \'*\' will not be automatically downloaded.'), T('Matched'), \ + ''.join(goodStr), T('Not matched'), ''.join(badStr), T('Downloaded'), ''.join(doneStr)) else: return ''' @@ -2381,7 +2382,7 @@ def ShowRssLog(feed, all):
-''' % (escape(feed), T('button-back'), escape(feed), T('rss-downloaded'), ''.join(doneStr)) +''' % (escape(feed), T('Back'), escape(feed), T('Downloaded so far'), ''.join(doneStr)) @@ -2423,7 +2424,7 @@ class ConfigEmail(object): for kw in LIST_EMAIL: msg = config.get_config('misc', kw).set(platform_encode(kwargs.get(kw))) if msg: - return badParameterResponse(T('error-badValue@2') % (kw, unicoder(msg))) + return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg))) config.save_config() raise dcRaiser(self.__root, kwargs) diff --git a/sabnzbd/lang.py b/sabnzbd/lang.py index c229684..ab18c0e 100644 --- a/sabnzbd/lang.py +++ b/sabnzbd/lang.py @@ -1,5 +1,5 @@ #!/usr/bin/python -OO -# Copyright 2008-2009 The SABnzbd-Team +# Copyright 2010 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -19,186 +19,86 @@ sabnzbd.lang - Language support """ -# Skin-specific files cannot overrule previous texts. -# Every acronym will be prexifed with the skin name ("skin-"). -# This is required, because two skins can be active at once. - - -import os -import glob -import logging -import re -import operator +# This module should be the first non-standard import to +# be done at the top of the application's main file. +# This will ensure that the default language is available +# and the special functions are active. +# +# Required keywords for pygettext.py: -k T -k Ta -k TT +# +# The following pseudo-builtins are provided. +# T() Unicode translation +# Ta() Latin-1 translation +# Tx() Unicode translation of an expression (not a literal string) +# TT() Dummy translation, use to mark table entries for POT scanning -_T = {} # Global language dictionary -_DIRS = [] # List of active (language-folder, prefix) tuples -def T(txt): - """ Translate an acronym to natural language """ - try: - return _T[txt] - except KeyError: - # Missing text: create text from acronym with %s attached - txt, num = _get_count(txt) - return '#' + txt + '#' + ' %s'*num +import gettext, __builtin__ +import glob, os, operator +# This module cannot import any application modules!! +__all__ = ['set_locale_info', 'set_language', 'list_languages'] -def Ta(txt): - """ Translate acronym, return latin-1 encoding """ - return T(txt).encode('latin-1', 'replace') +_DOMAIN = '' # Holds translation domain +_LOCALEDIR = '' # Holds path to the translation base folder -def Tspec(txt): - """ Translate special terms """ - if txt == 'None': - return T('none') - elif txt == 'Default': - return T('default') - else: - return txt - - -def reset_language(language): - """ Process active language folders with new language """ - # First fill the new dictionary and afterwards - # replace the global one. This way there will - # always be a valid dictionary available. - global _T, _DIRS - new_T = {} - dirs = _DIRS - _DIRS = [] - for tup in dirs: - install_language(tup[0], language, tup[1], new_T) - old = _T - _T = new_T - del old - - -def install_language(path, language, prefix='', dic=None): - """ Read language file for the active language - and default language. +def set_locale_info(domain, localedir): + """ Setup the domain and localedir for translations """ - # 'dic' parameter is for internal use by 'reset_language' only - global _DIRS - _DIRS.append((path, prefix)) + global _DOMAIN, _LOCALEDIR + _DOMAIN = domain + _LOCALEDIR = localedir - if dic is None: - dic = _T - if language != 'us-en': - name = os.path.join(path, language+'.txt') - if os.path.exists(name): - _parse_lang_file(dic, name, prefix) - name = os.path.join(path, 'us-en.txt') - if os.path.exists(name): - _parse_lang_file(dic, name, prefix) - - -def list_languages(path): - """ Return list of languages-choices - Each choice is a list, 0: short name, 1: long name +def set_language(language=''): + """ Activate language, empty language will set default texts. """ - lst = [] - for name in glob.glob(path + '/*.txt'): - lang = os.path.basename(name).replace('.txt','') - try: - fp = open(name, 'r') - except IOError: - continue - - encoding, language = _get_headers(fp) - long_name = u"%s" % language - lst.append((lang, long_name)) - fp.close() - return sorted(lst ,key=operator.itemgetter(1)) - - - -# Matches : acronym message text # comment -# | (1) |(2)| (3) | -_RE_LINE = re.compile(r'\s*(\S+)(\s*)([^#]*)') - -def _parse_lang_file(dic, name, prefix=''): - """ Parse language file and store new definitions in global dictionary + # 'codeset' will determine the output of lgettext + lng = gettext.translation(_DOMAIN, _LOCALEDIR, [language], fallback=True, codeset='latin-1') + + # The unicode flag will make _() return Unicode + lng.install(unicode=True, names=['lgettext']) + __builtin__.__dict__['T'] = __builtin__.__dict__['_'] # Unicode + __builtin__.__dict__['Ta'] = __builtin__.__dict__['lgettext'] # Latin-1 + __builtin__.__dict__['Tx'] = __builtin__.__dict__['_'] # Dynamic translation (unicode) + __builtin__.__dict__['TT'] = lambda x:x # Use in text tables + + +def list_languages(): + """ Return sorted list of (lang-code, lang-string) pairs, + representing the available languages. + When any language file is found, the default tuple ('en', 'English') + will be included. Otherwise an empty list is returned. """ - try: - f = open(name, "r") - except IOError: - logging.error("Cannot open language file %s", name) - return False - - encoding, language = _get_headers(f) - logging.debug("Language file %s, encoding=%s, language=%s", - name, encoding, language) - - if prefix: - prefix += '-' - lcount = 0 - multi = False - msg = '' - for line in f.xreadlines(): - line = line.strip('\n').decode(encoding) - lcount += 1 - m = re.search(_RE_LINE, line) - if m and not m.group(1).startswith('#'): - if multi: - if msg.endswith('\\n') or msg.endswith('\\r'): - msg = msg + m.group(1) + m.group(2) + m.group(3) - else: - msg = msg + " " + m.group(1) + m.group(2) + m.group(3) - else: - key = prefix + m.group(1) - msg = m.group(3) - if msg and msg.strip().endswith("\\"): - msg = msg.strip().strip("\\") - multi = True - else: - multi = False - msg = msg.strip() - if '\\' in msg: - msg = msg.replace('\\n', '
').replace('\\t', '\t').replace('\\@', '#').replace('\s', ' ').replace('\\r','\r\n') - if key not in dic: - if msg.count('%s') == _get_count(key)[1]: - dic[key] = msg - else: - logging.error("[%s:%s] Incorrect message for %s, should have %s parameters", - name, lcount, key, _get_count(key)[1]) - - - f.close() - return True - - -def _get_headers(fp): - """ Return encoding and language - # -*- coding: latin-1 -*- - # English (UK) # remarks - """ - txt = fp.readline() - m = re.search(r'#\s*-\*-\s+coding:\s+(\S+)\s+-\*-', txt) - if m and m.group(1): - encoding = m.group(1) - else: - encoding = 'latin-1' + # Findst find all the MO files. + # Each folder should also contain a dummy text file giving the language + # Example: + # /nl/LC_MESSAGES/SABnzbd.mo + # /nl/LC_MESSAGES/Nederlands - txt = fp.readline() - m = re.search(r'#\s*([^#]+)#*', txt) - if m: - language = m.group(1).strip().decode(encoding) + lst = [] + for path in glob.glob(os.path.join(_LOCALEDIR, '*')): + lng = None + language = None + for fpath in glob.glob(path + '/LC_MESSAGES/*'): + fname = os.path.basename(fpath) + if fname.endswith('.mo'): + lng = os.path.basename(path) + if fname == 'language.txt': + fp = open(fpath, 'r') + language = fp.readline().strip(' \n').decode('utf-8', 'replace') + fp.close() + if lng: + if not language: + language = lng + lst.append((lng, language)) + if lst: + lst.append(('en', 'English')) + return sorted(lst, key=operator.itemgetter(1)) else: - language = '' - - return encoding, language + return lst -_RE_COUNT = re.compile(r'(\S+)@(\d+)') -def _get_count(txt): - """ Return base key and counter - "CopyFile@2" --> "CopyFile", 2 - "Stop" --> "Stop", 0 - """ - m = re.search(_RE_COUNT, txt) - if m and m.group(2).isdigit(): - return m.group(1), int(m.group(2)) - else: - return txt, 0 +# Setup a safe null-translation +set_language() diff --git a/sabnzbd/misc.py b/sabnzbd/misc.py index 87a3666..398e4c2 100644 --- a/sabnzbd/misc.py +++ b/sabnzbd/misc.py @@ -42,7 +42,6 @@ import sabnzbd.nzbqueue import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.encoding import unicoder, latin1 -from sabnzbd.lang import T, Ta if sabnzbd.FOUNDATION: import Foundation @@ -304,13 +303,13 @@ def create_real_path(name, loc, path, umask=False): if not os.path.exists(my_dir): logging.info('%s directory: %s does not exist, try to create it', name, my_dir) if not create_all_dirs(my_dir, umask): - logging.error(Ta('error-createDir@1'), my_dir) + logging.error(Ta('Cannot create directory %s'), my_dir) return (False, my_dir) if os.access(my_dir, os.R_OK + os.W_OK): return (True, my_dir) else: - logging.error(Ta('error-accessDir@2'), name, my_dir) + logging.error(Ta('%s directory: %s error accessing'), name, my_dir) return (False, my_dir) else: return (False, "") @@ -330,14 +329,14 @@ def get_user_shellfolders(): try: hive = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER) except WindowsError: - logging.error(Ta('error-regConnect')) + logging.error(Ta('Cannot connect to registry hive HKEY_CURRENT_USER.')) return values # Then open the registry key where Windows stores the Shell Folder locations try: key = _winreg.OpenKey(hive, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") except WindowsError: - logging.error(Ta('error-regOpen@1'), r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") + logging.error(Ta('Cannot open registry key "%s".'), r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") _winreg.CloseKey(hive) return values @@ -364,7 +363,7 @@ def get_user_shellfolders(): return values except WindowsError: # On error, return empty dict. - logging.error(Ta('error-regSpecial')) + logging.error(Ta('Failed to read registry keys for special folders')) _winreg.CloseKey(key) _winreg.CloseKey(hive) return {} @@ -597,7 +596,7 @@ def panic_port(host, port): def panic_xport(host, port): launch_a_browser(panic_message(PANIC_XPORT, host, port)) - logging.error(Ta('error-portNoAccess@1'), port) + logging.error(Ta('You have no permisson to use port %s'), port) def panic_queue(name): launch_a_browser(panic_message(PANIC_QUEUE, name, 0)) @@ -631,7 +630,7 @@ def launch_a_browser(url, force=False): try: webbrowser.open(url, 1, 1) except: - logging.warning(Ta('warn-noBrowser')) + logging.warning(Ta('Cannot launch the browser, probably not found')) logging.info("Traceback: ", exc_info = True) @@ -882,7 +881,7 @@ def create_dirs(dirpath): if not os.path.exists(dirpath): logging.info('Creating directories: %s', dirpath) if not create_all_dirs(dirpath, True): - logging.error(Ta('error-makeFile@1'), dirpath) + logging.error(Ta('Failed making (%s)'), dirpath) logging.info("Traceback: ", exc_info = True) return None return dirpath @@ -907,7 +906,7 @@ def move_to_path(path, new_path, unique=True): shutil.copyfile(path, new_path) os.remove(path) except: - logging.error(Ta('error-moveFile@2'), path, new_path) + logging.error(Ta('Failed moving %s to %s'), path, new_path) logging.info("Traceback: ", exc_info = True) return new_path @@ -1019,7 +1018,7 @@ def bad_fetch(nzo, url, msg='', retry=False, content=False): if content: # Bad content - msg = T('his-badArchive') + msg = T('Unusable NZB file') else: # Failed fetch msg = ' (' + msg + ')' @@ -1030,7 +1029,7 @@ def bad_fetch(nzo, url, msg='', retry=False, content=False): nzbname = '&nzbname=%s' % urllib.quote(nzbname) else: nzbname = '' - text = T('his-retryURL1@1') + ', ' + T('his-retryURL2') + '' + text = T('URL Fetching failed; %s') + ', ' + T('Try again') + '' parms = (msg, cfg.api_key(), urllib.quote(url), pp, cat, script, nzbname) nzo.fail_msg = text % parms else: @@ -1101,9 +1100,9 @@ def format_time_string(seconds, days=0): def s_returner(item, value): if value == 1: - return T(item) + return Tx(item) else: - return T(item + 's') + return Tx(item + 's') def int_conv(value): """Safe conversion to int""" @@ -1160,7 +1159,7 @@ def create_https_certificates(ssl_cert, ssl_key): from sabnzbd.utils.certgen import createKeyPair, createCertRequest, createCertificate,\ TYPE_RSA, serial except: - logging.warning(Ta('warn-pyopenssl')) + logging.warning(Ta('pyopenssl module missing, please install for https access')) return False # Create the CA Certificate @@ -1179,7 +1178,7 @@ def create_https_certificates(ssl_cert, ssl_key): open(ssl_key, 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) open(ssl_cert, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) except: - logging.error(Ta('error-sslFiles')) + logging.error(Ta('Error creating SSL key and certificate')) logging.info("Traceback: ", exc_info = True) return False @@ -1249,7 +1248,7 @@ def win_hibernate(): subprocess.Popen("rundll32 powrprof.dll,SetSuspendState Hibernate") time.sleep(10) except: - logging.error(Ta('error-hibernate')) + logging.error(Ta('Failed to hibernate system')) logging.info("Traceback: ", exc_info = True) @@ -1258,7 +1257,7 @@ def win_standby(): subprocess.Popen("rundll32 powrprof.dll,SetSuspendState Standby") time.sleep(10) except: - logging.error(Ta('error-standby')) + logging.error(Ta('Failed to standby system')) logging.info("Traceback: ", exc_info = True) @@ -1285,7 +1284,7 @@ def osx_shutdown(): try: subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down']) except: - logging.error(Ta('error-shutdown')) + logging.error(Ta('#error-shutdown#')) logging.info("Traceback: ", exc_info = True) os._exit(0) @@ -1295,7 +1294,7 @@ def osx_standby(): subprocess.call(['osascript', '-e','tell app "System Events" to sleep']) time.sleep(10) except: - logging.error(Ta('error-standby')) + logging.error(Ta('Failed to standby system')) logging.info("Traceback: ", exc_info = True) diff --git a/sabnzbd/newsunpack.py b/sabnzbd/newsunpack.py index fdf1645..a6ceab0 100644 --- a/sabnzbd/newsunpack.py +++ b/sabnzbd/newsunpack.py @@ -33,7 +33,6 @@ from sabnzbd.utils.rarfile import RarFile, is_rarfile from sabnzbd.misc import format_time_string, find_on_path, make_script_path from sabnzbd.tvsort import SeriesSorter import sabnzbd.cfg as cfg -from sabnzbd.lang import T, Ta if sabnzbd.WIN32: try: @@ -280,10 +279,10 @@ def file_join(nzo, workdir, workdir_complete, delete, joinables): logging.debug("FJN, realsize: %s", real_size) if real_size != expected_size: - msg = T('error-joinMismatch') - nzo.fail_msg = T('error-joinFail@1') % msg - nzo.set_unpack_info('Filejoin', T('error-joinFail@2') % (unicoder(joinable_set), msg)) - logging.error(Ta('error-fileJoin@2'), msg, nzo.final_name) + msg = T('Expected size did not equal actual size') + nzo.fail_msg = T('File join of %s failed') % msg + nzo.set_unpack_info('Filejoin', T('[%s] Error "%s" while joining files') % (unicoder(joinable_set), msg)) + logging.error(Ta('Error "%s" while running file_join on %s'), msg, nzo.final_name) else: joinable_sets[joinable_set].sort() filename = joinable_set @@ -322,7 +321,7 @@ def file_join(nzo, workdir, workdir_complete, delete, joinables): join_num = len(joinable_sets[joinable_set]) perc = (100.0/join_num)*(i) logging.debug("Processing %s", joinable) - nzo.set_action_line(T('msg-joining'), '%.0f%%' % perc) + nzo.set_action_line(T('Joining'), '%.0f%%' % perc) f = open(joinable, 'rb') joined_file.write(f.read()) f.close() @@ -333,22 +332,22 @@ def file_join(nzo, workdir, workdir_complete, delete, joinables): joined_file.flush() joined_file.close() - msg = T('msg-joinOK@2') % (unicoder(joinable_set), i) + msg = T('[%s] Joined %s files') % (unicoder(joinable_set), i) nzo.set_unpack_info('Filejoin', msg, set=joinable_set) newfiles.append(joinable_set) except: msg = sys.exc_info()[1] - nzo.fail_msg = T('error-joinFail@1') % msg - nzo.set_unpack_info('Filejoin', T('error-joinFail@2') % (unicoder(joinable_set), msg)) - logging.error(Ta('error-fileJoin@2'), msg, nzo.final_name) + nzo.fail_msg = T('File join of %s failed') % msg + nzo.set_unpack_info('Filejoin', T('[%s] Error "%s" while joining files') % (unicoder(joinable_set), msg)) + logging.error(Ta('Error "%s" while running file_join on %s'), msg, nzo.final_name) return True, [] return False, newfiles except: msg = sys.exc_info()[1] - nzo.fail_msg = T('error-joinFail@1') % msg - nzo.set_unpack_info('Filejoin', T('error-joinFail@2') % (unicoder(joinable_set), msg)) - logging.error(Ta('error-fileJoin@2'), msg, nzo.final_name) + nzo.fail_msg = T('File join of %s failed') % msg + nzo.set_unpack_info('Filejoin', T('[%s] Error "%s" while joining files') % (unicoder(joinable_set), msg)) + logging.error(Ta('Error "%s" while running file_join on %s'), msg, nzo.final_name) return True, [] @@ -391,11 +390,11 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, rars): except: success = False msg = sys.exc_info()[1] - nzo.set_fail = T('error-unpackFail@1') % msg + nzo.set_fail = T('Unpacking failed, %s') % msg setname = nzo.final_name - nzo.set_unpack_info('Unpack', T('error-unpackFail@2') % (unicoder(setname), msg)) + nzo.set_unpack_info('Unpack', T('[%s] Error "%s" while unpacking RAR files') % (unicoder(setname), msg)) - logging.error(Ta('error-fileUnrar@2'), msg, setname) + logging.error(Ta('Error "%s" while running rar_unpack on %s'), msg, setname) if success: logging.debug('rar_unpack(): Rars: %s', rars) @@ -409,7 +408,7 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, rars): try: os.remove(rar) except OSError: - logging.warning(Ta('warn-delFailed@1'), rar) + logging.warning(Ta('Deleting %s failed!'), rar) brokenrar = '%s.1' % (rar) @@ -418,7 +417,7 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, rars): try: os.remove(brokenrar) except OSError: - logging.warning(Ta('warn-delFailed@1'), brokenrar) + logging.warning(Ta('Deleting %s failed!'), brokenrar) return not success, extracted_files @@ -434,8 +433,8 @@ def RAR_Extract(rarfile, numrars, nzo, setname, extraction_path): expected_files = zf.unamelist() zf.close() except: - nzo.fail_msg = T('error-badArchive') - nzo.set_unpack_info('Unpack', u'[%s] %s' % (unicoder(setname), T('error-badArchive')), set=setname) + nzo.fail_msg = T('Failed opening main archive (encrypted or damaged)') + nzo.set_unpack_info('Unpack', u'[%s] %s' % (unicoder(setname), T('Failed opening main archive (encrypted or damaged)')), set=setname) logging.info('Archive %s probably encrypted, skipping', rarfile) return ((), ()) @@ -470,7 +469,7 @@ def RAR_Extract(rarfile, numrars, nzo, setname, extraction_path): if p.stdin: p.stdin.close() - nzo.set_action_line(T('msg-unpacking'), '00/%02d' % (numrars)) + nzo.set_action_line(T('Unpacking'), '00/%02d' % (numrars)) # Loop over the output from rar! curr = 0 @@ -490,44 +489,44 @@ def RAR_Extract(rarfile, numrars, nzo, setname, extraction_path): if filename not in rarfiles: rarfiles.append(filename) curr += 1 - nzo.set_action_line(T('msg-unpacking'), '%02d/%02d' % (curr, numrars)) + nzo.set_action_line(T('Unpacking'), '%02d/%02d' % (curr, numrars)) elif line.startswith('Cannot find volume'): filename = os.path.basename(TRANS(line[19:])) - nzo.fail_msg = T('error-unpackFailed@1') % unicoder(filename) - msg = ('[%s] '+Ta('error-unpackFailed@1')) % (setname, filename) + nzo.fail_msg = T('Unpacking failed, unable to find %s') % unicoder(filename) + msg = ('[%s] '+Ta('Unpacking failed, unable to find %s')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg), set=setname) - logging.warning(Ta('warn-cannotFind@1'), filename) + logging.warning(Ta('ERROR: unable to find "%s"'), filename) fail = 1 elif line.endswith('- CRC failed'): filename = TRANS(line[:-12].strip()) - nzo.fail_msg = T('error-unpackCRC') - msg = ('[%s] '+Ta('warn-crcFailed@1')) % (setname, filename) + nzo.fail_msg = T('Unpacking failed, CRC error') + msg = ('[%s] '+Ta('ERROR: CRC failed in "%s"')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg), set=setname) - logging.warning(Ta('warn-crcFailed@1'), setname) + logging.warning(Ta('ERROR: CRC failed in "%s"'), setname) fail = 1 elif line.startswith('Write error'): - nzo.fail_msg = T('error-unpackFull') - msg = ('[%s] ' + Ta('error-unpackFull')) % setname + nzo.fail_msg = T('Unpacking failed, write error or disk is full?') + msg = ('[%s] ' + Ta('Unpacking failed, write error or disk is full?')) % setname nzo.set_unpack_info('Unpack', unicoder(msg), set=setname) - logging.warning(Ta('warn-writeError@1'), line[11:]) + logging.warning(Ta('ERROR: write error (%s)'), line[11:]) fail = 1 elif line.startswith('ERROR: '): - nzo.fail_msg = T('error-unpackFailLog') - logging.warning(Ta('warn-error@1'), (line[7:])) - msg = ('[%s] '+Ta('warn-error@1')) % (setname, line[7:]) + nzo.fail_msg = T('Unpacking failed, see log') + logging.warning(Ta('ERROR: %s'), (line[7:])) + msg = ('[%s] '+Ta('ERROR: %s')) % (setname, line[7:]) nzo.set_unpack_info('Unpack', unicoder(msg), set=setname) fail = 1 elif line.startswith('Encrypted file: CRC failed'): filename = TRANS(line[31:-23].strip()) - nzo.fail_msg = T('error-unpackPassword') - msg = ('[%s][%s] '+Ta('error-unpackPassword')) % (setname, filename) + nzo.fail_msg = T('Unpacking failed, archive requires a password') + msg = ('[%s][%s] '+Ta('Unpacking failed, archive requires a password')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg), set=setname) - logging.error('%s (%s)', Ta('error-unpackPassword'), filename) + logging.error('%s (%s)', Ta('Unpacking failed, archive requires a password'), filename) fail = 1 else: @@ -561,17 +560,17 @@ def RAR_Extract(rarfile, numrars, nzo, setname, extraction_path): if not os.path.exists(fullpath): # There was a missing file, show a warning all_found = False - logging.warning(Ta('warn-MissExpectedFile@1'), path) + logging.warning(Ta('Missing expected file: %s => unrar error?'), path) if not all_found: - nzo.fail_msg = T('error-unpackMissing') + nzo.fail_msg = T('Unpacking failed, an expected file was not unpacked') logging.debug("Expecting files: %s" % expected_files) - nzo.set_unpack_info('Unpack', T('error-unpackMissing'), set=setname) + nzo.set_unpack_info('Unpack', T('Unpacking failed, an expected file was not unpacked'), set=setname) return ((), ()) else: logging.info('Skipping unrar file check due to unreliable file names or old unrar') - msg = T('msg-unpackDone@2') % (str(len(extracted)), format_time_string(time() - start)) + msg = T('Unpacked %s files/folders in %s') % (str(len(extracted)), format_time_string(time() - start)) nzo.set_unpack_info('Unpack', '[%s] %s' % (unicoder(setname), msg), set=setname) logging.info('%s', msg) @@ -589,7 +588,7 @@ def unzip(nzo, workdir, workdir_complete, delete, zips): for _zip in zips: logging.info("Starting extract on zipfile: %s ", _zip) - nzo.set_action_line(T('msg-unpacking'), '%s' % unicoder(_zip)) + nzo.set_action_line(T('Unpacking'), '%s' % unicoder(_zip)) if workdir_complete and _zip.startswith(workdir): extraction_path = workdir_complete @@ -601,7 +600,7 @@ def unzip(nzo, workdir, workdir_complete, delete, zips): else: i += 1 - msg = T('msg-unzipDone@2') % (str(i), format_time_string(time() - tms)) + msg = T('%s files in %s') % (str(i), format_time_string(time() - tms)) nzo.set_unpack_info('Unpack', msg) # Delete the old files if we have to @@ -614,7 +613,7 @@ def unzip(nzo, workdir, workdir_complete, delete, zips): os.remove(_zip) i += 1 except OSError: - logging.warning(Ta('warn-delFailed@1'), _zip) + logging.warning(Ta('Deleting %s failed!'), _zip) brokenzip = '%s.1' % (_zip) @@ -624,13 +623,13 @@ def unzip(nzo, workdir, workdir_complete, delete, zips): os.remove(brokenzip) i += 1 except OSError: - logging.warning(Ta('warn-delFailed@1'), brokenzip) + logging.warning(Ta('Deleting %s failed!'), brokenzip) return unzip_failed except: msg = sys.exc_info()[1] - nzo.fail_msg = T('error-unpackFail@1') % msg - logging.error(Ta('error-fileUnzip@2'), msg, nzo.final_name) + nzo.fail_msg = T('Unpacking failed, %s') % msg + logging.error(Ta('Error "%s" while running unzip() on %s'), msg, nzo.final_name) return True def ZIP_Extract(zipfile, extraction_path): @@ -666,11 +665,11 @@ def par2_repair(parfile_nzf, nzo, workdir, setname): if cfg.quick_check(): nzo.status = 'QuickCheck' - nzo.set_action_line(T('msg-repair'), T('msg-QuickChecking')) + nzo.set_action_line(T('Repair'), T('Quick Checking')) result = QuickCheck(setname, nzo) if result: logging.info("Quick-check for %s is OK, skipping repair", setname) - nzo.set_unpack_info('Repair', T('msg-QuickOK@1') % unicoder(setname), set=setname) + nzo.set_unpack_info('Repair', T('[%s] Quick Check OK') % unicoder(setname), set=setname) pars = setpars if not result: @@ -678,7 +677,7 @@ def par2_repair(parfile_nzf, nzo, workdir, setname): result = False readd = False try: - nzo.set_action_line(T('msg-repair'), T('msg-startRepair')) + nzo.set_action_line(T('Repair'), T('Starting Repair')) logging.info('Scanning "%s"', parfile) joinables, zips, rars, ts = build_filelists(workdir, None, check_rar=False) @@ -702,8 +701,8 @@ def par2_repair(parfile_nzf, nzo, workdir, setname): return readd, False except: msg = sys.exc_info()[1] - nzo.fail_msg = T('error-repairFailed@1') % msg - logging.error(Ta('error-filePar2@2'), msg, setname) + nzo.fail_msg = T('Repairing failed, %s') % msg + logging.error(Ta('Error %s while running par2_repair on set %s'), msg, setname) logging.info("Traceback: ", exc_info = True) return readd, result @@ -719,7 +718,7 @@ def par2_repair(parfile_nzf, nzo, workdir, setname): logging.info("Deleting %s", path) os.remove(path) except: - logging.warning(Ta('warn-delFailed@1'), path) + logging.warning(Ta('Deleting %s failed!'), path) path = os.path.join(workdir, setname + '.par2') path2 = os.path.join(workdir, setname + '.PAR2') @@ -729,21 +728,21 @@ def par2_repair(parfile_nzf, nzo, workdir, setname): logging.info("Deleting %s", path) os.remove(path) except: - logging.warning(Ta('warn-delFailed@1'), path) + logging.warning(Ta('Deleting %s failed!'), path) if os.path.exists(path2): try: logging.info("Deleting %s", path2) os.remove(path2) except: - logging.warning(Ta('warn-delFailed@1'), path2) + logging.warning(Ta('Deleting %s failed!'), path2) if os.path.exists(parfile): try: logging.info("Deleting %s", parfile) os.remove(parfile) except OSError: - logging.warning(Ta('warn-delFailed@1'), parfile) + logging.warning(Ta('Deleting %s failed!'), parfile) deletables = [] for f in pars: @@ -758,11 +757,11 @@ def par2_repair(parfile_nzf, nzo, workdir, setname): try: os.remove(filepath) except OSError: - logging.warning(Ta('warn-delFailed@1'), filepath) + logging.warning(Ta('Deleting %s failed!'), filepath) except: msg = sys.exc_info()[1] - nzo.fail_msg = T('error-repairFailed@1') % msg - logging.error(Ta('error-repairBad@2'), msg, setname) + nzo.fail_msg = T('Repairing failed, %s') % msg + logging.error(Ta('Error "%s" while running par2_repair on set %s'), msg, setname) return readd, result @@ -836,14 +835,14 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): # And off we go if line.startswith('All files are correct'): - msg = T('msg-verifyOK@2') % (unicoder(setname), format_time_string(time() - start)) + msg = T('[%s] Verified in %s, all files correct') % (unicoder(setname), format_time_string(time() - start)) nzo.set_unpack_info('Repair', msg, set=setname) logging.info('Verified in %s, all files correct', format_time_string(time() - start)) finished = 1 elif line.startswith('Repair is required'): - msg = T('msg-repairNeeded@2') % (unicoder(setname), format_time_string(time() - start)) + msg = T('[%s] Verified in %s, repair is required') % (unicoder(setname), format_time_string(time() - start)) nzo.set_unpack_info('Repair', msg, set=setname) logging.info('Verified in %s, repair is required', format_time_string(time() - start)) @@ -852,7 +851,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): elif line.startswith('Main packet not found'): ## Initialparfile probaly didn't decode properly, - logging.info(Ta('error-noMainPacket')) + logging.info(Ta('Main packet not found...')) extrapars = parfile_nzf.extrapars @@ -906,7 +905,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): if (avail_blocks < needed_blocks) and (avail_blocks > 0): # Tell SAB that we always have enough blocks, so that # it will try to load all pars anyway - msg = T('error-repairBlocks@1') % str(int(needed_blocks - avail_blocks)) + msg = T('Repair failed, not enough repair blocks (%s short)') % str(int(needed_blocks - avail_blocks)) nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg, set=setname) @@ -933,12 +932,12 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): added_blocks, nzo.final_name) if not force: - msg = T('msg-fetchBlocks@1') % str(added_blocks) + msg = T('Fetching %s blocks...') % str(added_blocks) nzo.status = 'Fetching' - nzo.set_action_line(T('msg-fetching'), msg) + nzo.set_action_line(T('Fetching'), msg) else: - msg = T('error-repairBlocks@1') % str(needed_blocks) + msg = T('Repair failed, not enough repair blocks (%s short)') % str(needed_blocks) nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg, set=setname) @@ -947,16 +946,16 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): elif line.startswith('Repair is possible'): start = time() - nzo.set_action_line(T('msg-repairing'), '%2d%%' % (0)) + nzo.set_action_line(T('Repairing'), '%2d%%' % (0)) elif line.startswith('Repairing:'): chunks = line.split() per = float(chunks[-1][:-1]) - nzo.set_action_line(T('msg-repairing'), '%2d%%' % (per)) + nzo.set_action_line(T('Repairing'), '%2d%%' % (per)) nzo.status = 'Repairing' elif line.startswith('Repair complete'): - msg = T('msg-repairDone@2') % (unicoder(setname), format_time_string(time() - start)) + msg = T('[%s] Repaired in %s') % (unicoder(setname), format_time_string(time() - start)) nzo.set_unpack_info('Repair', msg, set=setname) logging.info('Repaired in %s', format_time_string(time() - start)) finished = 1 @@ -974,7 +973,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): elif not verified: if line.startswith('Verifying source files'): - nzo.set_action_line(T('msg-verifying'), '01/%02d' % verifytotal) + nzo.set_action_line(T('Verifying'), '01/%02d' % verifytotal) nzo.status = 'Verifying' elif line.startswith('Scanning:'): @@ -992,7 +991,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False): if m: if verifytotal == 0 or verifynum < verifytotal: verifynum += 1 - nzo.set_action_line(T('msg-verifying'), '%02d/%02d' % (verifynum, verifytotal)) + nzo.set_action_line(T('Verifying'), '%02d/%02d' % (verifynum, verifytotal)) nzo.status = 'Verifying' datafiles.append(m.group(1)) continue diff --git a/sabnzbd/newswrapper.py b/sabnzbd/newswrapper.py index 794a735..c12a78e 100644 --- a/sabnzbd/newswrapper.py +++ b/sabnzbd/newswrapper.py @@ -28,7 +28,6 @@ import logging import sabnzbd from sabnzbd.constants import * -from sabnzbd.lang import Ta try: from OpenSSL import SSL @@ -160,7 +159,7 @@ class NNTP(object): self.sock = SSLConnection(ctx, socket.socket(af, socktype, proto)) elif sslenabled and not _ssl: - logging.error(Ta('error-noSSL')) + logging.error(Ta('Error importing OpenSSL module. Connecting with NON-SSL')) self.sock = socket.socket(af, socktype, proto) else: self.sock = socket.socket(af, socktype, proto) diff --git a/sabnzbd/newzbin.py b/sabnzbd/newzbin.py index 88e82b4..6c4188b 100644 --- a/sabnzbd/newzbin.py +++ b/sabnzbd/newzbin.py @@ -42,7 +42,6 @@ from sabnzbd.encoding import name_fixer import sabnzbd.newswrapper import sabnzbd.nzbqueue import sabnzbd.cfg as cfg -from sabnzbd.lang import T, Ta from sabnzbd.utils import osx @@ -122,7 +121,7 @@ class MSGIDGrabber(Thread): try: sabnzbd.nzbqueue.insert_future_nzo(nzo, filename, msgid, data, pp=pp, script=script, cat=cat, priority=priority, nzbname=nzbname, nzo_info=nzo_info) except: - logging.error(Ta('error-nbUpdate@1'), msgid) + logging.error(Ta('Failed to update newzbin job %s'), msgid) logging.info("Traceback: ", exc_info = True) sabnzbd.nzbqueue.remove_nzo(nzo.nzo_id, False) msgid = None @@ -134,7 +133,7 @@ class MSGIDGrabber(Thread): bad_fetch(nzo, msgid, msg=nzo_info, retry=True) msgid = None - osx.sendGrowlMsg(T('grwl-nzbadd-title'),filename,osx.NOTIFICATION['download']) + osx.sendGrowlMsg(T('NZB added to queue'),filename,osx.NOTIFICATION['download']) # Keep some distance between the grabs sleeper(5) @@ -186,7 +185,7 @@ def _grabnzb(msgid): # Only some reports will generate a moreinfo header pass if not (rcode or rtext): - logging.error(T('error-nbProtocol')) + logging.error(T('Newzbin server changed its protocol')) return None, None, None, None # Official return codes: @@ -220,26 +219,26 @@ def _grabnzb(msgid): return int(wait+1), None, None, None if rcode in ('402'): - msg = Ta('warn-nbCredit') + msg = Ta('You have no credit on your Newzbin account') return None, None, None, msg if rcode in ('401'): - msg = Ta('warn-nbNoAuth') + msg = Ta('Unauthorised, check your newzbin username/password') return None, None, None, msg if rcode in ('400', '404'): - msg = Ta('error-nbReport@1') % msgid + msg = Ta('Newzbin report %s not found') % msgid return None, None, None, msg if rcode != '200': - msg = Ta('error-nbUnkownError@2') % (rcode, rtext) + msg = Ta('Newzbin gives undocumented error code (%s, %s)') % (rcode, rtext) return None, None, None, msg # Process data report_name = response.getheader('X-DNZB-Name') report_cat = response.getheader('X-DNZB-Category') if not (report_name and report_cat): - msg = Ta('error-nbInfo@1') % msgid + msg = Ta('Newzbin server fails to give info for %s') % msgid return None, None, None, msg # sanitize report_name @@ -323,9 +322,9 @@ class Bookmarks(object): if rcode == '204': logging.debug("No bookmarks set") elif rcode in ('401', '403'): - logging.warning(Ta('warn-nbNoAuth')) + logging.warning(Ta('Unauthorised, check your newzbin username/password')) elif rcode in ('402'): - logging.warning(Ta('warn-nbCredit')) + logging.warning(Ta('You have no credit on your Newzbin account')) elif rcode in ('500', '503'): _warn_user('Newzbin has a server problem (%s).' % rcode) elif rcode == '200': @@ -336,7 +335,7 @@ class Bookmarks(object): self.bookmarks.remove(delete) else: if delete in self.bookmarks: - logging.warning(Ta('warn-nbNoDelBM@1'), delete) + logging.warning(Ta('Could not delete newzbin bookmark %s'), delete) else: for line in data.split('\n'): try: @@ -348,7 +347,7 @@ class Bookmarks(object): logging.info("Found new bookmarked msgid %s (%s)", msgid, text) sabnzbd.add_msgid(int(msgid), None, None, priority=None) else: - logging.error(Ta('error-nbUnkownError@1'), rcode) + logging.error(Ta('Newzbin gives undocumented error code (%s)'), rcode) self.__busy = False diff --git a/sabnzbd/nzbqueue.py b/sabnzbd/nzbqueue.py index 20ba338..d61847d 100644 --- a/sabnzbd/nzbqueue.py +++ b/sabnzbd/nzbqueue.py @@ -37,7 +37,6 @@ import sabnzbd.cfg as cfg from sabnzbd.articlecache import ArticleCache import sabnzbd.downloader from sabnzbd.assembler import Assembler -from sabnzbd.lang import T, Ta from sabnzbd.utils import osx from sabnzbd.encoding import latin1 @@ -79,13 +78,13 @@ class NzbQueue(TryList): queue_vers, nzo_ids, dummy = data if not queue_vers == QUEUE_VERSION: nzo_ids = [] - logging.error(Ta('error-qBad')) + logging.error(Ta('Incompatible queuefile found, cannot proceed')) if not repair: panic_queue(os.path.join(cfg.cache_dir.get_path(),QUEUE_FILE_NAME)) exit_sab(2) except ValueError: nzo_ids = [] - logging.error(Ta('error-qCorruptFile@1'), + logging.error(Ta('Error loading %s, corrupt file detected'), os.path.join(cfg.cache_dir.get_path(), QUEUE_FILE_NAME)) if not repair: return @@ -215,7 +214,7 @@ class NzbQueue(TryList): self.reset_try_list() except: - logging.error(Ta('error-qAdd@1'), nzo_id) + logging.error(Ta('Error while adding %s, removing'), nzo_id) logging.info("Traceback: ", exc_info = True) self.remove(nzo_id, False) else: @@ -306,7 +305,7 @@ class NzbQueue(TryList): self.save(nzo) if nzo.status not in ('Fetching',): - osx.sendGrowlMsg(T('grwl-nzbadd-title'), nzo.filename, osx.NOTIFICATION['download']) + osx.sendGrowlMsg(T('NZB added to queue'), nzo.filename, osx.NOTIFICATION['download']) if self.__auto_sort: self.sort_by_avg_age() @@ -659,7 +658,7 @@ class NzbQueue(TryList): Assembler.do.process((nzo, nzf)) else: - logging.warning(Ta('warn-unknownEncoding@1'), filename) + logging.warning(Ta('%s -> Unknown encoding'), filename) if post_done: self.remove(nzo.nzo_id, add_to_history=False, cleanup=False) diff --git a/sabnzbd/nzbstuff.py b/sabnzbd/nzbstuff.py index 86d647c..238ca70 100644 --- a/sabnzbd/nzbstuff.py +++ b/sabnzbd/nzbstuff.py @@ -41,7 +41,6 @@ from sabnzbd.misc import to_units, cat_to_opts, cat_convert, sanitize_foldername sanitize_filename, globber, sanitize_foldername import sabnzbd.cfg as cfg from sabnzbd.trylist import TryList -from sabnzbd.lang import T, Ta from sabnzbd.encoding import unicoder, platform_encode, latin1 __all__ = ['Article', 'NzbFile', 'NzbObject'] @@ -379,7 +378,7 @@ class NzbParser(xml.sax.handler.ContentHandler): segm = str(''.join(self.article_id)) if partnum in self.article_db: if segm != self.article_db[partnum][0]: - logging.error(Ta('error-qDupPart@3'), + logging.error(Ta('Duplicate part %s, but different ID-s (%s // %s)'), partnum, self.article_db[partnum][0], segm) else: logging.info("Skipping duplicate article (%s)", segm) @@ -397,7 +396,7 @@ class NzbParser(xml.sax.handler.ContentHandler): # Create an NZF self.in_file = False if not self.article_db: - logging.warning(Ta('warn-emptyFile@1'), self.filename) + logging.warning(Ta('File %s is empty, skipping'), self.filename) return tm = datetime.datetime.fromtimestamp(self.file_date) nzf = NzbFile(tm, self.filename, self.article_db, self.file_bytes, self.nzo) @@ -424,7 +423,7 @@ class NzbParser(xml.sax.handler.ContentHandler): files = max(1, self.valids) self.nzo.avg_date = datetime.datetime.fromtimestamp(self.avg_age / files) if self.skipped_files: - logging.warning(Ta('warn-badImport@2'), + logging.warning(Ta('Failed to import %s files from %s'), self.skipped_files, self.nzo.filename) @@ -603,7 +602,7 @@ class NzbObject(TryList): if (not reuse) and nzb and sabnzbd.backup_exists(filename): # File already exists and we have no_dupes set - logging.warning(Ta('warn-skipDup@1'), filename) + logging.warning(Ta('Skipping duplicate NZB "%s"'), filename) raise TypeError if reuse: @@ -634,12 +633,12 @@ class NzbObject(TryList): parser.parse(inpsrc) except xml.sax.SAXParseException, err: self.purge_data(keep_basic=reuse) - logging.warning(Ta('warn-badNZB@3'), + logging.warning(Ta('Invalid NZB file %s, skipping (reason=%s, line=%s)'), filename, err.getMessage(), err.getLineNumber()) raise ValueError except Exception, err: self.purge_data(keep_basic=reuse) - logging.warning(Ta('warn-badNZB@3'), filename, err, 0) + logging.warning(Ta('Invalid NZB file %s, skipping (reason=%s, line=%s)'), filename, err, 0) raise ValueError sabnzbd.backup_nzb(filename, nzb) @@ -860,7 +859,7 @@ class NzbObject(TryList): if self.password: return '%s / %s' % (self.final_name, self.password) elif self.encrypted and self.status == 'Paused': - return '%s [%s]' % (self.final_name, Ta('msg-encrypted')) + return '%s [%s]' % (self.final_name, Ta('ENCRYPTED')) else: return self.final_name @@ -897,7 +896,7 @@ class NzbObject(TryList): #format the total time the download took, in days, hours, and minutes, or seconds. complete_time = format_time_string(seconds, timecompleted.days) - self.set_unpack_info('Download', T('msg-DownloadedIn@2') % + self.set_unpack_info('Download', T('Downloaded in %s at an average of %sB/s') % (complete_time, to_units(avg_bps*1024)), unique=True) @@ -915,7 +914,7 @@ class NzbObject(TryList): nzf.finish_import() # Still not finished? Something went wrong... if not nzf.import_finished: - logging.error(Ta('error-qImport@1'), nzf) + logging.error(Ta('Error importing %s'), nzf) nzf_remove_list.append(nzf) continue else: diff --git a/sabnzbd/postproc.py b/sabnzbd/postproc.py index c600814..98cfe96 100644 --- a/sabnzbd/postproc.py +++ b/sabnzbd/postproc.py @@ -46,7 +46,6 @@ import sabnzbd.cfg as cfg import sabnzbd.nzbqueue import sabnzbd.database as database from sabnzbd.utils import osx -from sabnzbd.lang import T, Ta #------------------------------------------------------------------------------ @@ -92,7 +91,7 @@ class PostProcessor(Thread): try: version, history_queue = data if POSTPROC_QUEUE_VERSION != version: - logging.warning(Ta('warn-badPPQueue@2'), POSTPROC_QUEUE_VERSION, version) + logging.warning(Ta('Failed to load postprocessing queue: Wrong version (need:%s, found:%s)'), POSTPROC_QUEUE_VERSION, version) if isinstance(history_queue, list): self.history_queue = [nzo for nzo in history_queue if os.path.exists(nzo.downpath)] except: @@ -121,7 +120,7 @@ class PostProcessor(Thread): self.history_queue.remove(nzo) except: nzo_id = getattr(nzo, 'nzo_id', 'unknown id') - logging.error(Ta('error-ppDelNzo'), nzo_id) + logging.error(Ta('Failed to remove nzo from postproc queue (id)'), nzo_id) self.save() def stop(self): @@ -213,7 +212,7 @@ def process_job(nzo): # if the directory has not been made, no files were assembled if not os.path.exists(workdir): - emsg = T('warn-OutRetention') + emsg = T('Download failed - Out of your server\'s retention?') nzo.fail_msg = emsg nzo.status = 'Failed' # do not run unpacking or parity verification @@ -280,7 +279,7 @@ def process_job(nzo): unpack_error, newfiles = unpack_magic(nzo, workdir, tmp_workdir_complete, flag_delete, (), (), (), ()) logging.info("unpack_magic finished on %s", filename) else: - nzo.set_unpack_info('Unpack', T('msg-noPostProc')) + nzo.set_unpack_info('Unpack', T('No post-processing because of failed verification')) if cfg.safe_postproc(): all_ok = all_ok and not unpack_error @@ -288,7 +287,7 @@ def process_job(nzo): if all_ok: ## Move any (left-over) files to destination nzo.status = 'Moving' - nzo.set_action_line(T('msg-moving'), '...') + nzo.set_action_line(T('Moving'), '...') for root, dirs, files in os.walk(workdir): if not root.endswith(JOB_ADMIN): for file_ in files: @@ -308,7 +307,7 @@ def process_job(nzo): ## Check if this is an NZB-only download, if so redirect to queue nzb_list = nzb_redirect(tmp_workdir_complete, nzo.pp, script, cat, priority=nzo.priority) if nzb_list: - nzo.set_unpack_info('Download', T('msg-sentToQ@1') % unicoder(nzb_list)) + nzo.set_unpack_info('Download', T('Sent %s to queue') % unicoder(nzb_list)) try: remove_dir(tmp_workdir_complete) except: @@ -328,7 +327,7 @@ def process_job(nzo): renamer(tmp_workdir_complete, workdir_complete) nzo.final_name = os.path.basename(workdir_complete) except: - logging.error(Ta('error-ppRename@2'), tmp_workdir_complete, workdir_complete) + logging.error(Ta('Error renaming "%s" to "%s"'), tmp_workdir_complete, workdir_complete) logging.info("Traceback: ", exc_info = True) job_result = int(par_error) + int(unpack_error)*2 @@ -347,8 +346,8 @@ def process_job(nzo): if all_ok and (not nzb_list) and script_path: #set the current nzo status to "Ext Script...". Used in History nzo.status = 'Running' - nzo.set_action_line(T('msg-running'), unicoder(script)) - nzo.set_unpack_info('Script', T('msg-runScript@1') % unicoder(script), unique=True) + nzo.set_action_line(T('Running script'), unicoder(script)) + nzo.set_unpack_info('Script', T('Running user script %s') % unicoder(script), unique=True) script_log, script_ret = external_processing(script_path, workdir_complete, nzo.filename, msgid, dirname, cat, nzo.group, job_result) script_line = get_last_line(script_log) @@ -357,7 +356,7 @@ def process_job(nzo): if script_line: nzo.set_unpack_info('Script', script_line, unique=True) else: - nzo.set_unpack_info('Script', T('msg-ranScript@1') % unicoder(script), unique=True) + nzo.set_unpack_info('Script', T('Ran %s') % unicoder(script), unique=True) else: script = "" script_line = "" @@ -378,11 +377,11 @@ def process_job(nzo): if script_line: nzo.set_unpack_info('Script', '%s%s (%s)' % (script_ret, script_line, urllib.quote(script_output), - T('link-more')), unique=True) + T('More')), unique=True) else: nzo.set_unpack_info('Script', '%s%s' % (script_ret, urllib.quote(script_output), - T('link-viewSc')), unique=True) + T('View script output')), unique=True) ## Remove newzbin bookmark, if any if msgid and all_ok: @@ -397,10 +396,10 @@ def process_job(nzo): nzo.status = 'Failed' except: - logging.error(Ta('error-ppFailed@2'), filename, crash_msg) + logging.error(Ta('Post Processing Failed for %s (%s)'), filename, crash_msg) if not crash_msg: logging.info("Traceback: ", exc_info = True) - nzo.fail_msg = T('warn-PostCrash@1') % unicoder(crash_msg) + nzo.fail_msg = T('PostProcessing Crashed, see logfile (%s)') % unicoder(crash_msg) osx.sendGrowlMsg("Download Failed", filename, osx.NOTIFICATION['complete']) nzo.status = 'Failed' par_error = True @@ -427,7 +426,7 @@ def process_job(nzo): logging.info('Cleaning up %s (keep_basic=%s)', filename, str(not all_ok)) sabnzbd.nzbqueue.cleanup_nzo(nzo, keep_basic=not all_ok) except: - logging.error(Ta('error-ppCleanup@1'), nzo.final_name) + logging.error(Ta('Cleanup of %s failed.'), nzo.final_name) logging.info("Traceback: ", exc_info = True) ## Remove download folder @@ -438,7 +437,7 @@ def process_job(nzo): remove_all(os.path.join(workdir, JOB_ADMIN)) remove_dir(workdir) except: - logging.error(Ta('error-ppDelWorkdir@1'), workdir) + logging.error(Ta('Error removing workdir (%s)'), workdir) logging.info("Traceback: ", exc_info = True) return True @@ -490,11 +489,11 @@ def parring(nzo, workdir): for sfv in globber(workdir, '*.sfv'): par_error = par_error or not sfv_check(sfv) if par_error: - nzo.set_unpack_info('Repair', T('msg-failedSFV@1') % unicoder(os.path.basename(sfv))) + nzo.set_unpack_info('Repair', T('Some files failed to verify against "%s"') % unicoder(os.path.basename(sfv))) if not sfv: logging.info("No par2 sets for %s", filename) - nzo.set_unpack_info('Repair', T('msg-noParSets@1') % unicoder(filename)) + nzo.set_unpack_info('Repair', T('[%s] No par2 sets') % unicoder(filename)) return par_error, re_add @@ -526,14 +525,14 @@ def perm_script(wdir, umask): os.chmod(root, umask) except: if report_errors: - logging.error(Ta('error-ppPermissions@1'), root) + logging.error(Ta('Cannot change permissions of %s'), root) logging.info("Traceback: ", exc_info = True) for name in files: try: os.chmod(join(root, name), umask_file) except: if report_errors: - logging.error(Ta('error-ppPermissions@1'), join(root, name)) + logging.error(Ta('Cannot change permissions of %s'), join(root, name)) logging.info("Traceback: ", exc_info = True) @@ -600,7 +599,7 @@ def cleanup_list(wdir, skip_nzb): logging.info("Removing unwanted file %s", path) os.remove(path) except: - logging.error(Ta('error-ppDelFailed@1'), path) + logging.error(Ta('Removing %s failed'), path) logging.info("Traceback: ", exc_info = True) @@ -671,5 +670,5 @@ def remove_samples(path): logging.info("Removing unwanted sample file %s", path) os.remove(path) except: - logging.error(Ta('error-ppDelFailed@1'), path) + logging.error(Ta('Removing %s failed'), path) logging.info("Traceback: ", exc_info = True) diff --git a/sabnzbd/rss.py b/sabnzbd/rss.py index 5149e8e..d62b9cd 100644 --- a/sabnzbd/rss.py +++ b/sabnzbd/rss.py @@ -34,7 +34,6 @@ import sabnzbd.emailer as emailer from sabnzbd.encoding import latin1, unicoder import sabnzbd.utils.feedparser as feedparser -from sabnzbd.lang import T, Ta __RSS = None # Global pointer to RSS-scanner instance @@ -118,7 +117,7 @@ def convert_filter(text): try: return re.compile(txt, re.I) except: - logging.error(Ta('error-rssRegex@1'), text) + logging.error(Ta('Could not compile regex: %s'), text) return None @@ -199,9 +198,9 @@ class RSSQueue(object): try: feeds = config.get_rss()[feed] except KeyError: - logging.error(Ta('error-rssBadFeed@1'), feed) + logging.error(Ta('Incorrect RSS feed description "%s"'), feed) logging.info("Traceback: ", exc_info = True) - return T('error-rssBadFeed@1') % feed + return T('Incorrect RSS feed description "%s"') % feed uri = feeds.uri() defCat = feeds.cat() @@ -250,13 +249,13 @@ class RSSQueue(object): d = feedparser.parse(uri.replace('feed://', 'http://')) logging.debug("Done parsing %s", uri) if not d: - logging.info(Ta('warn-failRSS@1'), uri) - return T('warn-failRSS@1') % uri + logging.info(Ta('Failed to retrieve RSS from %s'), uri) + return T('Failed to retrieve RSS from %s') % uri entries = d.get('entries') if 'bozo_exception' in d and not entries: - logging.info(Ta('warn-failRSS@2'), uri, str(d['bozo_exception'])) - return T('warn-failRSS@2') % (uri, str(d['bozo_exception'])) + logging.info(Ta('Failed to retrieve RSS from %s: %s'), uri, str(d['bozo_exception'])) + return T('Failed to retrieve RSS from %s: %s') % (uri, str(d['bozo_exception'])) if not entries: logging.info('RSS Feed was empty: %s', uri) return '' @@ -545,7 +544,7 @@ def _get_link(uri, entry): category = '' return link, category else: - logging.warning(Ta('warn-emptyRSS@1'), link) + logging.warning(Ta('Empty RSS entry found (%s)'), link) return None, '' diff --git a/sabnzbd/scheduler.py b/sabnzbd/scheduler.py index 6f5aaab..746ed09 100644 --- a/sabnzbd/scheduler.py +++ b/sabnzbd/scheduler.py @@ -34,7 +34,6 @@ import sabnzbd.misc import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.postproc import PostProcessor -from sabnzbd.lang import Ta __SCHED = None # Global pointer to Scheduler instance @@ -78,7 +77,7 @@ def init(): m = int(m) h = int(h) except: - logging.warning(Ta('warn-badSched@3'), action_name, m, h) + logging.warning(Ta('Bad schedule %s at %s:%s'), action_name, m, h) continue if d.isdigit(): @@ -114,7 +113,7 @@ def init(): elif action_name == 'scan_folder': action = sabnzbd.dirscanner.dirscan else: - logging.warning(Ta('warn-badSchedAction@1'), action_name) + logging.warning(Ta('Unknown action: %s'), action_name) continue logging.debug("scheduling %s(%s) on days %s at %s:%s", action_name, arguments, d, h, m) @@ -280,12 +279,12 @@ def analyse(was_paused=False): try: servers[value] = 1 except: - logging.warning(Ta('warn-schedNoServer@1'), value) + logging.warning(Ta('Schedule for non-existing server %s'), value) elif action == 'disable_server': try: servers[value] = 0 except: - logging.warning(Ta('warn-schedNoServer@1'), value) + logging.warning(Ta('Schedule for non-existing server %s'), value) if not was_paused: if paused_all: diff --git a/sabnzbd/skintext.py b/sabnzbd/skintext.py new file mode 100644 index 0000000..bb2f508 --- /dev/null +++ b/sabnzbd/skintext.py @@ -0,0 +1,725 @@ +#!/usr/bin/python -OO +# -*- coding: UTF-8 -*- +# Copyright 2010 The SABnzbd-Team +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +""" +sabnzbd.skintext - Language strings used in the templates +""" + +SKIN_TEXT = { + +# Special texts + 'stage-download' : TT('Download'), + 'stage-repair' : TT('Repair'), + 'stage-filejoin' : TT('Join files'), + 'stage-unpack' : TT('Unpack'), + 'stage-script' : TT('Script'), + + 'post-Completed' : TT('Completed'), + 'post-Failed' : TT('Failed'), + 'post-Queued' : TT('Queued'), + 'post-Repairing' : TT('Repairing...'), + 'post-Extracting' : TT('Extracting...'), + 'post-Moving' : TT('Moving...'), + 'post-Running' : TT('Running script...'), + 'post-Fetching' : TT('Fetching extra blocks...'), + 'post-QuickCheck' : TT('Quick Check...'), + 'post-Verifying' : TT('Verifying...'), + + 'sch-frequency' : TT('Frequency'), + 'sch-action' : TT('Action'), + 'sch-arguments' : TT('Arguments'), + 'sch-task' : TT('Task'), + 'sch-disable_server' : TT('disable server'), + 'sch-enable_server' : TT('enable server'), + 'sch-resume' : TT('Resume'), + 'sch-pause' : TT('Pause'), + 'sch-shutdown' : TT('Shutdown'), + 'sch-restart' : TT('Restart'), + 'sch-speedlimit' : TT('Speedlimit'), + 'sch-pause_all' : TT('Pause All'), + 'sch-pause_post' : TT('Pause post-processing'), + 'sch-resume_post' : TT('Resume post-processing'), + 'sch-scan_folder' : TT('Scan watched folder'), + +# General texts + 'default' : TT('Default'), + 'none' : TT('None'), + 'KBs' : TT('KB/s'), + 'MB' : TT('MB'), + 'GB' : TT('GB'), + 'hour' : TT('hour'), + 'hours' : TT('hours'), + 'minute' : TT('min'), + 'minutes' : TT('mins'), + 'second' : TT('sec'), + 'seconds' : TT('seconds'), + 'month' : TT('Month'), + 'year' : TT('Year'), + 'daily' : TT('Daily'), + 'monday' : TT('Monday'), + 'tuesday' : TT('Tuesday'), + 'wednesday' : TT('Wednesday'), + 'thursday' : TT('Thursday'), + 'friday' : TT('Friday'), + 'saturday' : TT('Saturday'), + 'sunday' : TT('Sunday'), + 'day-of-month' : TT('Day of month'), + 'thisWeek' : TT('This week'), + 'thisMonth' : TT('This month'), + 'today' : TT('Today'), + 'total' : TT('Total'), + +# General template elements + 'signOn' : TT('The automatic usenet download tool'), + 'button-save' : TT('Save'), + 'queued' : TT('Queued'), + 'button-back' : TT('Back'), + 'button-x' : TT('X'), + 'confirm' : TT('Are you sure?'), + 'delFiles' : TT('Delete all downloaded files?'), + +# Header + 'menu-home' : TT('Home'), + 'menu-queue' : TT('Queue'), + 'menu-history' : TT('History'), + 'menu-config' : TT('Config'), + 'menu-cons' : TT('Connections'), + 'menu-help' : TT('Help'), + 'menu-wiki' : TT('Wiki'), + 'menu-forums' : TT('Forum'), + 'menu-irc' : TT('IRC'), + 'cmenu-general' : TT('General'), + 'cmenu-folders' : TT('Folders'), + 'cmenu-switches' : TT('Switches'), + 'cmenu-servers' : TT('Servers'), + 'cmenu-scheduling' : TT('Scheduling'), + 'cmenu-rss' : TT('RSS'), + 'cmenu-email' : TT('Email'), + 'cmenu-newzbin' : TT('Index Sites'), + 'cmenu-cat' : TT('Categories'), + 'cmenu-sorting' : TT('Sorting'), + +# Footer + 'ft-download' : TT('Download Dir'), + 'ft-complete' : TT('Complete Dir'), + 'ft-speed' : TT('Download speed'), + 'ft-queued' : TT('Queued'), + 'ft-paused' : TT('PAUSED'), + 'ft-buffer@2' : TT('Cached %s articles (%s)'), + 'ft-sysload' : TT('Sysload'), + 'ft-warning' : TT('WARNINGS'), + 'ft-newRelease@1' : TT('New release %s available at'), + +# Main page + 'addNewJobs' : TT('Add new downloads'), + 'shutdownOK?' : TT('Are you sure you want to shutdown SABnzbd?'), + 'link-shutdown' : TT('Shutdown'), + 'link-pause' : TT('Pause'), + 'link-resume' : TT('Resume'), + 'button-add' : TT('Add'), + 'add' : TT('Add'), + 'reportId' : TT('Report-id'), + 'addFile' : TT('Add File'), + 'category' : TT('Category'), + 'pp' : TT('Processing'), + 'script' : TT('Script'), + 'priority' : TT('Priority'), + 'pp-none' : TT('Download'), + 'pp-repair' : TT('+Repair'), + 'pp-unpack' : TT('+Unpack'), + 'pp-delete' : TT('+Delete'), + 'pp-n' : TT(' '), + 'pp-r' : TT('R'), + 'pp-u' : TT('U'), + 'pp-d' : TT('D'), + 'pr-force' : TT('Force'), + 'pr-normal' : TT('Normal'), + 'pr-high' : TT('High'), + 'pr-low' : TT('Low'), + 'enterURL' : TT('Enter URL'), + 'enterID' : TT(' or Report ID'), + +# Queue page + 'link-sortByName' : TT('Sort by name'), + 'link-sortByAge' : TT('Sort by age'), + 'link-sortBySize' : TT('Sort by size'), + 'link-hideFiles' : TT('Hide files'), + 'link-showFiles' : TT('Show files'), + 'onQueueFinish' : TT('On queue finish'), + 'shutdownPc' : TT('Shutdown PC'), + 'standbyPc' : TT('Standby PC'), + 'hibernatePc' : TT('Hibernate PC'), + 'shutdownSab' : TT('Shutdown SABnzbd'), + 'speedLimit' : TT('Speed Limit'), + 'pauseFor' : TT('Pause for'), + 'mode' : TT('Processing'), + 'order' : TT('Order'), + 'name' : TT('Name'), + 'remainTotal' : TT('Remain/Total'), + 'eta' : TT('ETA'), + 'age' : TT('AGE'), + 'button-del' : TT('Del'), + 'button-resume' : TT('Resume'), + 'button-pause' : TT('Pause'), + 'button-retry' : TT('Retry'), + 'eoq-actions' : TT('Actions'), + 'eoq-scripts' : TT('Scripts'), + 'purgeQueue' : TT('Purge Queue'), + 'purgeQueueConf' : TT('Delete all items from the queue?'), + +# History page + 'purgeHist' : TT('Purge History'), + 'purgeHistConf' : TT('Delete all items from History?'), + 'hideDetails' : TT('Hide details'), + 'showDetails' : TT('Show details'), + 'sizeHist' : TT('History Size'), + 'completed' : TT('Completed'), + 'size' : TT('Size'), + 'status' : TT('Status'), + +# Connections page + 'link-forceDisc' : TT('Force Disconnect'), + 'askTestEmail' : TT('This will send a test email to your account.'), + 'link-showLog' : TT('Show Logging'), + 'link-showWeblog' : TT('Show Weblogging'), + 'link-testEmail' : TT('Test Email'), + 'logging' : TT('Logging'), + 'log-errWarn' : TT('Errors/Warning'), + 'log-info' : TT('+ Info'), + 'log-debug' : TT('+ Debug'), + 'connections' : TT('Connections'), + 'thread' : TT('Thread'), + 'emailResult' : TT('Email Test Result'), + 'lastWarnings' : TT('Latest Warnings'), + 'clearWarnings' : TT('clear'), + 'server-blocked' : TT('Unblock'), + +# Configuration + 'configuration' : TT('Configuration'), + 'confgFile' : TT('Config File'), + 'explain-Restart' : TT('The button below will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.'), + 'button-restart' : TT('Restart'), + 'button-scan' : TT('Scan'), + 'explain-Scan' : TT('The "Scan" button will search the temporary download folder for
folders missing from the queue.'), + 'button-repair' : TT('Repair'), + 'explain-Repair' : TT('The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.'), + 'version' : TT('Version'), + 'uptime' : TT('Uptime'), + +# Config->General + 'generalConfig' : TT('General configuration'), + 'restartRequired' : TT('Changes will require a SABnzbd restart!'), + 'webServer' : TT('SABnzbd Web Server'), + 'opt-host' : TT('SABnzbd Host'), + 'explain-host' : TT('Host SABnzbd should listen on.'), + 'opt-port' : TT('SABnzbd Port'), + 'explain-port' : TT('Port SABnzbd should listen on.'), + 'opt-web_dir' : TT('Web Interface'), + 'explain-web_dir' : TT('Choose a skin.'), + 'opt-web_dir2' : TT('Secondary Web Interface'), + 'explain-web_dir2' : TT('Activate an alternative skin.'), + 'webAuth' : TT('Web server authentication'), + 'opt-web_username' : TT('SABnzbd Username'), + 'explain-web_username' : TT('Optional authentication username.'), + 'opt-web_password' : TT('SABnzbd Password'), + 'explain-web_password' : TT('Optional authentication password.'), + 'httpsSupport' : TT('HTTPS Support'), + 'opt-enable_https' : TT('Enable HTTPS'), + 'opt-notInstalled' : TT('not installed'), + 'explain-enable_https' : TT('Enable accessing the interface from a HTTPS address.'), + 'opt-https_port' : TT('HTTPS Port'), + 'explain-https_port' : TT('Port SABnzbd should listen on for HTTPS communication.'), + 'opt-https_cert' : TT('HTTPS Certificate'), + 'explain-https_cert' : TT('File name or path to HTTPS Certificate.'), + 'opt-https_key' : TT('HTTPS Key'), + 'explain-https_key' : TT('File name or path to HTTPS Key.'), + 'tuning' : TT('Tuning'), + 'opt-refresh_rate' : TT('Queue auto refresh interval:'), + 'explain-refresh_rate' : TT('Refresh interval of the queue web-interface page(sec, 0= none).'), + 'opt-rss_rate' : TT('RSS Checking Interval'), + 'explain-rss_rate' : TT('Checking interval (in minutes, at least 15).'), + 'opt-bandwidth_limit' : TT('Download Speed Limit'), + 'explain-bandwidth_limit' : TT('Download rate limit (in KB/s - kilobytes per second).'), + 'opt-cache_limitstr' : TT('Article Cache Limit'), + 'explain-cache_limitstr' : TT('Cache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"'), + 'opt-cleanup_list' : TT('Cleanup List'), + 'explain-cleanup_list' : TT('List of file extensions that should be deleted after download.
For example: .nfo or .nfo, .sfv'), + 'button-saveChanges' : TT('Save Changes'), + 'opt-language' : TT('Language'), + 'explain-language' : TT('Select a web interface language.'), + 'opt-apikey' : TT('API Key'), + 'explain-apikey' : TT('This key is used to give 3rd party programs access to SABnzbd.'), + 'button-apikey' : TT('Generate New Key'), + 'opt-disableApikey' : TT('Disable API-key'), + 'explain-disableApikey' : TT('Do not require the API key.'), + 'explain-disableApikeyWarn' : TT('USE AT YOUR OWN RISK!'), + +# Config->Folders + 'folderConfig' : TT('Folder configuration'), + 'explain-folderConfig' : TT('NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.'), + 'userFolders' : TT('User Folders'), + 'in' : TT('In'), + 'opt-download_dir' : TT('Temporary Download Folder'), + 'explain-download_dir' : TT('Location to store unprocessed downloads.
Can only be changed when queue is empty.'), + 'opt-download_free' : TT('Minimum Free Space for Temporary Download Folder'), + 'explain-download_free' : TT('Auto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"'), + 'opt-complete_dir' : TT('Completed Download Folder'), + 'explain-complete_dir' : TT('Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.'), + 'opt-permissions' : TT('Permissions for completed downloads'), + 'explain-permissions' : TT('Set permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"'), + 'opt-dirscan_dir' : TT('Watched Folder'), + 'explain-dirscan_dir' : TT('Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.'), + 'opt-dirscan_speed' : TT('Watched Folder Scan Speed'), + 'explain-dirscan_speed' : TT('Number of seconds between scans for .nzb files.'), + 'opt-script_dir' : TT('Post-Processing Scripts Folder'), + 'explain-script_dir' : TT('Folder containing user scripts for post-processing.'), + 'opt-email_dir' : TT('Email Templates Folder'), + 'explain-email_dir' : TT('Folder containing user-defined email templates.'), + 'systemFolders' : TT('System Folders'), + 'opt-admin_dir' : TT('Administrative Folder'), + 'explain-admin_dir' : TT('Location for queue admin and history database.
Can only be changed when queue is empty.
Data will not be moved.
Requires SABnzbd restart!'), + 'opt-log_dir' : TT('Log Folder'), + 'explain-log_dir' : TT('Location of log files for SABnzbd.
Requires SABnzbd restart!'), + 'opt-nzb_backup_dir' : TT('.nzb Backup Folder'), + 'explain-nzb_backup_dir' : TT('Location where .nzb files will be stored.'), + +# Config->Switches + 'switchesConfig' : TT('Switches configuration'), + 'processingSwitches' : TT('Processing Switches'), + 'opt-quick_check' : TT('Enable Quick Check'), + 'explain-quick_check' : TT('Skip par2 checking when files are 100% valid.'), + 'opt-enable_unrar' : TT('Enable Unrar'), + 'explain-enable_unrar' : TT('Enable built-in unrar functionality.'), + 'opt-enable_unzip' : TT('Enable Unzip'), + 'explain-enable_unzip' : TT('Enable built-in unzip functionality.'), + 'opt-enable_filejoin' : TT('Enable Filejoin'), + 'explain-enable_filejoin' : TT('Join files ending in .001, .002 etc. into one file.'), + 'opt-enable_tsjoin' : TT('Enable TS Joining'), + 'explain-ts_join' : TT('Join files ending in .001.ts, .002.ts etc. into one file.'), + 'opt-enable_par_cleanup' : TT('Enable Par Cleanup'), + 'explain-enable_par_cleanup' : TT('Cleanup par files (if verifiying/repairing succeded).'), + 'opt-fail_on_crc' : TT('Fail on yEnc CRC Errors'), + 'explain-fail_on_crc' : TT('Use backup servers on yEnc crc errors.'), + 'opt-top_only' : TT('Only Get Articles for Top of Queue'), + 'explain-top_only' : TT('Enable for less memory usage. Disable to prevent slow jobs from blocking the queue.'), + 'opt-safe_postproc' : TT('Post-Process Only Verified Jobs'), + 'explain-safe_postproc' : TT('Only perform post-processing on jobs that passed all PAR2 checks.'), + 'opt-pause_on_pwrar' : TT('Pause job when encrypted RAR is downloaded'), + 'explain-pause_on_pwrar' : TT('You\'ll need to set a password and resume the job.'), + 'opt-no_dupes' : TT('Prevent Duplicate Downloads'), + 'explain-no_dupes' : TT('Skip a job if a backed-up .nzb with the same name exists.'), + 'opt-dirscan_opts' : TT('Default Post-Processing'), + 'explain-dirscan_opts' : TT('Used when no post-processing is defined by the category.'), + 'opt-dirscan_script' : TT('Default User Script'), + 'explain-dirscan_script' : TT('Used when no user script is defined by the category.'), + 'opt-pre_script' : TT('Pre-queue user script'), + 'explain-pre_script' : TT('Used before an NZB enters the queue.'), + 'opt-dirscan_priority' : TT('Default Priority'), + 'explain-dirscan_priority' : TT('Used when no priority is defined by the category.'), + 'opt-par2_multicore' : TT('Enable MultiCore Par2'), + 'explain-par2_multicore' : TT('Read the Wiki Help on this!'), + 'opt-par_option' : TT('Extra PAR2 Parameters'), + 'explain-par_option' : TT('Read the Wiki Help on this!'), + 'opt-nice' : TT('Nice Parameters'), + 'explain-nice' : TT('Read the Wiki Help on this!'), + 'opt-ionice' : TT('IONice Parameters'), + 'explain-ionice' : TT('Read the Wiki Help on this!'), + 'otherSwitches' : TT('Other Switches'), + 'opt-auto_disconnect' : TT('Disconnect on Empty Queue'), + 'explain-auto_disconnect' : TT('Disconnect from Usenet server(s) when queue is empty or paused.'), + 'opt-send_group' : TT('Send Group'), + 'explain-send_group' : TT('Send group command before requesting articles.'), + 'opt-auto_sort' : TT('Sort by Age'), + 'explain-auto_sort' : TT('Automatically sort items by (average) age.'), + 'opt-check_new_rel' : TT('Check for New Release'), + 'explain-check_new_rel' : TT('Weekly check for new SABnzbd release.'), + 'opt-replace_spaces' : TT('Replace Spaces in Foldername'), + 'explain-replace_spaces' : TT('Replace spaces with underscores in folder names.'), + 'opt-replace_illegal' : TT('Replace Illegal Characters in Folder Names'), + 'explain-replace_illegal' : TT('Replace illegal characters in folder names by equivalents (otherwise remove).'), + 'opt-auto_browser' : TT('Launch Browser on Startup'), + 'explain-auto_browser' : TT('Launch the default web browser when starting SABnzbd.'), + 'opt-pause_on_post_processing' : TT('Pause Downloading During Post-Processing'), + 'explain-pause_on_post_processing' : TT('Pauses downloading at the start of post processing and resumes when finished.'), + 'opt-ignore_samples' : TT('Ignore Samples'), + 'explain-ignore_samples' : TT('Filter out sample files (e.g. video samples).'), + 'igsam-off' : TT('Off'), + 'igsam-del' : TT('Delete after download'), + 'igsam-not' : TT('Do not download'), + 'opt-ssl_type' : TT('SSL type'), + 'explain-ssl_type' : TT('Use V23 unless your provider requires otherwise!'), + +# Config->Server + 'configServer' : TT('Server configuration'), + 'addServer' : TT('Add Server'), + 'srv-host' : TT('Host'), + 'srv-port' : TT('Port'), + 'srv-username' : TT('Username'), + 'srv-password' : TT('Password'), + 'srv-timeout' : TT('Timeout'), + 'srv-connections' : TT('Connections'), + 'srv-ssl' : TT('SSL'), + 'srv-fillserver' : TT('Backup server'), + 'srv-optional' : TT('Optional'), + 'srv-enable' : TT('Enable'), + 'button-addServer' : TT('Add Server'), + 'button-delServer' : TT('Remove Server'), + 'button-testServer' : TT('Test Server'), + 'srv-testing' : TT('Testing server details...'), + 'srv-testHint' : TT('Click below to test.'), + +# Config->Scheduling + 'configSchedule' : TT('Scheduling configuration'), + 'addSchedule' : TT('Add Schedule'), + 'sch-frequency' : TT('Frequency'), + 'sch-action' : TT('Action'), + 'sch-arguments' : TT('Arguments'), + 'button-addSchedule' : TT('Add Schedule'), + 'button-delSchedule' : TT('Remove'), + 'currentSchedules' : TT('Current Schedules'), + 'sch-resume' : TT('Resume'), + 'sch-pause' : TT('Pause'), + 'sch-shutdown' : TT('Shutdown'), + 'sch-restart' : TT('Restart'), + +# Config->RSS + 'configRSS' : TT('RSS Configuration'), + 'newFeedURI' : TT('New Feed URL'), + 'explain-RSS' : TT('The checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
The checking frequency is in the General page of the configuration.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".'), + 'feed' : TT('Feed'), + 'button-delFeed' : TT('Delete Feed'), + 'button-preFeed' : TT('Preview'), + 'button-forceFeed' : TT('Force Download'), + 'rss-order' : TT('Order'), + 'rss-type' : TT('Type'), + 'rss-filter' : TT('Filter'), + 'rss-skip' : TT('Skip'), + 'rss-accept' : TT('Accept'), + 'rss-reject' : TT('Reject'), + 'rss-must' : TT('Requires'), + 'rss-mustcat' : TT('RequiresCat'), + 'rss-delFilter' : TT('X'), + 'rss-matched' : TT('Matched'), + 'rss-notMatched' : TT('Not matched'), + 'rss-done' : TT('Downloaded'), + 'link-download' : TT('Download'), + +# Config->Email + 'configEmail' : TT('Email Notification'), + 'emailOptions' : TT('Email Options'), + 'opt-email_endjob' : TT('Email Notification On Job Completion'), + 'email-never' : TT('Never'), + 'email-always' : TT('Always'), + 'email-errorOnly' : TT('Error-only'), + 'opt-email_full' : TT('Disk Full Notifications'), + 'explain-email_full' : TT('Send email when disk is full and SABnzbd is paused.'), + 'opt-email_rss' : TT('Send RSS notifications'), + 'explain-email_rss' : TT('Send email when an RSS feed adds jobs to the queue.'), + 'emailAccount' : TT('Email Account Settings'), + 'opt-email_server' : TT('SMTP Server'), + 'explain-email_server' : TT('Set your ISP\'s server for outgoing email.'), + 'opt-email_to' : TT('Email Recipient'), + 'explain-email_to' : TT('Email address to send the email to.'), + 'opt-email_from' : TT('Email Sender'), + 'explain-email_from' : TT('Who should we say sent the email?'), + 'opt-email_account' : TT('OPTIONAL Account Username'), + 'explain-email_account' : TT('For authenticated email, account name.'), + 'opt-email_pwd' : TT('OPTIONAL Account Password'), + 'explain-email_pwd' : TT('For authenticated email, password.'), + +# Config->Newzbin + 'explain-newzbin' : TT('If you have an account at www.newzbin.com, you can enter your account info here.
This will unlock extra functionality.'), + 'accountInfo' : TT('Account info'), + 'opt-username_newzbin' : TT('Newzbin Username'), + 'explain-username_newzbin' : TT('Set your account username here.'), + 'opt-password_newzbin' : TT('Newzbin Password'), + 'explain-password_newzbin' : TT('Set your account password here.'), + 'newzbinBookmarks' : TT('Bookmark Processing'), + 'opt-newzbin_bookmarks' : TT('Auto-Fetch Bookmarks'), + 'explain-newzbin_bookmarks' : TT('Automatically retrieve jobs from your bookmarks.'), + 'link-getBookmarks' : TT('Get Bookmarks Now'), + 'link-HideBM' : TT('Hide Processed Bookmarks'), + 'link-ShowBM' : TT('Show Processed Bookmarks'), + 'opt-newzbin_unbookmark' : TT('Un-Bookmark If Download Complete'), + 'explain-newzbin_unbookmark' : TT('Remove from bookmark list when download is complete.'), + 'opt-bookmark_rate' : TT('Checking Interval'), + 'explain-bookmark_rate' : TT('In minutes (at least 15 min).'), + 'processedBM' : TT('Processed Bookmarks'), + 'explain-nzbmatrix' : TT('If you have an account at www.nzbmatrix.com, you can enter your account info here.
This is required if you want to use the RSS feeds of this site.'), + 'opt-username_matrix' : TT('NzbMatrix Username'), + 'explain-username_matrix' : TT('Set your account username here.'), + 'opt-apikey_matrix' : TT('NzbMatrix API key'), + 'explain-apikey_matrix' : TT('Set the NzbMatrix API key here.'), + +# Config->Cat + 'configCat' : TT('User-defined categories'), + 'explain-configCat' : TT('Defines post-processing and storage.'), + 'explain-catNewzbin' : TT('The Newzbin column will map listed Newzbin categories to your own.'), + 'link-initCat' : TT('Click here to setup newzbin categories.'), + 'explain-relFolder' : TT('Relative folders are based on'), + 'catFolderPath' : TT('Folder/Path'), + 'catNewzbin' : TT('NewzBin'), + 'catGroups' : TT('Groups'), + 'button-delCat' : TT('X'), + +# Config->Sorting + 'configSort' : TT('Sorting configuration'), + 'seriesSorting' : TT('Series Sorting'), + 'opt-tvsort' : TT('Enable TV Sorting'), + 'explain-tvsort' : TT('Enable sorting and renaming of episodes.'), + 'sort-legenda' : TT('Pattern Key'), + 'button-clear' : TT('Clear'), + 'presetSort' : TT('Presets'), + 'example' : TT('Example'), + 'genericSort' : TT('Generic Sorting'), + 'opt-movieSort' : TT('Enable Movie Sorting'), + 'explain-movieSort' : TT('Enable generic sorting and renaming of files.'), + 'opt-movieExtra' : TT('Keep loose downloads in extra folders'), + 'explain-movieExtra' : TT('Enable if downloads are not put in their own folders.'), + 'affectedCat' : TT('Affected Categories'), + 'sort-meaning' : TT('Meaning'), + 'sort-pattern' : TT('Pattern'), + 'sort-result' : TT('Result'), + 'button-Season1x05' : TT('1x05 Season Folder'), + 'button-SeasonS01E05' : TT('S01E05 Season Folder'), + 'button-Ep1x05' : TT('1x05 Episode Folder'), + 'button-EpS01E05' : TT('S01E05 Episode Folder'), + 'sort-title' : TT('Title'), + 'movie-sp-name' : TT('Movie Name'), + 'movie-dot-name' : TT('Movie.Name'), + 'movie-us-name' : TT('Movie_Name'), + 'show-name' : TT('Show Name'), + 'show-sp-name' : TT('Show Name'), + 'show-dot-name' : TT('Show.Name'), + 'show-us-name' : TT('Show_Name'), + 'show-seasonNum' : TT('Season Number'), + 'show-epNum' : TT('Episode Number'), + 'ep-name' : TT('Episode Name'), + 'ep-sp-name' : TT('Episode Name'), + 'ep-dot-name' : TT('Episode.Name'), + 'ep-us-name' : TT('Episode_Name'), + 'fileExt' : TT('File Extension'), + 'extension' : TT('Extension'), + 'partNumber' : TT('Part Number'), + 'decade' : TT('Decade'), + 'orgFilename' : TT('Original Filename'), + 'lowercase' : TT('Lower Case'), + 'TEXT' : TT('TEXT'), + 'text' : TT('text'), + 'sort-File' : TT('file'), + 'sortString' : TT('Sort String'), + 'multiPartLabel' : TT('Multi-part label'), + 'button-inFolders' : TT('In folders'), + 'button-noFolders' : TT('No folders'), + 'dateSorting' : TT('Date Sorting'), + 'opt-dateSort' : TT('Enable Date Sorting'), + 'explain-dateSort' : TT('Enable sorting and renaming of date named files.'), + 'button-ShowNameF' : TT('Show Name folder'), + 'button-YMF' : TT('Year-Month Folders'), + 'button-DailyF' : TT('Daily Folders'), + +# NZO + 'nzoDetails' : TT('Edit NZB Details'), + 'nzoName' : TT('Name'), + 'nzo-delete' : TT('Delete'), + 'nzo-top' : TT('Top'), + 'nzo-up' : TT('Up'), + 'nzo-down' : TT('Down'), + 'nzo-bottom' : TT('Bottom'), + 'nzo-all' : TT('All'), + 'nzo-none' : TT('None'), + 'nzo-invert' : TT('Invert'), + 'nzo-filename' : TT('Filename'), + 'nzo-subject' : TT('Subject'), + 'nzo-age' : TT('Age'), + 'nzo-selection' : TT('Selection'), + +# Internal texts + +# Errors and Warnings + 'msg-path' : TT('Path'), + 'stage-download' : TT('Download'), + 'stage-repair' : TT('Repair'), + 'stage-filejoin' : TT('Join files'), + 'stage-unpack' : TT('Unpack'), + 'stage-script' : TT('Script'), + +#Growl Messages + +#OSX Menu + 'Mobile-confirm-delete' : TT('Are you sure you want to delete'), + 'Mobile-button-refresh' : TT('Refresh'), + 'Mobile-warnings' : TT('Warnings'), + 'Mobile-button-options' : TT('Options'), + 'Mobile-page' : TT('Page'), + 'Mobile-button-prev' : TT('Prev'), + 'Mobile-button-next' : TT('Next'), + 'Mobile-button-first' : TT('First'), + 'Mobile-button-last' : TT('Last'), + 'Mobile-button-close' : TT('Close'), + 'Mobile-button-pauseInterval' : TT('Set Pause Interval'), + 'Mobile-sort' : TT('Sort'), + 'Mobile-confirm-purgeQ' : TT('Purge the Queue?'), + 'Mobile-button-purgeQ' : TT('Purge Queue'), + 'Mobile-pauseInterval' : TT('Pause Interval'), + 'Mobile-pause5m' : TT('Pause for 5 minutes'), + 'Mobile-pause15m' : TT('Pause for 15 minutes'), + 'Mobile-pause30m' : TT('Pause for 30 minutes'), + 'Mobile-pause1h' : TT('Pause for 1 hour'), + 'Mobile-pause3h' : TT('Pause for 3 hours'), + 'Mobile-pause6h' : TT('Pause for 6 hours'), + 'Mobile-pause12h' : TT('Pause for 12 hours'), + 'Mobile-pause24h' : TT('Pause for 24 hours'), + 'Mobile-sortAgeAsc' : TT('Sort by Age Oldest→Newest'), + 'Mobile-sortAgeDesc' : TT('Sort by Age Newest→Oldest'), + 'Mobile-sortNameAsc' : TT('Sort by Name A→Z'), + 'Mobile-sortNameDesc' : TT('Sort by Name Z→A'), + 'Mobile-sortSizeAsc' : TT('Sort by Size Smallest→Largest'), + 'Mobile-sortSizeDesc' : TT('Sort by Size Largest→Smallest'), + 'Mobile-rename' : TT('Rename'), + 'Mobile-left' : TT('Left'), + 'Mobile-confirm-purgeH' : TT('Purge the History?'), + 'Mobile-button-purgeH' : TT('Purge History'), + 'Plush-confirmWithoutSavingPrompt' : TT('Changes have not been saved, and will be lost.'), + 'Plush-cmenu-scheduling' : TT('Scheduling'), + 'Plush-confirm' : TT('Are you sure?'), + 'Plush-openSourceURL' : TT('Open Source URL'), + 'Plush-openInfoURL' : TT('Open Informational URL'), + 'Plush-path' : TT('Path'), + 'Plush-storage' : TT('Storage'), + 'Plush-viewScriptLog' : TT('View Script Log'), + 'Plush-prev' : TT('Prev'), + 'Plush-next' : TT('Next'), + 'Plush-confirmPurgeH' : TT('Purge the History?'), + 'Plush-enableJavascript' : TT('You must enable JavaScript for Plush to function!'), + 'Plush-addnzb' : TT('Add NZB'), + 'Plush-button-refresh' : TT('Refresh'), + 'Plush-options' : TT('Options'), + 'Plush-plushoptions' : TT('Plush Options'), + 'Plush-updateAvailable' : TT('Update Available!'), + 'Plush-pause5m' : TT('Pause for 5 minutes'), + 'Plush-pause15m' : TT('Pause for 15 minutes'), + 'Plush-pause30m' : TT('Pause for 30 minutes'), + 'Plush-pause1h' : TT('Pause for 1 hour'), + 'Plush-pause3h' : TT('Pause for 3 hours'), + 'Plush-pause6h' : TT('Pause for 6 hours'), + 'Plush-pauseForPrompt' : TT('Pause for how many minutes?'), + 'Plush-pauseFor' : TT('Pause for...'), + 'Plush-multiOperations' : TT('Multi-Operations'), + 'Plush-onQueueFinish' : TT('On Finish'), + 'Plush-sort' : TT('Sort'), + 'Plush-sortAgeAsc' : TT('Sort by Age (Oldest→Newest)'), + 'Plush-sortAgeDesc' : TT('Sort by Age (Newest→Oldest)'), + 'Plush-sortNameAsc' : TT('Sort by Name (A→Z)'), + 'Plush-sortNameDesc' : TT('Sort by Name (Z→A)'), + 'Plush-sortSizeAsc' : TT('Sort by Size (Smallest→Largest)'), + 'Plush-sortSizeDesc' : TT('Sort by Size (Largest→Smallest)'), + 'Plush-confirmPurgeQ' : TT('Purge the Queue?'), + 'Plush-purge' : TT('Purge'), + 'Plush-left' : TT('left'), + 'Plush-maxSpeed' : TT('Max Speed'), + 'Plush-nzo-range' : TT('Range'), + 'Plush-reset' : TT('Reset'), + 'Plush-applySelected' : TT('Apply to Selected'), + 'Plush-page' : TT('page'), + 'Plush-everything' : TT('Everything'), + 'Plush-disabled' : TT('Disabled'), + 'Plush-refreshRate' : TT('Refresh Rate'), + 'Plush-containerWidth' : TT('Container Width'), + 'Plush-confirmDeleteQueue' : TT('Confirm Queue Deletions'), + 'Plush-confirmDeleteHistory' : TT('Confirm History Deletions'), + 'Plush-explain-blockRefresh' : TT('This will prevent refreshing content when your mouse cursor is hovering over the queue.'), + 'Plush-blockRefresh' : TT('Block Refreshes on Hover'), + 'Plush-fetch' : TT('Fetch'), + 'Plush-uploadTip' : TT('Upload: .nzb .rar .zip .gz'), + 'Plush-addnzb-filename' : TT('Optionally specify a filename'), + 'Plush-progress' : TT('Progress'), + 'Plush-remaining' : TT('Remaining'), + 'Plush-notEnoughSpace' : TT('Not enough disk space to complete downloads!'), + 'Plush-freeSpace' : TT('Free Space'), + 'Plush-freeSpaceTemp' : TT('Free (Temp)'), + 'Plush-idle' : TT('IDLE'), + 'smpl-hourmin' : TT('Hour:Min'), + 'smpl-purgehist' : TT('Delete All'), + 'smpl-purgefailhistOK?' : TT('Delete the all failed items from the history?'), + 'smpl-purgefailhist' : TT('Delete Failed Items'), + 'smpl-links' : TT('Links'), + 'smpl-size' : TT('Size'), + 'smpl-path' : TT('Path'), + 'smpl-numresults@3' : TT('Showing %s to %s out of %s results'), + 'smpl-first' : TT('First'), + 'smpl-previous' : TT('Prev'), + 'smpl-next' : TT('Next'), + 'smpl-last' : TT('Last'), + 'smpl-pauseForPrompt' : TT('Pause for how many minutes?'), + 'smpl-paused' : TT('Paused'), + 'smpl-downloading' : TT('Downloading'), + 'smpl-idle' : TT('Idle'), + 'smpl-emailsent' : TT('Email Sent!'), + 'smpl-saving' : TT('Saving..'), + 'smpl-saved' : TT('Saved'), + 'smpl-failed' : TT('Failed'), + 'smpl-speed' : TT('Speed'), + 'smpl-toggleadd' : TT('Toggle Add NZB'), + 'smpl-dualView1' : TT('DualView1'), + 'smpl-dualView2' : TT('DualView2'), + 'smpl-warnings' : TT('Warnings'), + 'smpl-custom' : TT('Custom'), + 'smpl-getbookmarks' : TT('Get Bookmarks'), + 'smpl-restartOK?' : TT('Are you sure you want to restart SABnzbd?'), + 'smpl-refreshr' : TT('Refresh rate'), + 'smpl-purgeQueue' : TT('Delete All'), + 'smpl-hideEdit' : TT('Hide Edit Options'), + 'smpl-showEdit' : TT('Show Edit Options'), + 'smpl-eta' : TT('ETA'), + 'smpl-edit' : TT('Edit'), + 'smpl-progress' : TT('Progress'), + 'smpl-timeleft' : TT('Timeleft'), + 'smpl-age' : TT('Age'), + 'wizard-restarting' : TT('Restarting SABnzbd...'), + 'wizard-complete' : TT('Setup is now complete!'), + 'wizard-tip2' : TT('Closing any browser windows/tabs will NOT close SABnzbd.'), + 'wizard-tip3@1' : TT('After SABnzbd has finished restarting you will be able to access it at the following location%s'), + 'wizard-goto' : TT('Go to SABnzbd'), + 'wizard-index-explain' : TT('If you are a member of newzbin or nzbmatrix, you may enter your username and password here so we can fetch their nzb\'s. This stage can be skipped if you don\'t use either services.'), + 'wizard-optional' : TT('Optional'), + 'wizard-index-bookmark' : TT('Automatically download bookmarked posts.'), + 'wizard-previous' : TT('Previous'), + 'wizard-next' : TT('Next'), + 'wizard-skin' : TT('Skin'), + 'wizard-zoom' : TT('Zoom'), + 'wizard-server' : TT('Server Details'), + 'wizard-server-help' : TT('Help'), + 'wizard-server-help1' : TT('In order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.'), + 'wizard-server-help2@1' : TT('Don\'t have a usenet provider? We recommend trying %s.'), + 'wizard-example' : TT('E.g.'), + 'wizard-server-required' : TT('This field is required.'), + 'wizard-server-number' : TT('Please enter a whole number.'), + 'wizard-server-con-explain' : TT('The number of connections allowed by your provider'), + 'wizard-server-ssl-explain' : TT('Select only if your provider allows SSL connections.'), + 'wizard-button-testServer' : TT('Test Server'), + 'wizard-server-text' : TT('Click to test the entered details.'), + 'wizard-access' : TT('Access'), + 'wizard-access-anypc' : TT('I want SABnzbd to be viewable by any pc on my network.'), + 'wizard-access-mypc' : TT('I want SABnzbd to be viewable from my pc only.'), + 'wizard-access-pass' : TT('Password protect access to SABnzbd (recommended)'), + 'wizard-access-https' : TT('Enable HTTPS access to SABnzbd.'), + 'wizard-misc' : TT('Misc'), + 'wizard-misc-browser' : TT('Launch my internet browser with the SABnzbd page when the program starts.'), + + } diff --git a/sabnzbd/tvsort.py b/sabnzbd/tvsort.py index 54416f4..10ea290 100644 --- a/sabnzbd/tvsort.py +++ b/sabnzbd/tvsort.py @@ -32,7 +32,6 @@ from sabnzbd.misc import move_to_path, cleanup_empty_directories, \ from sabnzbd.constants import series_match, date_match, year_match, sample_match import sabnzbd.cfg as cfg from sabnzbd.encoding import titler -from sabnzbd.lang import Ta RE_SAMPLE = re.compile(sample_match, re.I) # Do not rename .vob files as they are usually DVD's @@ -275,7 +274,7 @@ class SeriesSorter(object): return True except: - logging.error(Ta('error-tvInfo@1'), self.original_dirname) + logging.error(Ta('Error getting TV info (%s)'), self.original_dirname) logging.info("Traceback: ", exc_info = True) return False @@ -616,7 +615,7 @@ class GenericSorter(object): logging.debug("Rename: %s to %s", filepath,newpath) renamer(filepath,newpath) except: - logging.error(Ta('error-tvRename@2'), filepath, newpath) + logging.error(Ta('Failed to rename: %s to %s'), filepath, newpath) logging.info("Traceback: ", exc_info = True) rename_similar(current_path, file, self.filename_set) @@ -638,7 +637,7 @@ class GenericSorter(object): logging.debug("Rename: %s to %s", filepath,newpath) renamer(filepath,newpath) except: - logging.error(Ta('error-tvRename@2'), filepath, newpath) + logging.error(Ta('Failed to rename: %s to %s'), filepath, newpath) logging.info("Traceback: ", exc_info = True) rename_similar(current_path, file, self.filename_set) else: @@ -816,7 +815,7 @@ class DateSorter(object): logging.debug("Rename: %s to %s", filepath,newpath) renamer(filepath,newpath) except: - logging.error(Ta('error-tvRename@2'), current_path, newpath) + logging.error(Ta('Failed to rename: %s to %s'), current_path, newpath) logging.info("Traceback: ", exc_info = True) rename_similar(current_path, file, self.filename_set) break @@ -1005,7 +1004,7 @@ def rename_similar(path, file, name): logging.debug("Rename: %s to %s", fpath,newpath) renamer(fpath,newpath) except: - logging.error(Ta('error-tvSimRename@2'), path, newpath) + logging.error(Ta('Failed to rename similar file: %s to %s'), path, newpath) logging.info("Traceback: ", exc_info = True) diff --git a/sabnzbd/urlgrabber.py b/sabnzbd/urlgrabber.py index 23a5794..85dcf7e 100644 --- a/sabnzbd/urlgrabber.py +++ b/sabnzbd/urlgrabber.py @@ -39,7 +39,6 @@ import sabnzbd.misc as misc import sabnzbd.dirscanner as dirscanner import sabnzbd.nzbqueue as nzbqueue import sabnzbd.cfg as cfg -from sabnzbd.lang import Ta #------------------------------------------------------------------------------ _RETRIES = 10 @@ -235,12 +234,12 @@ def _analyse_matrix(fn, matrix_id): return (None, msg, True) else: # Clear error message, don't retry - msg = Ta('warn-matrixFail@1') % data + msg = Ta('Problem accessing nzbmatrix server (%s)') % data return (None, msg, False) if data.startswith(" -# -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -""" -sabnzbd.utils.servertests - Debugging server connections. Currently only NNTP server tests are done. -""" - -import socket -import sys - -from sabnzbd.newswrapper import NewsWrapper -from sabnzbd.downloader import Server, clues_login, clues_too_many -from sabnzbd.config import get_servers -from sabnzbd.encoding import xml_name -from sabnzbd.interface import int_conv -from sabnzbd.lang import T - -def test_nntp_server_dict(kwargs): - # Grab the host/port/user/pass/connections/ssl - host = kwargs.get('host', '').strip() - if not host: - return False, T('srv-noHost') - username = kwargs.get('username', '').strip() - password = kwargs.get('password', '').strip() - connections = int_conv(kwargs.get('connections', 0)) - if not connections: - return False, T('srv-noConnections') - ssl = int_conv(kwargs.get('ssl', 0)) - port = int_conv(kwargs.get('port', 0)) - if not port: - if ssl: - port = 563 - else: - port = 119 - - - return test_nntp_server(host, port, username=username, \ - password=password, ssl=ssl) - - -def test_nntp_server(host, port, username=None, password=None, ssl=None): - ''' Will connect (blocking) to the nttp server and report back any errors ''' - timeout = 4.0 - if '*' in password and not password.strip('*'): - # If the password is masked, try retrieving it from the config - servers = get_servers() - got_pass = False - for server in servers: - if host in server: - srv = servers[server] - password = srv.password() - got_pass = True - if not got_pass: - return False, T('srv-starredPass') - try: - s = Server(-1, host, port, timeout, 1, 0, ssl, username, password) - except: - return False, T('srv-invalidDetails') - - try: - nw = NewsWrapper(s, -1, block=True) - nw.init_connect() - while not nw.connected: - nw.lines = [] - nw.recv_chunk(block=True) - nw.finish_connect('') - - except socket.timeout, e: - if port != 119 and not ssl: - return False, T('srv-timedoutSSL') - else: - return False, T('srv-timedout') - except socket.error, e: - return False, xml_name(str(e)) - - except: - return False, xml_name(str(sys.exc_info()[1])) - - - if not username or not password: - nw.nntp.sock.sendall('ARTICLE test\r\n') - try: - nw.lines = [] - nw.recv_chunk(block=True) - except: - return False, xml_name(str(sys.exc_info()[1])) - - # Could do with making a function for return codes to be used by downloader - code = nw.lines[0][:3] - - if code == '480': - return False, T('srv-noAuth') - - elif code == '100' or code.startswith('2') or code.startswith('4'): - return True, T('srv-success') - - elif code == '502' or clues_login(nw.lines[0]): - return False, T('srv-failedAuth') - - elif clues_too_many(nw.lines[0]): - return False, T('srv-tooManyConnections') - - else: - return False, T('srv-generalFail@1') % xml_name(nw.lines[0]) - - # Close the connection - nw.terminate(quit=True) +#!/usr/bin/python -OO +# Copyright 2008-2009 The SABnzbd-Team +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +""" +sabnzbd.utils.servertests - Debugging server connections. Currently only NNTP server tests are done. +""" + +import socket +import sys + +from sabnzbd.newswrapper import NewsWrapper +from sabnzbd.downloader import Server, clues_login, clues_too_many +from sabnzbd.config import get_servers +from sabnzbd.encoding import xml_name +from sabnzbd.misc import int_conv + +def test_nntp_server_dict(kwargs): + # Grab the host/port/user/pass/connections/ssl + host = kwargs.get('host', '').strip() + if not host: + return False, T('The hostname is not set.') + username = kwargs.get('username', '').strip() + password = kwargs.get('password', '').strip() + connections = int_conv(kwargs.get('connections', 0)) + if not connections: + return False, T('There are no connections set. Please set at least one connection.') + ssl = int_conv(kwargs.get('ssl', 0)) + port = int_conv(kwargs.get('port', 0)) + if not port: + if ssl: + port = 563 + else: + port = 119 + + + return test_nntp_server(host, port, username=username, \ + password=password, ssl=ssl) + + +def test_nntp_server(host, port, username=None, password=None, ssl=None): + ''' Will connect (blocking) to the nttp server and report back any errors ''' + timeout = 4.0 + if '*' in password and not password.strip('*'): + # If the password is masked, try retrieving it from the config + servers = get_servers() + got_pass = False + for server in servers: + if host in server: + srv = servers[server] + password = srv.password() + got_pass = True + if not got_pass: + return False, T('Password masked in ******, please re-enter') + try: + s = Server(-1, host, port, timeout, 1, 0, ssl, username, password) + except: + return False, T('Invalid server details') + + try: + nw = NewsWrapper(s, -1, block=True) + nw.init_connect() + while not nw.connected: + nw.lines = [] + nw.recv_chunk(block=True) + nw.finish_connect('') + + except socket.timeout, e: + if port != 119 and not ssl: + return False, T('Timed out: Try enabling SSL or connecting on a different port.') + else: + return False, T('Timed out') + except socket.error, e: + return False, xml_name(str(e)) + + except: + return False, xml_name(str(sys.exc_info()[1])) + + + if not username or not password: + nw.nntp.sock.sendall('ARTICLE test\r\n') + try: + nw.lines = [] + nw.recv_chunk(block=True) + except: + return False, xml_name(str(sys.exc_info()[1])) + + # Could do with making a function for return codes to be used by downloader + code = nw.lines[0][:3] + + if code == '480': + return False, T('Server requires username and password.') + + elif code == '100' or code.startswith('2') or code.startswith('4'): + return True, T('Connection Successful!') + + elif code == '502' or clues_login(nw.lines[0]): + return False, T('Authentication failed, check username/password.') + + elif clues_too_many(nw.lines[0]): + return False, T('Too many connections, please pause downloading or try again later') + + else: + return False, T('Could not determine connection result (%s)') % xml_name(nw.lines[0]) + + # Close the connection + nw.terminate(quit=True) diff --git a/sabnzbd/utils/upload.py b/sabnzbd/utils/upload.py index 1e561b6..8ca74c7 100644 --- a/sabnzbd/utils/upload.py +++ b/sabnzbd/utils/upload.py @@ -1,66 +1,66 @@ -#!/usr/bin/python -OO -# Copyright 2009 The SABnzbd-Team -# -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -""" -sabnzbd.utils.upload - File assosiation functions for adding nzb files to sabnzbd -""" - -import urllib2 -import urllib -import logging -import os -import sabnzbd.cfg as cfg -from sabnzbd.misc import get_ext, get_filename -from sabnzbd.dirscanner import ProcessArchiveFile, ProcessSingleFile - -def upload_file(url, fp): - """ Function for uploading nzbs to a running sabnzbd instance """ - try: - fp = urllib.quote_plus(fp) - pp = cfg.dirscan_pp() - script = cfg.dirscan_script() - priority = cfg.dirscan_priority() - url = '%sapi?mode=addlocalfile&name=%s&pp=%s&script=%s&priority=%s' % (url, fp, pp, script, priority) - username = cfg.username() - password = cfg.password() - apikey = cfg.api_key() - if username and password: - url = '%s&ma_username=%s&ma_password=%s' % (url, username, password) - if apikey: - url = '%s&apikey=%s' % (url, apikey) - u = urllib2.urlopen(url) - except: - logging.error("Failed to upload file: %s", fp) - logging.info("Traceback: ", exc_info = True) - - -def add_local(f): - """ Function for easily adding nzb/zip/rar/nzb.gz to sabnzbd """ - if os.path.exists(f): - fn = get_filename(f) - if fn: - pp = cfg.dirscan_pp() - script = cfg.dirscan_script() - priority = cfg.dirscan_priority() - if get_ext(fn) in ('.zip','.rar', '.gz'): - ProcessArchiveFile(fn, f, pp=pp, script=script, priority=priority, keep=True) - elif get_ext(fn) in ('.nzb'): - ProcessSingleFile(fn, f, pp=pp, script=script, priority=priority, keep=True) - else: - logging.error("Filename not found: %s", f) - else: +#!/usr/bin/python -OO +# Copyright 2009 The SABnzbd-Team +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +""" +sabnzbd.utils.upload - File assosiation functions for adding nzb files to sabnzbd +""" + +import urllib2 +import urllib +import logging +import os +import sabnzbd.cfg as cfg +from sabnzbd.misc import get_ext, get_filename +from sabnzbd.dirscanner import ProcessArchiveFile, ProcessSingleFile + +def upload_file(url, fp): + """ Function for uploading nzbs to a running sabnzbd instance """ + try: + fp = urllib.quote_plus(fp) + pp = cfg.dirscan_pp() + script = cfg.dirscan_script() + priority = cfg.dirscan_priority() + url = '%sapi?mode=addlocalfile&name=%s&pp=%s&script=%s&priority=%s' % (url, fp, pp, script, priority) + username = cfg.username() + password = cfg.password() + apikey = cfg.api_key() + if username and password: + url = '%s&ma_username=%s&ma_password=%s' % (url, username, password) + if apikey: + url = '%s&apikey=%s' % (url, apikey) + u = urllib2.urlopen(url) + except: + logging.error("Failed to upload file: %s", fp) + logging.info("Traceback: ", exc_info = True) + + +def add_local(f): + """ Function for easily adding nzb/zip/rar/nzb.gz to sabnzbd """ + if os.path.exists(f): + fn = get_filename(f) + if fn: + pp = cfg.dirscan_pp() + script = cfg.dirscan_script() + priority = cfg.dirscan_priority() + if get_ext(fn) in ('.zip','.rar', '.gz'): + ProcessArchiveFile(fn, f, pp=pp, script=script, priority=priority, keep=True) + elif get_ext(fn) in ('.nzb'): + ProcessSingleFile(fn, f, pp=pp, script=script, priority=priority, keep=True) + else: + logging.error("Filename not found: %s", f) + else: logging.error("File not found: %s", f) \ No newline at end of file diff --git a/sabnzbd/wizard.py b/sabnzbd/wizard.py index d5fe13f..566093c 100644 --- a/sabnzbd/wizard.py +++ b/sabnzbd/wizard.py @@ -25,7 +25,8 @@ from Cheetah.Template import Template import sabnzbd from sabnzbd.constants import * -from sabnzbd.lang import T, list_languages, reset_language +import sabnzbd.api +from sabnzbd.lang import list_languages, set_language from sabnzbd.utils.servertests import test_nntp_server_dict import sabnzbd.interface import sabnzbd.config as config @@ -49,7 +50,7 @@ class Wizard(object): info['num'] = '' info['number'] = 0 info['lang'] = cfg.language() - info['languages'] = list_languages(sabnzbd.DIR_LANGUAGE) + info['languages'] = list_languages() if not os.path.exists(self.__web_dir): # If the wizard folder does not exist, simply load the normal page @@ -66,9 +67,10 @@ class Wizard(object): if language and language != cfg.language(): cfg.language.set(language) reset_language(language) + sabnzbd.api.cache_skin_trans() info = self.info.copy() - info['num'] = '» %s' % T('wizard-step-one') + info['num'] = '» %s' % T('Step One') info['number'] = 1 info['skin'] = cfg.web_dir().lower() @@ -84,7 +86,7 @@ class Wizard(object): sabnzbd.interface.change_web_dir(kwargs['skin']) info = self.info.copy() - info['num'] = '» %s' % T('wizard-step-two') + info['num'] = '» %s' % T('Step Two') info['number'] = 2 host = cfg.cherryhost() @@ -122,7 +124,7 @@ class Wizard(object): if not cfg.username() or not cfg.password(): sabnzbd.interface.set_auth(cherrypy.config) info = self.info.copy() - info['num'] = '» %s' % T('wizard-step-three') + info['num'] = '» %s' % T('Step Three') info['number'] = 3 info['session'] = cfg.api_key() @@ -158,7 +160,7 @@ class Wizard(object): sabnzbd.interface.handle_server(kwargs) info = self.info.copy() - info['num'] = '» %s' % T('wizard-step-four') + info['num'] = '» %s' % T('Step Four') info['number'] = 4 info['newzbin_user'] = cfg.newzbin_username() info['newzbin_pass'] = cfg.newzbin_password.get_stars() @@ -184,7 +186,7 @@ class Wizard(object): config.save_config() info = self.info.copy() - info['num'] = '» %s' % T('wizard-step-five') + info['num'] = '» %s' % T('Step Five') info['number'] = 5 info['helpuri'] = 'http://wiki.sabnzbd.org/' info['session'] = cfg.api_key() diff --git a/tools/extract_pot.py b/tools/extract_pot.py new file mode 100644 index 0000000..c8af452 --- /dev/null +++ b/tools/extract_pot.py @@ -0,0 +1,143 @@ +#!/usr/bin/python -OO +# Copyright 2010 The SABnzbd-Team +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Extract translatable strings from all PY files + +import glob +import os +import sys +import re + +# Import version.py without the sabnzbd overhead +f = open('sabnzbd/version.py') +code = f.read() +f.close() +exec(code) + +# Fixed information for the POT header +HEADER = r'''# +# SABnzbd Translation Template file __TYPE__ +# Copyright (C) 2010 by the SABnzbd Team +# team@sabnzbd.org +# +msgid "" +msgstr "" +"Project-Id-Version: SABnzbd-%s\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: shypike@sabnzbd.org\n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ASCII\n" +"Content-Transfer-Encoding: 7bit\n" +''' % __version__ + +PO_DIR = 'po/main' +POE_DIR = 'po/email' +PON_DIR = 'po/nsis' +DOMAIN = 'SABnzbd' +DOMAIN_EMAIL = 'SABemail' +DOMAIN_NSIS = 'SABnsis' +PARMS = '-d %s -p %s -k T -k Ta -k TT -o %s.pot.tmp' % (DOMAIN, PO_DIR, DOMAIN) +FILES = 'SABnzbd.py SABHelper.py SABnzbdDelegate.py sabnzbd/*.py sabnzbd/utils/*.py' + +if not os.path.exists(PO_DIR): + os.makedirs(PO_DIR) + +# Determine location of PyGetText tool +path, exe = os.path.split(sys.executable) +if os.name == 'nt': + TOOL = os.path.join(path, r'Tools\i18n\pygettext.py') +else: + TOOL = os.path.join(path, 'pygettext.py') +if not os.path.exists(TOOL): + TOOL = 'pygettext.py' + + + +cmd = '%s %s %s' % (TOOL, PARMS, FILES) +print cmd +os.system(cmd) + +# Post-process the POT file +src = open('%s/%s.pot.tmp' % (PO_DIR, DOMAIN), 'r') +dst = open('%s/%s.pot' % (PO_DIR, DOMAIN), 'wb') +dst.write(HEADER.replace('__TYPE__', 'MAIN')) +header = True + +for line in src: + if line.startswith('#:'): + line = line.replace('\\', '/') + if header: + dst.write('\n\n') + header = False + if header: + if not ('"POT-Creation-Date:' in line or '"Generated-By:' in line): + continue + dst.write(line) + +src.close() +dst.close() +os.remove('%s/%s.pot.tmp' % (PO_DIR, DOMAIN)) + + +# Create the email POT file +if not os.path.exists(POE_DIR): + os.makedirs(POE_DIR) +dst = open(os.path.join(POE_DIR, DOMAIN_EMAIL+'.pot'), 'wb') +dst.write(HEADER.replace('__TYPE__', 'EMAIL')) + +src = open('language/email-en.tmpl', 'r') +dst.write('\n#: email/email.tmpl:1\n') +dst.write('msgid ""\n') +for line in src: + dst.write('"%s"\n' % line.replace('\n', '\\n').replace('"', '\\"')) +dst.write('msgstr ""\n\n') +src.close() + +src = open('language/rss-en.tmpl', 'r') +dst.write('#: email/rss.tmpl:1\n') +dst.write('msgid ""\n') +for line in src: + dst.write('"%s"\n' % line.replace('\n', '\\n').replace('"', '\\"')) +dst.write('msgstr ""\n\n') +src.close() + +dst.close() + + +# Create the NSIS POT file +NSIS= 'NSIS_Installer.nsi' +RE_NSIS = re.compile(r'LangString\s+\w+\s+\$\{LANG_ENGLISH\}\s+(".*)', re.I) + +print 'Creating the NSIS POT file' +if not os.path.exists(PON_DIR): + os.makedirs(PON_DIR) +src = open(NSIS, 'r') +dst = open(os.path.join(PON_DIR, DOMAIN_NSIS+'.pot'), 'w') +dst.write(HEADER.replace('__TYPE__', 'NSIS')) +dst.write('\n') +count = 0 +for line in src: + count += 1 + m = RE_NSIS.search(line) + if m: + dst.write('#: %s:%s\n' % (NSIS, count)) + text = m.group(1).replace('$\\"', '\\"').replace('$\\', '\\') + dst.write('msgid %s\n' % text) + dst.write('msgstr ""\n\n') +dst.close() +src.close() diff --git a/tools/make_mo.py b/tools/make_mo.py new file mode 100644 index 0000000..b2704b9 --- /dev/null +++ b/tools/make_mo.py @@ -0,0 +1,183 @@ +#!/usr/bin/python -OO +# Copyright 2010 The SABnzbd-Team +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Compile PO files to MO files + +import glob +import os +import re +import sys +import gettext + +PO_DIR = 'po/main' +POE_DIR = 'po/email' +PON_DIR = 'po/nsis' +MO_DIR = 'locale' +EMAIL_DIR = 'email' + +MO_LOCALE = '/LC_MESSAGES' +DOMAIN = 'SABnzbd' +DOMAIN_E = 'SABemail' +DOMAIN_N = 'SABnsis' +LANG_MARKER = 'language.txt' +NSIS= 'NSIS_Installer.nsi' + +LNG_TABLE = { # NSIS requires full English names for the languages + 'da' : 'DANISH', + 'de' : 'GERMAN', + 'fr' : 'FRENCH', + 'nl' : 'DUTCH', + 'no' : 'NORSE', + 'sv' : 'SWEDISH', + 'en' : '' +} + +# Determine location of PyGetText tool +path, exe = os.path.split(sys.executable) +if os.name == 'nt': + TOOL = os.path.join(path, r'Tools\i18n\msgfmt.py') +else: + TOOL = os.path.join(path, 'msgfmt.py') +if not os.path.exists(TOOL): + TOOL = 'msgfmt.py' + + +# Filter for retrieving readable language from PO file +RE_LANG = re.compile(r'"Language-Description:\s([^"]+)\\n') + +def process_po_folder(domain, folder): + """ Process each PO file in folder + """ + for fname in glob.glob(os.path.join(folder, '*.po')): + podir, basename = os.path.split(fname) + name, ext = os.path.splitext(basename) + mo_path = os.path.normpath('%s/%s%s' % (MO_DIR, name, MO_LOCALE)) + mo_name = '%s.mo' % domain + if not os.path.exists(mo_path): + os.makedirs(mo_path) + + # Create the MO file + mo_file = os.path.join(mo_path, mo_name) + print 'Compile %s' % mo_file + os.system('%s -o %s %s' % (TOOL, mo_file, fname)) + + # Determine language's pretty name + language = '' + fp = open(fname, 'r') + for line in fp: + m = RE_LANG.search(line) + if m: + language = m.group(1) + break + fp.close() + + # Create the readable name file + if language: + mo_file = os.path.join(mo_path, LANG_MARKER) + fp = open(mo_file, 'wb') + fp.write('%s\n' % language) + fp.close() + + +def make_templates(): + """ Create email templates + """ + if not os.path.exists('email'): + os.makedirs('email') + for path in glob.glob(os.path.join(MO_DIR, '*')): + lng = os.path.split(path)[1] + print 'Create email template for %s' % lng + trans = gettext.translation(DOMAIN_E, MO_DIR, [lng], fallback=False, codeset='latin-1') + # The unicode flag will make _() return Unicode + trans.install(unicode=True, names=['lgettext']) + + src = open(EMAIL_DIR + '/email-en.tmpl', 'r') + data = src.read().decode('utf-8') + src.close() + data = _(data).encode('utf-8') + fp = open('email/email-%s.tmpl' % lng, 'wb') + fp.write(data) + fp.close() + + src = open(EMAIL_DIR + '/rss-en.tmpl', 'r') + data = src.read().decode('utf-8') + src.close() + data = _(data).encode('utf-8') + fp = open('email/rss-%s.tmpl' % lng, 'wb') + fp.write(data) + fp.close() + mo_path = os.path.normpath('%s/%s%s/%s.mo' % (MO_DIR, path, MO_LOCALE, DOMAIN_E)) + if os.path.exists(mo_path): + os.remove(mo_path) + + +def patch_nsis(): + """ Patch translation into the NSIS script + """ + RE_NSIS = re.compile(r'^(\s*LangString\s+\w+\s+\$\{LANG_)(\w+)\}\s+(".*)', re.I) + languages = [os.path.split(path)[1] for path in glob.glob(os.path.join(MO_DIR, '*'))] + + src = open(NSIS, 'r') + new = [] + for line in src: + m = RE_NSIS.search(line) + if m: + leader = m.group(1) + langname = m.group(2).upper() + text = m.group(3).strip('"\n') + if langname == 'ENGLISH': + # Write back old content + new.append(line) + # Replace silly $\ construction with just a \ + text = text.replace('$\\"', '"').replace('$\\', '\\') + for lcode in languages: + lng = LNG_TABLE.get(lcode) + if lng: + trans = gettext.translation(DOMAIN_N, MO_DIR, [lcode], fallback=False, codeset='latin-1') + # The unicode flag will make _() return Unicode + trans.install(unicode=True, names=['lgettext']) + trans = lgettext(text) + trans = trans.replace('\\', '$\\').replace('"', '$\\"') + line = '%s%s "%s"\n' % (leader, lng, trans) + new.append(line) + elif lng is None: + print 'Warning: unsupported language %s, add to table in this script' % langname + else: + new.append(line) + src.close() + + dst = open(NSIS, 'w') + for line in new: + dst.write(line) + dst.close() + + +print 'Email MO files' +process_po_folder(DOMAIN_E, POE_DIR) + +print 'NSIS MO file' +process_po_folder(DOMAIN_N, PON_DIR) + +print 'Main program MO files' +process_po_folder(DOMAIN, PO_DIR) + +print "Create email templates from MO files" +make_templates() + +print "Patch NSIS script" +patch_nsis() +