message_formatter.cc 5.3 KB

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