UnicodeKeywords.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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/QuickSort.h>
  8. #include <AK/ScopeGuard.h>
  9. #include <LibUnicode/DateTimeFormat.h>
  10. #include <LibUnicode/ICU.h>
  11. #include <LibUnicode/UnicodeKeywords.h>
  12. #include <unicode/calendar.h>
  13. #include <unicode/coll.h>
  14. #include <unicode/locid.h>
  15. #include <unicode/numsys.h>
  16. #include <unicode/ucurr.h>
  17. namespace Unicode {
  18. Vector<String> available_keyword_values(StringView locale, StringView key)
  19. {
  20. if (key == "ca"sv)
  21. return available_calendars(locale);
  22. if (key == "co"sv)
  23. return available_collations(locale);
  24. if (key == "hc"sv)
  25. return available_hour_cycles(locale);
  26. if (key == "kf"sv)
  27. return available_collation_case_orderings();
  28. if (key == "kn"sv)
  29. return available_collation_numeric_orderings();
  30. if (key == "nu"sv)
  31. return available_number_systems(locale);
  32. TODO();
  33. }
  34. Vector<String> const& available_calendars()
  35. {
  36. static auto calendars = []() {
  37. auto calendars = available_calendars("und"sv);
  38. quick_sort(calendars);
  39. return calendars;
  40. }();
  41. return calendars;
  42. }
  43. Vector<String> available_calendars(StringView locale)
  44. {
  45. UErrorCode status = U_ZERO_ERROR;
  46. auto locale_data = LocaleData::for_locale(locale);
  47. if (!locale_data.has_value())
  48. return {};
  49. auto keywords = adopt_own_if_nonnull(icu::Calendar::getKeywordValuesForLocale("calendar", locale_data->locale(), 0, status));
  50. if (icu_failure(status))
  51. return {};
  52. auto calendars = icu_string_enumeration_to_list(move(keywords));
  53. for (auto& calendar : calendars) {
  54. if (calendar == "gregorian"sv)
  55. calendar = "gregory"_string;
  56. else if (calendar == "ethiopic-amete-alem"sv)
  57. calendar = "ethioaa"_string;
  58. }
  59. return calendars;
  60. }
  61. Vector<String> const& available_currencies()
  62. {
  63. static auto currencies = []() -> Vector<String> {
  64. UErrorCode status = U_ZERO_ERROR;
  65. auto* currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
  66. ScopeGuard guard { [&]() { uenum_close(currencies); } };
  67. if (icu_failure(status))
  68. return {};
  69. Vector<String> result;
  70. while (true) {
  71. i32 length = 0;
  72. char const* next = uenum_next(currencies, &length, &status);
  73. if (icu_failure(status))
  74. return {};
  75. if (next == nullptr)
  76. break;
  77. // https://unicode-org.atlassian.net/browse/ICU-21687
  78. if (StringView currency { next, static_cast<size_t>(length) }; currency != "LSM"sv)
  79. result.append(MUST(String::from_utf8(currency)));
  80. }
  81. quick_sort(result);
  82. return result;
  83. }();
  84. return currencies;
  85. }
  86. Vector<String> const& available_collation_case_orderings()
  87. {
  88. static Vector<String> case_orderings { "false"_string, "lower"_string, "upper"_string };
  89. return case_orderings;
  90. }
  91. Vector<String> const& available_collation_numeric_orderings()
  92. {
  93. static Vector<String> case_orderings { "false"_string, "true"_string };
  94. return case_orderings;
  95. }
  96. Vector<String> const& available_collations()
  97. {
  98. // FIXME: Implement this when we fully support Intl.Collator.
  99. static Vector<String> collations { "default"_string };
  100. return collations;
  101. }
  102. Vector<String> available_collations(StringView)
  103. {
  104. // FIXME: Implement this when we fully support Intl.Collator.
  105. return available_collations();
  106. }
  107. Vector<String> const& available_hour_cycles()
  108. {
  109. static Vector<String> case_orderings { "h11"_string, "h12"_string, "h23"_string, "h24"_string };
  110. return case_orderings;
  111. }
  112. Vector<String> available_hour_cycles(StringView locale)
  113. {
  114. auto preferred_hour_cycle = default_hour_cycle(locale);
  115. if (!preferred_hour_cycle.has_value())
  116. return available_hour_cycles();
  117. Vector<String> hour_cycles;
  118. hour_cycles.append(MUST(String::from_utf8(hour_cycle_to_string(*preferred_hour_cycle))));
  119. for (auto const& hour_cycle : available_hour_cycles()) {
  120. if (hour_cycle != hour_cycles[0])
  121. hour_cycles.append(hour_cycle);
  122. }
  123. return hour_cycles;
  124. }
  125. Vector<String> const& available_number_systems()
  126. {
  127. static auto number_systems = []() -> Vector<String> {
  128. UErrorCode status = U_ZERO_ERROR;
  129. auto keywords = adopt_own_if_nonnull(icu::NumberingSystem::getAvailableNames(status));
  130. if (icu_failure(status))
  131. return {};
  132. auto number_systems = icu_string_enumeration_to_list(move(keywords), [&](char const* keyword) {
  133. auto system = adopt_own_if_nonnull(icu::NumberingSystem::createInstanceByName(keyword, status));
  134. if (icu_failure(status))
  135. return false;
  136. return !static_cast<bool>(system->isAlgorithmic());
  137. });
  138. quick_sort(number_systems);
  139. return number_systems;
  140. }();
  141. return number_systems;
  142. }
  143. Vector<String> available_number_systems(StringView locale)
  144. {
  145. auto locale_data = LocaleData::for_locale(locale);
  146. if (!locale_data.has_value())
  147. return {};
  148. Vector<String> number_systems;
  149. auto const* preferred_number_system = locale_data->numbering_system().getName();
  150. number_systems.append(MUST(String::from_utf8({ preferred_number_system, strlen(preferred_number_system) })));
  151. for (auto const& number_system : available_number_systems()) {
  152. if (number_system != number_systems[0])
  153. number_systems.append(number_system);
  154. }
  155. return number_systems;
  156. }
  157. }