Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(612)

Side by Side Diff: components/autofill/core/browser/country_names.cc

Issue 1582353006: CountryNames: Separate data creation from usage (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@571610_exposeCountryNamesToTesting
Patch Set: Just rebased Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/browser/country_names.h" 5 #include "components/autofill/core/browser/country_names.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/lazy_instance.h"
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/singleton.h" 13 #include "base/memory/singleton.h"
13 #include "base/stl_util.h" 14 #include "base/stl_util.h"
14 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
16 #include "components/autofill/core/browser/country_data.h" 17 #include "components/autofill/core/browser/country_data.h"
17 #include "components/autofill/core/common/autofill_l10n_util.h" 18 #include "components/autofill/core/common/autofill_l10n_util.h"
18 #include "third_party/icu/source/common/unicode/unistr.h" 19 #include "third_party/icu/source/common/unicode/unistr.h"
19 #include "ui/base/l10n/l10n_util.h" 20 #include "ui/base/l10n/l10n_util.h"
20 21
21 namespace autofill { 22 namespace autofill {
22 namespace { 23 namespace {
23 24
25 // A copy of the application locale string, which should be ready for
26 // CountryName's construction.
27 static base::LazyInstance<std::string> g_application_locale =
28 LAZY_INSTANCE_INITIALIZER;
29
24 // Returns the ICU sort key corresponding to |str| for the given |collator|. 30 // Returns the ICU sort key corresponding to |str| for the given |collator|.
25 // Uses |buffer| as temporary storage, and might resize |buffer| as a side- 31 // Uses |buffer| as temporary storage, and might resize |buffer| as a side-
26 // effect. |buffer_size| should specify the |buffer|'s size, and is updated if 32 // effect. |buffer_size| should specify the |buffer|'s size, and is updated if
27 // the |buffer| is resized. 33 // the |buffer| is resized.
28 const std::string GetSortKey(const icu::Collator& collator, 34 const std::string GetSortKey(const icu::Collator& collator,
29 const base::string16& str, 35 const base::string16& str,
30 scoped_ptr<uint8_t[]>* buffer, 36 scoped_ptr<uint8_t[]>* buffer,
31 int32_t* buffer_size) { 37 int32_t* buffer_size) {
32 DCHECK(buffer); 38 DCHECK(buffer);
33 DCHECK(buffer_size); 39 DCHECK(buffer_size);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 // Add a few other common synonyms. 73 // Add a few other common synonyms.
68 common_names.insert(std::make_pair("UNITED STATES OF AMERICA", "US")); 74 common_names.insert(std::make_pair("UNITED STATES OF AMERICA", "US"));
69 common_names.insert(std::make_pair("U.S.A.", "US")); 75 common_names.insert(std::make_pair("U.S.A.", "US"));
70 common_names.insert(std::make_pair("GREAT BRITAIN", "GB")); 76 common_names.insert(std::make_pair("GREAT BRITAIN", "GB"));
71 common_names.insert(std::make_pair("UK", "GB")); 77 common_names.insert(std::make_pair("UK", "GB"));
72 common_names.insert(std::make_pair("BRASIL", "BR")); 78 common_names.insert(std::make_pair("BRASIL", "BR"));
73 common_names.insert(std::make_pair("DEUTSCHLAND", "DE")); 79 common_names.insert(std::make_pair("DEUTSCHLAND", "DE"));
74 return common_names; 80 return common_names;
75 } 81 }
76 82
83 // Creates collator for |locale| and sets its attributes as needed.
84 scoped_ptr<icu::Collator> CreateCollator(const icu::Locale& locale) {
85 scoped_ptr<icu::Collator> collator(
86 autofill::l10n::GetCollatorForLocale(locale));
87 if (!collator)
88 return nullptr;
89
90 // Compare case-insensitively and ignoring punctuation.
91 UErrorCode ignored = U_ZERO_ERROR;
92 collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored);
93 ignored = U_ZERO_ERROR;
94 collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored);
95
96 return collator;
97 }
98
99 // If |locale| is different from "en_US", returns a collator for "en_US" and
100 // sets its attributes as appropriate. Otherwise returns null.
101 scoped_ptr<icu::Collator> CreateDefaultCollator(const icu::Locale& locale) {
102 icu::Locale default_locale("en_US");
103
104 if (default_locale != locale)
105 return CreateCollator(default_locale);
106
107 return nullptr;
108 }
109
110 // Returns the mapping of country names localized to |locale| to their
111 // corresponding country codes. The provided |collator| should be suitable for
112 // the locale. The collator being null is handled gracefully by returning an
113 // empty map, to account for the very rare cases when the collator fails to
114 // initialize.
115 std::map<std::string, std::string> GetLocalizedNames(
116 const std::string& locale,
117 const icu::Collator* collator) {
118 if (!collator)
119 return std::map<std::string, std::string>();
120
121 std::map<std::string, std::string> localized_names;
122 int32_t buffer_size = 1000;
123 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
124
125 for (const std::string& country_code :
126 CountryDataMap::GetInstance()->country_codes()) {
127 base::string16 country_name =
128 l10n_util::GetDisplayNameForCountry(country_code, locale);
129 std::string sort_key =
130 GetSortKey(*collator, country_name, &buffer, &buffer_size);
131
132 localized_names.insert(std::make_pair(sort_key, country_code));
133 }
134 return localized_names;
135 }
136
77 } // namespace 137 } // namespace
78 138
79 // static 139 // static
80 CountryNames* CountryNames::GetInstance() { 140 CountryNames* CountryNames::GetInstance() {
81 return base::Singleton<CountryNames>::get(); 141 return base::Singleton<CountryNames>::get();
82 } 142 }
83 143
84 CountryNames::CountryNames() : common_names_(GetCommonNames()) {} 144 // static
145 void CountryNames::SetLocaleString(std::string locale) {
146 DCHECK(!locale.empty());
147 // Application locale should never be empty. The empty value of
148 // |g_application_locale| means that it has not been initialized yet.
149 std::string* storage = g_application_locale.Pointer();
150 if (storage->empty()) {
151 *storage = std::move(locale);
152 }
153 // TODO(crbug.com/579971) CountryNames currently cannot adapt to changed
154 // locale without Chrome's restart.
155 }
156
157 CountryNames::CountryNames(const std::string& locale_name)
158 : locale_(locale_name.c_str()),
159 collator_(CreateCollator(locale_)),
160 default_collator_(CreateDefaultCollator(locale_)),
161 common_names_(GetCommonNames()),
162 localized_names_(GetLocalizedNames(locale_name, collator_.get())),
163 default_localized_names_(
164 GetLocalizedNames("en_US", default_collator_.get())) {}
165
166 CountryNames::CountryNames() : CountryNames(g_application_locale.Get()) {
167 DCHECK(!g_application_locale.Get().empty());
168 }
85 169
86 CountryNames::~CountryNames() = default; 170 CountryNames::~CountryNames() = default;
87 171
88 const std::string CountryNames::GetCountryCode(const base::string16& country, 172 const std::string CountryNames::GetCountryCode(const base::string16& country) {
89 const std::string& locale_name) {
90 // First, check common country names, including 2- and 3-letter country codes. 173 // First, check common country names, including 2- and 3-letter country codes.
91 std::string country_utf8 = base::UTF16ToUTF8(base::ToUpperASCII(country)); 174 std::string country_utf8 = base::UTF16ToUTF8(base::ToUpperASCII(country));
92 const auto result = common_names_.find(country_utf8); 175 const auto result = common_names_.find(country_utf8);
93 if (result != common_names_.end()) 176 if (result != common_names_.end())
94 return result->second; 177 return result->second;
95 178
96 // Next, check country names localized to the current locale. 179 // Next, check country names localized to the current locale.
97 icu::Locale locale(locale_name.c_str()); 180 std::string country_code =
98 std::string country_code = GetCountryCodeForLocalizedName(country, locale); 181 GetCountryCodeForLocalizedName(country, localized_names_, *collator_);
99 if (!country_code.empty()) 182 if (!country_code.empty())
100 return country_code; 183 return country_code;
101 184
102 icu::Locale default_locale("en_US");
103 // Finally, check country names localized to US English, unless done already. 185 // Finally, check country names localized to US English, unless done already.
104 if (default_locale != locale) 186 if (default_collator_) {
105 return GetCountryCodeForLocalizedName(country, default_locale); 187 return GetCountryCodeForLocalizedName(country, default_localized_names_,
188 *default_collator_);
189 }
106 190
107 return std::string(); 191 return std::string();
108 } 192 }
109 193
110 void CountryNames::AddLocalizedNamesForLocale(const std::string& locale,
111 const icu::Collator& collator) {
112 // Nothing to do if we've previously added the localized names for the given
113 // |locale|.
114 if (locales_to_localized_names_.count(locale))
115 return;
116
117 std::map<std::string, std::string> localized_names;
118 int32_t buffer_size = 1000;
119 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
120
121 for (const std::string& country_code :
122 CountryDataMap::GetInstance()->country_codes()) {
123 base::string16 country_name =
124 l10n_util::GetDisplayNameForCountry(country_code, locale);
125 std::string sort_key =
126 GetSortKey(collator, country_name, &buffer, &buffer_size);
127
128 localized_names.insert(std::make_pair(sort_key, country_code));
129 }
130
131 locales_to_localized_names_.insert(std::make_pair(locale, localized_names));
132 }
133
134 const std::string CountryNames::GetCountryCodeForLocalizedName( 194 const std::string CountryNames::GetCountryCodeForLocalizedName(
135 const base::string16& country_name, 195 const base::string16& country_name,
136 const icu::Locale& locale) { 196 const std::map<std::string, std::string>& localized_names,
137 const icu::Collator* collator = GetCollatorForLocale(locale); 197 const icu::Collator& collator) {
138 // In very rare cases, the collator fails to initialize.
139 if (!collator)
140 return std::string();
141
142 std::string locale_name = locale.getName();
143 AddLocalizedNamesForLocale(locale_name, *collator);
144
145 // As recommended[1] by ICU, initialize the buffer size to four times the 198 // As recommended[1] by ICU, initialize the buffer size to four times the
146 // source string length. 199 // source string length.
147 // [1] http://userguide.icu-project.org/collation/api#TOC-Examples 200 // [1] http://userguide.icu-project.org/collation/api#TOC-Examples
148 int32_t buffer_size = country_name.size() * 4; 201 int32_t buffer_size = country_name.size() * 4;
149 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); 202 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
150 std::string sort_key = 203 std::string sort_key =
151 GetSortKey(*collator, country_name, &buffer, &buffer_size); 204 GetSortKey(collator, country_name, &buffer, &buffer_size);
152 205
153 const std::map<std::string, std::string>& localized_names = 206 auto result = localized_names.find(sort_key);
154 locales_to_localized_names_[locale_name];
155 std::map<std::string, std::string>::const_iterator result =
156 localized_names.find(sort_key);
157 207
158 if (result != localized_names.end()) 208 if (result != localized_names.end())
159 return result->second; 209 return result->second;
160 210
161 return std::string(); 211 return std::string();
162 } 212 }
163 213
164 const icu::Collator* CountryNames::GetCollatorForLocale(
165 const icu::Locale& locale) {
166 std::string locale_name = locale.getName();
167 if (!ContainsKey(collators_, locale_name)) {
168 scoped_ptr<icu::Collator> collator(
169 autofill::l10n::GetCollatorForLocale(locale));
170 if (!collator)
171 return nullptr;
172
173 // Compare case-insensitively and ignoring punctuation.
174 UErrorCode ignored = U_ZERO_ERROR;
175 collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored);
176 ignored = U_ZERO_ERROR;
177 collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored);
178
179 collators_[locale_name] = std::move(collator);
180 }
181
182 return collators_[locale_name].get();
183 }
184
185 } // namespace autofill 214 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/country_names.h ('k') | components/autofill/core/browser/country_names_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698