Add custom_tabs_client to third_party.
[chromium-blink-merge.git] / ui / base / l10n / formatter.cc
blob7f719330459173e195f656ff7c35d248cfee2419
1 // Copyright 2014 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.
5 #include "ui/base/l10n/formatter.h"
7 #include <vector>
9 #include "base/logging.h"
10 #include "third_party/icu/source/common/unicode/unistr.h"
11 #include "third_party/icu/source/i18n/unicode/msgfmt.h"
12 #include "ui/base/l10n/l10n_util.h"
13 #include "ui/base/l10n/l10n_util_plurals.h"
14 #include "ui/strings/grit/ui_strings.h"
16 namespace ui {
18 UI_BASE_EXPORT bool formatter_force_fallback = false;
20 struct Pluralities {
21 int id;
22 const char* const fallback_one;
23 const char* const fallback_other;
26 static const Pluralities IDS_ELAPSED_SHORT_SEC = {
27 IDS_TIME_ELAPSED_SECS,
28 "one{# sec ago}",
29 " other{# secs ago}"
31 static const Pluralities IDS_ELAPSED_SHORT_MIN = {
32 IDS_TIME_ELAPSED_MINS,
33 "one{# min ago}",
34 " other{# mins ago}"
36 static const Pluralities IDS_ELAPSED_HOUR = {
37 IDS_TIME_ELAPSED_HOURS,
38 "one{# hour ago}",
39 " other{# hours ago}"
41 static const Pluralities IDS_ELAPSED_DAY = {
42 IDS_TIME_ELAPSED_DAYS,
43 "one{# day ago}",
44 " other{# days ago}"
47 static const Pluralities IDS_REMAINING_SHORT_SEC = {
48 IDS_TIME_REMAINING_SECS,
49 "one{# sec left}",
50 " other{# secs left}"
52 static const Pluralities IDS_REMAINING_SHORT_MIN = {
53 IDS_TIME_REMAINING_MINS,
54 "one{# min left}",
55 " other{# mins left}"
58 static const Pluralities IDS_REMAINING_LONG_SEC = {
59 IDS_TIME_REMAINING_LONG_SECS,
60 "one{# second left}",
61 " other{# seconds left}"
63 static const Pluralities IDS_REMAINING_LONG_MIN = {
64 IDS_TIME_REMAINING_LONG_MINS,
65 "one{# minute left}",
66 " other{# minutes left}"
68 static const Pluralities IDS_REMAINING_HOUR = {
69 IDS_TIME_REMAINING_HOURS,
70 "one{# hour left}",
71 " other{# hours left}"
73 static const Pluralities IDS_REMAINING_DAY = {
74 IDS_TIME_REMAINING_DAYS,
75 "one{# day left}",
76 " other{# days left}"
79 static const Pluralities IDS_DURATION_SHORT_SEC = {
80 IDS_TIME_SECS,
81 "one{# sec}",
82 " other{# secs}"
84 static const Pluralities IDS_DURATION_SHORT_MIN = {
85 IDS_TIME_MINS,
86 "one{# min}",
87 " other{# mins}"
90 static const Pluralities IDS_LONG_SEC = {
91 IDS_TIME_LONG_SECS,
92 "one{# second}",
93 " other{# seconds}"
95 static const Pluralities IDS_LONG_MIN = {
96 IDS_TIME_LONG_MINS,
97 "one{# minute}",
98 " other{# minutes}"
100 static const Pluralities IDS_DURATION_HOUR = {
101 IDS_TIME_HOURS,
102 "one{# hour}",
103 " other{# hours}"
105 static const Pluralities IDS_DURATION_DAY = {
106 IDS_TIME_DAYS,
107 "one{# day}",
108 " other{# days}"
111 static const Pluralities IDS_LONG_MIN_1ST = {
112 IDS_TIME_LONG_MINS_1ST,
113 "one{# minute and }",
114 " other{# minutes and }"
116 static const Pluralities IDS_LONG_SEC_2ND = {
117 IDS_TIME_LONG_SECS_2ND,
118 "one{# second}",
119 " other{# seconds}"
121 static const Pluralities IDS_DURATION_HOUR_1ST = {
122 IDS_TIME_HOURS_1ST,
123 "one{# hour and }",
124 " other{# hours and }"
126 static const Pluralities IDS_LONG_MIN_2ND = {
127 IDS_TIME_LONG_MINS_2ND,
128 "one{# minute}",
129 " other{# minutes}"
131 static const Pluralities IDS_DURATION_DAY_1ST = {
132 IDS_TIME_DAYS_1ST,
133 "one{# day and }",
134 " other{# days and }"
136 static const Pluralities IDS_DURATION_HOUR_2ND = {
137 IDS_TIME_HOURS_2ND,
138 "one{# hour}",
139 " other{# hours}"
142 Formatter::Formatter(const Pluralities& sec_pluralities,
143 const Pluralities& min_pluralities,
144 const Pluralities& hour_pluralities,
145 const Pluralities& day_pluralities) {
146 simple_format_[UNIT_SEC] = InitFormat(sec_pluralities);
147 simple_format_[UNIT_MIN] = InitFormat(min_pluralities);
148 simple_format_[UNIT_HOUR] = InitFormat(hour_pluralities);
149 simple_format_[UNIT_DAY] = InitFormat(day_pluralities);
152 Formatter::Formatter(const Pluralities& sec_pluralities,
153 const Pluralities& min_pluralities,
154 const Pluralities& hour_pluralities,
155 const Pluralities& day_pluralities,
156 const Pluralities& min_sec_pluralities1,
157 const Pluralities& min_sec_pluralities2,
158 const Pluralities& hour_min_pluralities1,
159 const Pluralities& hour_min_pluralities2,
160 const Pluralities& day_hour_pluralities1,
161 const Pluralities& day_hour_pluralities2) {
162 simple_format_[UNIT_SEC] = InitFormat(sec_pluralities);
163 simple_format_[UNIT_MIN] = InitFormat(min_pluralities);
164 simple_format_[UNIT_HOUR] = InitFormat(hour_pluralities);
165 simple_format_[UNIT_DAY] = InitFormat(day_pluralities);
166 detailed_format_[TWO_UNITS_MIN_SEC][0] = InitFormat(min_sec_pluralities1);
167 detailed_format_[TWO_UNITS_MIN_SEC][1] = InitFormat(min_sec_pluralities2);
168 detailed_format_[TWO_UNITS_HOUR_MIN][0] = InitFormat(hour_min_pluralities1);
169 detailed_format_[TWO_UNITS_HOUR_MIN][1] = InitFormat(hour_min_pluralities2);
170 detailed_format_[TWO_UNITS_DAY_HOUR][0] = InitFormat(day_hour_pluralities1);
171 detailed_format_[TWO_UNITS_DAY_HOUR][1] = InitFormat(day_hour_pluralities2);
174 void Formatter::Format(Unit unit,
175 int value,
176 icu::UnicodeString* formatted_string) const {
177 DCHECK(simple_format_[unit]);
178 DCHECK(formatted_string->isEmpty() == TRUE);
179 UErrorCode error = U_ZERO_ERROR;
180 l10n_util::FormatNumberInPlural(*simple_format_[unit],
181 value, formatted_string, &error);
182 DCHECK(U_SUCCESS(error)) << "Error in icu::PluralFormat::format().";
183 return;
186 void Formatter::Format(TwoUnits units,
187 int value_1,
188 int value_2,
189 icu::UnicodeString* formatted_string) const {
190 DCHECK(detailed_format_[units][0])
191 << "Detailed() not implemented for your (format, length) combination!";
192 DCHECK(detailed_format_[units][1])
193 << "Detailed() not implemented for your (format, length) combination!";
194 DCHECK(formatted_string->isEmpty() == TRUE);
195 UErrorCode error = U_ZERO_ERROR;
196 l10n_util::FormatNumberInPlural(*detailed_format_[units][0], value_1,
197 formatted_string, &error);
198 DCHECK(U_SUCCESS(error));
199 l10n_util::FormatNumberInPlural(*detailed_format_[units][1], value_2,
200 formatted_string, &error);
201 DCHECK(U_SUCCESS(error));
202 return;
205 scoped_ptr<icu::MessageFormat> Formatter::CreateFallbackFormat(
206 const icu::PluralRules& rules,
207 const Pluralities& pluralities) const {
208 icu::UnicodeString pattern("{NUMBER, plural, ");
209 if (rules.isKeyword(UNICODE_STRING_SIMPLE("one")))
210 pattern += icu::UnicodeString(pluralities.fallback_one);
211 pattern += icu::UnicodeString(pluralities.fallback_other);
212 pattern.append(UChar(0x7du)); // "}" = U+007D
214 UErrorCode error = U_ZERO_ERROR;
215 scoped_ptr<icu::MessageFormat> format(
216 new icu::MessageFormat(pattern, error));
217 DCHECK(U_SUCCESS(error));
218 return format.Pass();
221 scoped_ptr<icu::MessageFormat> Formatter::InitFormat(
222 const Pluralities& pluralities) {
223 if (!formatter_force_fallback) {
224 base::string16 pattern = l10n_util::GetStringUTF16(pluralities.id);
225 UErrorCode error = U_ZERO_ERROR;
226 scoped_ptr<icu::MessageFormat> format(new icu::MessageFormat(
227 icu::UnicodeString(FALSE, pattern.data(), pattern.length()), error));
228 DCHECK(U_SUCCESS(error));
229 if (format.get())
230 return format.Pass();
233 scoped_ptr<icu::PluralRules> rules(l10n_util::BuildPluralRules());
234 return CreateFallbackFormat(*rules, pluralities);
237 const Formatter* FormatterContainer::Get(TimeFormat::Format format,
238 TimeFormat::Length length) const {
239 DCHECK(formatter_[format][length])
240 << "Combination of FORMAT_ELAPSED and LENGTH_LONG is not implemented!";
241 return formatter_[format][length].get();
244 FormatterContainer::FormatterContainer() {
245 Initialize();
248 FormatterContainer::~FormatterContainer() {
251 void FormatterContainer::Initialize() {
252 formatter_[TimeFormat::FORMAT_ELAPSED][TimeFormat::LENGTH_SHORT].reset(
253 new Formatter(IDS_ELAPSED_SHORT_SEC,
254 IDS_ELAPSED_SHORT_MIN,
255 IDS_ELAPSED_HOUR,
256 IDS_ELAPSED_DAY));
257 formatter_[TimeFormat::FORMAT_ELAPSED][TimeFormat::LENGTH_LONG].reset();
258 formatter_[TimeFormat::FORMAT_REMAINING][TimeFormat::LENGTH_SHORT].reset(
259 new Formatter(IDS_REMAINING_SHORT_SEC,
260 IDS_REMAINING_SHORT_MIN,
261 IDS_REMAINING_HOUR,
262 IDS_REMAINING_DAY));
263 formatter_[TimeFormat::FORMAT_REMAINING][TimeFormat::LENGTH_LONG].reset(
264 new Formatter(IDS_REMAINING_LONG_SEC,
265 IDS_REMAINING_LONG_MIN,
266 IDS_REMAINING_HOUR,
267 IDS_REMAINING_DAY));
268 formatter_[TimeFormat::FORMAT_DURATION][TimeFormat::LENGTH_SHORT].reset(
269 new Formatter(IDS_DURATION_SHORT_SEC,
270 IDS_DURATION_SHORT_MIN,
271 IDS_DURATION_HOUR,
272 IDS_DURATION_DAY));
273 formatter_[TimeFormat::FORMAT_DURATION][TimeFormat::LENGTH_LONG].reset(
274 new Formatter(IDS_LONG_SEC,
275 IDS_LONG_MIN,
276 IDS_DURATION_HOUR,
277 IDS_DURATION_DAY,
278 IDS_LONG_MIN_1ST,
279 IDS_LONG_SEC_2ND,
280 IDS_DURATION_HOUR_1ST,
281 IDS_LONG_MIN_2ND,
282 IDS_DURATION_DAY_1ST,
283 IDS_DURATION_HOUR_2ND));
286 void FormatterContainer::Shutdown() {
287 for (int format = 0; format < TimeFormat::FORMAT_COUNT; ++format) {
288 for (int length = 0; length < TimeFormat::LENGTH_COUNT; ++length) {
289 formatter_[format][length].reset();
294 } // namespace ui