Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (C) 2013 Google Inc. | 1 // Copyright (C) 2013 Google Inc. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 #include "rule.h" | 15 #include "rule.h" |
| 16 | 16 |
| 17 #include <libaddressinput/address_field.h> | 17 #include <libaddressinput/address_field.h> |
| 18 #include <libaddressinput/util/scoped_ptr.h> | 18 #include <libaddressinput/util/scoped_ptr.h> |
| 19 | 19 |
| 20 #include <map> | 20 #include <cassert> |
| 21 #include <cstddef> | |
| 21 #include <string> | 22 #include <string> |
| 22 #include <utility> | 23 #include <vector> |
| 23 | 24 |
| 24 #include "address_field_util.h" | |
| 25 #include "grit.h" | 25 #include "grit.h" |
| 26 #include "messages.h" | 26 #include "messages.h" |
| 27 #include "util/json.h" | 27 #include "util/json.h" |
| 28 #include "util/string_split.h" | 28 #include "util/string_split.h" |
| 29 | 29 |
| 30 namespace i18n { | 30 namespace i18n { |
| 31 namespace addressinput { | 31 namespace addressinput { |
| 32 | 32 |
| 33 namespace { | 33 namespace { |
| 34 | 34 |
| 35 typedef std::map<std::string, int> NameMessageIdMap; | 35 bool ParseToken(char c, AddressField* field) { |
| 36 | 36 assert(field != NULL); |
| 37 const char kAdminAreaNameTypeKey[] = "state_name_type"; | 37 switch (c) { |
| 38 const char kFormatKey[] = "fmt"; | 38 case 'R': |
| 39 const char kLanguageKey[] = "lang"; | 39 *field = COUNTRY; |
| 40 const char kLanguagesKey[] = "languages"; | 40 return true; |
| 41 const char kPostalCodeNameTypeKey[] = "zip_name_type"; | 41 case 'S': |
| 42 const char kSubKeysKey[] = "sub_keys"; | 42 *field = ADMIN_AREA; |
| 43 | 43 return true; |
| 44 // Used as a separator in a list of items. For example, the list of supported | 44 case 'C': |
| 45 // languages can be "de~fr~it". | 45 *field = LOCALITY; |
| 46 const char kSeparator = '~'; | 46 return true; |
| 47 | 47 case 'D': |
| 48 NameMessageIdMap InitAdminAreaMessageIds() { | 48 *field = DEPENDENT_LOCALITY; |
| 49 NameMessageIdMap message_ids; | 49 return true; |
| 50 message_ids.insert(std::make_pair( | 50 case 'X': |
| 51 "area", IDS_LIBADDRESSINPUT_I18N_AREA)); | 51 *field = SORTING_CODE; |
| 52 message_ids.insert(std::make_pair( | 52 return true; |
| 53 "county", IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL)); | 53 case 'Z': |
| 54 message_ids.insert(std::make_pair( | 54 *field = POSTAL_CODE; |
| 55 "department", IDS_LIBADDRESSINPUT_I18N_DEPARTMENT)); | 55 return true; |
| 56 message_ids.insert(std::make_pair( | 56 case 'A': |
| 57 "district", IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL)); | 57 *field = STREET_ADDRESS; |
| 58 message_ids.insert(std::make_pair( | 58 return true; |
| 59 "do_si", IDS_LIBADDRESSINPUT_I18N_DO_SI)); | 59 case 'O': |
| 60 message_ids.insert(std::make_pair( | 60 *field = ORGANIZATION; |
| 61 "emirate", IDS_LIBADDRESSINPUT_I18N_EMIRATE)); | 61 return true; |
| 62 message_ids.insert(std::make_pair( | 62 case 'N': |
| 63 "island", IDS_LIBADDRESSINPUT_I18N_ISLAND)); | 63 *field = RECIPIENT; |
| 64 message_ids.insert(std::make_pair( | 64 return true; |
| 65 "parish", IDS_LIBADDRESSINPUT_I18N_PARISH)); | 65 default: |
| 66 message_ids.insert(std::make_pair( | 66 return false; |
| 67 "prefecture", IDS_LIBADDRESSINPUT_I18N_PREFECTURE)); | 67 } |
| 68 message_ids.insert(std::make_pair( | |
| 69 "province", IDS_LIBADDRESSINPUT_I18N_PROVINCE)); | |
| 70 message_ids.insert(std::make_pair( | |
| 71 "state", IDS_LIBADDRESSINPUT_I18N_STATE_LABEL)); | |
| 72 return message_ids; | |
| 73 } | 68 } |
| 74 | 69 |
| 75 const NameMessageIdMap& GetAdminAreaMessageIds() { | 70 // Clears |fields|, parses |format|, and adds the format address fields to |
| 76 static const NameMessageIdMap kAdminAreaMessageIds(InitAdminAreaMessageIds()); | 71 // |fields|. |
| 77 return kAdminAreaMessageIds; | 72 // |
| 73 // For example, the address format in Switzerland is "%O%n%N%n%A%nAX-%Z | |
| 74 // %C%nÅLAND". It includes the allowed fields prefixed with %, newlines denoted | |
| 75 // %n, and the extra text that should be included on an envelope. This function | |
| 76 // parses only the tokens denoted % to determine how an address input form | |
| 77 // should be laid out. | |
| 78 // | |
| 79 // The format string "%O%n%N%n%A%nAX-%Z%C%nÅLAND" is parsed into | |
| 80 // {{ORGANIZATION}, {RECIPIENT}, {STREET_ADDRESS}, {POSTAL_CODE, LOCALITY}, {}}. | |
| 81 void ParseAddressFieldsFormat(const std::string& format, | |
| 82 std::vector<std::vector<AddressField> >* fields) { | |
| 83 assert(fields != NULL); | |
| 84 fields->clear(); | |
| 85 fields->resize(1); | |
| 86 std::vector<std::string> format_parts; | |
| 87 SplitString(format, '%', &format_parts); | |
| 88 for (std::vector<std::string>::size_type i = 1; | |
|
Evan Stade
2013/12/21 00:27:13
what's wrong with size_t?
please use gerrit instead
2014/01/02 19:49:39
You're right, size_t is better in this case. size_
| |
| 89 i < format_parts.size(); ++i) { | |
| 90 AddressField field = COUNTRY; | |
| 91 if (ParseToken(format_parts[i][0], &field)) { | |
| 92 fields->back().push_back(field); | |
| 93 } else if (format_parts[i][0] == 'n') { | |
| 94 fields->push_back(std::vector<AddressField>()); | |
| 95 } | |
| 96 } | |
| 78 } | 97 } |
| 79 | 98 |
| 80 NameMessageIdMap InitPostalCodeMessageIds() { | 99 // Clears |fields|, parses |required|, and adds the required fields to |fields|. |
| 81 NameMessageIdMap message_ids; | 100 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY, |
| 82 message_ids.insert(std::make_pair( | 101 // SORTING_CODE}. |
| 83 "postal", IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL)); | 102 void ParseAddressFieldsRequired(const std::string& required, |
| 84 message_ids.insert(std::make_pair( | 103 std::vector<AddressField>* fields) { |
| 85 "zip", IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL)); | 104 assert(fields != NULL); |
| 86 return message_ids; | 105 fields->clear(); |
| 106 for (std::string::const_iterator token = required.begin(); | |
|
Evan Stade
2013/12/21 00:27:13
nit: more idiomatic/easier to read imo:
for (size
please use gerrit instead
2014/01/02 19:49:39
Done.
| |
| 107 token != required.end(); ++token) { | |
| 108 AddressField field = COUNTRY; | |
| 109 if (ParseToken(*token, &field)) { | |
| 110 fields->push_back(field); | |
| 111 } | |
| 112 } | |
| 87 } | 113 } |
| 88 | 114 |
| 89 const NameMessageIdMap& GetPostalCodeMessageIds() { | 115 int GetAdminAreaMessageId(const std::string& admin_area_type) { |
| 90 static const NameMessageIdMap kPostalCodeMessageIds( | 116 if (admin_area_type == "area") { |
| 91 InitPostalCodeMessageIds()); | 117 return IDS_LIBADDRESSINPUT_I18N_AREA; |
| 92 return kPostalCodeMessageIds; | 118 } |
| 119 if (admin_area_type == "county") { | |
| 120 return IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL; | |
| 121 } | |
| 122 if (admin_area_type == "department") { | |
| 123 return IDS_LIBADDRESSINPUT_I18N_DEPARTMENT; | |
| 124 } | |
| 125 if (admin_area_type == "district") { | |
| 126 return IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL; | |
| 127 } | |
| 128 if (admin_area_type == "do_si") { | |
| 129 return IDS_LIBADDRESSINPUT_I18N_DO_SI; | |
| 130 } | |
| 131 if (admin_area_type == "emirate") { | |
| 132 return IDS_LIBADDRESSINPUT_I18N_EMIRATE; | |
| 133 } | |
| 134 if (admin_area_type == "island") { | |
| 135 return IDS_LIBADDRESSINPUT_I18N_ISLAND; | |
| 136 } | |
| 137 if (admin_area_type == "parish") { | |
| 138 return IDS_LIBADDRESSINPUT_I18N_PARISH; | |
| 139 } | |
| 140 if (admin_area_type == "prefecture") { | |
| 141 return IDS_LIBADDRESSINPUT_I18N_PREFECTURE; | |
| 142 } | |
| 143 if (admin_area_type == "province") { | |
| 144 return IDS_LIBADDRESSINPUT_I18N_PROVINCE; | |
| 145 } | |
| 146 if (admin_area_type == "state") { | |
| 147 return IDS_LIBADDRESSINPUT_I18N_STATE_LABEL; | |
| 148 } | |
| 149 return INVALID_MESSAGE_ID; | |
| 93 } | 150 } |
| 94 | 151 |
| 95 int GetMessageIdFromName(const std::string& name, | 152 int GetPostalCodeMessageId(const std::string& postal_code_type) { |
| 96 const NameMessageIdMap& message_ids) { | 153 if (postal_code_type == "postal") { |
| 97 NameMessageIdMap::const_iterator it = message_ids.find(name); | 154 return IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL; |
| 98 return it != message_ids.end() ? it->second : INVALID_MESSAGE_ID; | 155 } |
| 156 if (postal_code_type == "zip") { | |
| 157 return IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL; | |
| 158 } | |
| 159 return INVALID_MESSAGE_ID; | |
| 99 } | 160 } |
| 100 | 161 |
| 101 } // namespace | 162 } // namespace |
| 102 | 163 |
| 103 Rule::Rule() | 164 Rule::Rule() |
| 104 : format_(), | 165 : format_(), |
| 166 required_(), | |
| 105 sub_keys_(), | 167 sub_keys_(), |
| 106 languages_(), | 168 languages_(), |
| 107 language_(), | 169 language_(), |
| 170 postal_code_format_(), | |
| 108 admin_area_name_message_id_(INVALID_MESSAGE_ID), | 171 admin_area_name_message_id_(INVALID_MESSAGE_ID), |
| 109 postal_code_name_message_id_(INVALID_MESSAGE_ID) {} | 172 postal_code_name_message_id_(INVALID_MESSAGE_ID) {} |
| 110 | 173 |
| 111 Rule::~Rule() {} | 174 Rule::~Rule() {} |
| 112 | 175 |
| 113 void Rule::CopyFrom(const Rule& rule) { | 176 void Rule::CopyFrom(const Rule& rule) { |
| 114 format_ = rule.format_; | 177 format_ = rule.format_; |
| 178 required_ = rule.required_; | |
| 115 sub_keys_ = rule.sub_keys_; | 179 sub_keys_ = rule.sub_keys_; |
| 116 languages_ = rule.languages_; | 180 languages_ = rule.languages_; |
| 117 language_ = rule.language_; | 181 language_ = rule.language_; |
| 182 postal_code_format_ = rule.postal_code_format_; | |
| 118 admin_area_name_message_id_ = rule.admin_area_name_message_id_; | 183 admin_area_name_message_id_ = rule.admin_area_name_message_id_; |
| 119 postal_code_name_message_id_ = rule.postal_code_name_message_id_; | 184 postal_code_name_message_id_ = rule.postal_code_name_message_id_; |
| 120 } | 185 } |
| 121 | 186 |
| 122 bool Rule::ParseSerializedRule(const std::string& serialized_rule) { | 187 bool Rule::ParseSerializedRule(const std::string& serialized_rule) { |
| 123 scoped_ptr<Json> json(Json::Build()); | 188 scoped_ptr<Json> json(Json::Build()); |
| 124 if (!json->ParseObject(serialized_rule)) { | 189 if (!json->ParseObject(serialized_rule)) { |
| 125 return false; | 190 return false; |
| 126 } | 191 } |
| 127 | 192 |
| 193 static const char kFormatKey[] = "fmt"; | |
| 128 if (json->HasStringValueForKey(kFormatKey)) { | 194 if (json->HasStringValueForKey(kFormatKey)) { |
| 129 ParseAddressFieldsFormat(json->GetStringValueForKey(kFormatKey), &format_); | 195 ParseAddressFieldsFormat(json->GetStringValueForKey(kFormatKey), &format_); |
| 130 } | 196 } |
| 131 | 197 |
| 198 static const char kRequiredKey[] = "require"; | |
| 199 if (json->HasStringValueForKey(kRequiredKey)) { | |
| 200 ParseAddressFieldsRequired( | |
| 201 json->GetStringValueForKey(kRequiredKey), &required_); | |
| 202 } | |
| 203 | |
|
Evan Stade
2013/12/21 00:27:13
extra newline
| |
| 204 | |
| 205 // Used as a separator in a list of items. For example, the list of supported | |
| 206 // languages can be "de~fr~it". | |
| 207 static const char kSeparator = '~'; | |
| 208 static const char kSubKeysKey[] = "sub_keys"; | |
| 132 if (json->HasStringValueForKey(kSubKeysKey)) { | 209 if (json->HasStringValueForKey(kSubKeysKey)) { |
| 133 SplitString( | 210 SplitString( |
| 134 json->GetStringValueForKey(kSubKeysKey), kSeparator, &sub_keys_); | 211 json->GetStringValueForKey(kSubKeysKey), kSeparator, &sub_keys_); |
| 135 } | 212 } |
| 136 | 213 |
| 214 static const char kLanguagesKey[] = "languages"; | |
| 137 if (json->HasStringValueForKey(kLanguagesKey)) { | 215 if (json->HasStringValueForKey(kLanguagesKey)) { |
| 138 SplitString( | 216 SplitString( |
| 139 json->GetStringValueForKey(kLanguagesKey), kSeparator, &languages_); | 217 json->GetStringValueForKey(kLanguagesKey), kSeparator, &languages_); |
| 140 } | 218 } |
| 141 | 219 |
| 220 static const char kLanguageKey[] = "lang"; | |
| 142 if (json->HasStringValueForKey(kLanguageKey)) { | 221 if (json->HasStringValueForKey(kLanguageKey)) { |
| 143 language_ = json->GetStringValueForKey(kLanguageKey); | 222 language_ = json->GetStringValueForKey(kLanguageKey); |
| 144 } | 223 } |
| 145 | 224 |
| 146 if (json->HasStringValueForKey(kAdminAreaNameTypeKey)) { | 225 static const char kPostalCodeFormatKey[] = "zip"; |
| 147 admin_area_name_message_id_ = | 226 if (json->HasStringValueForKey(kPostalCodeFormatKey)) { |
| 148 GetMessageIdFromName(json->GetStringValueForKey(kAdminAreaNameTypeKey), | 227 postal_code_format_ = json->GetStringValueForKey(kPostalCodeFormatKey); |
| 149 GetAdminAreaMessageIds()); | |
| 150 } | 228 } |
| 151 | 229 |
| 230 static const char kAdminAreaNameTypeKey[] = "state_name_type"; | |
| 231 if (json->HasStringValueForKey(kAdminAreaNameTypeKey)) { | |
| 232 admin_area_name_message_id_ = GetAdminAreaMessageId( | |
| 233 json->GetStringValueForKey(kAdminAreaNameTypeKey)); | |
| 234 } | |
| 235 | |
| 236 static const char kPostalCodeNameTypeKey[] = "zip_name_type"; | |
| 152 if (json->HasStringValueForKey(kPostalCodeNameTypeKey)) { | 237 if (json->HasStringValueForKey(kPostalCodeNameTypeKey)) { |
| 153 postal_code_name_message_id_ = | 238 postal_code_name_message_id_ = GetPostalCodeMessageId( |
| 154 GetMessageIdFromName(json->GetStringValueForKey(kPostalCodeNameTypeKey), | 239 json->GetStringValueForKey(kPostalCodeNameTypeKey)); |
| 155 GetPostalCodeMessageIds()); | |
| 156 } | 240 } |
| 157 | 241 |
| 158 return true; | 242 return true; |
| 159 } | 243 } |
| 160 | 244 |
| 161 } // namespace addressinput | 245 } // namespace addressinput |
| 162 } // namespace i18n | 246 } // namespace i18n |
| OLD | NEW |