• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
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 "base/i18n/message_formatter.h"
6 
7 #include "base/check.h"
8 #include "base/i18n/unicodestring.h"
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/time/time.h"
12 #include "third_party/icu/source/common/unicode/unistr.h"
13 #include "third_party/icu/source/common/unicode/utypes.h"
14 #include "third_party/icu/source/i18n/unicode/fmtable.h"
15 #include "third_party/icu/source/i18n/unicode/msgfmt.h"
16 
17 using icu::UnicodeString;
18 
19 namespace base {
20 namespace i18n {
21 namespace {
UnicodeStringFromStringPiece(StringPiece str)22 UnicodeString UnicodeStringFromStringPiece(StringPiece str) {
23   return UnicodeString::fromUTF8(
24       icu::StringPiece(str.data(), base::checked_cast<int32_t>(str.size())));
25 }
26 }  // anonymous namespace
27 
28 namespace internal {
MessageArg()29 MessageArg::MessageArg() : formattable(nullptr) {}
30 
MessageArg(const char * s)31 MessageArg::MessageArg(const char* s)
32     : formattable(new icu::Formattable(UnicodeStringFromStringPiece(s))) {}
33 
MessageArg(StringPiece s)34 MessageArg::MessageArg(StringPiece s)
35     : formattable(new icu::Formattable(UnicodeStringFromStringPiece(s))) {}
36 
MessageArg(const std::string & s)37 MessageArg::MessageArg(const std::string& s)
38     : formattable(new icu::Formattable(UnicodeString::fromUTF8(s))) {}
39 
MessageArg(const std::u16string & s)40 MessageArg::MessageArg(const std::u16string& s)
41     : formattable(new icu::Formattable(UnicodeString(s.data(), s.size()))) {}
42 
MessageArg(int i)43 MessageArg::MessageArg(int i) : formattable(new icu::Formattable(i)) {}
44 
MessageArg(int64_t i)45 MessageArg::MessageArg(int64_t i) : formattable(new icu::Formattable(i)) {}
46 
MessageArg(double d)47 MessageArg::MessageArg(double d) : formattable(new icu::Formattable(d)) {}
48 
MessageArg(const Time & t)49 MessageArg::MessageArg(const Time& t)
50     : formattable(new icu::Formattable(
51           static_cast<UDate>(t.InMillisecondsFSinceUnixEpoch()))) {}
52 
53 MessageArg::~MessageArg() = default;
54 
55 // Tests if this argument has a value, and if so increments *count.
has_value(int * count) const56 bool MessageArg::has_value(int *count) const {
57   if (formattable == nullptr)
58     return false;
59 
60   ++*count;
61   return true;
62 }
63 
64 }  // namespace internal
65 
FormatWithNumberedArgs(StringPiece16 msg,const internal::MessageArg & arg0,const internal::MessageArg & arg1,const internal::MessageArg & arg2,const internal::MessageArg & arg3,const internal::MessageArg & arg4,const internal::MessageArg & arg5,const internal::MessageArg & arg6)66 std::u16string MessageFormatter::FormatWithNumberedArgs(
67     StringPiece16 msg,
68     const internal::MessageArg& arg0,
69     const internal::MessageArg& arg1,
70     const internal::MessageArg& arg2,
71     const internal::MessageArg& arg3,
72     const internal::MessageArg& arg4,
73     const internal::MessageArg& arg5,
74     const internal::MessageArg& arg6) {
75   int32_t args_count = 0;
76   icu::Formattable args[] = {
77       arg0.has_value(&args_count) ? *arg0.formattable : icu::Formattable(),
78       arg1.has_value(&args_count) ? *arg1.formattable : icu::Formattable(),
79       arg2.has_value(&args_count) ? *arg2.formattable : icu::Formattable(),
80       arg3.has_value(&args_count) ? *arg3.formattable : icu::Formattable(),
81       arg4.has_value(&args_count) ? *arg4.formattable : icu::Formattable(),
82       arg5.has_value(&args_count) ? *arg5.formattable : icu::Formattable(),
83       arg6.has_value(&args_count) ? *arg6.formattable : icu::Formattable(),
84   };
85 
86   UnicodeString msg_string(msg.data(), msg.size());
87   UErrorCode error = U_ZERO_ERROR;
88   icu::MessageFormat format(msg_string,  error);
89   icu::UnicodeString formatted;
90   icu::FieldPosition ignore(icu::FieldPosition::DONT_CARE);
91   format.format(args, args_count, formatted, ignore, error);
92   if (U_FAILURE(error)) {
93     LOG(ERROR) << "MessageFormat(" << msg << ") failed with "
94                << u_errorName(error);
95     return std::u16string();
96   }
97   return i18n::UnicodeStringToString16(formatted);
98 }
99 
FormatWithNamedArgs(StringPiece16 msg,StringPiece name0,const internal::MessageArg & arg0,StringPiece name1,const internal::MessageArg & arg1,StringPiece name2,const internal::MessageArg & arg2,StringPiece name3,const internal::MessageArg & arg3,StringPiece name4,const internal::MessageArg & arg4,StringPiece name5,const internal::MessageArg & arg5,StringPiece name6,const internal::MessageArg & arg6)100 std::u16string MessageFormatter::FormatWithNamedArgs(
101     StringPiece16 msg,
102     StringPiece name0,
103     const internal::MessageArg& arg0,
104     StringPiece name1,
105     const internal::MessageArg& arg1,
106     StringPiece name2,
107     const internal::MessageArg& arg2,
108     StringPiece name3,
109     const internal::MessageArg& arg3,
110     StringPiece name4,
111     const internal::MessageArg& arg4,
112     StringPiece name5,
113     const internal::MessageArg& arg5,
114     StringPiece name6,
115     const internal::MessageArg& arg6) {
116   icu::UnicodeString names[] = {
117       UnicodeStringFromStringPiece(name0),
118       UnicodeStringFromStringPiece(name1),
119       UnicodeStringFromStringPiece(name2),
120       UnicodeStringFromStringPiece(name3),
121       UnicodeStringFromStringPiece(name4),
122       UnicodeStringFromStringPiece(name5),
123       UnicodeStringFromStringPiece(name6),
124   };
125   int32_t args_count = 0;
126   icu::Formattable args[] = {
127       arg0.has_value(&args_count) ? *arg0.formattable : icu::Formattable(),
128       arg1.has_value(&args_count) ? *arg1.formattable : icu::Formattable(),
129       arg2.has_value(&args_count) ? *arg2.formattable : icu::Formattable(),
130       arg3.has_value(&args_count) ? *arg3.formattable : icu::Formattable(),
131       arg4.has_value(&args_count) ? *arg4.formattable : icu::Formattable(),
132       arg5.has_value(&args_count) ? *arg5.formattable : icu::Formattable(),
133       arg6.has_value(&args_count) ? *arg6.formattable : icu::Formattable(),
134   };
135 
136   UnicodeString msg_string(msg.data(), msg.size());
137   UErrorCode error = U_ZERO_ERROR;
138   icu::MessageFormat format(msg_string, error);
139 
140   icu::UnicodeString formatted;
141   format.format(names, args, args_count, formatted, error);
142   if (U_FAILURE(error)) {
143     LOG(ERROR) << "MessageFormat(" << msg << ") failed with "
144                << u_errorName(error);
145     return std::u16string();
146   }
147   return i18n::UnicodeStringToString16(formatted);
148 }
149 
150 }  // namespace i18n
151 }  // namespace base
152