Add default plural rules

This makes the PO loader correctly handle the situation where the optional
`Plural-Forms` header field does not exist.

The `Translation` class and its subclasses always have access to valid plural
rules via `_get_plural_rules()`. Plural rules are prioritized:

1. `Translation.plural_rules_override`
2. `TranslationServer.get_plural_rules(locale)`
3. The English plural rules: `nplurals=2; plurals=(n != 1)`

Co-Authored-By: Pāvels Nadtočajevs <7645683+bruvzg@users.noreply.github.com>
This commit is contained in:
Haoyu Qiu
2025-07-21 17:59:14 +08:00
parent ebb96e2303
commit e882e42e1b
11 changed files with 202 additions and 61 deletions

View File

@ -36,15 +36,6 @@
#include "core/os/os.h"
#include "core/string/locales.h"
Vector<TranslationServer::LocaleScriptInfo> TranslationServer::locale_script_info;
HashMap<String, String> TranslationServer::language_map;
HashMap<String, String> TranslationServer::script_map;
HashMap<String, String> TranslationServer::locale_rename_map;
HashMap<String, String> TranslationServer::country_name_map;
HashMap<String, String> TranslationServer::variant_map;
HashMap<String, String> TranslationServer::country_rename_map;
void TranslationServer::init_locale_info() {
// Init locale info.
language_map.clear();
@ -113,6 +104,18 @@ void TranslationServer::init_locale_info() {
}
idx++;
}
// Init plural rules.
plural_rules_map.clear();
idx = 0;
while (plural_rules[idx][0] != nullptr) {
const Vector<String> rule_locs = String(plural_rules[idx][0]).split(" ");
const String rule = String(plural_rules[idx][1]);
for (const String &l : rule_locs) {
plural_rules_map[l] = rule;
}
idx++;
}
}
TranslationServer::Locale::operator String() const {
@ -305,6 +308,26 @@ String TranslationServer::get_locale_name(const String &p_locale) const {
return name;
}
String TranslationServer::get_plural_rules(const String &p_locale) const {
const String *rule = plural_rules_map.getptr(p_locale);
if (rule) {
return *rule;
}
Locale l = Locale(*this, p_locale, false);
if (!l.country.is_empty()) {
rule = plural_rules_map.getptr(l.language + "_" + l.country);
if (rule) {
return *rule;
}
}
rule = plural_rules_map.getptr(l.language);
if (rule) {
return *rule;
}
return String();
}
Vector<String> TranslationServer::get_all_languages() const {
Vector<String> languages;
@ -584,6 +607,7 @@ void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_country_name", "country"), &TranslationServer::get_country_name);
ClassDB::bind_method(D_METHOD("get_locale_name", "locale"), &TranslationServer::get_locale_name);
ClassDB::bind_method(D_METHOD("get_plural_rules", "locale"), &TranslationServer::get_plural_rules);
ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationServer::translate, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("translate_plural", "message", "plural_message", "n", "context"), &TranslationServer::translate_plural, DEFVAL(StringName()));