Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: components/payments/currency_formatter.cc

Issue 2621033003: [Payments] Currency formatter for order amounts. (Closed)
Patch Set: currency formatter takes locale_name as string Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 #include "components/payments/currency_formatter.h"
6
7 #include <memory>
8
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "third_party/icu/source/common/unicode/stringpiece.h"
12 #include "third_party/icu/source/common/unicode/uchar.h"
13 #include "third_party/icu/source/common/unicode/unistr.h"
14 #include "third_party/icu/source/common/unicode/utypes.h"
15
16 namespace payments {
17
18 const char kIso4217CurrencySystem[] = "urn:iso:std:iso:4217";
19
20 namespace {
21
22 // Max currency code length. Length of currency code can be at most 2048.
23 const static size_t kMaxCurrencyCodeLength = 2048;
24
25 // Returns whether the |currency_code| is valid to be used in ICU.
26 bool ShouldUseCurrencyCode(const std::string& currency_code,
27 const base::Optional<std::string> currency_system) {
28 return currency_system.value_or(kIso4217CurrencySystem) ==
29 kIso4217CurrencySystem &&
30 !currency_code.empty() &&
31 currency_code.size() <= kMaxCurrencyCodeLength;
32 }
33
34 } // namespace
35
36 CurrencyFormatter::CurrencyFormatter(
37 const std::string& currency_code,
38 const base::Optional<std::string> currency_system,
39 const std::string& locale_name)
40 : locale_(locale_name.c_str()) {
41 UErrorCode error_code = U_ZERO_ERROR;
42 icu_formatter_.reset(
43 icu::NumberFormat::createCurrencyInstance(locale_, error_code));
44 if (U_FAILURE(error_code)) {
45 icu::UnicodeString name;
46 std::string locale_name;
please use gerrit instead 2017/01/12 19:23:24 Nit: it's confusing that your have a locale_name v
Mathieu 2017/01/12 20:29:57 Done.
47 locale_.getDisplayName(name).toUTF8String(locale_name);
48 LOG(ERROR) << "Failed to initialize the currency formatter for "
49 << locale_name;
50 return;
51 }
52
53 if (ShouldUseCurrencyCode(currency_code, currency_system)) {
54 currency_code_.reset(
55 new icu::UnicodeString(currency_code.c_str(), currency_code.length()));
56 } else {
57 // For non-ISO4217 currency system/code, we use a dummy code which is not
58 // going to appear in the output (stripped in Format()). This is because ICU
59 // NumberFormat will not accept an empty currency code. Under these
60 // circumstances, the number amount will be formatted according to locale,
61 // which is desirable (e.g. "55.00" -> "55,00" in fr_FR).
62 currency_code_.reset(new icu::UnicodeString("DUM", 3));
63 }
64
65 icu_formatter_->setCurrency(currency_code_->getBuffer(), error_code);
66 if (U_FAILURE(error_code)) {
67 std::string currency_code_str;
68 currency_code_->toUTF8String(currency_code_str);
69 LOG(ERROR) << "Could not set currency code on currency formatter: "
70 << currency_code_str;
71 return;
72 }
73 }
74
75 CurrencyFormatter::~CurrencyFormatter() {}
76
77 base::string16 CurrencyFormatter::Format(const std::string& amount) {
78 // It's possible that the ICU formatter didn't initialize properly.
79 if (!icu_formatter_ || !icu_formatter_->getCurrency()) {
please use gerrit instead 2017/01/12 19:23:24 nit: no need for {}
Mathieu 2017/01/12 20:29:56 Done.
80 return base::UTF8ToUTF16(amount);
81 }
82
83 icu::UnicodeString output;
84 UErrorCode error_code = U_ZERO_ERROR;
85 icu_formatter_->format(icu::StringPiece(amount.c_str()), output, nullptr,
86 error_code);
87
88 if (output.isEmpty()) {
please use gerrit instead 2017/01/12 19:23:24 ditto
Mathieu 2017/01/12 20:29:56 Done.
89 return base::UTF8ToUTF16(amount);
90 }
91
92 // Explicitly removes the currency code (truncated to its 3-letter and
93 // 2-letter versions) from the output, because callers are expected to
94 // displays the currency code alongside this result.
please use gerrit instead 2017/01/12 19:23:24 display
Mathieu 2017/01/12 20:29:57 Done.
95 //
96 // 3+ letters: If currency code is "ABCDEF" or "BTX", this code will
97 // transform "ABC55.00"/"BTX55.00" to "55.00".
98 // 2 letters: If currency code is "CAD", this code will transform "CA$55.00"
99 // to "$55.00" (en_US) or "55,00 $ CA" to "55,00 $" (fr_FR).
100 icu::UnicodeString tmp_currency_code(*currency_code_);
101 tmp_currency_code.truncate(3);
102 output.findAndReplace(tmp_currency_code, "");
103 tmp_currency_code.truncate(2);
104 output.findAndReplace(tmp_currency_code, "");
105 // Trims any unicode whitespace (including non-breaking space).
106 if (u_isUWhiteSpace(output[0])) {
107 output.remove(0, 1);
108 }
109 if (u_isUWhiteSpace(output[output.length() - 1])) {
110 output.remove(output.length() - 1, 1);
111 }
112
113 std::string output_str;
114 output.toUTF8String(output_str);
115 return base::UTF8ToUTF16(output_str);
116 }
117
118 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698