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.
5 #include "base/i18n/message_formatter.h"
9 #include "base/i18n/rtl.h"
10 #include "base/i18n/unicodestring.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/icu/source/common/unicode/unistr.h"
17 #include "third_party/icu/source/i18n/unicode/datefmt.h"
18 #include "third_party/icu/source/i18n/unicode/msgfmt.h"
20 typedef testing::Test MessageFormatterTest;
25 class MessageFormatterTest : public testing::Test {
27 MessageFormatterTest() {
28 original_locale_ = GetConfiguredLocale();
29 SetICUDefaultLocale("en-US");
31 ~MessageFormatterTest() override {
32 SetICUDefaultLocale(original_locale_);
36 std::string original_locale_;
41 void AppendFormattedDateTime(const std::unique_ptr<icu::DateFormat>& df,
43 std::u16string* result) {
44 icu::UnicodeString formatted;
45 result->append(UnicodeStringToString16(df->format(
46 static_cast<UDate>(now.InMillisecondsFSinceUnixEpoch()), formatted)));
51 TEST_F(MessageFormatterTest, PluralNamedArgs) {
52 const std::u16string pattern =
53 u"{num_people, plural, "
54 u"=0 {I met nobody in {place}.}"
55 u"=1 {I met a person in {place}.}"
56 u"other {I met # people in {place}.}}";
58 std::u16string result = MessageFormatter::FormatWithNamedArgs(
59 pattern, "num_people", 0, "place", "Paris");
60 EXPECT_EQ(u"I met nobody in Paris.", result);
61 result = MessageFormatter::FormatWithNamedArgs(pattern, "num_people", 1,
63 EXPECT_EQ(u"I met a person in Paris.", result);
64 result = MessageFormatter::FormatWithNamedArgs(pattern, "num_people", 5,
66 EXPECT_EQ(u"I met 5 people in Paris.", result);
69 TEST_F(MessageFormatterTest, PluralNamedArgsWithOffset) {
70 const std::u16string pattern =
71 u"{num_people, plural, offset:1 "
72 u"=0 {I met nobody in {place}.}"
73 u"=1 {I met {person} in {place}.}"
74 u"=2 {I met {person} and one other person in {place}.}"
75 u"=13 {I met {person} and a dozen other people in {place}.}"
76 u"other {I met {person} and # other people in {place}.}}";
78 std::u16string result = MessageFormatter::FormatWithNamedArgs(
79 pattern, "num_people", 0, "place", "Paris");
80 EXPECT_EQ(u"I met nobody in Paris.", result);
81 // {person} is ignored if {num_people} is 0.
82 result = MessageFormatter::FormatWithNamedArgs(
83 pattern, "num_people", 0, "place", "Paris", "person", "Peter");
84 EXPECT_EQ(u"I met nobody in Paris.", result);
85 result = MessageFormatter::FormatWithNamedArgs(
86 pattern, "num_people", 1, "place", "Paris", "person", "Peter");
87 EXPECT_EQ(u"I met Peter in Paris.", result);
88 result = MessageFormatter::FormatWithNamedArgs(
89 pattern, "num_people", 2, "place", "Paris", "person", "Peter");
90 EXPECT_EQ(u"I met Peter and one other person in Paris.", result);
91 result = MessageFormatter::FormatWithNamedArgs(
92 pattern, "num_people", 13, "place", "Paris", "person", "Peter");
93 EXPECT_EQ(u"I met Peter and a dozen other people in Paris.", result);
94 result = MessageFormatter::FormatWithNamedArgs(
95 pattern, "num_people", 50, "place", "Paris", "person", "Peter");
96 EXPECT_EQ(u"I met Peter and 49 other people in Paris.", result);
99 TEST_F(MessageFormatterTest, PluralNumberedArgs) {
100 const std::u16string pattern =
102 u"=1 {The cert for {0} expired yesterday.}"
103 u"=7 {The cert for {0} expired a week ago.}"
104 u"other {The cert for {0} expired # days ago.}}";
106 std::u16string result =
107 MessageFormatter::FormatWithNumberedArgs(pattern, "example.com", 1);
108 EXPECT_EQ(u"The cert for example.com expired yesterday.", result);
109 result = MessageFormatter::FormatWithNumberedArgs(pattern, "example.com", 7);
110 EXPECT_EQ(u"The cert for example.com expired a week ago.", result);
111 result = MessageFormatter::FormatWithNumberedArgs(pattern, "example.com", 15);
112 EXPECT_EQ(u"The cert for example.com expired 15 days ago.", result);
115 TEST_F(MessageFormatterTest, PluralNumberedArgsWithDate) {
116 const std::u16string pattern =
118 u"=1 {The cert for {0} expired yesterday. Today is {2,date,full}}"
119 u"other {The cert for {0} expired # days ago. Today is {2,date,full}}}";
121 base::Time now = base::Time::Now();
122 using icu::DateFormat;
123 std::unique_ptr<DateFormat> df(
124 DateFormat::createDateInstance(DateFormat::FULL));
125 std::u16string second_sentence = u" Today is ";
126 AppendFormattedDateTime(df, now, &second_sentence);
128 std::u16string result =
129 MessageFormatter::FormatWithNumberedArgs(pattern, "example.com", 1, now);
130 EXPECT_EQ(u"The cert for example.com expired yesterday." + second_sentence,
133 MessageFormatter::FormatWithNumberedArgs(pattern, "example.com", 15, now);
134 EXPECT_EQ(u"The cert for example.com expired 15 days ago." + second_sentence,
138 TEST_F(MessageFormatterTest, DateTimeAndNumber) {
139 // Note that using 'mph' for all locales is not a good i18n practice.
140 const std::u16string pattern =
141 u"At {0,time, short} on {0,date, medium}, "
142 u"there was {1} at building {2,number,integer}. "
143 u"The speed of the wind was {3,number,###.#} mph.";
145 using icu::DateFormat;
146 std::unique_ptr<DateFormat> tf(
147 DateFormat::createTimeInstance(DateFormat::SHORT));
148 std::unique_ptr<DateFormat> df(
149 DateFormat::createDateInstance(DateFormat::MEDIUM));
151 base::Time now = base::Time::Now();
152 std::u16string expected = u"At ";
153 AppendFormattedDateTime(tf, now, &expected);
154 expected.append(u" on ");
155 AppendFormattedDateTime(df, now, &expected);
157 u", there was an explosion at building 3. "
158 "The speed of the wind was 37.4 mph.");
160 EXPECT_EQ(expected, MessageFormatter::FormatWithNumberedArgs(
161 pattern, now, "an explosion", 3, 37.413));
164 TEST_F(MessageFormatterTest, SelectorSingleOrMultiple) {
165 const std::u16string pattern =
167 u"single {Select a file to upload.}"
168 u"multiple {Select files to upload.}"
171 std::u16string result =
172 MessageFormatter::FormatWithNumberedArgs(pattern, "single");
173 EXPECT_EQ(u"Select a file to upload.", result);
174 result = MessageFormatter::FormatWithNumberedArgs(pattern, "multiple");
175 EXPECT_EQ(u"Select files to upload.", result);
177 // fallback if a parameter is not selectors specified in the message pattern.
178 result = MessageFormatter::FormatWithNumberedArgs(pattern, "foobar");
179 EXPECT_EQ(u"UNUSED", result);