OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 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 // A stub implementation of internationalized address input fields for | |
6 // interactive autofill dialog. The implementation always returns the same | |
7 // address fields until libaddressinput library is integrated. | |
8 // | |
9 // After libaddressinput library is integrated, these enums will removed below: | |
10 // i18n::addressinput::AddressField | |
11 // i18n::addressinput::LengthHint | |
12 // Also, GetI18nFields() will call libaddressinput library to determine the | |
13 // address fields instead of always returning US address fields. | |
14 // | |
15 // GuessCountry() uses only the application locale and should be improved to use | |
Evan Stade
2013/10/08 23:44:51
link to the bug
also, we should probably look at
Evan Stade
2013/11/18 19:39:47
note that I've been working on this, the code is L
| |
16 // the timezone and possibly geolocation. | |
17 | |
18 #include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h" | |
19 | |
20 #include "base/command_line.h" | |
21 #include "chrome/browser/browser_process.h" | |
22 #include "chrome/common/chrome_switches.h" | |
23 #include "components/autofill/core/browser/autofill_country.h" | |
24 #include "grit/component_strings.h" | |
25 #include "grit/generated_resources.h" | |
26 | |
27 namespace autofill { | |
28 namespace i18ninput { | |
29 | |
30 namespace { | |
31 | |
32 // TODO(rouslan): Use the enums from libaddressinput instead after the library | |
33 // has been integrated. | |
34 namespace i18n { | |
35 namespace addressinput { | |
36 | |
37 enum AddressField { | |
38 COUNTRY, | |
39 ADMIN_AREA, | |
40 LOCALITY, | |
41 DEPENDENT_LOCALITY, | |
42 POSTAL_CODE, | |
43 SORTING_CODE, | |
44 STREET_ADDRESS, | |
45 ORGANIZATION, | |
46 RECIPIENT, | |
47 }; | |
48 | |
49 enum LengthHint { | |
50 LENGTH_HINT_SHORT, | |
51 LENGTH_HINT_LONG, | |
52 }; | |
53 | |
54 } // namespace addressinput | |
55 } // namespace i18n | |
56 | |
57 // Indexes into arrays of address field data. The values in | |
58 // i18n::addressinput::AddressField enum cannot be used directly because they | |
59 // are not sequential. | |
60 enum AddressFieldIndex { | |
61 COUNTRY_INDEX, | |
62 ADMIN_AREA_INDEX, | |
63 LOCALITY_INDEX, | |
64 POSTAL_CODE_INDEX, | |
65 STREET_ADDRESS_1_INDEX, | |
66 STREET_ADDRESS_2_INDEX, | |
67 RECIPIENT_INDEX, | |
68 }; | |
69 | |
70 // Indexes into arrays of street address line data. | |
71 enum StreetAddressLine { | |
72 STREET_ADDRESS_LINE_1, | |
73 STREET_ADDRESS_LINE_2, | |
74 }; | |
75 | |
76 // The number of address types. | |
77 const int kNumberOfAddressTypes = ADDRESS_TYPE_BILLING + 1; | |
78 | |
79 // The maximum number of input fields. | |
80 const int kMaxNumberOfInputFields = RECIPIENT_INDEX + 1; | |
81 | |
82 // The maximum number of street address lines. | |
83 const int kMaxNumberOfStreetAddressLines = STREET_ADDRESS_LINE_2 + 1; | |
84 | |
85 // A mapping of StreetAddressLine to corresponding values in AddressFieldIndex. | |
86 // Used to lookup address field data for street address lines. | |
87 const AddressFieldIndex kStreetAddressLineIndex | |
88 [kMaxNumberOfStreetAddressLines] = { | |
89 STREET_ADDRESS_1_INDEX, | |
90 STREET_ADDRESS_2_INDEX, | |
91 }; | |
92 | |
93 // A mapping of AddressFieldIndex and AddressType to autofill field types. | |
94 const ServerFieldType kServerFields[kMaxNumberOfInputFields] | |
95 [kNumberOfAddressTypes] = { | |
96 {ADDRESS_HOME_COUNTRY, ADDRESS_BILLING_COUNTRY}, | |
Evan Stade
2013/10/08 23:44:51
space after { and before }
also, this seems to be
| |
97 {ADDRESS_HOME_STATE, ADDRESS_BILLING_STATE}, | |
98 {ADDRESS_HOME_CITY, ADDRESS_BILLING_CITY}, | |
99 {ADDRESS_HOME_ZIP, ADDRESS_BILLING_ZIP}, | |
100 {ADDRESS_HOME_LINE1, ADDRESS_BILLING_LINE1}, | |
101 {ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE2}, | |
102 {NAME_FULL, NAME_BILLING_FULL}, | |
103 }; | |
104 | |
105 // A mapping of AddressFieldIndex and AddressType to string identifiers for | |
Evan Stade
2013/10/08 23:44:51
you should make this a map from autofill field typ
| |
106 // placeholder text. | |
107 const int kPlaceHolderStringIds[kMaxNumberOfInputFields] | |
Evan Stade
2013/10/08 23:44:51
s/PlaceHolder/Placeholder
| |
108 [kNumberOfAddressTypes] = { | |
109 {IDS_AUTOFILL_FIELD_LABEL_COUNTRY, IDS_AUTOFILL_FIELD_LABEL_COUNTRY}, | |
110 {IDS_AUTOFILL_FIELD_LABEL_STATE, IDS_AUTOFILL_FIELD_LABEL_STATE}, | |
111 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY, | |
112 IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY}, | |
113 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE, | |
114 IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE}, | |
115 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1, | |
116 IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1}, | |
117 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2, | |
118 IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2}, | |
119 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESSEE_NAME, | |
120 IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARDHOLDER_NAME}, | |
121 }; | |
122 | |
123 // Returns the AddressFieldIndex for the given i18n::addressinput::AddressField. | |
124 // If the address field is STREET_ADDRESS, then uses the given StreetAddressLine | |
125 // to determine whether to return STREET_ADDRESS_1_INDEX or | |
126 // STREET_ADDRESS_2_INDEX. | |
127 AddressFieldIndex AddressFieldToIndex( | |
128 i18n::addressinput::AddressField field_type, | |
129 StreetAddressLine street_address_line) { | |
130 switch (field_type) { | |
131 case i18n::addressinput::COUNTRY: | |
132 return COUNTRY_INDEX; | |
133 case i18n::addressinput::ADMIN_AREA: | |
134 return ADMIN_AREA_INDEX; | |
135 case i18n::addressinput::LOCALITY: | |
136 return LOCALITY_INDEX; | |
137 case i18n::addressinput::POSTAL_CODE: | |
138 return POSTAL_CODE_INDEX; | |
139 case i18n::addressinput::STREET_ADDRESS: | |
140 return kStreetAddressLineIndex[street_address_line]; | |
Evan Stade
2013/10/08 23:44:51
2 returns in a row?
| |
141 return POSTAL_CODE_INDEX; | |
142 case i18n::addressinput::RECIPIENT: | |
143 return RECIPIENT_INDEX; | |
144 default: | |
145 NOTREACHED(); | |
146 return COUNTRY_INDEX; | |
147 } | |
148 } | |
149 | |
150 // Sets the address field types and length hints for the given |country_region| | |
151 // and |language|. | |
152 void GetI18nFields(const std::string country_region, | |
Evan Stade
2013/10/08 23:44:51
const ref?
| |
153 const std::string& language, | |
154 std::vector<i18n::addressinput::AddressField>* field_types, | |
155 std::vector<i18n::addressinput::LengthHint>* length_hints) { | |
Evan Stade
2013/10/08 23:44:51
I'd prefer if this were a single vector, of either
| |
156 // TODO(rouslan): Use the country_region and language specific | |
157 // address input field types and names after libaddressinput is integrated. | |
158 field_types->push_back(i18n::addressinput::RECIPIENT); | |
159 length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); | |
160 | |
161 field_types->push_back(i18n::addressinput::STREET_ADDRESS); | |
162 length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); | |
163 | |
164 field_types->push_back(i18n::addressinput::LOCALITY); | |
165 length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); | |
166 | |
167 field_types->push_back(i18n::addressinput::ADMIN_AREA); | |
168 length_hints->push_back(i18n::addressinput::LENGTH_HINT_SHORT); | |
169 | |
170 field_types->push_back(i18n::addressinput::POSTAL_CODE); | |
171 length_hints->push_back(i18n::addressinput::LENGTH_HINT_SHORT); | |
172 | |
173 field_types->push_back(i18n::addressinput::COUNTRY); | |
174 length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); | |
175 | |
Evan Stade
2013/10/08 23:44:51
^H
| |
176 } | |
177 | |
178 // Returns an incremented |row_index| if |length_hint| and |prev_length_hint| | |
179 // indicate that the current input should start on a new line. | |
180 int IncrementRowIndexBasedOnLengthHint( | |
181 i18n::addressinput::LengthHint prev_length_hint, | |
182 i18n::addressinput::LengthHint length_hint, | |
183 int row_index) { | |
184 if (length_hint == i18n::addressinput::LENGTH_HINT_LONG || | |
185 prev_length_hint != length_hint) { | |
Evan Stade
2013/10/08 23:44:51
optional nit: imo, this is easier to grok as
if (
| |
186 return row_index + 1; | |
187 } | |
188 return row_index; | |
189 } | |
190 | |
191 // Appends the |field_type| input to |inputs|. Appends | |
192 // kMaxNumberOfStreetAddressLines inputs if |field_type| is STREET_ADDRESS. | |
Evan Stade
2013/10/08 23:44:51
can you document the other params? I don't underst
| |
193 int BuildI18nInput(int row_index, | |
Evan Stade
2013/10/08 23:44:51
instead of passing row_index around, I think you c
| |
194 i18n::addressinput::AddressField field_type, | |
195 i18n::addressinput::LengthHint prev_length_hint, | |
196 i18n::addressinput::LengthHint length_hint, | |
197 AddressType address_type, | |
198 DetailInputs* inputs) { | |
199 int field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_1); | |
Evan Stade
2013/10/08 23:44:51
this is confusing because most of the time STREET_
| |
200 row_index = IncrementRowIndexBasedOnLengthHint( | |
201 prev_length_hint, length_hint, row_index); | |
202 inputs->push_back({row_index, kServerFields[field_index][address_type], | |
203 kPlaceHolderStringIds[field_index][address_type]}); | |
204 | |
205 if (field_type == i18n::addressinput::STREET_ADDRESS) { | |
206 field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_2); | |
207 row_index = IncrementRowIndexBasedOnLengthHint( | |
208 prev_length_hint, length_hint, row_index); | |
209 inputs->push_back({row_index, kServerFields[field_index][address_type], | |
210 kPlaceHolderStringIds[field_index][address_type]}); | |
211 } | |
212 | |
213 return row_index; | |
214 } | |
215 | |
216 // Returns the language of the current application locale. | |
217 std::string GetLocaleLanguage() { | |
218 const std::string& locale = g_browser_process->GetApplicationLocale(); | |
219 return locale.substr(0, locale.find('-')); | |
Evan Stade
2013/10/08 23:44:51
AutofillCountry::CountryCodeForLocale
| |
220 } | |
221 | |
222 } // namespace | |
223 | |
224 bool IsI18nAddressInputEnabled() { | |
225 return CommandLine::ForCurrentProcess()->HasSwitch( | |
226 ::switches::kEnableAutofillAddressInternationalization); | |
227 } | |
228 | |
229 std::string GuessCountry() { | |
230 if (!IsI18nAddressInputEnabled()) | |
231 return "US"; | |
232 | |
233 // TODO(rouslan): Improve on this rudimentary implementation of guessing the | |
234 // current country code. | |
235 return AutofillCountry::CountryCodeForLocale( | |
236 g_browser_process->GetApplicationLocale()); | |
237 } | |
238 | |
239 void BuildI18nInputs(AddressType address_type, | |
240 const std::string& country_region, | |
241 int row_index, | |
242 DetailInputs* inputs) { | |
243 std::vector<i18n::addressinput::AddressField> field_types; | |
244 std::vector<i18n::addressinput::LengthHint> length_hints; | |
245 GetI18nFields( | |
246 country_region, GetLocaleLanguage(), &field_types, &length_hints); | |
247 i18n::addressinput::LengthHint prev_length_hint = | |
248 i18n::addressinput::LENGTH_HINT_LONG; | |
249 for (size_t i = 0; i < field_types.size() && i < length_hints.size(); ++i) { | |
250 row_index = BuildI18nInput(row_index, | |
251 field_types[i], | |
252 prev_length_hint, | |
253 length_hints[i], | |
254 address_type, | |
255 inputs); | |
256 prev_length_hint = length_hints[i]; | |
257 } | |
258 } | |
259 | |
260 } // namespace i18ninput | |
261 } // namespace autofill | |
OLD | NEW |