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