Chromium Code Reviews| Index: chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc |
| diff --git a/chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc b/chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f62133bbaebca635a604f947583abde22af41ba2 |
| --- /dev/null |
| +++ b/chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc |
| @@ -0,0 +1,261 @@ |
| +// Copyright 2013 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. |
| +// |
| +// A stub implementation of internationalized address input fields for |
| +// interactive autofill dialog. The implementation always returns the same |
| +// address fields until libaddressinput library is integrated. |
| +// |
| +// After libaddressinput library is integrated, these enums will removed below: |
| +// i18n::addressinput::AddressField |
| +// i18n::addressinput::LengthHint |
| +// Also, GetI18nFields() will call libaddressinput library to determine the |
| +// address fields instead of always returning US address fields. |
| +// |
| +// 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
|
| +// the timezone and possibly geolocation. |
| + |
| +#include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h" |
| + |
| +#include "base/command_line.h" |
| +#include "chrome/browser/browser_process.h" |
| +#include "chrome/common/chrome_switches.h" |
| +#include "components/autofill/core/browser/autofill_country.h" |
| +#include "grit/component_strings.h" |
| +#include "grit/generated_resources.h" |
| + |
| +namespace autofill { |
| +namespace i18ninput { |
| + |
| +namespace { |
| + |
| +// TODO(rouslan): Use the enums from libaddressinput instead after the library |
| +// has been integrated. |
| +namespace i18n { |
| +namespace addressinput { |
| + |
| +enum AddressField { |
| + COUNTRY, |
| + ADMIN_AREA, |
| + LOCALITY, |
| + DEPENDENT_LOCALITY, |
| + POSTAL_CODE, |
| + SORTING_CODE, |
| + STREET_ADDRESS, |
| + ORGANIZATION, |
| + RECIPIENT, |
| +}; |
| + |
| +enum LengthHint { |
| + LENGTH_HINT_SHORT, |
| + LENGTH_HINT_LONG, |
| +}; |
| + |
| +} // namespace addressinput |
| +} // namespace i18n |
| + |
| +// Indexes into arrays of address field data. The values in |
| +// i18n::addressinput::AddressField enum cannot be used directly because they |
| +// are not sequential. |
| +enum AddressFieldIndex { |
| + COUNTRY_INDEX, |
| + ADMIN_AREA_INDEX, |
| + LOCALITY_INDEX, |
| + POSTAL_CODE_INDEX, |
| + STREET_ADDRESS_1_INDEX, |
| + STREET_ADDRESS_2_INDEX, |
| + RECIPIENT_INDEX, |
| +}; |
| + |
| +// Indexes into arrays of street address line data. |
| +enum StreetAddressLine { |
| + STREET_ADDRESS_LINE_1, |
| + STREET_ADDRESS_LINE_2, |
| +}; |
| + |
| +// The number of address types. |
| +const int kNumberOfAddressTypes = ADDRESS_TYPE_BILLING + 1; |
| + |
| +// The maximum number of input fields. |
| +const int kMaxNumberOfInputFields = RECIPIENT_INDEX + 1; |
| + |
| +// The maximum number of street address lines. |
| +const int kMaxNumberOfStreetAddressLines = STREET_ADDRESS_LINE_2 + 1; |
| + |
| +// A mapping of StreetAddressLine to corresponding values in AddressFieldIndex. |
| +// Used to lookup address field data for street address lines. |
| +const AddressFieldIndex kStreetAddressLineIndex |
| + [kMaxNumberOfStreetAddressLines] = { |
| + STREET_ADDRESS_1_INDEX, |
| + STREET_ADDRESS_2_INDEX, |
| +}; |
| + |
| +// A mapping of AddressFieldIndex and AddressType to autofill field types. |
| +const ServerFieldType kServerFields[kMaxNumberOfInputFields] |
| + [kNumberOfAddressTypes] = { |
| + {ADDRESS_HOME_COUNTRY, ADDRESS_BILLING_COUNTRY}, |
|
Evan Stade
2013/10/08 23:44:51
space after { and before }
also, this seems to be
|
| + {ADDRESS_HOME_STATE, ADDRESS_BILLING_STATE}, |
| + {ADDRESS_HOME_CITY, ADDRESS_BILLING_CITY}, |
| + {ADDRESS_HOME_ZIP, ADDRESS_BILLING_ZIP}, |
| + {ADDRESS_HOME_LINE1, ADDRESS_BILLING_LINE1}, |
| + {ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE2}, |
| + {NAME_FULL, NAME_BILLING_FULL}, |
| +}; |
| + |
| +// 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
|
| +// placeholder text. |
| +const int kPlaceHolderStringIds[kMaxNumberOfInputFields] |
|
Evan Stade
2013/10/08 23:44:51
s/PlaceHolder/Placeholder
|
| + [kNumberOfAddressTypes] = { |
| + {IDS_AUTOFILL_FIELD_LABEL_COUNTRY, IDS_AUTOFILL_FIELD_LABEL_COUNTRY}, |
| + {IDS_AUTOFILL_FIELD_LABEL_STATE, IDS_AUTOFILL_FIELD_LABEL_STATE}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESSEE_NAME, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARDHOLDER_NAME}, |
| +}; |
| + |
| +// Returns the AddressFieldIndex for the given i18n::addressinput::AddressField. |
| +// If the address field is STREET_ADDRESS, then uses the given StreetAddressLine |
| +// to determine whether to return STREET_ADDRESS_1_INDEX or |
| +// STREET_ADDRESS_2_INDEX. |
| +AddressFieldIndex AddressFieldToIndex( |
| + i18n::addressinput::AddressField field_type, |
| + StreetAddressLine street_address_line) { |
| + switch (field_type) { |
| + case i18n::addressinput::COUNTRY: |
| + return COUNTRY_INDEX; |
| + case i18n::addressinput::ADMIN_AREA: |
| + return ADMIN_AREA_INDEX; |
| + case i18n::addressinput::LOCALITY: |
| + return LOCALITY_INDEX; |
| + case i18n::addressinput::POSTAL_CODE: |
| + return POSTAL_CODE_INDEX; |
| + case i18n::addressinput::STREET_ADDRESS: |
| + return kStreetAddressLineIndex[street_address_line]; |
|
Evan Stade
2013/10/08 23:44:51
2 returns in a row?
|
| + return POSTAL_CODE_INDEX; |
| + case i18n::addressinput::RECIPIENT: |
| + return RECIPIENT_INDEX; |
| + default: |
| + NOTREACHED(); |
| + return COUNTRY_INDEX; |
| + } |
| +} |
| + |
| +// Sets the address field types and length hints for the given |country_region| |
| +// and |language|. |
| +void GetI18nFields(const std::string country_region, |
|
Evan Stade
2013/10/08 23:44:51
const ref?
|
| + const std::string& language, |
| + std::vector<i18n::addressinput::AddressField>* field_types, |
| + 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
|
| + // TODO(rouslan): Use the country_region and language specific |
| + // address input field types and names after libaddressinput is integrated. |
| + field_types->push_back(i18n::addressinput::RECIPIENT); |
| + length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); |
| + |
| + field_types->push_back(i18n::addressinput::STREET_ADDRESS); |
| + length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); |
| + |
| + field_types->push_back(i18n::addressinput::LOCALITY); |
| + length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); |
| + |
| + field_types->push_back(i18n::addressinput::ADMIN_AREA); |
| + length_hints->push_back(i18n::addressinput::LENGTH_HINT_SHORT); |
| + |
| + field_types->push_back(i18n::addressinput::POSTAL_CODE); |
| + length_hints->push_back(i18n::addressinput::LENGTH_HINT_SHORT); |
| + |
| + field_types->push_back(i18n::addressinput::COUNTRY); |
| + length_hints->push_back(i18n::addressinput::LENGTH_HINT_LONG); |
| + |
|
Evan Stade
2013/10/08 23:44:51
^H
|
| +} |
| + |
| +// Returns an incremented |row_index| if |length_hint| and |prev_length_hint| |
| +// indicate that the current input should start on a new line. |
| +int IncrementRowIndexBasedOnLengthHint( |
| + i18n::addressinput::LengthHint prev_length_hint, |
| + i18n::addressinput::LengthHint length_hint, |
| + int row_index) { |
| + if (length_hint == i18n::addressinput::LENGTH_HINT_LONG || |
| + prev_length_hint != length_hint) { |
|
Evan Stade
2013/10/08 23:44:51
optional nit: imo, this is easier to grok as
if (
|
| + return row_index + 1; |
| + } |
| + return row_index; |
| +} |
| + |
| +// Appends the |field_type| input to |inputs|. Appends |
| +// 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
|
| +int BuildI18nInput(int row_index, |
|
Evan Stade
2013/10/08 23:44:51
instead of passing row_index around, I think you c
|
| + i18n::addressinput::AddressField field_type, |
| + i18n::addressinput::LengthHint prev_length_hint, |
| + i18n::addressinput::LengthHint length_hint, |
| + AddressType address_type, |
| + DetailInputs* inputs) { |
| + 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_
|
| + row_index = IncrementRowIndexBasedOnLengthHint( |
| + prev_length_hint, length_hint, row_index); |
| + inputs->push_back({row_index, kServerFields[field_index][address_type], |
| + kPlaceHolderStringIds[field_index][address_type]}); |
| + |
| + if (field_type == i18n::addressinput::STREET_ADDRESS) { |
| + field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_2); |
| + row_index = IncrementRowIndexBasedOnLengthHint( |
| + prev_length_hint, length_hint, row_index); |
| + inputs->push_back({row_index, kServerFields[field_index][address_type], |
| + kPlaceHolderStringIds[field_index][address_type]}); |
| + } |
| + |
| + return row_index; |
| +} |
| + |
| +// Returns the language of the current application locale. |
| +std::string GetLocaleLanguage() { |
| + const std::string& locale = g_browser_process->GetApplicationLocale(); |
| + return locale.substr(0, locale.find('-')); |
|
Evan Stade
2013/10/08 23:44:51
AutofillCountry::CountryCodeForLocale
|
| +} |
| + |
| +} // namespace |
| + |
| +bool IsI18nAddressInputEnabled() { |
| + return CommandLine::ForCurrentProcess()->HasSwitch( |
| + ::switches::kEnableAutofillAddressInternationalization); |
| +} |
| + |
| +std::string GuessCountry() { |
| + if (!IsI18nAddressInputEnabled()) |
| + return "US"; |
| + |
| + // TODO(rouslan): Improve on this rudimentary implementation of guessing the |
| + // current country code. |
| + return AutofillCountry::CountryCodeForLocale( |
| + g_browser_process->GetApplicationLocale()); |
| +} |
| + |
| +void BuildI18nInputs(AddressType address_type, |
| + const std::string& country_region, |
| + int row_index, |
| + DetailInputs* inputs) { |
| + std::vector<i18n::addressinput::AddressField> field_types; |
| + std::vector<i18n::addressinput::LengthHint> length_hints; |
| + GetI18nFields( |
| + country_region, GetLocaleLanguage(), &field_types, &length_hints); |
| + i18n::addressinput::LengthHint prev_length_hint = |
| + i18n::addressinput::LENGTH_HINT_LONG; |
| + for (size_t i = 0; i < field_types.size() && i < length_hints.size(); ++i) { |
| + row_index = BuildI18nInput(row_index, |
| + field_types[i], |
| + prev_length_hint, |
| + length_hints[i], |
| + address_type, |
| + inputs); |
| + prev_length_hint = length_hints[i]; |
| + } |
| +} |
| + |
| +} // namespace i18ninput |
| +} // namespace autofill |