Chromium Code Reviews| Index: chrome/common/plural_formatter.cc |
| diff --git a/chrome/common/plural_formatter.cc b/chrome/common/plural_formatter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..dc996b66002014afea694be2afecbb597d8618f8 |
| --- /dev/null |
| +++ b/chrome/common/plural_formatter.cc |
| @@ -0,0 +1,131 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/common/plural_formatter.h" |
| + |
| +#include <vector> |
| + |
| +#include "base/scoped_ptr.h" |
| +#include "base/stl_util-inl.h" |
| +#include "base/string16.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "grit/generated_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "unicode/locid.h" |
| +#include "unicode/plurfmt.h" |
| +#include "unicode/plurrule.h" |
| + |
| +namespace { |
| + |
| +// This is the functor for mapping message IDs to strings. We reset |
| +// it for tests so that we can avoid grit for the tests. |
| +static PluralFormatter::StringSourceFunction g_string_source = |
| + l10n_util::GetStringUTF8; |
| + |
| +static const char* g_override_locale = NULL; |
| +} // anonymous namespace |
|
Paweł Hajdan Jr.
2011/03/25 09:32:19
nit: Add empty line above.
Greg Spencer (Chromium)
2011/03/25 23:05:31
Done.
|
| + |
| +class PluralFormatterImpl { |
|
Paweł Hajdan Jr.
2011/03/25 09:32:19
Is it worth to have an Impl class here? How about
Greg Spencer (Chromium)
2011/03/25 23:05:31
This is a good point, and I considered it, but an
Paweł Hajdan Jr.
2011/03/28 18:52:28
Makes sense.
|
| + public: |
| + explicit PluralFormatterImpl(const int message_ids[]); |
| + string16 GetPluralString(int number); |
| + private: |
| + scoped_ptr<icu::PluralFormat> formatter_; |
| +}; |
| + |
| +PluralFormatterImpl::PluralFormatterImpl(const int message_ids[]) { |
| + static const icu::UnicodeString kKeywords[] = { |
| + UNICODE_STRING_SIMPLE("zero"), UNICODE_STRING_SIMPLE("one"), |
| + UNICODE_STRING_SIMPLE("two"), UNICODE_STRING_SIMPLE("few"), |
| + UNICODE_STRING_SIMPLE("many"), UNICODE_STRING_SIMPLE("other"), |
| + }; |
| + |
| + UErrorCode err = U_ZERO_ERROR; |
| + scoped_ptr<icu::PluralRules> rules; |
| + if (g_override_locale) { |
| + icu::Locale overridden_locale(g_override_locale); |
| + rules.reset(icu::PluralRules::forLocale(overridden_locale, err)); |
| + } else { |
| + rules.reset(icu::PluralRules::forLocale(icu::Locale::getDefault(), err)); |
| + } |
| + if (U_FAILURE(err)) { |
| + err = U_ZERO_ERROR; |
| + icu::UnicodeString fallback_rules("one: n is 1", -1, US_INV); |
| + rules.reset(icu::PluralRules::createRules(fallback_rules, err)); |
| + DCHECK(U_SUCCESS(err)); |
|
Paweł Hajdan Jr.
2011/03/25 09:32:19
DCHECKs are only for Debug builds. Don't you want
Greg Spencer (Chromium)
2011/03/25 23:05:31
In this case, we want to fall back to a simple rul
Paweł Hajdan Jr.
2011/03/28 18:52:28
My understanding of this code is that this DCHECK
|
| + } |
| + |
| + icu::UnicodeString pattern; |
| + for (size_t j = 0; j < arraysize(kKeywords); ++j) { |
| + int msg_id = message_ids[j]; |
| + std::string sub_pattern = (*g_string_source)(msg_id); |
| + // NA means this keyword is not used in the current locale. Even |
| + // if a translator translated for this keyword, we do not use it |
| + // unless it's 'other' or it's defined in the rules for the |
| + // current locale. Special-casing of 'other' (j = 5) will be |
| + // removed once ICU's isKeyword is fixed to return true for |
| + // isKeyword('other'). |
| + if (sub_pattern.compare("NA") != 0 && |
| + (j == 5 || rules->isKeyword(kKeywords[j]))) { |
| + pattern += kKeywords[j]; |
| + pattern += UNICODE_STRING_SIMPLE("{"); |
| + pattern += icu::UnicodeString(sub_pattern.c_str(), "UTF-8"); |
| + pattern += UNICODE_STRING_SIMPLE("}"); |
| + } |
| + } |
| + |
| + scoped_ptr<icu::PluralFormat> format( |
| + new icu::PluralFormat(*rules, pattern, err)); |
| + DCHECK(U_SUCCESS(err)); |
|
Paweł Hajdan Jr.
2011/03/25 09:32:19
Similarly here, I think you want to always check t
Greg Spencer (Chromium)
2011/03/25 23:05:31
I had that at first, and went back to DCHECK to be
|
| + formatter_.swap(format); |
| +} |
| + |
| +string16 PluralFormatterImpl::GetPluralString(int number) { |
| + icu::UnicodeString plural_string; |
| + UErrorCode error = U_ZERO_ERROR; |
| + plural_string = formatter_->format(number, error); |
| + DCHECK(U_SUCCESS(error)); |
| + string16 result; |
| + int capacity = plural_string.length() + 1; |
| + plural_string.extract(static_cast<UChar*>(WriteInto(&result, capacity)), |
| + capacity, error); |
| + DCHECK(U_SUCCESS(error)); |
| + return result; |
| +} |
| + |
| +PluralFormatter::PluralFormatter(int zero_message_id, |
| + int one_message_id, |
| + int two_message_id, |
| + int few_message_id, |
| + int many_message_id, |
| + int default_message_id) { |
| + int message_ids[6]; |
| + message_ids[0] = zero_message_id; |
| + message_ids[1] = one_message_id; |
| + message_ids[2] = two_message_id; |
| + message_ids[3] = few_message_id; |
| + message_ids[4] = many_message_id; |
| + message_ids[5] = default_message_id; |
| + impl_ = new PluralFormatterImpl(message_ids); |
| +} |
| + |
| +PluralFormatter::PluralFormatter(const int message_ids[]) |
| + : impl_(new PluralFormatterImpl(message_ids)) { |
| +} |
| + |
| +PluralFormatter::~PluralFormatter() { |
| + delete impl_; |
| +} |
| + |
| +string16 PluralFormatter::GetPluralString(int number) { |
| + return impl_->GetPluralString(number); |
| +} |
| + |
| +void PluralFormatter::SetStringSource(StringSourceFunction string_source) { |
| + g_string_source = string_source; |
| +} |
| + |
| +void PluralFormatter::SetOverrideLocale(const char* overrride_locale) { |
| + g_override_locale = overrride_locale; |
| +} |