tdesktop/Telegram/SourceFiles/lang/lang_tag.cpp
2023-10-04 22:24:25 +04:00

1023 lines
26 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "lang/lang_tag.h"
#include "lang/lang_keys.h"
#include "ui/text/text.h"
#include "base/qt/qt_common_adapters.h"
namespace Lang {
namespace {
//
// http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
//
constexpr auto kShiftZero = ushort(0);
constexpr auto kShiftOne = ushort(1);
constexpr auto kShiftTwo = ushort(2);
constexpr auto kShiftFew = ushort(3);
constexpr auto kShiftMany = ushort(4);
constexpr auto kShiftOther = ushort(5);
//
// n absolute value of the source number (integer and decimals).
// i integer digits of n.
// v number of visible fraction digits in n, with trailing zeros.
// w number of visible fraction digits in n, without trailing zeros.
// f visible fractional digits in n, with trailing zeros.
// t visible fractional digits in n, without trailing zeros.
//
// Let n be int, being -1 for non-integer numbers and n == i for integer numbers.
// It is fine while in the rules we compare n only to integers.
//
// -123.450: n = -1, i = 123, v = 3, w = 2, f = 450, t = 45
//
using ChoosePluralMethod = ushort (*)(int n, int i, int v, int w, int f, int t);
ushort ChoosePlural1(int n, int i, int v, int w, int f, int t) {
return kShiftOther;
}
ushort ChoosePlural2fil(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto mod10 = (i % 10);
if (i == 1 || i == 2 || i == 3) {
return kShiftOne;
} else if (mod10 != 4 && mod10 != 6 && mod10 != 9) {
return kShiftOne;
}
return kShiftOther;
}
const auto mod10 = (f % 10);
if (mod10 != 4 && mod10 != 6 && mod10 != 9) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2tzm(int n, int i, int v, int w, int f, int t) {
if (n == 0 || n == 1) {
return kShiftOne;
} else if (n >= 11 && n <= 99) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2is(int n, int i, int v, int w, int f, int t) {
if (t == 0) {
const auto mod10 = (i % 10);
const auto mod100 = (i % 100);
if (mod10 == 1 && mod100 != 11) {
return kShiftOne;
}
return kShiftOther;
}
return kShiftOne;
}
ushort ChoosePlural2mk(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto mod10 = (i % 10);
const auto mod100 = (i % 100);
if (mod10 == 1 && mod100 != 11) {
return kShiftOne;
}
}
const auto mod10 = (f % 10);
const auto mod100 = (f % 100);
if ((mod10 == 1) && (mod100 != 11)) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2ak(int n, int i, int v, int w, int f, int t) {
if (n == 0 || n == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2am(int n, int i, int v, int w, int f, int t) {
if (i == 0 || n == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2hy(int n, int i, int v, int w, int f, int t) {
if (i == 0 || i == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2si(int n, int i, int v, int w, int f, int t) {
if (n == 0 || n == 1) {
return kShiftOne;
} else if (i == 0 && f == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2bh(int n, int i, int v, int w, int f, int t) {
// not documented
if (n == 0 || n == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2af(int n, int i, int v, int w, int f, int t) {
if (n == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2ast(int n, int i, int v, int w, int f, int t) {
if (i == 1 && v == 0) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural2da(int n, int i, int v, int w, int f, int t) {
if (n == 1) {
return kShiftOne;
} else if (t != 0 && ((i == 0) || (i == 1))) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural3lv(int n, int i, int v, int w, int f, int t) {
const auto nmod10 = (n % 10);
const auto nmod100 = (n % 100);
const auto fmod10 = (f % 10);
const auto fmod100 = (f % 100);
if (nmod10 == 0) {
return kShiftZero;
} else if ((nmod100 >= 11) && (nmod100 <= 19)) {
return kShiftZero;
} else if ((v == 2) && (fmod100 >= 11) && (fmod100 <= 19)) {
return kShiftZero;
} else if ((nmod10 == 1) && (nmod100 != 11)) {
return kShiftOne;
} else if ((v == 2) && (fmod10 == 1) && (fmod100 != 11)) {
return kShiftOne;
} else if ((v != 2) && (fmod10 == 1)) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural3ksh(int n, int i, int v, int w, int f, int t) {
if (n == 0) {
return kShiftZero;
} else if (n == 1) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural3lag(int n, int i, int v, int w, int f, int t) {
if (n == 0) {
return kShiftZero;
} else if ((n != 0) && ((i == 0) || (i == 1))) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural3kw(int n, int i, int v, int w, int f, int t) {
if (n == 1) {
return kShiftOne;
} else if (n == 2) {
return kShiftTwo;
}
return kShiftOther;
}
ushort ChoosePlural3bs(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto mod10 = (i % 10);
const auto mod100 = (i % 100);
if ((mod10 >= 2) && (mod10 <= 4) && (mod100 < 12 || mod100 > 14)) {
return kShiftFew;
} else if ((mod10 == 1) && (mod100 != 11)) {
return kShiftOne;
}
return kShiftOther;
}
const auto mod10 = (f % 10);
const auto mod100 = (f % 100);
if ((mod10 >= 2) && (mod10 <= 4) && (mod100 < 12 || mod100 > 14)) {
return kShiftFew;
} else if ((mod10 == 1) && (mod100 != 11)) {
return kShiftOne;
}
return kShiftOther;
}
ushort ChoosePlural3shi(int n, int i, int v, int w, int f, int t) {
if (i == 0 || n == 1) {
return kShiftOne;
} else if (n >= 2 && n <= 10) {
return kShiftFew;
}
return kShiftOther;
}
ushort ChoosePlural3mo(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto mod100 = (n % 100);
if (i == 1) {
return kShiftOne;
} else if (n == 0) {
return kShiftFew;
} else if ((n != 1) && (mod100 >= 1) && (mod100 <= 19)) {
return kShiftFew;
}
return kShiftOther;
}
return kShiftFew;
}
ushort ChoosePlural4be(int n, int i, int v, int w, int f, int t) {
const auto mod10 = (n % 10);
const auto mod100 = (n % 100);
if ((mod10 >= 2) && (mod10 <= 4) && (mod100 < 12 || mod100 > 14)) {
return kShiftFew;
} else if ((mod10 == 1) && (mod100 != 11)) {
return kShiftOne;
} else if (mod10 == 0) {
return kShiftMany;
} else if ((mod10 >= 5) && (mod10 <= 9)) {
return kShiftMany;
} else if ((mod100 >= 11) && (mod100 <= 14)) {
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural4ru(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto mod10 = (i % 10);
const auto mod100 = (i % 100);
if ((mod10 >= 2) && (mod10 <= 4) && (mod100 < 12 || mod100 > 14)) {
return kShiftFew;
} else if ((mod10 == 1) && (mod100 != 11)) {
return kShiftOne;
}
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural4pl(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
if (i == 1) {
return kShiftOne;
}
const auto mod10 = (i % 10);
const auto mod100 = (i % 100);
if ((mod10 >= 2) && (mod10 <= 4) && (mod100 < 12 || mod100 > 14)) {
return kShiftFew;
} else {
return kShiftMany;
}
}
return kShiftOther;
}
ushort ChoosePlural4lt(int n, int i, int v, int w, int f, int t) {
const auto mod10 = (n % 10);
const auto mod100 = (n % 100);
if ((mod10 >= 2) && (mod10 <= 9) && (mod100 < 11 || mod100 > 19)) {
return kShiftFew;
} else if ((mod10 == 1) && (mod100 != 11)) {
return kShiftOne;
} else if (f != 0) {
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural4cs(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
if (i == 1) {
return kShiftOne;
} else if (i >= 2 && i <= 4) {
return kShiftFew;
}
return kShiftOther;
}
return kShiftMany;
}
ushort ChoosePlural4gd(int n, int i, int v, int w, int f, int t) {
if (n == 1 || n == 11) {
return kShiftOne;
} else if (n == 2 || n == 12) {
return kShiftTwo;
} else if (n >= 3 && n <= 10) {
return kShiftFew;
} else if (n >= 13 && n <= 19) {
return kShiftFew;
}
return kShiftOther;
}
ushort ChoosePlural4dsb(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto imod100 = (i % 100);
if (imod100 == 1) {
return kShiftOne;
} else if (imod100 == 2) {
return kShiftTwo;
} else if (imod100 == 3 || imod100 == 4) {
return kShiftFew;
}
}
const auto fmod100 = (f % 100);
if (fmod100 == 1) {
return kShiftOne;
} else if (fmod100 == 2) {
return kShiftTwo;
} else if (fmod100 == 3 || fmod100 == 4) {
return kShiftFew;
}
return kShiftOther;
}
ushort ChoosePlural4sl(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto imod100 = (i % 100);
if (imod100 == 3 || imod100 == 4) {
return kShiftFew;
} else if (imod100 == 1) {
return kShiftOne;
} else if (imod100 == 2) {
return kShiftTwo;
}
return kShiftOther;
}
return kShiftFew;
}
ushort ChoosePlural4he(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
if (i == 1) {
return kShiftOne;
} else if (i == 2) {
return kShiftTwo;
} else if ((n != 0) && (n != 10) && ((n % 10) == 0)) {
return kShiftMany;
}
return kShiftOther;
}
return kShiftOther;
}
ushort ChoosePlural4mt(int n, int i, int v, int w, int f, int t) {
const auto mod100 = (n % 100);
if (n == 1) {
return kShiftOne;
} else if (n == 0) {
return kShiftFew;
} else if (mod100 >= 2 && mod100 <= 10) {
return kShiftFew;
} else if (mod100 >= 11 && mod100 <= 19) {
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural5gv(int n, int i, int v, int w, int f, int t) {
if (v == 0) {
const auto mod10 = (i % 10);
const auto mod20 = (i % 20);
if (mod10 == 1) {
return kShiftOne;
} else if (mod10 == 2) {
return kShiftTwo;
} else if (mod20 == 0) {
return kShiftFew;
}
return kShiftOther;
}
return kShiftMany;
}
ushort ChoosePlural5br(int n, int i, int v, int w, int f, int t) {
const auto mod10 = (n % 10);
const auto mod100 = (n % 100);
if ((mod10 == 1)
&& (mod100 != 11)
&& (mod100 != 71)
&& (mod100 != 91)) {
return kShiftOne;
} else if ((mod10 == 2)
&& (mod100 != 12)
&& (mod100 != 72)
&& (mod100 != 92)) {
return kShiftTwo;
} else if (((mod10 == 3) || (mod10 == 4) || (mod10 == 9))
&& ((mod100 < 10) || (mod100 > 19))
&& ((mod100 < 70) || (mod100 > 79))
&& ((mod100 < 90) || (mod100 > 99))) {
return kShiftFew;
} else if ((n != 0) && (n % 1000000 == 0)) {
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural5ga(int n, int i, int v, int w, int f, int t) {
if (n == 1) {
return kShiftOne;
} else if (n == 2) {
return kShiftTwo;
} else if (n >= 3 && n <= 6) {
return kShiftFew;
} else if (n >= 7 && n <= 10) {
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural6ar(int n, int i, int v, int w, int f, int t) {
if (n == 0) {
return kShiftZero;
} else if (n == 1) {
return kShiftOne;
} else if (n == 2) {
return kShiftTwo;
} else if (n < 0) {
return kShiftOther;
}
const auto mod100 = (n % 100);
if (mod100 >= 3 && mod100 <= 10) {
return kShiftFew;
} else if (mod100 >= 11 && mod100 <= 99) {
return kShiftMany;
}
return kShiftOther;
}
ushort ChoosePlural6cy(int n, int i, int v, int w, int f, int t) {
if (n == 0) {
return kShiftZero;
} else if (n == 1) {
return kShiftOne;
} else if (n == 2) {
return kShiftTwo;
} else if (n == 3) {
return kShiftFew;
} else if (n == 6) {
return kShiftMany;
}
return kShiftOther;
}
struct PluralsKey {
PluralsKey(uint64 key);
PluralsKey(const char *value);
inline operator uint64() const {
return data;
}
uint64 data = 0;
};
char ConvertKeyChar(char ch) {
return (ch == '_') ? '-' : QChar::toLower(ch);
}
PluralsKey::PluralsKey(uint64 key) : data(key) {
}
PluralsKey::PluralsKey(const char *value) {
for (auto ch = *value; ch; ch = *++value) {
data = (data << 8) | uint64(ConvertKeyChar(ch));
}
}
std::map<PluralsKey, ChoosePluralMethod> GeneratePluralRulesMap() {
return {
//{ "bm", ChoosePlural1 },
//{ "my", ChoosePlural1 },
//{ "yue", ChoosePlural1 },
//{ "zh", ChoosePlural1 },
//{ "dz", ChoosePlural1 },
//{ "ig", ChoosePlural1 },
//{ "id", ChoosePlural1 },
//{ "in", ChoosePlural1 }, // same as "id"
//{ "ja", ChoosePlural1 },
//{ "jv", ChoosePlural1 },
//{ "jw", ChoosePlural1 }, // same as "jv"
//{ "kea", ChoosePlural1 },
//{ "km", ChoosePlural1 },
//{ "ko", ChoosePlural1 },
//{ "ses", ChoosePlural1 },
//{ "lkt", ChoosePlural1 },
//{ "lo", ChoosePlural1 },
//{ "jbo", ChoosePlural1 },
//{ "kde", ChoosePlural1 },
//{ "ms", ChoosePlural1 },
//{ "nqo", ChoosePlural1 },
//{ "sah", ChoosePlural1 },
//{ "sg", ChoosePlural1 },
//{ "ii", ChoosePlural1 },
//{ "th", ChoosePlural1 },
//{ "bo", ChoosePlural1 },
//{ "to", ChoosePlural1 },
//{ "vi", ChoosePlural1 },
//{ "wo", ChoosePlural1 },
//{ "yo", ChoosePlural1 },
//{ default, ChoosePlural1 },
{ "fil", ChoosePlural2fil },
{ "tl", ChoosePlural2fil },
{ "tzm", ChoosePlural2tzm },
{ "is", ChoosePlural2is },
{ "mk", ChoosePlural2mk },
{ "ak", ChoosePlural2ak },
{ "guw", ChoosePlural2ak },
{ "ln", ChoosePlural2ak },
{ "mg", ChoosePlural2ak },
{ "nso", ChoosePlural2ak },
{ "pa", ChoosePlural2ak },
{ "ti", ChoosePlural2ak },
{ "wa", ChoosePlural2ak },
{ "am", ChoosePlural2am },
{ "as", ChoosePlural2am },
{ "bn", ChoosePlural2am },
{ "gu", ChoosePlural2am },
{ "hi", ChoosePlural2am },
{ "kn", ChoosePlural2am },
{ "mr", ChoosePlural2am },
{ "fa", ChoosePlural2am },
{ "zu", ChoosePlural2am },
{ "hy", ChoosePlural2hy },
{ "fr", ChoosePlural2hy },
{ "ff", ChoosePlural2hy },
{ "kab", ChoosePlural2hy },
{ "pt", ChoosePlural2hy },
{ "si", ChoosePlural2si },
{ "bh", ChoosePlural2bh },
{ "bho", ChoosePlural2bh },
{ "af", ChoosePlural2af },
{ "sq", ChoosePlural2af },
{ "asa", ChoosePlural2af },
{ "az", ChoosePlural2af },
{ "eu", ChoosePlural2af },
{ "bem", ChoosePlural2af },
{ "bez", ChoosePlural2af },
{ "brx", ChoosePlural2af },
{ "bg", ChoosePlural2af },
{ "ckb", ChoosePlural2af },
{ "ce", ChoosePlural2af },
{ "chr", ChoosePlural2af },
{ "cgg", ChoosePlural2af },
{ "dv", ChoosePlural2af },
{ "eo", ChoosePlural2af },
{ "ee", ChoosePlural2af },
{ "fo", ChoosePlural2af },
{ "fur", ChoosePlural2af },
{ "ka", ChoosePlural2af },
{ "el", ChoosePlural2af },
{ "ha", ChoosePlural2af },
{ "haw", ChoosePlural2af },
{ "hu", ChoosePlural2af },
{ "kaj", ChoosePlural2af },
{ "kkj", ChoosePlural2af },
{ "kl", ChoosePlural2af },
{ "ks", ChoosePlural2af },
{ "kk", ChoosePlural2af },
{ "ku", ChoosePlural2af },
{ "ky", ChoosePlural2af },
{ "lb", ChoosePlural2af },
{ "jmc", ChoosePlural2af },
{ "ml", ChoosePlural2af },
{ "mas", ChoosePlural2af },
{ "mgo", ChoosePlural2af },
{ "mn", ChoosePlural2af },
{ "nah", ChoosePlural2af },
{ "ne", ChoosePlural2af },
{ "nnh", ChoosePlural2af },
{ "jgo", ChoosePlural2af },
{ "nd", ChoosePlural2af },
{ "no", ChoosePlural2af },
{ "nb", ChoosePlural2af },
{ "nn", ChoosePlural2af },
{ "ny", ChoosePlural2af },
{ "nyn", ChoosePlural2af },
{ "or", ChoosePlural2af },
{ "om", ChoosePlural2af },
{ "os", ChoosePlural2af },
{ "pap", ChoosePlural2af },
{ "ps", ChoosePlural2af },
{ "rm", ChoosePlural2af },
{ "rof", ChoosePlural2af },
{ "rwk", ChoosePlural2af },
{ "ssy", ChoosePlural2af },
{ "saq", ChoosePlural2af },
{ "seh", ChoosePlural2af },
{ "ksb", ChoosePlural2af },
{ "sn", ChoosePlural2af },
{ "sd", ChoosePlural2af },
{ "xog", ChoosePlural2af },
{ "so", ChoosePlural2af },
{ "nr", ChoosePlural2af },
{ "sdh", ChoosePlural2af },
{ "st", ChoosePlural2af },
{ "es", ChoosePlural2af },
{ "ss", ChoosePlural2af },
{ "gsw", ChoosePlural2af },
{ "syr", ChoosePlural2af },
{ "ta", ChoosePlural2af },
{ "te", ChoosePlural2af },
{ "teo", ChoosePlural2af },
{ "tig", ChoosePlural2af },
{ "ts", ChoosePlural2af },
{ "tn", ChoosePlural2af },
{ "tr", ChoosePlural2af },
{ "tk", ChoosePlural2af },
{ "kcg", ChoosePlural2af },
{ "ug", ChoosePlural2af },
{ "uz", ChoosePlural2af },
{ "ve", ChoosePlural2af },
{ "vo", ChoosePlural2af },
{ "vun", ChoosePlural2af },
{ "wae", ChoosePlural2af },
{ "xh", ChoosePlural2af },
{ "", ChoosePlural2ast },
{ "ast", ChoosePlural2ast },
{ "ca", ChoosePlural2ast },
{ "nl", ChoosePlural2ast },
{ "en", ChoosePlural2ast },
{ "et", ChoosePlural2ast },
{ "pt_PT", ChoosePlural2ast },
{ "fi", ChoosePlural2ast },
{ "gl", ChoosePlural2ast },
{ "lg", ChoosePlural2ast },
{ "de", ChoosePlural2ast },
{ "io", ChoosePlural2ast },
{ "ia", ChoosePlural2ast },
{ "it", ChoosePlural2ast },
{ "sc", ChoosePlural2ast },
{ "scn", ChoosePlural2ast },
{ "sw", ChoosePlural2ast },
{ "sv", ChoosePlural2ast },
{ "ur", ChoosePlural2ast },
{ "fy", ChoosePlural2ast },
{ "ji", ChoosePlural2ast },
{ "yi", ChoosePlural2ast }, // same as "ji"
{ "da", ChoosePlural2da },
{ "lv", ChoosePlural3lv },
{ "prg", ChoosePlural3lv },
{ "ksh", ChoosePlural3ksh },
{ "lag", ChoosePlural3lag },
{ "kw", ChoosePlural3kw },
{ "smn", ChoosePlural3kw },
{ "iu", ChoosePlural3kw },
{ "smj", ChoosePlural3kw },
{ "naq", ChoosePlural3kw },
{ "se", ChoosePlural3kw },
{ "smi", ChoosePlural3kw },
{ "sms", ChoosePlural3kw },
{ "sma", ChoosePlural3kw },
{ "bs", ChoosePlural3bs },
{ "hr", ChoosePlural3bs },
{ "sr", ChoosePlural3bs },
{ "sh", ChoosePlural3bs },
{ "sr_Latn", ChoosePlural3bs }, // same as "sh"
{ "shi", ChoosePlural3shi },
{ "mo", ChoosePlural3mo },
{ "ro_MD", ChoosePlural3mo }, // same as "mo"
{ "ro", ChoosePlural3mo },
{ "be", ChoosePlural4be },
{ "ru", ChoosePlural4ru },
{ "uk", ChoosePlural4ru },
{ "pl", ChoosePlural4pl },
{ "lt", ChoosePlural4lt },
{ "cs", ChoosePlural4cs },
{ "sk", ChoosePlural4cs },
{ "gd", ChoosePlural4gd },
{ "dsb", ChoosePlural4dsb },
{ "hsb", ChoosePlural4dsb },
{ "sl", ChoosePlural4sl },
{ "he", ChoosePlural4he },
{ "iw", ChoosePlural4he }, // same as "he"
{ "mt", ChoosePlural4mt },
{ "gv", ChoosePlural5gv },
{ "br", ChoosePlural5br },
{ "ga", ChoosePlural5ga },
{ "ar", ChoosePlural6ar },
{ "ars", ChoosePlural6ar },
{ "cy", ChoosePlural6cy },
};
//return {
// //{ "af", ChoosePluralEn },
// { "ak", ChoosePluralPt },
// { "am", ChoosePluralPt },
// { "ar", ChoosePluralAr },
// { "as", ChoosePluralPt },
// { "az", ChoosePluralEs },
// { "be", ChoosePluralRu }, // should be different
// { "bg", ChoosePluralEs },
// { "bh", ChoosePluralPt },
// { "bm", ChoosePluralKo },
// { "bn", ChoosePluralPt },
// { "bo", ChoosePluralKo },
// { "bs", ChoosePluralSr },
// //{ "ca", ChoosePluralEn },
// //{ "ce", ChoosePluralEn },
// { "cs", ChoosePluralSk },
// { "da", ChoosePluralDa },
// //{ "de", ChoosePluralEn },
// //{ "dv", ChoosePluralEn },
// { "dz", ChoosePluralKo },
// //{ "ee", ChoosePluralEn },
// { "el", ChoosePluralEs },
// //{ "en", ChoosePluralEn },
// { "es", ChoosePluralEs },
// { "eo", ChoosePluralEs },
// //{ "et", ChoosePluralEn },
// { "eu", ChoosePluralEs },
// { "fa", ChoosePluralPt },
// { "ff", ChoosePluralPt },
// //{ "fi", ChoosePluralEn },
// //{ "fo", ChoosePluralEn },
// { "fr", ChoosePluralPt },
// //{ "fy", ChoosePluralEn },
// //{ "gl", ChoosePluralEn },
// { "gu", ChoosePluralPt },
// //{ "ha", ChoosePluralEn },
// { "he", ChoosePluralHe },
// { "hi", ChoosePluralPt },
// { "hr", ChoosePluralSr },
// { "hu", ChoosePluralEs },
// { "hy", ChoosePluralPt },
// //{ "ia", ChoosePluralEn },
// { "ig", ChoosePluralKo },
// { "ii", ChoosePluralKo },
// { "in", ChoosePluralKo },
// //{ "io", ChoosePluralEn },
// { "is", ChoosePluralIs },
// //{ "it", ChoosePluralEn },
// { "ja", ChoosePluralKo },
// { "jw", ChoosePluralKo },
// //{ "ka", ChoosePluralEn },
// //{ "kk", ChoosePluralEn },
// //{ "kl", ChoosePluralEn },
// { "km", ChoosePluralKo },
// { "kn", ChoosePluralPt },
// { "ko", ChoosePluralKo },
// //{ "ks", ChoosePluralEn },
// //{ "ku", ChoosePluralEn },
// //{ "ky", ChoosePluralEn },
// //{ "lb", ChoosePluralEn },
// //{ "lg", ChoosePluralEn },
// { "ln", ChoosePluralPt },
// { "lo", ChoosePluralKo },
// { "mg", ChoosePluralPt },
// { "mk", ChoosePluralIs },
// //{ "ml", ChoosePluralEn },
// //{ "mn", ChoosePluralEn },
// { "mo", ChoosePluralRo },
// { "mr", ChoosePluralPt },
// { "ms", ChoosePluralKo },
// { "mt", ChoosePluralMt },
// { "my", ChoosePluralKo },
// { "nb", ChoosePluralEs },
// //{ "nd", ChoosePluralEn },
// //{ "ne", ChoosePluralEn },
// //{ "nl", ChoosePluralEn },
// //{ "nn", ChoosePluralEn },
// //{ "no", ChoosePluralEn },
// //{ "nr", ChoosePluralEn },
// //{ "ny", ChoosePluralEn },
// //{ "om", ChoosePluralEn },
// //{ "or", ChoosePluralEn },
// //{ "os", ChoosePluralEn },
// { "pa", ChoosePluralPt },
// //{ "ps", ChoosePluralEn },
// { "pt", ChoosePluralPt },
// //{ "pt_PT", ChoosePluralEn }, // not supported
// //{ "rm", ChoosePluralEn },
// { "ro", ChoosePluralRo },
// { "ru", ChoosePluralRu },
// //{ "sc", ChoosePluralEn },
// //{ "sd", ChoosePluralEn },
// { "sg", ChoosePluralKo },
// { "sk", ChoosePluralSk },
// //{ "sn", ChoosePluralEn },
// //{ "so", ChoosePluralEn },
// { "sh", ChoosePluralSr },
// { "si", ChoosePluralPt },
// { "sr", ChoosePluralSr },
// //{ "ss", ChoosePluralEn },
// //{ "st", ChoosePluralEn },
// //{ "sv", ChoosePluralEn },
// //{ "sw", ChoosePluralEn },
// { "ta", ChoosePluralEs },
// //{ "te", ChoosePluralEn },
// { "th", ChoosePluralKo },
// { "ti", ChoosePluralPt },
// { "tk", ChoosePluralEs },
// { "tl", ChoosePluralTl },
// //{ "tn", ChoosePluralEn },
// { "to", ChoosePluralKo },
// { "tr", ChoosePluralEs },
// //{ "ts", ChoosePluralEn },
// //{ "ug", ChoosePluralEn },
// { "uk", ChoosePluralRu },
// //{ "ur", ChoosePluralEn },
// { "uz", ChoosePluralEs },
// { "pl", ChoosePluralPl },
// { "sq", ChoosePluralEs },
// //{ "ve", ChoosePluralEn },
// { "vi", ChoosePluralKo },
// //{ "vo", ChoosePluralEn },
// { "wa", ChoosePluralPt },
// { "wo", ChoosePluralKo },
// //{ "xh", ChoosePluralEn },
// //{ "yi", ChoosePluralEn },
// { "yo", ChoosePluralKo },
// { "zh", ChoosePluralKo },
// { "zu", ChoosePluralPt },
//};
}
const auto ChoosePluralDefault = &ChoosePlural2ast;
auto ChoosePlural = ChoosePluralDefault;
} // namespace
int FindTagReplacementPosition(const QString &original, ushort tag) {
for (auto s = original.constData(), ch = s, e = ch + original.size(); ch != e;) {
if (ch->unicode() == kTextCommand) {
if (ch + kTagReplacementSize <= e
&& (ch + 1)->unicode() == kTextCommandLangTag
&& (ch + 3)->unicode() == kTextCommand) {
if ((ch + 2)->unicode() == 0x0020 + tag) {
return ch - s;
} else {
ch += kTagReplacementSize;
}
} else {
++ch;
}
} else {
++ch;
}
}
return -1;
}
QString FormatDouble(float64 value) {
auto result = QString::number(value, 'f', 6);
while (result.endsWith('0')) {
result.chop(1);
}
if (result.endsWith('.')) {
result.chop(1);
}
return result;
}
int NonZeroPartToInt(QString value) {
auto zeros = 0;
for (const auto &ch : value) {
if (ch == '0') {
++zeros;
} else {
break;
}
}
return (zeros > 0)
? (zeros < value.size() ? base::StringViewMid(value, zeros).toInt() : 0)
: (value.isEmpty() ? 0 : value.toInt());
}
ShortenedCount FormatCountToShort(int64 number) {
auto result = ShortenedCount{ number };
const auto abs = std::abs(number);
const auto shorten = [&](int64 divider, char multiplier) {
const auto sign = (number > 0) ? 1 : -1;
const auto rounded = abs / (divider / 10);
result.string = QString::number(sign * rounded / 10);
if (rounded % 10) {
result.string += '.' + QString::number(rounded % 10) + multiplier;
} else {
result.string += multiplier;
}
// Update given number.
// E.g. 12345 will be 12000.
result.number = rounded * divider;
};
if (abs >= 1'000'000) {
shorten(1'000'000, 'M');
} else if (abs >= 10'000) {
shorten(1'000, 'K');
} else {
result.string = QString::number(number);
}
return result;
}
QString FormatCountDecimal(int64 number) {
return QString("%L1").arg(number);
}
PluralResult Plural(
ushort keyBase,
float64 value,
lngtag_count type) {
// To correctly select a shift for PluralType::Short
// we must first round the number.
const auto shortened = (type == lt_count_short)
? FormatCountToShort(qRound(value))
: ShortenedCount();
// Simplified.
const auto n = std::abs(shortened.number ? float64(shortened.number) : value);
const auto i = int(std::floor(n));
const auto integer = (int(std::ceil(n)) == i);
const auto formatted = integer ? QString() : FormatDouble(n);
const auto dot = formatted.indexOf('.');
const auto fraction = (dot >= 0) ? formatted.mid(dot + 1) : QString();
const auto v = fraction.size();
const auto w = v;
const auto f = NonZeroPartToInt(fraction);
const auto t = f;
const auto useNonDefaultPlural = (ChoosePlural != ChoosePluralDefault)
&& Lang::details::IsNonDefaultPlural(keyBase);
const auto shift = (useNonDefaultPlural ? ChoosePlural : ChoosePluralDefault)(
(integer ? i : -1),
i,
v,
w,
f,
t);
if (integer) {
const auto round = qRound(value);
if (type == lt_count_short) {
return { shift, shortened.string };
} else if (type == lt_count_decimal) {
return { shift, FormatCountDecimal(round) };
}
return { shift, QString::number(round) };
}
return { shift, FormatDouble(value) };
}
void UpdatePluralRules(const QString &languageId) {
static auto kMap = GeneratePluralRulesMap();
auto parent = uint64(0);
auto key = uint64(0);
for (const auto &ch : languageId) {
const auto converted = ConvertKeyChar(ch.unicode());
if (converted == '-' && !parent) {
parent = key;
}
key = (key << 8) | uint64(converted);
}
const auto i = [&] {
const auto result = kMap.find(key);
return (result != end(kMap) || !parent)
? result
: kMap.find(parent);
}();
ChoosePlural = (i == end(kMap)) ? ChoosePlural1 : i->second;
}
QString ReplaceTag<QString>::Replace(QString &&original, const QString &replacement, int replacementPosition) {
auto result = QString();
result.reserve(original.size() + replacement.size() - kTagReplacementSize);
if (replacementPosition > 0) {
result.append(base::StringViewMid(original, 0, replacementPosition));
}
result.append(replacement);
if (replacementPosition + kTagReplacementSize < original.size()) {
result.append(base::StringViewMid(original, replacementPosition + kTagReplacementSize));
}
return result;
}
} // namespace Lang