ListFormat.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #define AK_DONT_REPLACE_STD
  7. #include <AK/NonnullOwnPtr.h>
  8. #include <LibLocale/ICU.h>
  9. #include <LibLocale/ListFormat.h>
  10. #include <unicode/listformatter.h>
  11. namespace Locale {
  12. ListFormatType list_format_type_from_string(StringView list_format_type)
  13. {
  14. if (list_format_type == "conjunction"sv)
  15. return ListFormatType::Conjunction;
  16. if (list_format_type == "disjunction"sv)
  17. return ListFormatType::Disjunction;
  18. if (list_format_type == "unit"sv)
  19. return ListFormatType::Unit;
  20. VERIFY_NOT_REACHED();
  21. }
  22. StringView list_format_type_to_string(ListFormatType list_format_type)
  23. {
  24. switch (list_format_type) {
  25. case ListFormatType::Conjunction:
  26. return "conjunction"sv;
  27. case ListFormatType::Disjunction:
  28. return "disjunction"sv;
  29. case ListFormatType::Unit:
  30. return "unit"sv;
  31. }
  32. VERIFY_NOT_REACHED();
  33. }
  34. static constexpr UListFormatterType icu_list_format_type(ListFormatType type)
  35. {
  36. switch (type) {
  37. case ListFormatType::Conjunction:
  38. return ULISTFMT_TYPE_AND;
  39. case ListFormatType::Disjunction:
  40. return ULISTFMT_TYPE_OR;
  41. case ListFormatType::Unit:
  42. return ULISTFMT_TYPE_UNITS;
  43. }
  44. VERIFY_NOT_REACHED();
  45. }
  46. static constexpr UListFormatterWidth icu_list_format_width(Style style)
  47. {
  48. switch (style) {
  49. case Style::Long:
  50. return ULISTFMT_WIDTH_WIDE;
  51. case Style::Short:
  52. return ULISTFMT_WIDTH_SHORT;
  53. case Style::Narrow:
  54. return ULISTFMT_WIDTH_NARROW;
  55. }
  56. VERIFY_NOT_REACHED();
  57. }
  58. static constexpr StringView icu_list_format_field_to_string(i32 field)
  59. {
  60. switch (field) {
  61. case ULISTFMT_LITERAL_FIELD:
  62. return "literal"sv;
  63. case ULISTFMT_ELEMENT_FIELD:
  64. return "element"sv;
  65. }
  66. VERIFY_NOT_REACHED();
  67. }
  68. class ListFormatImpl : public ListFormat {
  69. public:
  70. ListFormatImpl(NonnullOwnPtr<icu::ListFormatter> formatter)
  71. : m_formatter(move(formatter))
  72. {
  73. }
  74. virtual ~ListFormatImpl() override = default;
  75. virtual String format(ReadonlySpan<String> list) const override
  76. {
  77. UErrorCode status = U_ZERO_ERROR;
  78. auto formatted = format_list_impl(list);
  79. if (!formatted.has_value())
  80. return {};
  81. auto formatted_string = formatted->toTempString(status);
  82. if (icu_failure(status))
  83. return {};
  84. return icu_string_to_string(formatted_string);
  85. }
  86. virtual Vector<Partition> format_to_parts(ReadonlySpan<String> list) const override
  87. {
  88. UErrorCode status = U_ZERO_ERROR;
  89. auto formatted = format_list_impl(list);
  90. if (!formatted.has_value())
  91. return {};
  92. auto formatted_string = formatted->toTempString(status);
  93. if (icu_failure(status))
  94. return {};
  95. Vector<Partition> result;
  96. icu::ConstrainedFieldPosition position;
  97. position.constrainCategory(UFIELD_CATEGORY_LIST);
  98. while (static_cast<bool>(formatted->nextPosition(position, status)) && icu_success(status)) {
  99. auto type = icu_list_format_field_to_string(position.getField());
  100. auto part = formatted_string.tempSubStringBetween(position.getStart(), position.getLimit());
  101. result.empend(type, icu_string_to_string(part));
  102. }
  103. return result;
  104. }
  105. private:
  106. Optional<icu::FormattedList> format_list_impl(ReadonlySpan<String> list) const
  107. {
  108. UErrorCode status = U_ZERO_ERROR;
  109. auto icu_list = icu_string_list(list);
  110. auto formatted_list = m_formatter->formatStringsToValue(icu_list.data(), static_cast<i32>(icu_list.size()), status);
  111. if (icu_failure(status))
  112. return {};
  113. return formatted_list;
  114. }
  115. NonnullOwnPtr<icu::ListFormatter> m_formatter;
  116. };
  117. NonnullOwnPtr<ListFormat> ListFormat::create(StringView locale, ListFormatType type, Style style)
  118. {
  119. UErrorCode status = U_ZERO_ERROR;
  120. auto locale_data = LocaleData::for_locale(locale);
  121. VERIFY(locale_data.has_value());
  122. auto formatter = adopt_own(*icu::ListFormatter::createInstance(locale_data->locale(), icu_list_format_type(type), icu_list_format_width(style), status));
  123. VERIFY(icu_success(status));
  124. return adopt_own(*new ListFormatImpl(move(formatter)));
  125. }
  126. }