1// Copyright (C) 2013 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (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
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <libaddressinput/localization.h>
16
17#include <libaddressinput/address_data.h>
18#include <libaddressinput/address_field.h>
19#include <libaddressinput/address_problem.h>
20
21#include <cassert>
22#include <cstddef>
23#include <string>
24
25#include "grit.h"
26#include "region_data_constants.h"
27#include "rule.h"
28#include "util/string_split.h"
29#include "util/string_util.h"
30
31namespace {
32
33void PushBackUrl(std::vector<std::string>& parameters, const std::string url) {
34  // TODO: HTML-escape the "url".
35  parameters.push_back("<a href=\"" + url + "\">");
36  parameters.push_back("</a>");
37}
38
39}  // namespace
40
41namespace i18n {
42namespace addressinput {
43
44namespace {
45
46#include "en_messages.cc"
47
48std::string GetEnglishString(int message_id) {
49  const char* str = GetString(message_id);
50  return str != NULL ? std::string(str) : std::string();
51}
52
53}  // namespace
54
55Localization::Localization() : get_string_(&GetEnglishString) {}
56
57Localization::~Localization() {}
58
59std::string Localization::GetString(int message_id) const {
60  return get_string_(message_id);
61}
62
63std::string Localization::GetErrorMessage(const AddressData& address,
64                                          AddressField field,
65                                          AddressProblem problem,
66                                          bool enable_examples,
67                                          bool enable_links) const {
68  if (field == POSTAL_CODE) {
69    Rule rule;
70    rule.CopyFrom(Rule::GetDefault());
71    std::string postal_code_example, post_service_url;
72    if (rule.ParseSerializedRule(
73            RegionDataConstants::GetRegionData(address.region_code))) {
74      if (enable_examples) {
75        std::vector<std::string> examples_list;
76        SplitString(rule.GetPostalCodeExample(), ',', &examples_list);
77        if (!examples_list.empty()) {
78          postal_code_example = examples_list.front();
79        }
80      }
81      if (enable_links) {
82        post_service_url = rule.GetPostServiceUrl();
83      }
84    } else {
85      assert(false);
86    }
87    // If we can't parse the serialized rule |uses_postal_code_as_label| will be
88    // determined from the default rule.
89    bool uses_postal_code_as_label =
90        rule.GetPostalCodeNameMessageId() ==
91        IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL;
92    return GetErrorMessageForPostalCode(address, problem,
93                                        uses_postal_code_as_label,
94                                        postal_code_example, post_service_url);
95  } else {
96    if (problem == MISSING_REQUIRED_FIELD) {
97      return get_string_(IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD);
98    } else if (problem == UNKNOWN_VALUE) {
99      std::vector<std::string> parameters;
100      if (AddressData::IsRepeatedFieldValue(field)) {
101        std::vector<std::string> values = address.GetRepeatedFieldValue(field);
102        assert(!values.empty());
103        parameters.push_back(values.front());
104      } else {
105        parameters.push_back(address.GetFieldValue(field));
106      }
107      return DoReplaceStringPlaceholders(
108          get_string_(IDS_LIBADDRESSINPUT_UNKNOWN_VALUE), parameters);
109    } else if (problem == USES_P_O_BOX) {
110      return get_string_(IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE);
111    } else {
112      // Keep the default under "else" so the compiler helps us check that all
113      // handled cases return and don't fall through.
114      assert(false);
115      return "";
116    }
117  }
118}
119
120void Localization::SetGetter(std::string (*getter)(int)) {
121  assert(getter != NULL);
122  get_string_ = getter;
123}
124
125std::string Localization::GetErrorMessageForPostalCode(
126    const AddressData& address,
127    AddressProblem problem,
128    bool uses_postal_code_as_label,
129    std::string postal_code_example,
130    std::string post_service_url) const {
131  int message_id;
132  std::vector<std::string> parameters;
133  if (problem == MISSING_REQUIRED_FIELD) {
134    if (!postal_code_example.empty() && !post_service_url.empty()) {
135      message_id = uses_postal_code_as_label ?
136          IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL :
137          IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL;
138      parameters.push_back(postal_code_example);
139      PushBackUrl(parameters, post_service_url);
140    } else if (!postal_code_example.empty()) {
141      message_id = uses_postal_code_as_label ?
142          IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE :
143          IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE ;
144      parameters.push_back(postal_code_example);
145    } else {
146      message_id = IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD;
147    }
148    return DoReplaceStringPlaceholders(get_string_(message_id), parameters);
149  } else if (problem == INVALID_FORMAT) {
150    if (!postal_code_example.empty() && !post_service_url.empty()) {
151      message_id = uses_postal_code_as_label ?
152          IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL :
153          IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL;
154      parameters.push_back(postal_code_example);
155      PushBackUrl(parameters, post_service_url);
156    } else if (!postal_code_example.empty()) {
157      message_id = uses_postal_code_as_label ?
158          IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE :
159          IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE;
160      parameters.push_back(postal_code_example);
161    } else {
162      message_id = uses_postal_code_as_label ?
163          IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE :
164          IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP;
165    }
166    return DoReplaceStringPlaceholders(get_string_(message_id), parameters);
167  } else if (problem == MISMATCHING_VALUE) {
168    if (!post_service_url.empty()) {
169      message_id = uses_postal_code_as_label ?
170          IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL :
171          IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL;
172      PushBackUrl(parameters, post_service_url);
173    } else {
174      message_id = uses_postal_code_as_label ?
175          IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE :
176          IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP;
177    }
178    return DoReplaceStringPlaceholders(get_string_(message_id), parameters);
179  } else {
180    // Keep the default under "else" so the compiler helps us check that all
181    // handled cases return and don't fall through.
182    assert(false);
183    return "";
184  }
185}
186
187}  // namespace addressinput
188}  // namespace i18n
189