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; |
+} |