diff --git a/headers/os/locale/MessageFormat.h b/headers/os/locale/MessageFormat.h index ff2a9c2d84..21b447245c 100644 --- a/headers/os/locale/MessageFormat.h +++ b/headers/os/locale/MessageFormat.h @@ -9,10 +9,32 @@ #include +namespace icu { + class MessageFormat; + class UnicodeString; +} + + class BMessageFormat: public BFormat { public: - status_t Format(BString& buffer, const BString message, - const int32 arg); + BMessageFormat(const BString pattern); + ~BMessageFormat(); + + status_t InitCheck(); + + status_t SetLanguage(const BLanguage& newLanguage); + status_t SetFormattingConventions( + const BFormattingConventions& + conventions); + + status_t Format(BString& buffer, const int32 arg) const; + +private: + status_t _Initialize(const icu::UnicodeString&); + +private: + status_t fInitStatus; + icu::MessageFormat* fFormatter; }; diff --git a/src/add-ons/mail_daemon/inbound_filters/notifier/filter.cpp b/src/add-ons/mail_daemon/inbound_filters/notifier/filter.cpp index 1ad15ebb53..e79b0fd9bc 100644 --- a/src/add-ons/mail_daemon/inbound_filters/notifier/filter.cpp +++ b/src/add-ons/mail_daemon/inbound_filters/notifier/filter.cpp @@ -68,11 +68,12 @@ NotifyFilter::MailboxSynced(status_t status) system_beep("New E-mail"); if (fStrategy & alert) { - BString text; - BMessageFormat().Format(text, B_TRANSLATE( + static BMessageFormat format(B_TRANSLATE( "You have {0, plural, one{# new message} other{# new messages}} " - "for %account."), fNNewMessages); + "for %account.")); + BString text; + format.Format(text, fNNewMessages); text.ReplaceFirst("%account", fMailProtocol.AccountSettings().Name()); BAlert *alert = new BAlert(B_TRANSLATE("New messages"), text.String(), @@ -97,11 +98,11 @@ NotifyFilter::MailboxSynced(status_t status) } if (fStrategy & log_window) { - BString message; - BMessageFormat().Format(message, B_TRANSLATE( - "{0, plural, one{# new message} other{# new messages}}"), - fNNewMessages); + static BMessageFormat format(B_TRANSLATE("{0, plural, " + "one{# new message} other{# new messages}}")); + BString message; + format.Format(message, fNNewMessages); fMailProtocol.ShowMessage(message.String()); } diff --git a/src/apps/aboutsystem/AboutSystem.cpp b/src/apps/aboutsystem/AboutSystem.cpp index d1d284e1d8..736a6c215e 100644 --- a/src/apps/aboutsystem/AboutSystem.cpp +++ b/src/apps/aboutsystem/AboutSystem.cpp @@ -443,10 +443,12 @@ AboutView::AboutView() B_ALIGN_VERTICAL_UNSET)); // CPU count, type and clock speed - BString processorLabel; - BMessageFormat().Format(processorLabel, B_TRANSLATE_COMMENT( + static BMessageFormat format(B_TRANSLATE_COMMENT( "{0, plural, one{Processor:} other{# Processors:}}", - "\"Processor:\" or \"2 Processors:\""), systemInfo.cpu_count); + "\"Processor:\" or \"2 Processors:\"")); + + BString processorLabel; + format.Format(processorLabel, systemInfo.cpu_count); uint32 topologyNodeCount = 0; cpu_topology_node_info* topology = NULL; diff --git a/src/apps/diskusage/StatusView.cpp b/src/apps/diskusage/StatusView.cpp index 734d8b3de2..586c72a261 100644 --- a/src/apps/diskusage/StatusView.cpp +++ b/src/apps/diskusage/StatusView.cpp @@ -151,9 +151,10 @@ StatusView::ShowInfo(const FileInfo* info) fSizeView->SetText(label); if (info->count > 0) { + static BMessageFormat format(B_TRANSLATE("{0, plural, " + "one{# file}, other{# files}}")); BString label; - BMessageFormat().Format(label, B_TRANSLATE("{0, plural, one{# file}, " - "other{# files}}"), info->count); + format.Format(label, info->count); fCountView->SetText(label); } else { fCountView->SetText(kEmptyStr); diff --git a/src/apps/haikudepot/ui/PackageListView.cpp b/src/apps/haikudepot/ui/PackageListView.cpp index 4496492dc0..5a04e23624 100644 --- a/src/apps/haikudepot/ui/PackageListView.cpp +++ b/src/apps/haikudepot/ui/PackageListView.cpp @@ -609,9 +609,11 @@ public: private: BString _GetLabel() const { + static BMessageFormat format(B_TRANSLATE("{0, plural, " + "one{# item} other{# items}}")); + BString label; - BMessageFormat().Format(label, B_TRANSLATE("{0, plural, one{# item} " - "other{# items}}"), fItemCount); + format.Format(label, fItemCount); return label; } diff --git a/src/apps/magnify/Magnify.cpp b/src/apps/magnify/Magnify.cpp index 9e9599de31..7dfa1af79c 100644 --- a/src/apps/magnify/Magnify.cpp +++ b/src/apps/magnify/Magnify.cpp @@ -829,16 +829,19 @@ TInfoView::Draw(BRect updateRect) MovePenTo(10, fFontHeight + 5); + static BMessageFormat format(B_TRANSLATE("%width x %height @ {0, plural, " + "one{# pixel/pixel} other{# pixels/pixel}}")); + BString dimensionsInfo; - BMessageFormat().Format(dimensionsInfo, - B_TRANSLATE("%width x %height @ {0, plural, one{# pixel/pixel} " - "other{# pixels/pixel}}"), pixelSize); + format.Format(dimensionsInfo, pixelSize); + BString rep; rep << hPixelCount; dimensionsInfo.ReplaceAll("%width", rep); rep = ""; rep << vPixelCount; dimensionsInfo.ReplaceAll("%height", rep); + invalRect.Set(10, 5, 10 + StringWidth(fInfoStr), fFontHeight+7); SetHighColor(ViewColor()); FillRect(invalRect); diff --git a/src/apps/pairs/PairsWindow.cpp b/src/apps/pairs/PairsWindow.cpp index 8a198a277f..e0379e023f 100644 --- a/src/apps/pairs/PairsWindow.cpp +++ b/src/apps/pairs/PairsWindow.cpp @@ -305,10 +305,10 @@ PairsWindow::MessageReceived(BMessage* message) // Note: in english the singular form is never used, but other // languages behave differently. - BMessageFormat().Format(strAbout, B_TRANSLATE( + static BMessageFormat format(B_TRANSLATE( "You completed the game in " - "{0, plural, one{# click} other{# clicks}}.\n"), - fButtonClicks); + "{0, plural, one{# click} other{# clicks}}.\n")); + format.Format(strAbout, fButtonClicks); BAlert* alert = new BAlert("about", strAbout.String(), diff --git a/src/apps/poorman/StatusSlider.cpp b/src/apps/poorman/StatusSlider.cpp index 551b2f340c..68aad6c08b 100644 --- a/src/apps/poorman/StatusSlider.cpp +++ b/src/apps/poorman/StatusSlider.cpp @@ -15,7 +15,7 @@ StatusSlider::StatusSlider(const char* name, const char* label, const char* statusPrefix, BMessage* message, int32 minValue, int32 maxValue) : BSlider(name, label, message, minValue, maxValue, B_HORIZONTAL), - fStatusPrefix(statusPrefix) + fFormat(statusPrefix) { } @@ -23,6 +23,7 @@ StatusSlider::StatusSlider(const char* name, const char* label, const char* StatusSlider::UpdateText() const { - BMessageFormat().Format(fStr, fStatusPrefix, Value()); + fStr.Truncate(0); + fFormat.Format(fStr, Value()); return fStr.String(); } diff --git a/src/apps/poorman/StatusSlider.h b/src/apps/poorman/StatusSlider.h index 1236ee75ac..1f3c53ff6a 100644 --- a/src/apps/poorman/StatusSlider.h +++ b/src/apps/poorman/StatusSlider.h @@ -10,6 +10,7 @@ //#define BEOS_R5_COMPATIBLE +#include #include #include @@ -26,7 +27,7 @@ public: virtual const char* UpdateText() const; private: - const char* fStatusPrefix; + BMessageFormat fFormat; mutable BString fStr; }; diff --git a/src/kits/locale/MessageFormat.cpp b/src/kits/locale/MessageFormat.cpp index b5af3eca36..e2e249d895 100644 --- a/src/kits/locale/MessageFormat.cpp +++ b/src/kits/locale/MessageFormat.cpp @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -12,9 +13,74 @@ #include -status_t -BMessageFormat::Format(BString& output, const BString message, const int32 arg) +BMessageFormat::BMessageFormat(const BString pattern) + : BFormat() { + _Initialize(UnicodeString::fromUTF8(pattern.String())); +} + + +BMessageFormat::~BMessageFormat() +{ + delete fFormatter; +} + + +status_t +BMessageFormat::InitCheck() +{ + return fInitStatus; +} + + +status_t +BMessageFormat::SetLanguage(const BLanguage& newLanguage) +{ + if (!fFormatter) + return B_NO_INIT; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + fInitStatus = BFormat::SetLanguage(newLanguage); + + if (fInitStatus == B_OK) { + UnicodeString storage; + _Initialize(fFormatter->toPattern(storage)); + } + return fInitStatus; +} + + +status_t +BMessageFormat::SetFormattingConventions( + const BFormattingConventions& conventions) +{ + if (!fFormatter) + return B_NO_INIT; + + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + + fInitStatus = BFormat::SetFormattingConventions(conventions); + + if (fInitStatus == B_OK) { + UnicodeString storage; + _Initialize(fFormatter->toPattern(storage)); + } + return fInitStatus; +} + + +status_t +BMessageFormat::Format(BString& output, const int32 arg) const +{ + BAutolock lock(fLock); + if (!lock.IsLocked()) + return B_ERROR; + UnicodeString buffer; UErrorCode error = U_ZERO_ERROR; @@ -22,15 +88,8 @@ BMessageFormat::Format(BString& output, const BString message, const int32 arg) (int32_t)arg }; - Locale* icuLocale - = fConventions.UseStringsFromPreferredLanguage() - ? BLanguage::Private(&fLanguage).ICULocale() - : BFormattingConventions::Private(&fConventions).ICULocale(); - - MessageFormat formatter(UnicodeString::fromUTF8(message.String()), - *icuLocale, error); FieldPosition pos; - buffer = formatter.format(arguments, 1, buffer, pos, error); + buffer = fFormatter->format(arguments, 1, buffer, pos, error); if (!U_SUCCESS(error)) return B_ERROR; @@ -39,3 +98,27 @@ BMessageFormat::Format(BString& output, const BString message, const int32 arg) return B_OK; } + + +status_t +BMessageFormat::_Initialize(const UnicodeString& pattern) +{ + UErrorCode error = U_ZERO_ERROR; + Locale* icuLocale + = fConventions.UseStringsFromPreferredLanguage() + ? BLanguage::Private(&fLanguage).ICULocale() + : BFormattingConventions::Private(&fConventions).ICULocale(); + + fFormatter = new MessageFormat(pattern, *icuLocale, error); + + if (fFormatter == NULL) + fInitStatus = B_NO_MEMORY; + + if (!U_SUCCESS(error)) { + delete fFormatter; + fInitStatus = B_ERROR; + fFormatter = NULL; + } + + return fInitStatus; +} diff --git a/src/kits/tracker/CountView.cpp b/src/kits/tracker/CountView.cpp index 195ac4f65b..a1d3c7c813 100644 --- a/src/kits/tracker/CountView.cpp +++ b/src/kits/tracker/CountView.cpp @@ -232,10 +232,10 @@ BCountView::Draw(BRect updateRect) if (fLastCount == 0) itemString << B_TRANSLATE("no items"); else { - BMessageFormat().Format(itemString, B_TRANSLATE_COMMENT( + static BMessageFormat format(B_TRANSLATE_COMMENT( "{0, plural, one{# item} other{# items}}", - "Number of selected items: \"1 item\" or \"2 items\""), - fLastCount); + "Number of selected items: \"1 item\" or \"2 items\"")); + format.Format(itemString, fLastCount); } } diff --git a/src/kits/tracker/InfoWindow.cpp b/src/kits/tracker/InfoWindow.cpp index 0e311e5758..72036a0b44 100644 --- a/src/kits/tracker/InfoWindow.cpp +++ b/src/kits/tracker/InfoWindow.cpp @@ -675,23 +675,25 @@ BInfoWindow::MessageReceived(BMessage* message) void BInfoWindow::GetSizeString(BString &result, off_t size, int32 fileCount) { - char sizeBuffer[128]; - BMessageFormat messageFormat; + static BMessageFormat sizeFormat(B_TRANSLATE( + "{0, plural, one{(# byte)} other{(# bytes)}}")); + static BMessageFormat countFormat(B_TRANSLATE( + "{0, plural, one{for # file} other{for # files}}")); + char sizeBuffer[128]; result << string_for_size((double)size, sizeBuffer, sizeof(sizeBuffer)); if (size >= kKBSize) { result << " "; - messageFormat.Format(result, B_TRANSLATE( - "{0, plural, one{(# byte)} other{(# bytes)}}"), size); + + sizeFormat.Format(result, size); // "bytes" translation could come from string_for_size // which could be part of the localekit itself } if (fileCount != 0) { result << " "; - messageFormat.Format(result, B_TRANSLATE( - "{0, plural, one{for # file} other{for # files}}"), fileCount); + countFormat.Format(result, fileCount); } } diff --git a/src/servers/mail/DeskbarView.cpp b/src/servers/mail/DeskbarView.cpp index 520c5b9482..33117a95cd 100644 --- a/src/servers/mail/DeskbarView.cpp +++ b/src/servers/mail/DeskbarView.cpp @@ -542,10 +542,10 @@ DeskbarView::_BuildMenu() // The New E-mail query if (fNewMessages > 0) { + static BMessageFormat format(B_TRANSLATE( + "{0, plural, one{# new message} other{# new messages}}")); BString string; - BMessageFormat().Format(string, B_TRANSLATE( - "{0, plural, one{# new message} other{# new messages}}"), - fNewMessages); + format.Format(string, fNewMessages); _GetNewQueryRef(ref); diff --git a/src/servers/mail/MailDaemon.cpp b/src/servers/mail/MailDaemon.cpp index f1e5dab4b6..cdad239091 100644 --- a/src/servers/mail/MailDaemon.cpp +++ b/src/servers/mail/MailDaemon.cpp @@ -178,9 +178,10 @@ MailDaemonApp::ReadyToRun() BString string; if (fNewMessages > 0) { - BMessageFormat().Format(string, B_TRANSLATE( - "{0, plural, one{# new message} other{# new messages}}"), - fNewMessages); + static BMessageFormat format(B_TRANSLATE( + "{0, plural, one{# new message} other{# new messages}}")); + + format.Format(string, fNewMessages); } else string = B_TRANSLATE("No new messages"); @@ -344,11 +345,12 @@ MailDaemonApp::MessageReceived(BMessage* msg) case 'numg': { - int32 numMessages = msg->FindInt32("num_messages"); - BMessageFormat().Format(fAlertString, B_TRANSLATE( - "{0, plural, one{# new message} other{# new messages}} " - "for %name\n"), numMessages); + static BMessageFormat format(B_TRANSLATE("{0, plural, " + "one{# new message} other{# new messages}} for %name\n")); + int32 numMessages = msg->FindInt32("num_messages"); + fAlertString.Truncate(0); + format.Format(fAlertString, numMessages); fAlertString.ReplaceFirst("%name", msg->FindString("name")); break; } @@ -369,9 +371,9 @@ MailDaemonApp::MessageReceived(BMessage* msg) BString string; if (fNewMessages > 0) { - BMessageFormat().Format(string, B_TRANSLATE( - "{0, plural, one{# new message.} other{# new messages.}}"), - fNewMessages); + static BMessageFormat format(B_TRANSLATE( + "{0, plural, one{# new message.} other{# new messages.}}")); + format.Format(string, fNewMessages); } else string << B_TRANSLATE("No new messages."); diff --git a/src/tests/kits/locale/MessageFormatTest.cpp b/src/tests/kits/locale/MessageFormatTest.cpp index 65407cb76c..e91b5f07fd 100644 --- a/src/tests/kits/locale/MessageFormatTest.cpp +++ b/src/tests/kits/locale/MessageFormatTest.cpp @@ -27,7 +27,6 @@ void MessageFormatTest::TestFormat() { BString output; - BMessageFormat formatter; struct Test { const char* locale; @@ -55,9 +54,10 @@ MessageFormatTest::TestFormat() NextSubTest(); output.Truncate(0); BLanguage language(tests[i].locale); + BMessageFormat formatter(tests[i].pattern); formatter.SetLanguage(language); - result = formatter.Format(output, tests[i].pattern, tests[i].number); + result = formatter.Format(output, tests[i].number); CPPUNIT_ASSERT_EQUAL(B_OK, result); CPPUNIT_ASSERT_EQUAL(BString(tests[i].expected), output); }