message_formatter_unittest.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/i18n/message_formatter.h"
  5. #include <memory>
  6. #include "base/i18n/rtl.h"
  7. #include "base/strings/string_piece.h"
  8. #include "base/strings/string_util.h"
  9. #include "base/strings/utf_string_conversions.h"
  10. #include "base/time/time.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "third_party/icu/source/common/unicode/unistr.h"
  13. #include "third_party/icu/source/i18n/unicode/datefmt.h"
  14. #include "third_party/icu/source/i18n/unicode/msgfmt.h"
  15. typedef testing::Test MessageFormatterTest;
  16. namespace base {
  17. namespace i18n {
  18. class MessageFormatterTest : public testing::Test {
  19. protected:
  20. MessageFormatterTest() {
  21. original_locale_ = GetConfiguredLocale();
  22. SetICUDefaultLocale("en-US");
  23. }
  24. ~MessageFormatterTest() override {
  25. SetICUDefaultLocale(original_locale_);
  26. }
  27. private:
  28. std::string original_locale_;
  29. };
  30. namespace {
  31. void AppendFormattedDateTime(const std::unique_ptr<icu::DateFormat>& df,
  32. const Time& now,
  33. std::string* result) {
  34. icu::UnicodeString formatted;
  35. df->format(static_cast<UDate>(now.ToJsTime()), formatted).
  36. toUTF8String(*result);
  37. }
  38. } // namespace
  39. TEST_F(MessageFormatterTest, PluralNamedArgs) {
  40. const std::u16string pattern =
  41. u"{num_people, plural, "
  42. u"=0 {I met nobody in {place}.}"
  43. u"=1 {I met a person in {place}.}"
  44. u"other {I met # people in {place}.}}";
  45. std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  46. pattern, "num_people", 0, "place", "Paris"));
  47. EXPECT_EQ("I met nobody in Paris.", result);
  48. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  49. pattern, "num_people", 1, "place", "Paris"));
  50. EXPECT_EQ("I met a person in Paris.", result);
  51. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  52. pattern, "num_people", 5, "place", "Paris"));
  53. EXPECT_EQ("I met 5 people in Paris.", result);
  54. }
  55. TEST_F(MessageFormatterTest, PluralNamedArgsWithOffset) {
  56. const std::u16string pattern =
  57. u"{num_people, plural, offset:1 "
  58. u"=0 {I met nobody in {place}.}"
  59. u"=1 {I met {person} in {place}.}"
  60. u"=2 {I met {person} and one other person in {place}.}"
  61. u"=13 {I met {person} and a dozen other people in {place}.}"
  62. u"other {I met {person} and # other people in {place}.}}";
  63. std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  64. pattern, "num_people", 0, "place", "Paris"));
  65. EXPECT_EQ("I met nobody in Paris.", result);
  66. // {person} is ignored if {num_people} is 0.
  67. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  68. pattern, "num_people", 0, "place", "Paris", "person", "Peter"));
  69. EXPECT_EQ("I met nobody in Paris.", result);
  70. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  71. pattern, "num_people", 1, "place", "Paris", "person", "Peter"));
  72. EXPECT_EQ("I met Peter in Paris.", result);
  73. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  74. pattern, "num_people", 2, "place", "Paris", "person", "Peter"));
  75. EXPECT_EQ("I met Peter and one other person in Paris.", result);
  76. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  77. pattern, "num_people", 13, "place", "Paris", "person", "Peter"));
  78. EXPECT_EQ("I met Peter and a dozen other people in Paris.", result);
  79. result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
  80. pattern, "num_people", 50, "place", "Paris", "person", "Peter"));
  81. EXPECT_EQ("I met Peter and 49 other people in Paris.", result);
  82. }
  83. TEST_F(MessageFormatterTest, PluralNumberedArgs) {
  84. const std::u16string pattern =
  85. u"{1, plural, "
  86. u"=1 {The cert for {0} expired yesterday.}"
  87. u"=7 {The cert for {0} expired a week ago.}"
  88. u"other {The cert for {0} expired # days ago.}}";
  89. std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  90. pattern, "example.com", 1));
  91. EXPECT_EQ("The cert for example.com expired yesterday.", result);
  92. result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  93. pattern, "example.com", 7));
  94. EXPECT_EQ("The cert for example.com expired a week ago.", result);
  95. result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  96. pattern, "example.com", 15));
  97. EXPECT_EQ("The cert for example.com expired 15 days ago.", result);
  98. }
  99. TEST_F(MessageFormatterTest, PluralNumberedArgsWithDate) {
  100. const std::u16string pattern =
  101. u"{1, plural, "
  102. u"=1 {The cert for {0} expired yesterday. Today is {2,date,full}}"
  103. u"other {The cert for {0} expired # days ago. Today is {2,date,full}}}";
  104. base::Time now = base::Time::Now();
  105. using icu::DateFormat;
  106. std::unique_ptr<DateFormat> df(
  107. DateFormat::createDateInstance(DateFormat::FULL));
  108. std::string second_sentence = " Today is ";
  109. AppendFormattedDateTime(df, now, &second_sentence);
  110. std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  111. pattern, "example.com", 1, now));
  112. EXPECT_EQ("The cert for example.com expired yesterday." + second_sentence,
  113. result);
  114. result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  115. pattern, "example.com", 15, now));
  116. EXPECT_EQ("The cert for example.com expired 15 days ago." + second_sentence,
  117. result);
  118. }
  119. TEST_F(MessageFormatterTest, DateTimeAndNumber) {
  120. // Note that using 'mph' for all locales is not a good i18n practice.
  121. const std::u16string pattern =
  122. u"At {0,time, short} on {0,date, medium}, "
  123. u"there was {1} at building {2,number,integer}. "
  124. u"The speed of the wind was {3,number,###.#} mph.";
  125. using icu::DateFormat;
  126. std::unique_ptr<DateFormat> tf(
  127. DateFormat::createTimeInstance(DateFormat::SHORT));
  128. std::unique_ptr<DateFormat> df(
  129. DateFormat::createDateInstance(DateFormat::MEDIUM));
  130. base::Time now = base::Time::Now();
  131. std::string expected = "At ";
  132. AppendFormattedDateTime(tf, now, &expected);
  133. expected.append(" on ");
  134. AppendFormattedDateTime(df, now, &expected);
  135. expected.append(", there was an explosion at building 3. "
  136. "The speed of the wind was 37.4 mph.");
  137. EXPECT_EQ(expected, UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  138. pattern, now, "an explosion", 3, 37.413)));
  139. }
  140. TEST_F(MessageFormatterTest, SelectorSingleOrMultiple) {
  141. const std::u16string pattern =
  142. u"{0, select,"
  143. u"single {Select a file to upload.}"
  144. u"multiple {Select files to upload.}"
  145. u"other {UNUSED}}";
  146. std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  147. pattern, "single"));
  148. EXPECT_EQ("Select a file to upload.", result);
  149. result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  150. pattern, "multiple"));
  151. EXPECT_EQ("Select files to upload.", result);
  152. // fallback if a parameter is not selectors specified in the message pattern.
  153. result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
  154. pattern, "foobar"));
  155. EXPECT_EQ("UNUSED", result);
  156. }
  157. } // namespace i18n
  158. } // namespace base