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 (size_t i = 1; i < format_parts.size(); ++i) { |
| 89 AddressField field = COUNTRY; |
| 90 if (ParseToken(format_parts[i][0], &field)) { |
| 91 fields->back().push_back(field); |
| 92 } else if (format_parts[i][0] == 'n') { |
| 93 fields->push_back(std::vector<AddressField>()); |
| 94 } |
| 95 } |
78 } | 96 } |
79 | 97 |
80 NameMessageIdMap InitPostalCodeMessageIds() { | 98 // Clears |fields|, parses |required|, and adds the required fields to |fields|. |
81 NameMessageIdMap message_ids; | 99 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY, |
82 message_ids.insert(std::make_pair( | 100 // SORTING_CODE}. |
83 "postal", IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL)); | 101 void ParseAddressFieldsRequired(const std::string& required, |
84 message_ids.insert(std::make_pair( | 102 std::vector<AddressField>* fields) { |
85 "zip", IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL)); | 103 assert(fields != NULL); |
86 return message_ids; | 104 fields->clear(); |
| 105 for (size_t i = 0; i < required.length(); ++i) { |
| 106 AddressField field = COUNTRY; |
| 107 if (ParseToken(required[i], &field)) { |
| 108 fields->push_back(field); |
| 109 } |
| 110 } |
87 } | 111 } |
88 | 112 |
89 const NameMessageIdMap& GetPostalCodeMessageIds() { | 113 int GetAdminAreaMessageId(const std::string& admin_area_type) { |
90 static const NameMessageIdMap kPostalCodeMessageIds( | 114 if (admin_area_type == "area") { |
91 InitPostalCodeMessageIds()); | 115 return IDS_LIBADDRESSINPUT_I18N_AREA; |
92 return kPostalCodeMessageIds; | 116 } |
| 117 if (admin_area_type == "county") { |
| 118 return IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL; |
| 119 } |
| 120 if (admin_area_type == "department") { |
| 121 return IDS_LIBADDRESSINPUT_I18N_DEPARTMENT; |
| 122 } |
| 123 if (admin_area_type == "district") { |
| 124 return IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL; |
| 125 } |
| 126 if (admin_area_type == "do_si") { |
| 127 return IDS_LIBADDRESSINPUT_I18N_DO_SI; |
| 128 } |
| 129 if (admin_area_type == "emirate") { |
| 130 return IDS_LIBADDRESSINPUT_I18N_EMIRATE; |
| 131 } |
| 132 if (admin_area_type == "island") { |
| 133 return IDS_LIBADDRESSINPUT_I18N_ISLAND; |
| 134 } |
| 135 if (admin_area_type == "parish") { |
| 136 return IDS_LIBADDRESSINPUT_I18N_PARISH; |
| 137 } |
| 138 if (admin_area_type == "prefecture") { |
| 139 return IDS_LIBADDRESSINPUT_I18N_PREFECTURE; |
| 140 } |
| 141 if (admin_area_type == "province") { |
| 142 return IDS_LIBADDRESSINPUT_I18N_PROVINCE; |
| 143 } |
| 144 if (admin_area_type == "state") { |
| 145 return IDS_LIBADDRESSINPUT_I18N_STATE_LABEL; |
| 146 } |
| 147 return INVALID_MESSAGE_ID; |
93 } | 148 } |
94 | 149 |
95 int GetMessageIdFromName(const std::string& name, | 150 int GetPostalCodeMessageId(const std::string& postal_code_type) { |
96 const NameMessageIdMap& message_ids) { | 151 if (postal_code_type == "postal") { |
97 NameMessageIdMap::const_iterator it = message_ids.find(name); | 152 return IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL; |
98 return it != message_ids.end() ? it->second : INVALID_MESSAGE_ID; | 153 } |
| 154 if (postal_code_type == "zip") { |
| 155 return IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL; |
| 156 } |
| 157 return INVALID_MESSAGE_ID; |
99 } | 158 } |
100 | 159 |
101 } // namespace | 160 } // namespace |
102 | 161 |
103 Rule::Rule() | 162 Rule::Rule() |
104 : format_(), | 163 : format_(), |
| 164 required_(), |
105 sub_keys_(), | 165 sub_keys_(), |
106 languages_(), | 166 languages_(), |
107 language_(), | 167 language_(), |
| 168 postal_code_format_(), |
108 admin_area_name_message_id_(INVALID_MESSAGE_ID), | 169 admin_area_name_message_id_(INVALID_MESSAGE_ID), |
109 postal_code_name_message_id_(INVALID_MESSAGE_ID) {} | 170 postal_code_name_message_id_(INVALID_MESSAGE_ID) {} |
110 | 171 |
111 Rule::~Rule() {} | 172 Rule::~Rule() {} |
112 | 173 |
113 void Rule::CopyFrom(const Rule& rule) { | 174 void Rule::CopyFrom(const Rule& rule) { |
114 format_ = rule.format_; | 175 format_ = rule.format_; |
| 176 required_ = rule.required_; |
115 sub_keys_ = rule.sub_keys_; | 177 sub_keys_ = rule.sub_keys_; |
116 languages_ = rule.languages_; | 178 languages_ = rule.languages_; |
117 language_ = rule.language_; | 179 language_ = rule.language_; |
| 180 postal_code_format_ = rule.postal_code_format_; |
118 admin_area_name_message_id_ = rule.admin_area_name_message_id_; | 181 admin_area_name_message_id_ = rule.admin_area_name_message_id_; |
119 postal_code_name_message_id_ = rule.postal_code_name_message_id_; | 182 postal_code_name_message_id_ = rule.postal_code_name_message_id_; |
120 } | 183 } |
121 | 184 |
122 bool Rule::ParseSerializedRule(const std::string& serialized_rule) { | 185 bool Rule::ParseSerializedRule(const std::string& serialized_rule) { |
123 scoped_ptr<Json> json(Json::Build()); | 186 scoped_ptr<Json> json(Json::Build()); |
124 if (!json->ParseObject(serialized_rule)) { | 187 if (!json->ParseObject(serialized_rule)) { |
125 return false; | 188 return false; |
126 } | 189 } |
127 | 190 |
128 std::string format; | 191 std::string value; |
129 if (json->GetStringValueForKey(kFormatKey, &format)) { | 192 if (json->GetStringValueForKey("fmt", &value)) { |
130 ParseAddressFieldsFormat(format, &format_); | 193 ParseAddressFieldsFormat(value, &format_); |
131 } | 194 } |
132 | 195 |
133 std::string subkeys; | 196 if (json->GetStringValueForKey("require", &value)) { |
134 if (json->GetStringValueForKey(kSubKeysKey, &subkeys)) { | 197 ParseAddressFieldsRequired(value, &required_); |
135 SplitString(subkeys, kSeparator, &sub_keys_); | |
136 } | 198 } |
137 | 199 |
138 std::string languages; | 200 // Used as a separator in a list of items. For example, the list of supported |
139 if (json->GetStringValueForKey(kLanguagesKey, &languages)) { | 201 // languages can be "de~fr~it". |
140 SplitString(languages, kSeparator, &languages_); | 202 static const char kSeparator = '~'; |
| 203 if (json->GetStringValueForKey("sub_keys", &value)) { |
| 204 SplitString(value, kSeparator, &sub_keys_); |
141 } | 205 } |
142 | 206 |
143 json->GetStringValueForKey(kLanguageKey, &language_); | 207 if (json->GetStringValueForKey("languages", &value)) { |
144 | 208 SplitString(value, kSeparator, &languages_); |
145 std::string area_name_type; | |
146 if (json->GetStringValueForKey(kAdminAreaNameTypeKey, &area_name_type)) { | |
147 admin_area_name_message_id_ = | |
148 GetMessageIdFromName(area_name_type, GetAdminAreaMessageIds()); | |
149 } | 209 } |
150 | 210 |
151 std::string postal_code_name_type; | 211 if (json->GetStringValueForKey("lang", &value)) { |
152 if (json->GetStringValueForKey(kPostalCodeNameTypeKey, | 212 language_ = value; |
153 &postal_code_name_type)) { | 213 } |
154 postal_code_name_message_id_ = | 214 |
155 GetMessageIdFromName(postal_code_name_type, GetPostalCodeMessageIds()); | 215 if (json->GetStringValueForKey("zip", &value)) { |
| 216 postal_code_format_ = value; |
| 217 } |
| 218 |
| 219 if (json->GetStringValueForKey("state_name_type", &value)) { |
| 220 admin_area_name_message_id_ = GetAdminAreaMessageId(value); |
| 221 } |
| 222 |
| 223 if (json->GetStringValueForKey("zip_name_type", &value)) { |
| 224 postal_code_name_message_id_ = GetPostalCodeMessageId(value); |
156 } | 225 } |
157 | 226 |
158 return true; | 227 return true; |
159 } | 228 } |
160 | 229 |
161 } // namespace addressinput | 230 } // namespace addressinput |
162 } // namespace i18n | 231 } // namespace i18n |
OLD | NEW |