OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "ui/base/l10n/formatter.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/logging.h" | |
10 #include "grit/ui_strings.h" | |
11 #include "third_party/icu/source/common/unicode/unistr.h" | |
12 #include "ui/base/l10n/l10n_util_plurals.h" | |
13 | |
14 namespace ui { | |
15 | |
16 // static | |
17 bool Formatter::force_fallback_ = false; | |
18 | |
19 static const size_t kNPluralities = 6; | |
bartfab (slow)
2014/02/20 16:31:23
Nit: Avoid abbreviations like "N" whenever possibl
Thiemo Nagel
2014/02/22 21:44:10
Done.
| |
20 struct Pluralities { | |
21 int Ids[kNPluralities]; | |
22 const char* fallback_one; | |
23 const char* fallback_other; | |
24 }; | |
25 | |
26 static const Pluralities IDS_ELAPSED_SHORT_SEC = { | |
27 { IDS_TIME_ELAPSED_SECS_DEFAULT, IDS_TIME_ELAPSED_SEC_SINGULAR, | |
28 IDS_TIME_ELAPSED_SECS_ZERO, IDS_TIME_ELAPSED_SECS_TWO, | |
29 IDS_TIME_ELAPSED_SECS_FEW, IDS_TIME_ELAPSED_SECS_MANY }, | |
30 "one{# sec ago}", | |
31 " other{# secs ago}" | |
32 }; | |
33 static const Pluralities IDS_ELAPSED_SHORT_MIN = { | |
34 { IDS_TIME_ELAPSED_MINS_DEFAULT, IDS_TIME_ELAPSED_MIN_SINGULAR, | |
35 IDS_TIME_ELAPSED_MINS_ZERO, IDS_TIME_ELAPSED_MINS_TWO, | |
36 IDS_TIME_ELAPSED_MINS_FEW, IDS_TIME_ELAPSED_MINS_MANY }, | |
37 "one{# min ago}", | |
38 " other{# mins ago}" | |
39 }; | |
40 static const Pluralities IDS_ELAPSED_HOUR = { | |
41 { IDS_TIME_ELAPSED_HOURS_DEFAULT, IDS_TIME_ELAPSED_HOUR_SINGULAR, | |
42 IDS_TIME_ELAPSED_HOURS_ZERO, IDS_TIME_ELAPSED_HOURS_TWO, | |
43 IDS_TIME_ELAPSED_HOURS_FEW, IDS_TIME_ELAPSED_HOURS_MANY }, | |
44 "one{# hour ago}", | |
45 " other{# hours ago}" | |
46 }; | |
47 static const Pluralities IDS_ELAPSED_DAY = { | |
48 { IDS_TIME_ELAPSED_DAYS_DEFAULT, IDS_TIME_ELAPSED_DAY_SINGULAR, | |
49 IDS_TIME_ELAPSED_DAYS_ZERO, IDS_TIME_ELAPSED_DAYS_TWO, | |
50 IDS_TIME_ELAPSED_DAYS_FEW, IDS_TIME_ELAPSED_DAYS_MANY }, | |
51 "one{# day ago}", | |
52 " other{# days ago}" | |
53 }; | |
54 | |
55 static const Pluralities IDS_REMAINING_SHORT_SEC = { | |
56 { IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SEC_SINGULAR, | |
57 IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO, | |
58 IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY }, | |
59 "one{# sec left}", | |
60 " other{# secs left}" | |
61 }; | |
62 static const Pluralities IDS_REMAINING_SHORT_MIN = { | |
63 { IDS_TIME_REMAINING_MINS_DEFAULT, IDS_TIME_REMAINING_MIN_SINGULAR, | |
64 IDS_TIME_REMAINING_MINS_ZERO, IDS_TIME_REMAINING_MINS_TWO, | |
65 IDS_TIME_REMAINING_MINS_FEW, IDS_TIME_REMAINING_MINS_MANY }, | |
66 "one{# min left}", | |
67 " other{# mins left}" | |
68 }; | |
69 | |
70 static const Pluralities IDS_REMAINING_LONG_SEC = { | |
71 { IDS_TIME_REMAINING_LONG_SECS_DEFAULT, IDS_TIME_REMAINING_LONG_SEC_SINGULAR, | |
72 IDS_TIME_REMAINING_LONG_SECS_ZERO, IDS_TIME_REMAINING_LONG_SECS_TWO, | |
73 IDS_TIME_REMAINING_LONG_SECS_FEW, IDS_TIME_REMAINING_LONG_SECS_MANY }, | |
74 "one{# second left}", | |
75 " other{# seconds left}" | |
76 }; | |
77 static const Pluralities IDS_REMAINING_LONG_MIN = { | |
78 { IDS_TIME_REMAINING_LONG_MINS_DEFAULT, IDS_TIME_REMAINING_LONG_MIN_SINGULAR, | |
79 IDS_TIME_REMAINING_LONG_MINS_ZERO, IDS_TIME_REMAINING_LONG_MINS_TWO, | |
80 IDS_TIME_REMAINING_LONG_MINS_FEW, IDS_TIME_REMAINING_LONG_MINS_MANY }, | |
81 "one{# minute left}", | |
82 " other{# minutes left}" | |
83 }; | |
84 static const Pluralities IDS_REMAINING_HOUR = { | |
85 { IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOUR_SINGULAR, | |
86 IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO, | |
87 IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY }, | |
88 "one{# hour left}", | |
89 " other{# hours left}" | |
90 }; | |
91 static const Pluralities IDS_REMAINING_DAY = { | |
92 { IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAY_SINGULAR, | |
93 IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO, | |
94 IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY }, | |
95 "one{# day left}", | |
96 " other{# days left}" | |
97 }; | |
98 | |
99 static const Pluralities IDS_DURATION_SHORT_SEC = { | |
100 { IDS_TIME_SECS_DEFAULT, IDS_TIME_SEC_SINGULAR, IDS_TIME_SECS_ZERO, | |
101 IDS_TIME_SECS_TWO, IDS_TIME_SECS_FEW, IDS_TIME_SECS_MANY }, | |
102 "one{# sec}", | |
103 " other{# secs}" | |
104 }; | |
105 static const Pluralities IDS_DURATION_SHORT_MIN = { | |
106 { IDS_TIME_MINS_DEFAULT, IDS_TIME_MIN_SINGULAR, IDS_TIME_MINS_ZERO, | |
107 IDS_TIME_MINS_TWO, IDS_TIME_MINS_FEW, IDS_TIME_MINS_MANY }, | |
108 "one{# min}", | |
109 " other{# mins}" | |
110 }; | |
111 | |
112 static const Pluralities IDS_LONG_SEC = { | |
113 { IDS_TIME_LONG_SECS_DEFAULT, IDS_TIME_LONG_SEC_SINGULAR, | |
114 IDS_TIME_LONG_SECS_ZERO, IDS_TIME_LONG_SECS_TWO, | |
115 IDS_TIME_LONG_SECS_FEW, IDS_TIME_LONG_SECS_MANY }, | |
116 "one{# second}", | |
117 " other{# seconds}" | |
118 }; | |
119 static const Pluralities IDS_LONG_MIN = { | |
120 { IDS_TIME_LONG_MINS_DEFAULT, IDS_TIME_LONG_MIN_SINGULAR, | |
121 IDS_TIME_LONG_MINS_ZERO, IDS_TIME_LONG_MINS_TWO, | |
122 IDS_TIME_LONG_MINS_FEW, IDS_TIME_LONG_MINS_MANY }, | |
123 "one{# minute}", | |
124 " other{# minutes}" | |
125 }; | |
126 static const Pluralities IDS_DURATION_HOUR = { | |
127 { IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOUR_SINGULAR, IDS_TIME_HOURS_ZERO, | |
128 IDS_TIME_HOURS_TWO, IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY }, | |
129 "one{# hour}", | |
130 " other{# hours}" | |
131 }; | |
132 static const Pluralities IDS_DURATION_DAY = { | |
133 { IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAY_SINGULAR, IDS_TIME_DAYS_ZERO, | |
134 IDS_TIME_DAYS_TWO, IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY }, | |
135 "one{# day}", | |
136 " other{# days}" | |
137 }; | |
138 | |
139 static const Pluralities IDS_LONG_MIN_1ST = { | |
140 { IDS_TIME_LONG_MINS_1ST_DEFAULT, IDS_TIME_LONG_MIN_1ST_SINGULAR, | |
141 IDS_TIME_LONG_MINS_1ST_ZERO, IDS_TIME_LONG_MINS_1ST_TWO, | |
142 IDS_TIME_LONG_MINS_1ST_FEW, IDS_TIME_LONG_MINS_1ST_MANY }, | |
143 "one{# minute }", | |
144 " other{# minutes }" | |
145 }; | |
146 static const Pluralities IDS_LONG_SEC_2ND = { | |
147 { IDS_TIME_LONG_SECS_2ND_DEFAULT, IDS_TIME_LONG_SEC_2ND_SINGULAR, | |
148 IDS_TIME_LONG_SECS_2ND_ZERO, IDS_TIME_LONG_SECS_2ND_TWO, | |
149 IDS_TIME_LONG_SECS_2ND_FEW, IDS_TIME_LONG_SECS_2ND_MANY }, | |
150 "one{# second}", | |
151 " other{# seconds}" | |
152 }; | |
153 static const Pluralities IDS_DURATION_HOUR_1ST = { | |
154 { IDS_TIME_HOURS_1ST_DEFAULT, IDS_TIME_HOUR_1ST_SINGULAR, | |
155 IDS_TIME_HOURS_1ST_ZERO, IDS_TIME_HOURS_1ST_TWO, | |
156 IDS_TIME_HOURS_1ST_FEW, IDS_TIME_HOURS_1ST_MANY }, | |
157 "one{# hour }", | |
158 " other{# hours }" | |
159 }; | |
160 static const Pluralities IDS_LONG_MIN_2ND = { | |
161 { IDS_TIME_LONG_MINS_2ND_DEFAULT, IDS_TIME_LONG_MIN_2ND_SINGULAR, | |
162 IDS_TIME_LONG_MINS_2ND_ZERO, IDS_TIME_LONG_MINS_2ND_TWO, | |
163 IDS_TIME_LONG_MINS_2ND_FEW, IDS_TIME_LONG_MINS_2ND_MANY }, | |
164 "one{# minute}", | |
165 " other{# minutes}" | |
166 }; | |
167 static const Pluralities IDS_DURATION_DAY_1ST = { | |
168 { IDS_TIME_DAYS_1ST_DEFAULT, IDS_TIME_DAY_1ST_SINGULAR, | |
169 IDS_TIME_DAYS_1ST_ZERO, IDS_TIME_DAYS_1ST_TWO, | |
170 IDS_TIME_DAYS_1ST_FEW, IDS_TIME_DAYS_1ST_MANY }, | |
171 "one{# day }", | |
172 " other{# days }" | |
173 }; | |
174 static const Pluralities IDS_DURATION_HOUR_2ND = { | |
175 { IDS_TIME_HOURS_2ND_DEFAULT, IDS_TIME_HOUR_2ND_SINGULAR, | |
176 IDS_TIME_HOURS_2ND_ZERO, IDS_TIME_HOURS_2ND_TWO, | |
177 IDS_TIME_HOURS_2ND_FEW, IDS_TIME_HOURS_2ND_MANY }, | |
178 "one{# hour}", | |
179 " other{# hours}" | |
180 }; | |
181 | |
182 Formatter::Formatter(const Pluralities& sec_pluralities, | |
183 const Pluralities& min_pluralities, | |
184 const Pluralities& hour_pluralities, | |
185 const Pluralities& day_pluralities) { | |
186 simple_format_[UNIT_SEC] = InitFormat(sec_pluralities); | |
187 simple_format_[UNIT_MIN] = InitFormat(min_pluralities); | |
188 simple_format_[UNIT_HOUR] = InitFormat(hour_pluralities); | |
189 simple_format_[UNIT_DAY] = InitFormat(day_pluralities); | |
190 } | |
191 | |
192 Formatter::Formatter(const Pluralities& sec_pluralities, | |
193 const Pluralities& min_pluralities, | |
194 const Pluralities& hour_pluralities, | |
195 const Pluralities& day_pluralities, | |
196 const Pluralities& min_sec_pluralities1, | |
197 const Pluralities& min_sec_pluralities2, | |
198 const Pluralities& hour_min_pluralities1, | |
199 const Pluralities& hour_min_pluralities2, | |
200 const Pluralities& day_hour_pluralities1, | |
201 const Pluralities& day_hour_pluralities2) { | |
202 simple_format_[UNIT_SEC] = InitFormat(sec_pluralities); | |
203 simple_format_[UNIT_MIN] = InitFormat(min_pluralities); | |
204 simple_format_[UNIT_HOUR] = InitFormat(hour_pluralities); | |
205 simple_format_[UNIT_DAY] = InitFormat(day_pluralities); | |
206 detailed_format_[TWOUNITS_MIN_SEC][0] = InitFormat(min_sec_pluralities1); | |
207 detailed_format_[TWOUNITS_MIN_SEC][1] = InitFormat(min_sec_pluralities2); | |
208 detailed_format_[TWOUNITS_HOUR_MIN][0] = InitFormat(hour_min_pluralities1); | |
209 detailed_format_[TWOUNITS_HOUR_MIN][1] = InitFormat(hour_min_pluralities2); | |
210 detailed_format_[TWOUNITS_DAY_HOUR][0] = InitFormat(day_hour_pluralities1); | |
211 detailed_format_[TWOUNITS_DAY_HOUR][1] = InitFormat(day_hour_pluralities2); | |
212 } | |
213 | |
214 void Formatter::Format(Unit unit, | |
215 int value, | |
216 icu::UnicodeString& formatted_string) const { | |
217 DCHECK(simple_format_[unit]); | |
218 UErrorCode error = U_ZERO_ERROR; | |
219 formatted_string = simple_format_[unit]->format(value, error); | |
220 DCHECK(U_SUCCESS(error)) << "Error in icu::PluralFormat::format()."; | |
221 return; | |
222 } | |
223 | |
224 void Formatter::Format(TwoUnits units, | |
225 int value1, | |
226 int value2, | |
227 icu::UnicodeString& formatted_string) const { | |
228 DCHECK(detailed_format_[units][0]) | |
229 << "Detailed() not implemented for your (format, length) combination!"; | |
230 DCHECK(detailed_format_[units][1]) | |
231 << "Detailed() not implemented for your (format, length) combination!"; | |
232 UErrorCode error = U_ZERO_ERROR; | |
233 formatted_string = detailed_format_[units][0]->format(value1, error); | |
234 DCHECK(U_SUCCESS(error)); | |
235 formatted_string += detailed_format_[units][1]->format(value2, error); | |
236 DCHECK(U_SUCCESS(error)); | |
237 return; | |
238 } | |
239 | |
240 scoped_ptr<icu::PluralFormat> Formatter::CreateFallbackFormat( | |
241 const icu::PluralRules& rules, | |
242 const Pluralities& pluralities) const { | |
243 icu::UnicodeString pattern; | |
244 if (rules.isKeyword(UNICODE_STRING_SIMPLE("one"))) { | |
245 pattern += icu::UnicodeString(pluralities.fallback_one); | |
246 } | |
247 pattern += icu::UnicodeString(pluralities.fallback_other); | |
248 | |
249 UErrorCode error = U_ZERO_ERROR; | |
250 scoped_ptr<icu::PluralFormat> format( | |
251 new icu::PluralFormat(rules, pattern, error)); | |
252 DCHECK(U_SUCCESS(error)); | |
253 return format.Pass(); | |
254 } | |
255 | |
256 scoped_ptr<icu::PluralFormat> Formatter::InitFormat( | |
257 const Pluralities& pluralities) { | |
258 if (!Formatter::force_fallback_) { | |
259 icu::UnicodeString pattern; | |
260 std::vector<int> ids; | |
261 for (size_t j = 0; j < kNPluralities; ++j) { | |
262 ids.push_back(pluralities.Ids[j]); | |
263 } | |
264 scoped_ptr<icu::PluralFormat> format = l10n_util::BuildPluralFormat(ids); | |
265 if (format.get()) | |
266 return format.Pass(); | |
267 } | |
268 | |
269 scoped_ptr<icu::PluralRules> rules(l10n_util::BuildPluralRules()); | |
270 return CreateFallbackFormat(*rules, pluralities); | |
271 } | |
272 | |
273 const Formatter* FormatterContainer::Get(TimeFormat::Format format, | |
274 TimeFormat::Length length) const { | |
275 DCHECK(formatter_[format][length]) | |
276 << "Combination of FORMAT_ELAPSED and LENGTH_LONG is not implemented!"; | |
277 return formatter_[format][length].get(); | |
278 } | |
279 | |
280 FormatterContainer::FormatterContainer() { | |
281 Initialize(); | |
282 } | |
283 | |
284 FormatterContainer::~FormatterContainer() { | |
285 } | |
286 | |
287 void FormatterContainer::Initialize() { | |
288 formatter_[TimeFormat::FORMAT_ELAPSED][TimeFormat::LENGTH_SHORT].reset( | |
289 new Formatter(IDS_ELAPSED_SHORT_SEC, | |
290 IDS_ELAPSED_SHORT_MIN, | |
291 IDS_ELAPSED_HOUR, | |
292 IDS_ELAPSED_DAY)); | |
293 formatter_[TimeFormat::FORMAT_ELAPSED][TimeFormat::LENGTH_LONG].reset(); | |
294 formatter_[TimeFormat::FORMAT_REMAINING][TimeFormat::LENGTH_SHORT].reset( | |
295 new Formatter(IDS_REMAINING_SHORT_SEC, | |
296 IDS_REMAINING_SHORT_MIN, | |
297 IDS_REMAINING_HOUR, | |
298 IDS_REMAINING_DAY)); | |
299 formatter_[TimeFormat::FORMAT_REMAINING][TimeFormat::LENGTH_LONG].reset( | |
300 new Formatter(IDS_REMAINING_LONG_SEC, | |
301 IDS_REMAINING_LONG_MIN, | |
302 IDS_REMAINING_HOUR, | |
303 IDS_REMAINING_DAY)); | |
304 formatter_[TimeFormat::FORMAT_DURATION][TimeFormat::LENGTH_SHORT].reset( | |
305 new Formatter(IDS_DURATION_SHORT_SEC, | |
306 IDS_DURATION_SHORT_MIN, | |
307 IDS_DURATION_HOUR, | |
308 IDS_DURATION_DAY)); | |
309 formatter_[TimeFormat::FORMAT_DURATION][TimeFormat::LENGTH_LONG].reset( | |
310 new Formatter(IDS_LONG_SEC, | |
311 IDS_LONG_MIN, | |
312 IDS_DURATION_HOUR, | |
313 IDS_DURATION_DAY, | |
314 IDS_LONG_MIN_1ST, | |
315 IDS_LONG_SEC_2ND, | |
316 IDS_DURATION_HOUR_1ST, | |
317 IDS_LONG_MIN_2ND, | |
318 IDS_DURATION_DAY_1ST, | |
319 IDS_DURATION_HOUR_2ND)); | |
320 } | |
321 | |
322 void FormatterContainer::Shutdown() { | |
323 for (int format = 0; format < TimeFormat::FORMAT_COUNT; ++format) { | |
324 for (int length = 0; length < TimeFormat::LENGTH_COUNT; ++length) { | |
325 formatter_[format][length].reset(); | |
326 } | |
327 } | |
328 } | |
329 | |
330 } // namespace ui | |
OLD | NEW |