lang_values.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. #include "lang/lang_tag.h"
  9. enum lngtag_count : int;
  10. namespace Lang {
  11. namespace details {
  12. inline constexpr auto kPluralCount = 6;
  13. template <typename Tag>
  14. inline constexpr ushort TagValue();
  15. template <typename P>
  16. using S = std::decay_t<decltype(std::declval<P>()(QString()))>;
  17. [[nodiscard]] QString Current(ushort key);
  18. [[nodiscard]] rpl::producer<QString> Value(ushort key);
  19. [[nodiscard]] bool IsNonDefaultPlural(ushort keyBase);
  20. template <int Index, typename Type, typename Tuple>
  21. [[nodiscard]] Type ReplaceUnwrapTuple(Type accumulated, const Tuple &tuple) {
  22. return accumulated;
  23. }
  24. template <
  25. int Index,
  26. typename Type,
  27. typename Tuple,
  28. typename Tag,
  29. typename ...Tags>
  30. [[nodiscard]] Type ReplaceUnwrapTuple(
  31. Type accumulated,
  32. const Tuple &tuple,
  33. Tag tag,
  34. Tags ...tags) {
  35. return ReplaceUnwrapTuple<Index + 1>(
  36. ReplaceTag<Type>::Call(
  37. std::move(accumulated),
  38. tag,
  39. std::get<Index>(tuple)),
  40. tuple,
  41. tags...);
  42. }
  43. template <typename ...Tags>
  44. struct ReplaceUnwrap;
  45. template <>
  46. struct ReplaceUnwrap<> {
  47. template <typename Type>
  48. [[nodiscard]] static Type Call(Type accumulated) {
  49. return accumulated;
  50. }
  51. };
  52. template <typename Tag, typename ...Tags>
  53. struct ReplaceUnwrap<Tag, Tags...> {
  54. template <typename Type, typename Value, typename ...Values>
  55. [[nodiscard]] static Type Call(
  56. Type accumulated,
  57. const Value &value,
  58. const Values &...values) {
  59. return ReplaceUnwrap<Tags...>::Call(
  60. ReplaceTag<Type>::Call(
  61. std::move(accumulated),
  62. TagValue<Tag>(),
  63. value),
  64. values...);
  65. }
  66. };
  67. template <typename ...Tags>
  68. struct Producer {
  69. template <typename P, typename ...Values>
  70. [[nodiscard]] static rpl::producer<S<P>> Combine(ushort base, P p, Values &...values) {
  71. return rpl::combine(
  72. Value(base),
  73. std::move(values)...
  74. ) | rpl::map([p = std::move(p)](auto tuple) {
  75. return ReplaceUnwrapTuple<1>(p(std::get<0>(tuple)), tuple, TagValue<Tags>()...);
  76. });
  77. }
  78. template <typename P, typename ...Values>
  79. [[nodiscard]] static S<P> Current(ushort base, P p, const Values &...values) {
  80. return ReplaceUnwrap<Tags...>::Call(
  81. p(Lang::details::Current(base)),
  82. values...);
  83. }
  84. };
  85. template <>
  86. struct Producer<> {
  87. template <typename P>
  88. [[nodiscard]] static rpl::producer<S<P>> Combine(ushort base, P p) {
  89. return Value(base) | rpl::map(std::move(p));
  90. }
  91. template <typename P>
  92. [[nodiscard]] static S<P> Current(ushort base, P p) {
  93. return p(Lang::details::Current(base));
  94. }
  95. };
  96. template <typename ...Tags>
  97. struct Producer<lngtag_count, Tags...> {
  98. template <typename P, typename ...Values>
  99. [[nodiscard]] static rpl::producer<S<P>> Combine(
  100. ushort base,
  101. P p,
  102. lngtag_count type,
  103. rpl::producer<float64> &count,
  104. Values &...values) {
  105. return rpl::combine(
  106. Value(base),
  107. Value(base + 1),
  108. Value(base + 2),
  109. Value(base + 3),
  110. Value(base + 4),
  111. Value(base + 5),
  112. std::move(count),
  113. std::move(values)...
  114. ) | rpl::map([base, type, p = std::move(p)](auto tuple) {
  115. auto plural = Plural(base, std::get<6>(tuple), type);
  116. const auto select = [&] {
  117. switch (plural.keyShift) {
  118. case 0: return std::get<0>(tuple);
  119. case 1: return std::get<1>(tuple);
  120. case 2: return std::get<2>(tuple);
  121. case 3: return std::get<3>(tuple);
  122. case 4: return std::get<4>(tuple);
  123. case 5: return std::get<5>(tuple);
  124. }
  125. Unexpected("Lang shift value in Plural result.");
  126. };
  127. return ReplaceUnwrapTuple<7>(
  128. ReplaceTag<S<P>>::Call(
  129. p(select()),
  130. TagValue<lngtag_count>(),
  131. StartReplacements<S<P>>::Call(
  132. std::move(plural.replacement))),
  133. tuple,
  134. TagValue<Tags>()...);
  135. });
  136. }
  137. template <typename P, typename ...Values>
  138. [[nodiscard]] static S<P> Current(
  139. ushort base,
  140. P p,
  141. lngtag_count type,
  142. float64 count,
  143. const Values &...values) {
  144. auto plural = Plural(base, count, type);
  145. return ReplaceUnwrap<Tags...>::Call(
  146. ReplaceTag<S<P>>::Call(
  147. p(Lang::details::Current(base + plural.keyShift)),
  148. TagValue<lngtag_count>(),
  149. StartReplacements<S<P>>::Call(
  150. std::move(plural.replacement))),
  151. values...);
  152. }
  153. };
  154. } // namespace details
  155. } // namespace Lang