mirror of
https://github.com/minetest/minetest.git
synced 2025-01-03 20:07:30 +01:00
Fixup parsing for Plural-Forms
(#15519)
This commit is contained in:
parent
1e59b9a756
commit
ac7406c8a1
@ -90,16 +90,16 @@ class TernaryOperation: public GettextPluralForm
|
||||
};
|
||||
|
||||
typedef std::pair<GettextPluralForm::Ptr, std::wstring_view> ParserResult;
|
||||
typedef ParserResult (*Parser)(const size_t, const std::wstring_view &);
|
||||
typedef ParserResult (*Parser)(const size_t, std::wstring_view);
|
||||
|
||||
static ParserResult parse_expr(const size_t nplurals, const std::wstring_view &str);
|
||||
static ParserResult parse_expr(const size_t nplurals, std::wstring_view str);
|
||||
|
||||
template<Parser Parser, template<typename> typename Operator>
|
||||
static ParserResult reduce_ltr(const size_t nplurals, const ParserResult &res, const wchar_t* pattern)
|
||||
{
|
||||
if (!str_starts_with(res.second, pattern))
|
||||
return ParserResult(nullptr, res.second);
|
||||
auto next = Parser(nplurals, res.second.substr(std::char_traits<wchar_t>::length(pattern)));
|
||||
auto next = Parser(nplurals, trim(res.second.substr(std::char_traits<wchar_t>::length(pattern))));
|
||||
if (!next.first)
|
||||
return next;
|
||||
next.first = GettextPluralForm::Ptr(new BinaryOperation<Operator>(res.first, next.first));
|
||||
@ -123,7 +123,7 @@ static ParserResult reduce_ltr(const size_t nplurals, const ParserResult &res, c
|
||||
}
|
||||
|
||||
template<Parser Parser, template<typename> typename Operator, template<typename> typename... Operators>
|
||||
static ParserResult parse_ltr(const size_t nplurals, const std::wstring_view &str, const wchar_t** patterns)
|
||||
static ParserResult parse_ltr(const size_t nplurals, std::wstring_view str, const wchar_t** patterns)
|
||||
{
|
||||
auto &&pres = Parser(nplurals, str);
|
||||
if (!pres.first)
|
||||
@ -139,7 +139,7 @@ static ParserResult parse_ltr(const size_t nplurals, const std::wstring_view &st
|
||||
return pres;
|
||||
}
|
||||
|
||||
static ParserResult parse_atomic(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_atomic(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
if (str.empty())
|
||||
return ParserResult(nullptr, str);
|
||||
@ -151,7 +151,7 @@ static ParserResult parse_atomic(const size_t nplurals, const std::wstring_view
|
||||
return ParserResult(new ConstValue(nplurals, val), trim(str.substr(endp-str.data())));
|
||||
}
|
||||
|
||||
static ParserResult parse_parenthesized(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_parenthesized(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
if (str.empty())
|
||||
return ParserResult(nullptr, str);
|
||||
@ -167,7 +167,7 @@ static ParserResult parse_parenthesized(const size_t nplurals, const std::wstrin
|
||||
return result;
|
||||
}
|
||||
|
||||
static ParserResult parse_negation(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_negation(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
if (str.empty())
|
||||
return ParserResult(nullptr, str);
|
||||
@ -179,43 +179,43 @@ static ParserResult parse_negation(const size_t nplurals, const std::wstring_vie
|
||||
return result;
|
||||
}
|
||||
|
||||
static ParserResult parse_multiplicative(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_multiplicative(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
static const wchar_t *patterns[] = { L"*", L"/", L"%" };
|
||||
return parse_ltr<parse_negation, std::multiplies, std::divides, std::modulus>(nplurals, str, patterns);
|
||||
}
|
||||
|
||||
static ParserResult parse_additive(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_additive(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
static const wchar_t *patterns[] = { L"+", L"-" };
|
||||
return parse_ltr<parse_multiplicative, std::plus, std::minus>(nplurals, str, patterns);
|
||||
}
|
||||
|
||||
static ParserResult parse_comparison(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_comparison(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
static const wchar_t *patterns[] = { L"<=", L">=", L"<", L">" };
|
||||
return parse_ltr<parse_additive, std::less_equal, std::greater_equal, std::less, std::greater>(nplurals, str, patterns);
|
||||
}
|
||||
|
||||
static ParserResult parse_equality(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_equality(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
static const wchar_t *patterns[] = { L"==", L"!=" };
|
||||
return parse_ltr<parse_comparison, std::equal_to, std::not_equal_to>(nplurals, str, patterns);
|
||||
}
|
||||
|
||||
static ParserResult parse_conjunction(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_conjunction(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
static const wchar_t *and_pattern[] = { L"&&" };
|
||||
return parse_ltr<parse_equality, std::logical_and>(nplurals, str, and_pattern);
|
||||
}
|
||||
|
||||
static ParserResult parse_disjunction(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_disjunction(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
static const wchar_t *or_pattern[] = { L"||" };
|
||||
return parse_ltr<parse_conjunction, std::logical_or>(nplurals, str, or_pattern);
|
||||
}
|
||||
|
||||
static ParserResult parse_ternary(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_ternary(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
auto pres = parse_disjunction(nplurals, str);
|
||||
if (pres.second.empty() || pres.second[0] != '?') // no ? :
|
||||
@ -229,12 +229,12 @@ static ParserResult parse_ternary(const size_t nplurals, const std::wstring_view
|
||||
return ParserResult(new TernaryOperation(cond, val, pres.first), pres.second);
|
||||
}
|
||||
|
||||
static ParserResult parse_expr(const size_t nplurals, const std::wstring_view &str)
|
||||
static ParserResult parse_expr(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
return parse_ternary(nplurals, trim(str));
|
||||
}
|
||||
|
||||
GettextPluralForm::Ptr GettextPluralForm::parse(const size_t nplurals, const std::wstring_view &str)
|
||||
GettextPluralForm::Ptr GettextPluralForm::parse(const size_t nplurals, std::wstring_view str)
|
||||
{
|
||||
if (nplurals == 0)
|
||||
return nullptr;
|
||||
@ -244,7 +244,7 @@ GettextPluralForm::Ptr GettextPluralForm::parse(const size_t nplurals, const std
|
||||
return result.first;
|
||||
}
|
||||
|
||||
GettextPluralForm::Ptr GettextPluralForm::parseHeaderLine(const std::wstring_view &str)
|
||||
GettextPluralForm::Ptr GettextPluralForm::parseHeaderLine(std::wstring_view str)
|
||||
{
|
||||
if (!str_starts_with(str, L"Plural-Forms: nplurals=") || !str_ends_with(str, L";"))
|
||||
return nullptr;
|
||||
|
@ -24,8 +24,8 @@ public:
|
||||
}
|
||||
virtual ~GettextPluralForm() {};
|
||||
|
||||
static GettextPluralForm::Ptr parse(const size_t nplurals, const std::wstring_view &str);
|
||||
static GettextPluralForm::Ptr parseHeaderLine(const std::wstring_view &str);
|
||||
static GettextPluralForm::Ptr parse(const size_t nplurals, std::wstring_view str);
|
||||
static GettextPluralForm::Ptr parseHeaderLine(std::wstring_view str);
|
||||
protected:
|
||||
GettextPluralForm(size_t nplurals): nplurals(nplurals) {};
|
||||
private:
|
||||
|
@ -25,12 +25,41 @@ TEST_CASE("test translations")
|
||||
{
|
||||
SECTION("Plural-Forms function for translations")
|
||||
{
|
||||
auto form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; plural= (n-1+1)<=1 ? n||1?0:1 : 1?(!!2):2;");
|
||||
REQUIRE(form);
|
||||
REQUIRE(form->size() == 3);
|
||||
#define REQUIRE_FORM_SIZE(x) {REQUIRE(form); REQUIRE(form->size() == (x));}
|
||||
// Test cases from https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
|
||||
auto form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=2; plural=n != 1;");
|
||||
REQUIRE_FORM_SIZE(2);
|
||||
CHECK((*form)(0) == 1);
|
||||
CHECK((*form)(1) == 0);
|
||||
CHECK((*form)(2) == 1);
|
||||
|
||||
form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;");
|
||||
REQUIRE_FORM_SIZE(3);
|
||||
CHECK((*form)(0) == 2);
|
||||
CHECK((*form)(1) == 0);
|
||||
CHECK((*form)(102) == 1);
|
||||
CHECK((*form)(111) == 1);
|
||||
|
||||
form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; "
|
||||
"plural=n%10==1 && n%100!=11 ? 0 : "
|
||||
"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;");
|
||||
REQUIRE_FORM_SIZE(3);
|
||||
CHECK((*form)(0) == 2);
|
||||
CHECK((*form)(1) == 0);
|
||||
CHECK((*form)(102) == 1);
|
||||
CHECK((*form)(104) == 1);
|
||||
CHECK((*form)(111) == 2);
|
||||
CHECK((*form)(112) == 2);
|
||||
CHECK((*form)(121) == 0);
|
||||
CHECK((*form)(122) == 1);
|
||||
|
||||
// Edge cases
|
||||
form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; plural= (n-1+1)<=1 ? n||1?0:1 : 1?(!!2):2;");
|
||||
REQUIRE_FORM_SIZE(3);
|
||||
CHECK((*form)(0) == 0);
|
||||
CHECK((*form)(1) == 0);
|
||||
CHECK((*form)(2) == 1);
|
||||
#undef REQUIRE_FORM_SIZE
|
||||
}
|
||||
|
||||
SECTION("PO file parser")
|
||||
|
Loading…
Reference in New Issue
Block a user