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"
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"
18 UI_BASE_EXPORT
bool formatter_force_fallback
= false;
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
,
31 static const Pluralities IDS_ELAPSED_SHORT_MIN
= {
32 IDS_TIME_ELAPSED_MINS
,
36 static const Pluralities IDS_ELAPSED_HOUR
= {
37 IDS_TIME_ELAPSED_HOURS
,
41 static const Pluralities IDS_ELAPSED_DAY
= {
42 IDS_TIME_ELAPSED_DAYS
,
47 static const Pluralities IDS_REMAINING_SHORT_SEC
= {
48 IDS_TIME_REMAINING_SECS
,
52 static const Pluralities IDS_REMAINING_SHORT_MIN
= {
53 IDS_TIME_REMAINING_MINS
,
58 static const Pluralities IDS_REMAINING_LONG_SEC
= {
59 IDS_TIME_REMAINING_LONG_SECS
,
61 " other{# seconds left}"
63 static const Pluralities IDS_REMAINING_LONG_MIN
= {
64 IDS_TIME_REMAINING_LONG_MINS
,
66 " other{# minutes left}"
68 static const Pluralities IDS_REMAINING_HOUR
= {
69 IDS_TIME_REMAINING_HOURS
,
71 " other{# hours left}"
73 static const Pluralities IDS_REMAINING_DAY
= {
74 IDS_TIME_REMAINING_DAYS
,
79 static const Pluralities IDS_DURATION_SHORT_SEC
= {
84 static const Pluralities IDS_DURATION_SHORT_MIN
= {
90 static const Pluralities IDS_LONG_SEC
= {
95 static const Pluralities IDS_LONG_MIN
= {
100 static const Pluralities IDS_DURATION_HOUR
= {
105 static const Pluralities IDS_DURATION_DAY
= {
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
,
121 static const Pluralities IDS_DURATION_HOUR_1ST
= {
124 " other{# hours and }"
126 static const Pluralities IDS_LONG_MIN_2ND
= {
127 IDS_TIME_LONG_MINS_2ND
,
131 static const Pluralities IDS_DURATION_DAY_1ST
= {
134 " other{# days and }"
136 static const Pluralities IDS_DURATION_HOUR_2ND
= {
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
,
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().";
186 void Formatter::Format(TwoUnits units
,
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
));
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
));
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() {
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
,
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
,
263 formatter_
[TimeFormat::FORMAT_REMAINING
][TimeFormat::LENGTH_LONG
].reset(
264 new Formatter(IDS_REMAINING_LONG_SEC
,
265 IDS_REMAINING_LONG_MIN
,
268 formatter_
[TimeFormat::FORMAT_DURATION
][TimeFormat::LENGTH_SHORT
].reset(
269 new Formatter(IDS_DURATION_SHORT_SEC
,
270 IDS_DURATION_SHORT_MIN
,
273 formatter_
[TimeFormat::FORMAT_DURATION
][TimeFormat::LENGTH_LONG
].reset(
274 new Formatter(IDS_LONG_SEC
,
280 IDS_DURATION_HOUR_1ST
,
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();