ListFormat.cpp 4.2 KB

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