From 1e7579ac0859f8bf52bc3cf18b56efc7c73094d2 Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Sun, 21 Mar 2021 18:47:58 -0500 Subject: [PATCH] Localization support --- Makefile | 28 +++++++++---------- README.md | 1 + TODO.txt | 4 --- locales/en.catkeys | 61 ++++++++++++++++++++++++++++++++++++++++++ locales/eo.catkeys | 61 ++++++++++++++++++++++++++++++++++++++++++ src/App.cpp | 2 -- src/AtomFeed.cpp | 20 +++++++++++--- src/EntriesView.cpp | 55 ++++++++++++++++++++----------------- src/FeedController.cpp | 7 ++++- src/FeedEditWindow.cpp | 33 ++++++++++++++--------- src/FeedListItem.cpp | 7 ++++- src/FeedsView.cpp | 14 +++++++--- src/MainWindow.cpp | 21 ++++++++------- src/Notifier.cpp | 56 ++++++++++++++++++++++++++------------ src/Preferences.cpp | 29 +++++++++++--------- src/RssFeed.cpp | 20 +++++++++++--- src/UpdatesView.cpp | 40 +++++++++++++++++++-------- 17 files changed, 341 insertions(+), 118 deletions(-) create mode 100644 locales/en.catkeys create mode 100644 locales/eo.catkeys diff --git a/Makefile b/Makefile index c7aa462..aecf982 100644 --- a/Makefile +++ b/Makefile @@ -29,21 +29,21 @@ APP_MIME_SIG = application/x-vnd.Pogger # same name (source.c or source.cpp) are included from different directories. # Also note that spaces in folder names do not work well with this Makefile. SRCS = \ - src/App.cpp, \ - src/AtomFeed.cpp, \ - src/Entry.cpp, \ - src/EntriesView.cpp, \ - src/Feed.cpp, \ + src/App.cpp \ + src/AtomFeed.cpp \ + src/Entry.cpp \ + src/EntriesView.cpp \ + src/Feed.cpp \ src/FeedController.cpp \ src/FeedEditWindow.cpp \ src/FeedListItem.cpp \ - src/FeedsView.cpp, \ - src/MainWindow.cpp, \ - src/Mimetypes.cpp, \ - src/Notifier.cpp, \ - src/Preferences.cpp, \ - src/RssFeed.cpp, \ - src/UpdatesView.cpp, \ + src/FeedsView.cpp \ + src/MainWindow.cpp \ + src/Mimetypes.cpp \ + src/Notifier.cpp \ + src/Preferences.cpp \ + src/RssFeed.cpp \ + src/UpdatesView.cpp \ src/Util.cpp # Specify the resource definition files to use. Full or relative paths can be @@ -80,7 +80,7 @@ RSRCS = \ # - if your library does not follow the standard library naming scheme, # you need to specify the path to the library and it's name. # (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a") -LIBS = be tracker bnetapi network netservices shared tinyxml2 $(STDCPPLIBS) +LIBS = be bnetapi localestub network netservices shared tinyxml2 tracker $(STDCPPLIBS) # Specify additional paths to directories following the standard libXXX.so # or libXXX.a naming scheme. You can specify full paths or paths relative @@ -111,7 +111,7 @@ OPTIMIZE := FULL # will recreate only the "locales/en.catkeys" file. Use it as a template # for creating catkeys for other languages. All localization files must be # placed in the "locales" subdirectory. -LOCALES = en +LOCALES = en eo # Specify all the preprocessor symbols to be defined. The symbols will not # have their values set automatically; you must supply the value (if any) to diff --git a/README.md b/README.md index 372c4cb..560cc47 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ In "Updates" you can toggle notifications and set the frequency of updates. ## Building `$ make` +`$ make bindcatalogs` Uses netservices, and has TinyXML2 as a dependency. diff --git a/TODO.txt b/TODO.txt index 250fec3..13bf64f 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,7 +1,3 @@ -Important Features: -* Localization - -Improvements: * Memory leaks * ~.05MB per feed on download, in Util.ccp, fetch(). I'm stumped here. * ~.02MB per feed on parsing diff --git a/locales/en.catkeys b/locales/en.catkeys new file mode 100644 index 0000000..f5b6fb1 --- /dev/null +++ b/locales/en.catkeys @@ -0,0 +1,61 @@ +1 English application/x-vnd.Pogger 1418478689 +Updates MainWindow Updates +Edit… FeedsView Edit… +Invalid Feed FeedEditWindow Invalid Feed +Never automatically update UpdatesView Never automatically update +Entries Directory EntriesView Entries Directory +{0, plural,=1{Failed to update %source% and one other.}other{Failed to update %source% and # others.}} Notifier {0, plural,=1{Failed to update %source% and one other.}other{Failed to update %source% and # others.}} +Browse… EntriesView Browse… +Entries MainWindow Entries +Feeds MainWindow Feeds +Feed name: FeedEditWindow Feed name: +Update Now MainWindow Update Now +There is not enough memory available on your system to load the preferences file.\nPlease try closing a few applications and restarting Pogger. Preferences There is not enough memory available on your system to load the preferences file.\nPlease try closing a few applications and restarting Pogger. +Select… EntriesView Select… +Scheduling UpdatesView Scheduling +{0, plural,=1{%n% new entries from %source% and one other.}other{%n% new entries from %source% and # others.}} Notifier {0, plural,=1{%n% new entries from %source% and one other.}other{%n% new entries from %source% and # others.}} +Open as: EntriesView Open as: +Couldn't open the preferences file because permission was denied.\nThis usually means that you don't have read permissions to your settings directory.\nPlease make sure that your user has read-access to your settings directory― likely %path%.\nCheck your OS documentation for more information. Preferences Couldn't open the preferences file because permission was denied.\nThis usually means that you don't have read permissions to your settings directory.\nPlease make sure that your user has read-access to your settings directory― likely %path%.\nCheck your OS documentation for more information. +Pogger System name Pogger +Update every 30 minutes UpdatesView Update every 30 minutes +Channel '%source%' at %url%:\n RssFeed Channel '%source%' at %url%:\n +Notify about new entries UpdatesView Notify about new entries +{0, plural,=1{Update every hour}other{Update every # hours}} UpdatesView {0, plural,=1{Update every hour}other{Update every # hours}} +OK EntriesView OK +Couldn't open this folder because no path was specified.\nPlease select a new folder. EntriesView Couldn't open this folder because no path was specified.\nPlease select a new folder. +Cancel MainWindow Cancel +Saving EntriesView Saving +Couldn't open the preferences file because the path is not specified.\nThis usually means that the programmer made a mistake.\nPlease submit a bug report to the Pogger repository on GitHub.\nYour personal settings will not be loaded. Preferences Couldn't open the preferences file because the path is not specified.\nThis usually means that the programmer made a mistake.\nPlease submit a bug report to the Pogger repository on GitHub.\nYour personal settings will not be loaded. +\t-%count% entries-\n RssFeed \t-%count% entries-\n +Update daily UpdatesView Update daily +HTML EntriesView HTML +Feed Updates Notifier Feed Updates +Notify about update failures UpdatesView Notify about update failures +Update Failure Notifier Update Failure +The path you selected isn't a folder― please choose another path. EntriesView The path you selected isn't a folder― please choose another path. +Untitled Feed Notifier Untitled Feed +24 hours UpdatesView 24 hours +There is not enough memory available on your system to access the given path.\nPlease try closing a few applications and restarting Pogger. EntriesView There is not enough memory available on your system to access the given path.\nPlease try closing a few applications and restarting Pogger. +Untitled Feed FeedListItem Untitled Feed +Never UpdatesView Never +Feed URL: FeedEditWindow Feed URL: +New Feed FeedEditWindow New Feed +Channel '%source%' at %url%:\n AtomFeed Channel '%source%' at %url%:\n +Downloading feed from FeedController Downloading feed from +URL EntriesView URL +Please enter a URL. FeedEditWindow Please enter a URL. +OK FeedEditWindow OK +Preferences file Preferences Preferences file +Notifications UpdatesView Notifications +Save FeedEditWindow Save +Failed to update %source%. Notifier Failed to update %source%. +Fetching %source%… FeedsView Fetching %source%… +{0, plural,=1{One new entry from %source%.}other{# new entries from %source%.}} Notifier {0, plural,=1{One new entry from %source%.}other{# new entries from %source%.}} +Edit Feed FeedEditWindow Edit Feed +Opening EntriesView Opening +The given URL is invalid. Please make sure you typed it in correctly. FeedEditWindow The given URL is invalid. Please make sure you typed it in correctly. +Delete FeedEditWindow Delete +Entry folder: EntriesView Entry folder: +\t-%count% entries-\n AtomFeed \t-%count% entries-\n +Couldn't open this folder because permission was denied.\nThis usually means that you don't have read permissions.\nPlease make sure that your user has read-access to this folder.\nCheck your OS documentation for more information. EntriesView Couldn't open this folder because permission was denied.\nThis usually means that you don't have read permissions.\nPlease make sure that your user has read-access to this folder.\nCheck your OS documentation for more information. +Open with: EntriesView Open with: diff --git a/locales/eo.catkeys b/locales/eo.catkeys new file mode 100644 index 0000000..ca945ad --- /dev/null +++ b/locales/eo.catkeys @@ -0,0 +1,61 @@ +1 Esperanto application/x-vnd.Pogger 1418478689 +Updates MainWindow Ĝisdatigoj +Edit… FeedsView Redakti… +Invalid Feed FeedEditWindow Malvalida Fonto +Never automatically update UpdatesView Neniam ĝisdatigas aŭtomate +Entries Directory EntriesView Dosierujo de Afiŝoj +{0, plural,=1{Failed to update %source% and one other.}other{Failed to update %source% and # others.}} Notifier {0, plural,=1{Eraris ĝisdatigante %source% k alian.}other{Eraris ĝisdatigante %source% kaj # aliaj.}} +Browse… EntriesView Foliumi… +Entries MainWindow Afiŝoj +Feeds MainWindow Fontoj +Feed name: FeedEditWindow Fontonomo: +Update Now MainWindow Ĝisdatigi +There is not enough memory available on your system to load the preferences file.\nPlease try closing a few applications and restarting Pogger. Preferences Restas nesufiĉa kvanto de memoro je via sistmo, por ŝalti la agordan dosieron.\nBonvole provu malfermi kelkajn programojn, kaj poste restartigi Pogger. +Select… EntriesView Elekti… +Scheduling UpdatesView Tempoplano +{0, plural,=1{%n% new entries from %source% and one other.}other{%n% new entries from %source% and # others.}} Notifier {0, plural,=1{%n% novaj afiŝoj de %source% kaj alia.}other{%n% novaj afiŝoj de %source% kaj # aliaj.}} +Open as: EntriesView Malfermi kiel: +Couldn't open the preferences file because permission was denied.\nThis usually means that you don't have read permissions to your settings directory.\nPlease make sure that your user has read-access to your settings directory― likely %path%.\nCheck your OS documentation for more information. Preferences Neeblis malfermi la agordan dosieron, ĉar mankas permeso.\nTio probable signifas ke vi ne rajtas legi vian agordan dosierujon.\nBonvole certigi, ke via uzanto rajtas legi la agordan dosieron― probable %path%.\nReferenci vian funkcisisteman helpolibron, por lerni pli. +Pogger System name Pogger +Update every 30 minutes UpdatesView Ĝisdatigas duonhore +Channel '%source%' at %url%:\n RssFeed Fonoto '%source%' ĉe %url%:\n +Notify about new entries UpdatesView Sciigi pri novaj afiŝoj +{0, plural,=1{Update every hour}other{Update every # hours}} UpdatesView {0, plural,=1{Ĝisdatigas hore}other{Ĝisdatigas po # horoj}} +OK EntriesView Bone +Couldn't open this folder because no path was specified.\nPlease select a new folder. EntriesView Neeblis malfermi ĉi tiun dosierujon, ĉar la loko estas nedifinita.\nBonvole elektu novan dosierujon. +Cancel MainWindow Nuligi +Saving EntriesView Konservado +Couldn't open the preferences file because the path is not specified.\nThis usually means that the programmer made a mistake.\nPlease submit a bug report to the Pogger repository on GitHub.\nYour personal settings will not be loaded. Preferences Neeblis malfermi agordan dosieron ĉar la loko estas nedifinita.\nProbable tio signifas, ke la programisto eraris iel.\nBonvole raporti la problemon al la Pogger deponojo ĉe Github.\nViaj propraj agordoj ne ŝaltiĝos. Bedaŭron. +\t-%count% entries-\n RssFeed \t-%count% afiŝoj-\n +Update daily UpdatesView Ĝisdatigas tage +HTML EntriesView HTML +Feed Updates Notifier Fonto Ĝisdatigoj +Notify about update failures UpdatesView Sciigi pri eraroj ĝisdatigaj +Update Failure Notifier Eraris Ĝisdatigante +The path you selected isn't a folder― please choose another path. EntriesView La loko kiun vi elektis ne estas dosierujo― bonvole, elektu alian lokon. +Untitled Feed Notifier Sennoma Fonto +24 hours UpdatesView 24 horoj +There is not enough memory available on your system to access the given path.\nPlease try closing a few applications and restarting Pogger. EntriesView Restas nesufiĉa kvanto de memoro je via sistmo, por aliri tiun lokon.\nBonvole provu malfermi kelkajn programojn, kaj poste restartigi Pogger. +Untitled Feed FeedListItem Sennoma Fonto +Never UpdatesView Neniam +Feed URL: FeedEditWindow Fonto URL: +New Feed FeedEditWindow Nova Fonto +Channel '%source%' at %url%:\n AtomFeed Fonto '%source%' ĉe %url%:\n +Downloading feed from FeedController Elŝultante fonton de +Please enter a URL. FeedEditWindow Bonvole enigu URL-on. +URL EntriesView URL +OK FeedEditWindow Bone +Preferences file Preferences Agorda dosiero +Notifications UpdatesView Sciigoj +Save FeedEditWindow Konservi +Failed to update %source%. Notifier Eraris ĝisdatigante %source%. +Fetching %source%… FeedsView Elŝultante %source%… +{0, plural,=1{One new entry from %source%.}other{# new entries from %source%.}} Notifier {0, plural,=1{Nova afiŝo de %source%.}other{# novaj afiŝoj de %source%.}} +Edit Feed FeedEditWindow Redakti Fonton +Opening EntriesView Malfermado +The given URL is invalid. Please make sure you typed it in correctly. FeedEditWindow La enigita URL nevalidas. Bonvole, certigu ke vi ĝin ĝuste tajpis. +Delete FeedEditWindow Forigi +Entry folder: EntriesView Afiŝa dosierujo: +\t-%count% entries-\n AtomFeed \t-%count% afiŝoj-\n +Couldn't open this folder because permission was denied.\nThis usually means that you don't have read permissions.\nPlease make sure that your user has read-access to this folder.\nCheck your OS documentation for more information. EntriesView Neeblis malfermi la tiun dosierujon, ĉar mankas permeso.\nTio probable signifas ke vi ne rajtas legi ĝin.\n\nBonvole certigi, ke via uzanto rajtas legi ĝin.\nReferenci vian funkcisisteman helpolibron, por lerni pli. +Open with: EntriesView Malfermi per: diff --git a/src/App.cpp b/src/App.cpp index a64916b..2b153af 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -5,8 +5,6 @@ #include "App.h" -#include - #include #include #include diff --git a/src/AtomFeed.cpp b/src/AtomFeed.cpp index c1ca0b6..b14edd7 100644 --- a/src/AtomFeed.cpp +++ b/src/AtomFeed.cpp @@ -7,6 +7,8 @@ #include +#include + #include #include "App.h" @@ -14,6 +16,10 @@ #include "Util.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "AtomFeed" + + AtomFeed::AtomFeed() { fTitle = BString(""); @@ -65,8 +71,11 @@ AtomFeed::RootParse(tinyxml2::XMLElement* xfeed) if (!set && xentry) set = _SetDate(xentry->FirstChildElement("published")); - std::cout << "Channel '" << fTitle << "' at '" << fXmlUrl.UrlString() - << "':\n"; + BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n")); + logString.ReplaceAll("%source%", fTitle.String()); + logString.ReplaceAll("%url%", fXmlUrl.UrlString()); + + std::cout << logString.String(); } @@ -117,7 +126,12 @@ AtomFeed::ParseEntries(tinyxml2::XMLElement* xfeed) int entryCount = _XmlCountSiblings(xentry, "entry"); fEntries = BObjectList(entryCount, true); - std::cout << "\t-" << entryCount << "-\n"; + BString logString(B_TRANSLATE("\t-%count% entries-\n")); + BString entryStr; + entryStr << entryCount; + logString.ReplaceAll("%count%", entryStr); + + std::cout << logString.String(); while (xentry) { EntryParse(xentry); diff --git a/src/EntriesView.cpp b/src/EntriesView.cpp index 8dfcbd6..625e41a 100644 --- a/src/EntriesView.cpp +++ b/src/EntriesView.cpp @@ -5,11 +5,10 @@ #include "EntriesView.h" -#include - #include #include #include +#include #include #include #include @@ -22,6 +21,10 @@ #include "Util.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "EntriesView" + + EntriesView::EntriesView(const char* name) : BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING) @@ -138,29 +141,31 @@ EntriesView::_InitInterface() { // Saving fSavingBox = new BBox("saving"); - fSavingBox->SetLabel("Saving"); + fSavingBox->SetLabel(B_TRANSLATE("Saving")); - fEntryFolderLabel = new BStringView("entryFolderLabel", "Entry folder:"); + fEntryFolderLabel = new BStringView("entryFolderLabel", + B_TRANSLATE("Entry folder:")); fEntryFolderText = new BTextControl("entryFolder", "", "", new BMessage(kEntryFolderText)); - fEntryFolderBrowseButton = new BButton("entryFolderBrowse", "Browse…", - new BMessage(kEntryFolderBrowse)); + fEntryFolderBrowseButton = new BButton("entryFolderBrowse", + B_TRANSLATE("Browse…"), new BMessage(kEntryFolderBrowse)); // Opening fOpeningBox = new BBox("opening"); - fOpeningBox->SetLabel("Opening"); + fOpeningBox->SetLabel(B_TRANSLATE("Opening")); - fOpenAsLabel = new BStringView("openAsLabel", "Open as:"); - fOpenAsHtmlRadio = new BRadioButton("asHtml", "HTML", + fOpenAsLabel = new BStringView("openAsLabel", B_TRANSLATE("Open as:")); + fOpenAsHtmlRadio = new BRadioButton("asHtml", B_TRANSLATE("HTML"), new BMessage(kOpenHtmlRadio)); - fOpenAsUrlRadio = new BRadioButton("asUrl", "URL", + fOpenAsUrlRadio = new BRadioButton("asUrl", B_TRANSLATE("URL"), new BMessage(kOpenUrlRadio)); - fOpenWithLabel = new BStringView("openWithLabel", "Open with:"); + fOpenWithLabel = new BStringView("openWithLabel", + B_TRANSLATE("Open with:")); fOpenWithMenu = new BPopUpMenu("openWith"); fOpenWithMenuField = new BMenuField("openWithMenu", NULL, fOpenWithMenu); - fOpenWithSelectButton = new BButton("openWithSelect", "Select…", - new BMessage(kOpenWithBrowse)); + fOpenWithSelectButton = new BButton("openWithSelect", + B_TRANSLATE("Select…"), new BMessage(kOpenWithBrowse)); // Display current settings @@ -251,22 +256,24 @@ EntriesView::_FileError(status_t result) find_directory(B_USER_SETTINGS_DIRECTORY, &cfgPath); if (result == B_NOT_A_DIRECTORY) { - BAlert* alert = new BAlert("Entries Directory", "The path you " - "selected isn't a folder― please choose another path.", "OK", - NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); - alert->Go(); + BAlert* alert = new BAlert(B_TRANSLATE("Entries Directory"), + B_TRANSLATE("The path you selected isn't a folder― please choose " + "another path."), B_TRANSLATE("OK"), NULL, NULL, + B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->Go(); return; } - userFileError(result, "Entries Directory", - "Couldn't open this folder because no path was specified.\n" - "Please select a new folder.", - "Couldn't open this folder because permission was denied.\n" + userFileError(result, B_TRANSLATE("Entries Directory"), + B_TRANSLATE("Couldn't open this folder because no path was specified.\n" + "Please select a new folder."), + B_TRANSLATE("Couldn't open this folder because permission was denied.\n" "This usually means that you don't have read permissions.\nPlease make " "sure that your user has read-access to this folder.\nCheck your OS " - "documentation for more information.", - "There is not enough memory available on your system to access the " - "given path.\nPlease try closing a few applications and restarting Pogger."); + "documentation for more information."), + B_TRANSLATE("There is not enough memory available on your system to " + "access the given path.\nPlease try closing a few applications and " + "restarting Pogger.")); } diff --git a/src/FeedController.cpp b/src/FeedController.cpp index abe05c9..a336ea7 100644 --- a/src/FeedController.cpp +++ b/src/FeedController.cpp @@ -7,6 +7,7 @@ #include +#include #include #include #include @@ -19,6 +20,10 @@ #include "RssFeed.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "FeedController" + + FeedController::FeedController() : fEnqueuedTotal(0), @@ -222,7 +227,7 @@ FeedController::_DownloadLoop(void* data) Feed* feedBuffer = (Feed*)malloc(sizeof(Feed)); receive_data(&sender, (void*)feedBuffer, sizeof(Feed)); - std::cout << "Downloading feed from " + std::cout << B_TRANSLATE("Downloading feed from ") << feedBuffer->XmlUrl().UrlString() << "…\n"; if (feedBuffer->Fetch()) { diff --git a/src/FeedEditWindow.cpp b/src/FeedEditWindow.cpp index 4127672..693e1ea 100644 --- a/src/FeedEditWindow.cpp +++ b/src/FeedEditWindow.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -20,10 +21,15 @@ #include "Util.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "FeedEditWindow" + + FeedEditWindow::FeedEditWindow() : - BWindow(((App*)be_app)->fPreferences->fFeedEditRect, "New Feed", - B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) + BWindow(((App*)be_app)->fPreferences->fFeedEditRect, + B_TRANSLATE("New Feed"), B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE) { _InitInterface(); MoveOnScreen(); @@ -37,7 +43,7 @@ FeedEditWindow::FeedEditWindow(BEntry feedEntry) : FeedEditWindow() { - SetTitle("Edit Feed"); + SetTitle(B_TRANSLATE("Edit Feed")); fFeed = Feed(feedEntry); fFeedNameText->SetText(fFeed.Title().String()); @@ -83,15 +89,15 @@ void FeedEditWindow::_InitInterface() { // Name and URL - fFeedNameLabel = new BStringView("feedNameLabel", "Feed name:"); + fFeedNameLabel = new BStringView("feedNameLabel", B_TRANSLATE("Feed name:")); fFeedNameText = new BTextControl("feedName", "", "", NULL); - fFeedUrlLabel = new BStringView("feedUrlLabel", "Feed URL:"); + fFeedUrlLabel = new BStringView("feedUrlLabel", B_TRANSLATE("Feed URL:")); fFeedUrlText = new BTextControl("feedUrl", "", "", NULL); // Save/Delete - fSaveButton = new BButton("save", "Save", + fSaveButton = new BButton("save", B_TRANSLATE("Save"), new BMessage(kSaveButton)); - fDeleteButton = new BButton("delete", "Delete", + fDeleteButton = new BButton("delete", B_TRANSLATE("Delete"), new BMessage(kDeleteButton)); BLayoutBuilder::Group<>(this, B_VERTICAL, 0) @@ -147,17 +153,18 @@ FeedEditWindow::_SaveFeed() BUrl url = BUrl(urlString); if (BString(urlString).IsEmpty() == true) { - BAlert* emptyAlert = new BAlert("Invalid Feed", - "Please enter a URL.", "OK", NULL, NULL, - B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + BAlert* emptyAlert = new BAlert(B_TRANSLATE("Invalid Feed"), + B_TRANSLATE("Please enter a URL."), B_TRANSLATE("OK"), NULL, NULL, + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); emptyAlert->Go(); return; } if (url.IsValid() == false) { - BAlert* invAlert = new BAlert("Invalid Feed", - "The given URL is invalid. Please make sure you typed it in correctly.", - "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + BAlert* invAlert = new BAlert(B_TRANSLATE("Invalid Feed"), + B_TRANSLATE("The given URL is invalid. Please make sure you typed " + "it in correctly."), B_TRANSLATE("OK"), NULL, NULL, + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); invAlert->Go(); return; } diff --git a/src/FeedListItem.cpp b/src/FeedListItem.cpp index 3740d2c..28ee1a4 100644 --- a/src/FeedListItem.cpp +++ b/src/FeedListItem.cpp @@ -5,12 +5,17 @@ #include "FeedListItem.h" +#include #include #include "Feed.h" #include "Util.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "FeedListItem" + + FeedListItem::FeedListItem(Feed* feed) : BStringItem(feed->Title().String(), 0, false), @@ -19,7 +24,7 @@ FeedListItem::FeedListItem(Feed* feed) fFeedPath(feed->CachePath()) { if (feed->Title().IsEmpty() == true) - SetText("Untitled Feed"); + SetText(B_TRANSLATE("Untitled Feed")); } diff --git a/src/FeedsView.cpp b/src/FeedsView.cpp index ba790e2..476112d 100644 --- a/src/FeedsView.cpp +++ b/src/FeedsView.cpp @@ -5,6 +5,7 @@ #include "FeedsView.h" +#include #include #include #include @@ -22,6 +23,10 @@ #include "Notifier.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "FeedsView" + + FeedsView::FeedsView(const char* name) : BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING) @@ -121,7 +126,8 @@ FeedsView::_InitInterface() // Add, Remove, Edit fAddButton = new BButton("addFeed", "+", new BMessage(kFeedsAddButton)); fRemoveButton = new BButton("removeFeed", "-", new BMessage(kFeedsRemoveButton)); - fEditButton = new BButton("editFeed", "Edit…", new BMessage(kFeedsEditButton)); + fEditButton = new BButton("editFeed", B_TRANSLATE("Edit…"), + new BMessage(kFeedsEditButton)); font_height fontHeight; GetFontHeight(&fontHeight); @@ -224,12 +230,12 @@ FeedsView::_UpdateProgress(BMessage* msg, int8 status) BString feedName, feedUrl; if (msg->FindString("feed_url", &feedUrl) != B_OK) return; - if (msg->FindString("feed_name", &feedName) != B_OK) + if (msg->FindString("feed_name", &feedName) != B_OK || feedName.IsEmpty()) feedName = feedUrl; if (status == kDownloadingStatus) { - BString label("Fetching "); - label << feedName << "…"; + BString label(B_TRANSLATE("Fetching %source%…")); + label.ReplaceAll("%source%", feedName); fProgressLabel->SetText(label); } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 6422f13..216b494 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -5,9 +5,8 @@ #include "MainWindow.h" -#include - #include +#include #include #include #include @@ -23,10 +22,14 @@ #include "UpdatesView.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "MainWindow" + + MainWindow::MainWindow() : - BWindow(((App*)be_app)->fPreferences->fMainWindowRect, "Pogger", - B_TITLED_WINDOW, NULL) + BWindow(((App*)be_app)->fPreferences->fMainWindowRect, + B_TRANSLATE_SYSTEM_NAME("Pogger"), B_TITLED_WINDOW, 0) { _InitInterface(); MoveOnScreen(); @@ -99,9 +102,9 @@ MainWindow::_InitInterface() // Tabs fBaseView = new BGroupView("baseView"); fTabView = new BTabView("tabView", B_WIDTH_FROM_WIDEST); - fFeedsView = new FeedsView("Feeds"); - fEntriesView = new EntriesView("Entries"); - fUpdatesView = new UpdatesView("Updates"); + fFeedsView = new FeedsView(B_TRANSLATE("Feeds")); + fEntriesView = new EntriesView(B_TRANSLATE("Entries")); + fUpdatesView = new UpdatesView(B_TRANSLATE("Updates")); fTabView->AddTab(fFeedsView); fTabView->AddTab(fEntriesView); @@ -161,10 +164,10 @@ void MainWindow::_SetUpdateButton(bool cancel) { if (cancel == true) { - fUpdateButton->SetLabel("Cancel"); + fUpdateButton->SetLabel(B_TRANSLATE("Cancel")); fUpdateButton->SetMessage(new BMessage(kClearQueue)); } else { - fUpdateButton->SetLabel("Update Now"); + fUpdateButton->SetLabel(B_TRANSLATE("Update Now")); fUpdateButton->SetMessage(new BMessage(kUpdateSubscribed)); } } diff --git a/src/Notifier.cpp b/src/Notifier.cpp index 33edf24..f658ebc 100644 --- a/src/Notifier.cpp +++ b/src/Notifier.cpp @@ -5,14 +5,20 @@ #include "Notifier.h" +#include #include #include +#include #include #include "App.h" #include "FeedController.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Notifier" + + Notifier::Notifier() : fFailedFeeds(new BList()), @@ -92,20 +98,31 @@ Notifier::_SendUpdatedNotification() } BNotification notifyNew(B_INFORMATION_NOTIFICATION); - BString notifyLabel("Feed Updates"); - BString notifyText("%n% new entries from %source%"); + BString notifyLabel(B_TRANSLATE("Feed Updates")); + BString notifyText; - if (fUpdatedFeeds->CountItems() > 1) - notifyText = "%n% new entries from %source% and %m% others"; + static BStringFormat oneSourceFormat(B_TRANSLATE("{0, plural," + "=1{One new entry from %source%.}" + "other{# new entries from %source%.}}")); - BString entryNum,feedNum = ""; + static BStringFormat multiSourceFormat(B_TRANSLATE("{0, plural," + "=1{%n% new entries from %source% and one other.}" + "other{%n% new entries from %source% and # others.}}")); + + if (fUpdatedFeeds->CountItems() > 1) + multiSourceFormat.Format(notifyText, fUpdatedFeeds->CountItems() - 1); + else + oneSourceFormat.Format(notifyText, fTotalEntries); + + BString entryNum = ""; entryNum << fTotalEntries; - feedNum << fUpdatedFeeds->CountItems() - 1; + + BString* feedTitle = (BString*)fUpdatedFeeds->ItemAt(0); + if (feedTitle->IsEmpty()) + feedTitle->SetTo(B_TRANSLATE("Untitled Feed")); notifyText.ReplaceAll("%n%", entryNum); - notifyText.ReplaceAll("%m%", feedNum); - notifyText.ReplaceAll("%source%", - ((BString*)fUpdatedFeeds->ItemAt(0))->String()); + notifyText.ReplaceAll("%source%", feedTitle->String()); notifyNew.SetTitle(notifyLabel); notifyNew.SetContent(notifyText); @@ -127,18 +144,23 @@ Notifier::_SendFailedNotification() } BNotification notifyError(B_ERROR_NOTIFICATION); - BString notifyLabel("Update Failure"); - BString notifyText("Failed to update %source%"); + BString notifyLabel(B_TRANSLATE("Update Failure")); + BString notifyText; + + static BStringFormat multiSourceFormat(B_TRANSLATE("{0, plural," + "=1{Failed to update %source% and one other.}" + "other{Failed to update %source% and # others.}}")); if (fFailedFeeds->CountItems() > 1) - notifyText = "Failed to update %source% and %m% others"; + multiSourceFormat.Format(notifyText, fFailedFeeds->CountItems() - 1); + else + notifyText = B_TRANSLATE("Failed to update %source%."); - BString feedNum = ""; - feedNum << fFailedFeeds->CountItems() - 1; + BString* feedTitle = (BString*)fFailedFeeds->ItemAt(0); + if (feedTitle->IsEmpty()) + feedTitle->SetTo(B_TRANSLATE("Untitled Feed")); - notifyText.ReplaceAll("%m%", feedNum); - notifyText.ReplaceAll("%source%", - ((BString*)fFailedFeeds->ItemAt(0))->String()); + notifyText.ReplaceAll("%source%", feedTitle->String()); notifyError.SetTitle(notifyLabel); notifyError.SetContent(notifyText); diff --git a/src/Preferences.cpp b/src/Preferences.cpp index 11e475c..08ce349 100644 --- a/src/Preferences.cpp +++ b/src/Preferences.cpp @@ -5,11 +5,16 @@ #include "Preferences.h" +#include #include #include "Util.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Preferences" + + Preferences::Preferences() { } @@ -189,22 +194,22 @@ Preferences::_FileError(status_t result) BPath cfgPath; find_directory(B_USER_SETTINGS_DIRECTORY, &cfgPath); - BString permLabel("Couldn't open the preferences file because permission " - "was denied.\nThis usually means that you don't have read permissions to " - "your settings directory.\nPlease make sure that your user has " - "read-access to your settings directory― likely %path%.\nCheck your OS " - "documentation for more information."); + BString permLabel(B_TRANSLATE("Couldn't open the preferences file because " + "permission was denied.\nThis usually means that you don't have read " + "permissions to your settings directory.\nPlease make sure that your user " + "has read-access to your settings directory― likely %path%.\nCheck your OS " + "documentation for more information.")); permLabel.ReplaceAll("%path%", cfgPath.Path()); - userFileError(result, "Preferences file", - "Couldn't open the preferences file because the path is not " - "specified.\nThis usually means that the programmer made a mistake.\n" + userFileError(result, B_TRANSLATE("Preferences file"), + B_TRANSLATE("Couldn't open the preferences file because the path is " + "not specified.\nThis usually means that the programmer made a mistake.\n" "Please submit a bug report to the Pogger repository on GitHub.\n" - "Your personal settings will not be loaded.", + "Your personal settings will not be loaded."), permLabel.String(), - "There is not enough memory available on your system to load the " - "preferences file.\nPlease try closing a few applications and restarting " - "Pogger."); + B_TRANSLATE("There is not enough memory available on your system to " + "load the preferences file.\nPlease try closing a few applications and " + "restarting Pogger.")); } diff --git a/src/RssFeed.cpp b/src/RssFeed.cpp index fe937c0..247bcce 100644 --- a/src/RssFeed.cpp +++ b/src/RssFeed.cpp @@ -7,11 +7,17 @@ #include +#include + #include "App.h" #include "Entry.h" #include "Util.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "RssFeed" + + RssFeed::RssFeed() { fTitle = BString(""); @@ -52,8 +58,11 @@ RssFeed::RootParse(tinyxml2::XMLElement* xchan) _SetTitle(xchan->FirstChildElement("title")); _SetDate(xchan->FirstChildElement("lastBuildDate")); - std::cout << "Channel '" << fTitle.String() << "' at '" << fXmlUrl.UrlString() - << ":\n"; + BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n")); + logString.ReplaceAll("%source%", fTitle.String()); + logString.ReplaceAll("%url%", fXmlUrl.UrlString()); + + std::cout << logString.String(); } @@ -86,7 +95,12 @@ RssFeed::ParseEntries(tinyxml2::XMLElement* xchan) int entryCount = _XmlCountSiblings(xitem, "item"); fEntries = BObjectList(entryCount, true); - std::cout << "\t-" << entryCount << " entries-\n"; + BString logString(B_TRANSLATE("\t-%count% entries-\n")); + BString entryStr; + entryStr << entryCount; + logString.ReplaceAll("%count%", entryStr); + + std::cout << logString.String(); while (xitem) { EntryParse(xitem); diff --git a/src/UpdatesView.cpp b/src/UpdatesView.cpp index a514021..d41a1f6 100644 --- a/src/UpdatesView.cpp +++ b/src/UpdatesView.cpp @@ -6,15 +6,21 @@ #include "UpdatesView.h" #include +#include #include +#include #include #include -#include #include +#include #include "App.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "UpdatesView" + + UpdatesView::UpdatesView(const char* name) : BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING) @@ -73,24 +79,27 @@ UpdatesView::_InitInterface() { // Notifications fNotificationsBox = new BBox("notifications"); - fNotificationsBox->SetLabel("Notifications"); + fNotificationsBox->SetLabel(B_TRANSLATE("Notifications")); - fNotifyNewCheck = new BCheckBox("newNotify", "Notify about new entries", + fNotifyNewCheck = new BCheckBox("newNotify", + B_TRANSLATE("Notify about new entries"), new BMessage(kNotifyNewCheckbox)); fNotifyFailCheck = new BCheckBox("errorNotify", - "Notify about update failures", new BMessage(kNotifyFailCheckbox)); + B_TRANSLATE("Notify about update failures"), + new BMessage(kNotifyFailCheckbox)); // Update scheduling fSchedulingBox = new BBox("scheduling"); - fSchedulingBox->SetLabel("Scheduling"); + fSchedulingBox->SetLabel(B_TRANSLATE("Scheduling")); fIntervalSlider = - new BSlider("interval", "Never automatically update", + new BSlider("interval", B_TRANSLATE("Never automatically update"), new BMessage(kIntervalChanged), 0, 25, B_HORIZONTAL); fIntervalSlider->SetHashMarkCount(26); fIntervalSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); - fIntervalSlider->SetLimitLabels("Never", "24 hours"); + fIntervalSlider->SetLimitLabels(B_TRANSLATE("Never"), + B_TRANSLATE("24 hours")); fIntervalSlider->SetModificationMessage(new BMessage(kIntervalChanged)); @@ -160,19 +169,28 @@ UpdatesView::_UpdateIntervalLabel() { case -1: { - newLabel = "Never automatically update"; + newLabel = B_TRANSLATE("Never automatically update"); break; } case 0: { - newLabel = "Update every 30 minutes"; + newLabel = B_TRANSLATE("Update every 30 minutes"); + break; + } + case 24: + { + newLabel = B_TRANSLATE("Update daily"); break; } default: - newLabel = "Update every %hour% hours"; + { + static BStringFormat format(B_TRANSLATE("{0, plural," + "=1{Update every hour}" + "other{Update every # hours}}")); + format.Format(newLabel, hours); + } } - newLabel.ReplaceAll("%hour%", strHour); fIntervalSlider->SetLabel(newLabel.String()); }