Localization support

This commit is contained in:
Jaidyn Ann 2021-03-21 18:47:58 -05:00
parent f67d0814a6
commit 1e7579ac08
17 changed files with 341 additions and 118 deletions

View File

@ -29,21 +29,21 @@ APP_MIME_SIG = application/x-vnd.Pogger
# same name (source.c or source.cpp) are included from different directories. # 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. # Also note that spaces in folder names do not work well with this Makefile.
SRCS = \ SRCS = \
src/App.cpp, \ src/App.cpp \
src/AtomFeed.cpp, \ src/AtomFeed.cpp \
src/Entry.cpp, \ src/Entry.cpp \
src/EntriesView.cpp, \ src/EntriesView.cpp \
src/Feed.cpp, \ src/Feed.cpp \
src/FeedController.cpp \ src/FeedController.cpp \
src/FeedEditWindow.cpp \ src/FeedEditWindow.cpp \
src/FeedListItem.cpp \ src/FeedListItem.cpp \
src/FeedsView.cpp, \ src/FeedsView.cpp \
src/MainWindow.cpp, \ src/MainWindow.cpp \
src/Mimetypes.cpp, \ src/Mimetypes.cpp \
src/Notifier.cpp, \ src/Notifier.cpp \
src/Preferences.cpp, \ src/Preferences.cpp \
src/RssFeed.cpp, \ src/RssFeed.cpp \
src/UpdatesView.cpp, \ src/UpdatesView.cpp \
src/Util.cpp src/Util.cpp
# Specify the resource definition files to use. Full or relative paths can be # 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, # - if your library does not follow the standard library naming scheme,
# you need to specify the path to the library and it's name. # 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") # (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 # Specify additional paths to directories following the standard libXXX.so
# or libXXX.a naming scheme. You can specify full paths or paths relative # 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 # will recreate only the "locales/en.catkeys" file. Use it as a template
# for creating catkeys for other languages. All localization files must be # for creating catkeys for other languages. All localization files must be
# placed in the "locales" subdirectory. # placed in the "locales" subdirectory.
LOCALES = en LOCALES = en eo
# Specify all the preprocessor symbols to be defined. The symbols will not # 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 # have their values set automatically; you must supply the value (if any) to

View File

@ -29,6 +29,7 @@ In "Updates" you can toggle notifications and set the frequency of updates.
## Building ## Building
`$ make` `$ make`
`$ make bindcatalogs`
Uses netservices, and has TinyXML2 as a dependency. Uses netservices, and has TinyXML2 as a dependency.

View File

@ -1,7 +1,3 @@
Important Features:
* Localization
Improvements:
* Memory leaks * Memory leaks
* ~.05MB per feed on download, in Util.ccp, fetch(). I'm stumped here. * ~.05MB per feed on download, in Util.ccp, fetch(). I'm stumped here.
* ~.02MB per feed on parsing * ~.02MB per feed on parsing

61
locales/en.catkeys Normal file
View File

@ -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:

61
locales/eo.catkeys Normal file
View File

@ -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:

View File

@ -5,8 +5,6 @@
#include "App.h" #include "App.h"
#include <iostream>
#include <MessageRunner.h> #include <MessageRunner.h>
#include <Roster.h> #include <Roster.h>
#include <StorageKit.h> #include <StorageKit.h>

View File

@ -7,6 +7,8 @@
#include <iostream> #include <iostream>
#include <Catalog.h>
#include <tinyxml2.h> #include <tinyxml2.h>
#include "App.h" #include "App.h"
@ -14,6 +16,10 @@
#include "Util.h" #include "Util.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "AtomFeed"
AtomFeed::AtomFeed() AtomFeed::AtomFeed()
{ {
fTitle = BString(""); fTitle = BString("");
@ -65,8 +71,11 @@ AtomFeed::RootParse(tinyxml2::XMLElement* xfeed)
if (!set && xentry) if (!set && xentry)
set = _SetDate(xentry->FirstChildElement("published")); set = _SetDate(xentry->FirstChildElement("published"));
std::cout << "Channel '" << fTitle << "' at '" << fXmlUrl.UrlString() BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n"));
<< "':\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"); int entryCount = _XmlCountSiblings(xentry, "entry");
fEntries = BObjectList<Entry>(entryCount, true); fEntries = BObjectList<Entry>(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) { while (xentry) {
EntryParse(xentry); EntryParse(xentry);

View File

@ -5,11 +5,10 @@
#include "EntriesView.h" #include "EntriesView.h"
#include <iostream>
#include <Alert.h> #include <Alert.h>
#include <Box.h> #include <Box.h>
#include <Button.h> #include <Button.h>
#include <Catalog.h>
#include <Message.h> #include <Message.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <PopUpMenu.h> #include <PopUpMenu.h>
@ -22,6 +21,10 @@
#include "Util.h" #include "Util.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "EntriesView"
EntriesView::EntriesView(const char* name) EntriesView::EntriesView(const char* name)
: :
BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING) BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING)
@ -138,29 +141,31 @@ EntriesView::_InitInterface()
{ {
// Saving // Saving
fSavingBox = new BBox("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", "", "", fEntryFolderText = new BTextControl("entryFolder", "", "",
new BMessage(kEntryFolderText)); new BMessage(kEntryFolderText));
fEntryFolderBrowseButton = new BButton("entryFolderBrowse", "Browse…", fEntryFolderBrowseButton = new BButton("entryFolderBrowse",
new BMessage(kEntryFolderBrowse)); B_TRANSLATE("Browse…"), new BMessage(kEntryFolderBrowse));
// Opening // Opening
fOpeningBox = new BBox("opening"); fOpeningBox = new BBox("opening");
fOpeningBox->SetLabel("Opening"); fOpeningBox->SetLabel(B_TRANSLATE("Opening"));
fOpenAsLabel = new BStringView("openAsLabel", "Open as:"); fOpenAsLabel = new BStringView("openAsLabel", B_TRANSLATE("Open as:"));
fOpenAsHtmlRadio = new BRadioButton("asHtml", "HTML", fOpenAsHtmlRadio = new BRadioButton("asHtml", B_TRANSLATE("HTML"),
new BMessage(kOpenHtmlRadio)); new BMessage(kOpenHtmlRadio));
fOpenAsUrlRadio = new BRadioButton("asUrl", "URL", fOpenAsUrlRadio = new BRadioButton("asUrl", B_TRANSLATE("URL"),
new BMessage(kOpenUrlRadio)); new BMessage(kOpenUrlRadio));
fOpenWithLabel = new BStringView("openWithLabel", "Open with:"); fOpenWithLabel = new BStringView("openWithLabel",
B_TRANSLATE("Open with:"));
fOpenWithMenu = new BPopUpMenu("openWith"); fOpenWithMenu = new BPopUpMenu("openWith");
fOpenWithMenuField = new BMenuField("openWithMenu", NULL, fOpenWithMenu); fOpenWithMenuField = new BMenuField("openWithMenu", NULL, fOpenWithMenu);
fOpenWithSelectButton = new BButton("openWithSelect", "Select…", fOpenWithSelectButton = new BButton("openWithSelect",
new BMessage(kOpenWithBrowse)); B_TRANSLATE("Select…"), new BMessage(kOpenWithBrowse));
// Display current settings // Display current settings
@ -251,22 +256,24 @@ EntriesView::_FileError(status_t result)
find_directory(B_USER_SETTINGS_DIRECTORY, &cfgPath); find_directory(B_USER_SETTINGS_DIRECTORY, &cfgPath);
if (result == B_NOT_A_DIRECTORY) { if (result == B_NOT_A_DIRECTORY) {
BAlert* alert = new BAlert("Entries Directory", "The path you " BAlert* alert = new BAlert(B_TRANSLATE("Entries Directory"),
"selected isn't a folder― please choose another path.", "OK", B_TRANSLATE("The path you selected isn't a folder― please choose "
NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); "another path."), B_TRANSLATE("OK"), NULL, NULL,
alert->Go(); B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->Go();
return; return;
} }
userFileError(result, "Entries Directory", userFileError(result, B_TRANSLATE("Entries Directory"),
"Couldn't open this folder because no path was specified.\n" B_TRANSLATE("Couldn't open this folder because no path was specified.\n"
"Please select a new folder.", "Please select a new folder."),
"Couldn't open this folder because permission was denied.\n" B_TRANSLATE("Couldn't open this folder because permission was denied.\n"
"This usually means that you don't have read permissions.\nPlease make " "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 " "sure that your user has read-access to this folder.\nCheck your OS "
"documentation for more information.", "documentation for more information."),
"There is not enough memory available on your system to access the " B_TRANSLATE("There is not enough memory available on your system to "
"given path.\nPlease try closing a few applications and restarting Pogger."); "access the given path.\nPlease try closing a few applications and "
"restarting Pogger."));
} }

View File

@ -7,6 +7,7 @@
#include <iostream> #include <iostream>
#include <Catalog.h>
#include <Directory.h> #include <Directory.h>
#include <Message.h> #include <Message.h>
#include <MessageRunner.h> #include <MessageRunner.h>
@ -19,6 +20,10 @@
#include "RssFeed.h" #include "RssFeed.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FeedController"
FeedController::FeedController() FeedController::FeedController()
: :
fEnqueuedTotal(0), fEnqueuedTotal(0),
@ -222,7 +227,7 @@ FeedController::_DownloadLoop(void* data)
Feed* feedBuffer = (Feed*)malloc(sizeof(Feed)); Feed* feedBuffer = (Feed*)malloc(sizeof(Feed));
receive_data(&sender, (void*)feedBuffer, 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"; << feedBuffer->XmlUrl().UrlString() << "\n";
if (feedBuffer->Fetch()) { if (feedBuffer->Fetch()) {

View File

@ -7,6 +7,7 @@
#include <Alert.h> #include <Alert.h>
#include <Button.h> #include <Button.h>
#include <Catalog.h>
#include <Message.h> #include <Message.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <SeparatorView.h> #include <SeparatorView.h>
@ -20,10 +21,15 @@
#include "Util.h" #include "Util.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FeedEditWindow"
FeedEditWindow::FeedEditWindow() FeedEditWindow::FeedEditWindow()
: :
BWindow(((App*)be_app)->fPreferences->fFeedEditRect, "New Feed", BWindow(((App*)be_app)->fPreferences->fFeedEditRect,
B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) B_TRANSLATE("New Feed"), B_TITLED_WINDOW,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
{ {
_InitInterface(); _InitInterface();
MoveOnScreen(); MoveOnScreen();
@ -37,7 +43,7 @@ FeedEditWindow::FeedEditWindow(BEntry feedEntry)
: :
FeedEditWindow() FeedEditWindow()
{ {
SetTitle("Edit Feed"); SetTitle(B_TRANSLATE("Edit Feed"));
fFeed = Feed(feedEntry); fFeed = Feed(feedEntry);
fFeedNameText->SetText(fFeed.Title().String()); fFeedNameText->SetText(fFeed.Title().String());
@ -83,15 +89,15 @@ void
FeedEditWindow::_InitInterface() FeedEditWindow::_InitInterface()
{ {
// Name and URL // Name and URL
fFeedNameLabel = new BStringView("feedNameLabel", "Feed name:"); fFeedNameLabel = new BStringView("feedNameLabel", B_TRANSLATE("Feed name:"));
fFeedNameText = new BTextControl("feedName", "", "", NULL); fFeedNameText = new BTextControl("feedName", "", "", NULL);
fFeedUrlLabel = new BStringView("feedUrlLabel", "Feed URL:"); fFeedUrlLabel = new BStringView("feedUrlLabel", B_TRANSLATE("Feed URL:"));
fFeedUrlText = new BTextControl("feedUrl", "", "", NULL); fFeedUrlText = new BTextControl("feedUrl", "", "", NULL);
// Save/Delete // Save/Delete
fSaveButton = new BButton("save", "Save", fSaveButton = new BButton("save", B_TRANSLATE("Save"),
new BMessage(kSaveButton)); new BMessage(kSaveButton));
fDeleteButton = new BButton("delete", "Delete", fDeleteButton = new BButton("delete", B_TRANSLATE("Delete"),
new BMessage(kDeleteButton)); new BMessage(kDeleteButton));
BLayoutBuilder::Group<>(this, B_VERTICAL, 0) BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
@ -147,17 +153,18 @@ FeedEditWindow::_SaveFeed()
BUrl url = BUrl(urlString); BUrl url = BUrl(urlString);
if (BString(urlString).IsEmpty() == true) { if (BString(urlString).IsEmpty() == true) {
BAlert* emptyAlert = new BAlert("Invalid Feed", BAlert* emptyAlert = new BAlert(B_TRANSLATE("Invalid Feed"),
"Please enter a URL.", "OK", NULL, NULL, B_TRANSLATE("Please enter a URL."), B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
emptyAlert->Go(); emptyAlert->Go();
return; return;
} }
if (url.IsValid() == false) { if (url.IsValid() == false) {
BAlert* invAlert = new BAlert("Invalid Feed", BAlert* invAlert = new BAlert(B_TRANSLATE("Invalid Feed"),
"The given URL is invalid. Please make sure you typed it in correctly.", B_TRANSLATE("The given URL is invalid. Please make sure you typed "
"OK", NULL, NULL, B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); "it in correctly."), B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT);
invAlert->Go(); invAlert->Go();
return; return;
} }

View File

@ -5,12 +5,17 @@
#include "FeedListItem.h" #include "FeedListItem.h"
#include <Catalog.h>
#include <View.h> #include <View.h>
#include "Feed.h" #include "Feed.h"
#include "Util.h" #include "Util.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FeedListItem"
FeedListItem::FeedListItem(Feed* feed) FeedListItem::FeedListItem(Feed* feed)
: :
BStringItem(feed->Title().String(), 0, false), BStringItem(feed->Title().String(), 0, false),
@ -19,7 +24,7 @@ FeedListItem::FeedListItem(Feed* feed)
fFeedPath(feed->CachePath()) fFeedPath(feed->CachePath())
{ {
if (feed->Title().IsEmpty() == true) if (feed->Title().IsEmpty() == true)
SetText("Untitled Feed"); SetText(B_TRANSLATE("Untitled Feed"));
} }

View File

@ -5,6 +5,7 @@
#include "FeedsView.h" #include "FeedsView.h"
#include <Catalog.h>
#include <Message.h> #include <Message.h>
#include <GroupView.h> #include <GroupView.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
@ -22,6 +23,10 @@
#include "Notifier.h" #include "Notifier.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FeedsView"
FeedsView::FeedsView(const char* name) FeedsView::FeedsView(const char* name)
: :
BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING) BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING)
@ -121,7 +126,8 @@ FeedsView::_InitInterface()
// Add, Remove, Edit // Add, Remove, Edit
fAddButton = new BButton("addFeed", "+", new BMessage(kFeedsAddButton)); fAddButton = new BButton("addFeed", "+", new BMessage(kFeedsAddButton));
fRemoveButton = new BButton("removeFeed", "-", new BMessage(kFeedsRemoveButton)); 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; font_height fontHeight;
GetFontHeight(&fontHeight); GetFontHeight(&fontHeight);
@ -224,12 +230,12 @@ FeedsView::_UpdateProgress(BMessage* msg, int8 status)
BString feedName, feedUrl; BString feedName, feedUrl;
if (msg->FindString("feed_url", &feedUrl) != B_OK) if (msg->FindString("feed_url", &feedUrl) != B_OK)
return; return;
if (msg->FindString("feed_name", &feedName) != B_OK) if (msg->FindString("feed_name", &feedName) != B_OK || feedName.IsEmpty())
feedName = feedUrl; feedName = feedUrl;
if (status == kDownloadingStatus) { if (status == kDownloadingStatus) {
BString label("Fetching "); BString label(B_TRANSLATE("Fetching %source%…"));
label << feedName << ""; label.ReplaceAll("%source%", feedName);
fProgressLabel->SetText(label); fProgressLabel->SetText(label);
} }

View File

@ -5,9 +5,8 @@
#include "MainWindow.h" #include "MainWindow.h"
#include <iostream>
#include <Button.h> #include <Button.h>
#include <Catalog.h>
#include <GroupView.h> #include <GroupView.h>
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <SeparatorView.h> #include <SeparatorView.h>
@ -23,10 +22,14 @@
#include "UpdatesView.h" #include "UpdatesView.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "MainWindow"
MainWindow::MainWindow() MainWindow::MainWindow()
: :
BWindow(((App*)be_app)->fPreferences->fMainWindowRect, "Pogger", BWindow(((App*)be_app)->fPreferences->fMainWindowRect,
B_TITLED_WINDOW, NULL) B_TRANSLATE_SYSTEM_NAME("Pogger"), B_TITLED_WINDOW, 0)
{ {
_InitInterface(); _InitInterface();
MoveOnScreen(); MoveOnScreen();
@ -99,9 +102,9 @@ MainWindow::_InitInterface()
// Tabs // Tabs
fBaseView = new BGroupView("baseView"); fBaseView = new BGroupView("baseView");
fTabView = new BTabView("tabView", B_WIDTH_FROM_WIDEST); fTabView = new BTabView("tabView", B_WIDTH_FROM_WIDEST);
fFeedsView = new FeedsView("Feeds"); fFeedsView = new FeedsView(B_TRANSLATE("Feeds"));
fEntriesView = new EntriesView("Entries"); fEntriesView = new EntriesView(B_TRANSLATE("Entries"));
fUpdatesView = new UpdatesView("Updates"); fUpdatesView = new UpdatesView(B_TRANSLATE("Updates"));
fTabView->AddTab(fFeedsView); fTabView->AddTab(fFeedsView);
fTabView->AddTab(fEntriesView); fTabView->AddTab(fEntriesView);
@ -161,10 +164,10 @@ void
MainWindow::_SetUpdateButton(bool cancel) MainWindow::_SetUpdateButton(bool cancel)
{ {
if (cancel == true) { if (cancel == true) {
fUpdateButton->SetLabel("Cancel"); fUpdateButton->SetLabel(B_TRANSLATE("Cancel"));
fUpdateButton->SetMessage(new BMessage(kClearQueue)); fUpdateButton->SetMessage(new BMessage(kClearQueue));
} else { } else {
fUpdateButton->SetLabel("Update Now"); fUpdateButton->SetLabel(B_TRANSLATE("Update Now"));
fUpdateButton->SetMessage(new BMessage(kUpdateSubscribed)); fUpdateButton->SetMessage(new BMessage(kUpdateSubscribed));
} }
} }

View File

@ -5,14 +5,20 @@
#include "Notifier.h" #include "Notifier.h"
#include <Catalog.h>
#include <List.h> #include <List.h>
#include <Message.h> #include <Message.h>
#include <StringFormat.h>
#include <Notification.h> #include <Notification.h>
#include "App.h" #include "App.h"
#include "FeedController.h" #include "FeedController.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Notifier"
Notifier::Notifier() Notifier::Notifier()
: :
fFailedFeeds(new BList()), fFailedFeeds(new BList()),
@ -92,20 +98,31 @@ Notifier::_SendUpdatedNotification()
} }
BNotification notifyNew(B_INFORMATION_NOTIFICATION); BNotification notifyNew(B_INFORMATION_NOTIFICATION);
BString notifyLabel("Feed Updates"); BString notifyLabel(B_TRANSLATE("Feed Updates"));
BString notifyText("%n% new entries from %source%"); BString notifyText;
if (fUpdatedFeeds->CountItems() > 1) static BStringFormat oneSourceFormat(B_TRANSLATE("{0, plural,"
notifyText = "%n% new entries from %source% and %m% others"; "=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; 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("%n%", entryNum);
notifyText.ReplaceAll("%m%", feedNum); notifyText.ReplaceAll("%source%", feedTitle->String());
notifyText.ReplaceAll("%source%",
((BString*)fUpdatedFeeds->ItemAt(0))->String());
notifyNew.SetTitle(notifyLabel); notifyNew.SetTitle(notifyLabel);
notifyNew.SetContent(notifyText); notifyNew.SetContent(notifyText);
@ -127,18 +144,23 @@ Notifier::_SendFailedNotification()
} }
BNotification notifyError(B_ERROR_NOTIFICATION); BNotification notifyError(B_ERROR_NOTIFICATION);
BString notifyLabel("Update Failure"); BString notifyLabel(B_TRANSLATE("Update Failure"));
BString notifyText("Failed to update %source%"); 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) 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 = ""; BString* feedTitle = (BString*)fFailedFeeds->ItemAt(0);
feedNum << fFailedFeeds->CountItems() - 1; if (feedTitle->IsEmpty())
feedTitle->SetTo(B_TRANSLATE("Untitled Feed"));
notifyText.ReplaceAll("%m%", feedNum); notifyText.ReplaceAll("%source%", feedTitle->String());
notifyText.ReplaceAll("%source%",
((BString*)fFailedFeeds->ItemAt(0))->String());
notifyError.SetTitle(notifyLabel); notifyError.SetTitle(notifyLabel);
notifyError.SetContent(notifyText); notifyError.SetContent(notifyText);

View File

@ -5,11 +5,16 @@
#include "Preferences.h" #include "Preferences.h"
#include <Catalog.h>
#include <String.h> #include <String.h>
#include "Util.h" #include "Util.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Preferences"
Preferences::Preferences() { Preferences::Preferences() {
} }
@ -189,22 +194,22 @@ Preferences::_FileError(status_t result)
BPath cfgPath; BPath cfgPath;
find_directory(B_USER_SETTINGS_DIRECTORY, &cfgPath); find_directory(B_USER_SETTINGS_DIRECTORY, &cfgPath);
BString permLabel("Couldn't open the preferences file because permission " BString permLabel(B_TRANSLATE("Couldn't open the preferences file because "
"was denied.\nThis usually means that you don't have read permissions to " "permission was denied.\nThis usually means that you don't have read "
"your settings directory.\nPlease make sure that your user has " "permissions to your settings directory.\nPlease make sure that your user "
"read-access to your settings directory― likely %path%.\nCheck your OS " "has read-access to your settings directory― likely %path%.\nCheck your OS "
"documentation for more information."); "documentation for more information."));
permLabel.ReplaceAll("%path%", cfgPath.Path()); permLabel.ReplaceAll("%path%", cfgPath.Path());
userFileError(result, "Preferences file", userFileError(result, B_TRANSLATE("Preferences file"),
"Couldn't open the preferences file because the path is not " B_TRANSLATE("Couldn't open the preferences file because the path is "
"specified.\nThis usually means that the programmer made a mistake.\n" "not specified.\nThis usually means that the programmer made a mistake.\n"
"Please submit a bug report to the Pogger repository on GitHub.\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(), permLabel.String(),
"There is not enough memory available on your system to load the " B_TRANSLATE("There is not enough memory available on your system to "
"preferences file.\nPlease try closing a few applications and restarting " "load the preferences file.\nPlease try closing a few applications and "
"Pogger."); "restarting Pogger."));
} }

View File

@ -7,11 +7,17 @@
#include <iostream> #include <iostream>
#include <Catalog.h>
#include "App.h" #include "App.h"
#include "Entry.h" #include "Entry.h"
#include "Util.h" #include "Util.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "RssFeed"
RssFeed::RssFeed() RssFeed::RssFeed()
{ {
fTitle = BString(""); fTitle = BString("");
@ -52,8 +58,11 @@ RssFeed::RootParse(tinyxml2::XMLElement* xchan)
_SetTitle(xchan->FirstChildElement("title")); _SetTitle(xchan->FirstChildElement("title"));
_SetDate(xchan->FirstChildElement("lastBuildDate")); _SetDate(xchan->FirstChildElement("lastBuildDate"));
std::cout << "Channel '" << fTitle.String() << "' at '" << fXmlUrl.UrlString() BString logString(B_TRANSLATE("Channel '%source%' at %url%:\n"));
<< ":\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"); int entryCount = _XmlCountSiblings(xitem, "item");
fEntries = BObjectList<Entry>(entryCount, true); fEntries = BObjectList<Entry>(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) { while (xitem) {
EntryParse(xitem); EntryParse(xitem);

View File

@ -6,15 +6,21 @@
#include "UpdatesView.h" #include "UpdatesView.h"
#include <Box.h> #include <Box.h>
#include <Catalog.h>
#include <CheckBox.h> #include <CheckBox.h>
#include <LayoutBuilder.h>
#include <Message.h> #include <Message.h>
#include <MessageRunner.h> #include <MessageRunner.h>
#include <LayoutBuilder.h>
#include <Slider.h> #include <Slider.h>
#include <StringFormat.h>
#include "App.h" #include "App.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "UpdatesView"
UpdatesView::UpdatesView(const char* name) UpdatesView::UpdatesView(const char* name)
: :
BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING) BGroupView(name, B_VERTICAL, B_USE_DEFAULT_SPACING)
@ -73,24 +79,27 @@ UpdatesView::_InitInterface()
{ {
// Notifications // Notifications
fNotificationsBox = new BBox("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)); new BMessage(kNotifyNewCheckbox));
fNotifyFailCheck = new BCheckBox("errorNotify", fNotifyFailCheck = new BCheckBox("errorNotify",
"Notify about update failures", new BMessage(kNotifyFailCheckbox)); B_TRANSLATE("Notify about update failures"),
new BMessage(kNotifyFailCheckbox));
// Update scheduling // Update scheduling
fSchedulingBox = new BBox("scheduling"); fSchedulingBox = new BBox("scheduling");
fSchedulingBox->SetLabel("Scheduling"); fSchedulingBox->SetLabel(B_TRANSLATE("Scheduling"));
fIntervalSlider = fIntervalSlider =
new BSlider("interval", "Never automatically update", new BSlider("interval", B_TRANSLATE("Never automatically update"),
new BMessage(kIntervalChanged), 0, 25, B_HORIZONTAL); new BMessage(kIntervalChanged), 0, 25, B_HORIZONTAL);
fIntervalSlider->SetHashMarkCount(26); fIntervalSlider->SetHashMarkCount(26);
fIntervalSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 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)); fIntervalSlider->SetModificationMessage(new BMessage(kIntervalChanged));
@ -160,19 +169,28 @@ UpdatesView::_UpdateIntervalLabel()
{ {
case -1: case -1:
{ {
newLabel = "Never automatically update"; newLabel = B_TRANSLATE("Never automatically update");
break; break;
} }
case 0: case 0:
{ {
newLabel = "Update every 30 minutes"; newLabel = B_TRANSLATE("Update every 30 minutes");
break;
}
case 24:
{
newLabel = B_TRANSLATE("Update daily");
break; break;
} }
default: 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()); fIntervalSlider->SetLabel(newLabel.String());
} }