From 0da7796e6c95de168ac77151a520c853c120a968 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 7 Oct 2014 08:51:23 +0200 Subject: [PATCH] Add BMessageFormat class. This can be used to format complex messages properly. It moves the complexity of handling plural forms, gender, and anything else needed into the localizable string, rather than hardcoding it in the code. This moves the difficulty of handling these things properly to people doing translations, rather than relying on developers to do it. Fixes #10755, but our localization must now be updated to make use of the feature. --- headers/os/locale/MessageFormat.h | 19 +++++ src/kits/locale/Jamfile | 1 + src/kits/locale/MessageFormat.cpp | 41 +++++++++++ src/tests/kits/locale/Jamfile | 1 + src/tests/kits/locale/LocaleKitTestAddon.cpp | 2 + src/tests/kits/locale/MessageFormatTest.cpp | 76 ++++++++++++++++++++ src/tests/kits/locale/MessageFormatTest.h | 24 +++++++ 7 files changed, 164 insertions(+) create mode 100644 headers/os/locale/MessageFormat.h create mode 100644 src/kits/locale/MessageFormat.cpp create mode 100644 src/tests/kits/locale/MessageFormatTest.cpp create mode 100644 src/tests/kits/locale/MessageFormatTest.h diff --git a/headers/os/locale/MessageFormat.h b/headers/os/locale/MessageFormat.h new file mode 100644 index 0000000000..ff2a9c2d84 --- /dev/null +++ b/headers/os/locale/MessageFormat.h @@ -0,0 +1,19 @@ +/* + * Copyright 2014, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _B_MESSAGE_FORMAT_H_ +#define _B_MESSAGE_FORMAT_H_ + + +#include + + +class BMessageFormat: public BFormat { +public: + status_t Format(BString& buffer, const BString message, + const int32 arg); +}; + + +#endif diff --git a/src/kits/locale/Jamfile b/src/kits/locale/Jamfile index 5b3f509eff..c21abbaaf8 100644 --- a/src/kits/locale/Jamfile +++ b/src/kits/locale/Jamfile @@ -27,6 +27,7 @@ local sources = DateFormat.cpp DateTimeFormat.cpp DurationFormat.cpp + MessageFormat.cpp NumberFormat.cpp TimeFormat.cpp TimeUnitFormat.cpp diff --git a/src/kits/locale/MessageFormat.cpp b/src/kits/locale/MessageFormat.cpp new file mode 100644 index 0000000000..b5af3eca36 --- /dev/null +++ b/src/kits/locale/MessageFormat.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2014, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#include + +#include +#include + +#include + +#include + + +status_t +BMessageFormat::Format(BString& output, const BString message, const int32 arg) +{ + UnicodeString buffer; + UErrorCode error = U_ZERO_ERROR; + + Formattable arguments[] = { + (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); + if (!U_SUCCESS(error)) + return B_ERROR; + + BStringByteSink byteSink(&output); + buffer.toUTF8(byteSink); + + return B_OK; +} diff --git a/src/tests/kits/locale/Jamfile b/src/tests/kits/locale/Jamfile index af5166c2c1..2fd68b621f 100644 --- a/src/tests/kits/locale/Jamfile +++ b/src/tests/kits/locale/Jamfile @@ -52,6 +52,7 @@ UnitTestLib localekittest.so : DateFormatTest.cpp DurationFormatTest.cpp LanguageTest.cpp + MessageFormatTest.cpp UnicodeCharTest.cpp : be [ TargetLibstdc++ ] diff --git a/src/tests/kits/locale/LocaleKitTestAddon.cpp b/src/tests/kits/locale/LocaleKitTestAddon.cpp index 460f32f725..2d04a79b97 100644 --- a/src/tests/kits/locale/LocaleKitTestAddon.cpp +++ b/src/tests/kits/locale/LocaleKitTestAddon.cpp @@ -11,6 +11,7 @@ #include "DateFormatTest.h" #include "DurationFormatTest.h" #include "LanguageTest.h" +#include "MessageFormatTest.h" #include "UnicodeCharTest.h" @@ -23,6 +24,7 @@ getTestSuite() DateFormatTest::AddTests(*suite); DurationFormatTest::AddTests(*suite); LanguageTest::AddTests(*suite); + MessageFormatTest::AddTests(*suite); UnicodeCharTest::AddTests(*suite); return suite; diff --git a/src/tests/kits/locale/MessageFormatTest.cpp b/src/tests/kits/locale/MessageFormatTest.cpp new file mode 100644 index 0000000000..65407cb76c --- /dev/null +++ b/src/tests/kits/locale/MessageFormatTest.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2014 Haiku, Inc. + * Distributed under the terms of the MIT License. + */ + + +#include "MessageFormatTest.h" + +#include +#include + +#include +#include + + +MessageFormatTest::MessageFormatTest() +{ +} + + +MessageFormatTest::~MessageFormatTest() +{ +} + + +void +MessageFormatTest::TestFormat() +{ + BString output; + BMessageFormat formatter; + + struct Test { + const char* locale; + const char* pattern; + int32 number; + const char* expected; + }; + + static const char* polishTemplate = "{0, plural, one{Wybrano # obiekt} " + "few{Wybrano # obiekty} many{Wybrano # obiektów} " + "other{Wybrano # obyektu}}"; + + static const Test tests[] = { + {"en_US", "{0, plural, one{# dog} other{# dogs}}", 1, "1 dog"}, + {"en_US", "{0, plural, one{# dog} other{# dogs}}", 2, "2 dogs"}, + {"pl_PL", polishTemplate, 1, "Wybrano 1 obiekt"}, + {"pl_PL", polishTemplate, 3, "Wybrano 3 obyektu"}, + {"pl_PL", polishTemplate, 5, "Wybrano 5 obyektu"}, + {"pl_PL", polishTemplate, 23, "Wybrano 23 obyektu"}, + {NULL, NULL, 0, NULL} + }; + + for (int i = 0; tests[i].pattern != NULL; i++) { + status_t result; + NextSubTest(); + output.Truncate(0); + BLanguage language(tests[i].locale); + formatter.SetLanguage(language); + + result = formatter.Format(output, tests[i].pattern, tests[i].number); + CPPUNIT_ASSERT_EQUAL(B_OK, result); + CPPUNIT_ASSERT_EQUAL(BString(tests[i].expected), output); + } +} + + +/*static*/ void +MessageFormatTest::AddTests(BTestSuite& parent) +{ + CppUnit::TestSuite& suite = *new CppUnit::TestSuite("MessageFormatTest"); + + suite.addTest(new CppUnit::TestCaller( + "MessageFormatTest::TestFormat", &MessageFormatTest::TestFormat)); + + parent.addTest("MessageFormatTest", &suite); +} diff --git a/src/tests/kits/locale/MessageFormatTest.h b/src/tests/kits/locale/MessageFormatTest.h new file mode 100644 index 0000000000..924f679623 --- /dev/null +++ b/src/tests/kits/locale/MessageFormatTest.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef MESSAGE_FORMAT_TEST_H +#define MESSAGE_FORMAT_TEST_H + + +#include +#include + + +class MessageFormatTest: public BTestCase { +public: + MessageFormatTest(); + virtual ~MessageFormatTest(); + + void TestFormat(); + + static void AddTests(BTestSuite& suite); +}; + + +#endif