summaryrefslogtreecommitdiff
path: root/core/translation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/translation.cpp')
-rw-r--r--core/translation.cpp217
1 files changed, 146 insertions, 71 deletions
diff --git a/core/translation.cpp b/core/translation.cpp
index 4f835bd7b4..8c8ca06740 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -794,17 +794,12 @@ static const char *locale_renames[][2] = {
///////////////////////////////////////////////
-Vector<String> Translation::_get_messages() const {
- Vector<String> msgs;
- msgs.resize(translation_map.size() * 2);
- int idx = 0;
+Dictionary Translation::_get_messages() const {
+ Dictionary d;
for (const Map<StringName, StringName>::Element *E = translation_map.front(); E; E = E->next()) {
- msgs.set(idx + 0, E->key());
- msgs.set(idx + 1, E->get());
- idx += 2;
+ d[E->key()] = E->value();
}
-
- return msgs;
+ return d;
}
Vector<String> Translation::_get_message_list() const {
@@ -819,14 +814,11 @@ Vector<String> Translation::_get_message_list() const {
return msgs;
}
-void Translation::_set_messages(const Vector<String> &p_messages) {
- int msg_count = p_messages.size();
- ERR_FAIL_COND(msg_count % 2);
-
- const String *r = p_messages.ptr();
-
- for (int i = 0; i < msg_count; i += 2) {
- add_message(r[i + 0], r[i + 1]);
+void Translation::_set_messages(const Dictionary &p_messages) {
+ List<Variant> keys;
+ p_messages.get_key_list(&keys);
+ for (auto E = keys.front(); E; E = E->next()) {
+ translation_map[E->get()] = p_messages[E->get()];
}
}
@@ -848,11 +840,21 @@ void Translation::set_locale(const String &p_locale) {
}
}
-void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text) {
+void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context) {
translation_map[p_src_text] = p_xlated_text;
}
-StringName Translation::get_message(const StringName &p_src_text) const {
+void Translation::add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context) {
+ WARN_PRINT("Translation class doesn't handle plural messages. Calling add_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class");
+ ERR_FAIL_COND_MSG(p_plural_xlated_texts.empty(), "Parameter vector p_plural_xlated_texts passed in is empty.");
+ translation_map[p_src_text] = p_plural_xlated_texts[0];
+}
+
+StringName Translation::get_message(const StringName &p_src_text, const StringName &p_context) const {
+ if (p_context != StringName()) {
+ WARN_PRINT("Translation class doesn't handle context. Using context in get_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class");
+ }
+
const Map<StringName, StringName>::Element *E = translation_map.find(p_src_text);
if (!E) {
return StringName();
@@ -861,7 +863,16 @@ StringName Translation::get_message(const StringName &p_src_text) const {
return E->get();
}
-void Translation::erase_message(const StringName &p_src_text) {
+StringName Translation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
+ WARN_PRINT("Translation class doesn't handle plural messages. Calling get_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class");
+ return get_message(p_src_text);
+}
+
+void Translation::erase_message(const StringName &p_src_text, const StringName &p_context) {
+ if (p_context != StringName()) {
+ WARN_PRINT("Translation class doesn't handle context. Using context in erase_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class");
+ }
+
translation_map.erase(p_src_text);
}
@@ -878,15 +889,17 @@ int Translation::get_message_count() const {
void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_locale", "locale"), &Translation::set_locale);
ClassDB::bind_method(D_METHOD("get_locale"), &Translation::get_locale);
- ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message"), &Translation::add_message);
- ClassDB::bind_method(D_METHOD("get_message", "src_message"), &Translation::get_message);
- ClassDB::bind_method(D_METHOD("erase_message", "src_message"), &Translation::erase_message);
+ ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message", "context"), &Translation::add_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("add_plural_message", "src_message", "xlated_messages", "context"), &Translation::add_plural_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_message", "src_message", "context"), &Translation::get_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale");
}
@@ -1020,11 +1033,35 @@ void TranslationServer::remove_translation(const Ref<Translation> &p_translation
translations.erase(p_translation);
}
+Ref<Translation> TranslationServer::get_translation_object(const String &p_locale) {
+ Ref<Translation> res;
+ String lang = get_language_code(p_locale);
+ bool near_match_found = false;
+
+ for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
+ const Ref<Translation> &t = E->get();
+ ERR_FAIL_COND_V(t.is_null(), nullptr);
+ String l = t->get_locale();
+
+ // Exact match.
+ if (l == p_locale) {
+ return t;
+ }
+
+ // If near match found, keep that match, but keep looking to try to look for perfect match.
+ if (get_language_code(l) == lang && !near_match_found) {
+ res = t;
+ near_match_found = true;
+ }
+ }
+ return res;
+}
+
void TranslationServer::clear() {
translations.clear();
}
-StringName TranslationServer::translate(const StringName &p_message) const {
+StringName TranslationServer::translate(const StringName &p_message, const StringName &p_context) const {
// Match given message against the translation catalog for the project locale.
if (!enabled) {
@@ -1033,6 +1070,46 @@ StringName TranslationServer::translate(const StringName &p_message) const {
ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid.");
+ StringName res = _get_message_from_translations(p_message, p_context, locale, false);
+
+ if (!res && fallback.length() >= 2) {
+ res = _get_message_from_translations(p_message, p_context, fallback, false);
+ }
+
+ if (!res) {
+ return p_message;
+ }
+
+ return res;
+}
+
+StringName TranslationServer::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (!enabled) {
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+ }
+
+ ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid.");
+
+ StringName res = _get_message_from_translations(p_message, p_context, locale, true, p_message_plural, p_n);
+
+ if (!res && fallback.length() >= 2) {
+ res = _get_message_from_translations(p_message, p_context, fallback, true, p_message_plural, p_n);
+ }
+
+ if (!res) {
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+ }
+
+ return res;
+}
+
+StringName TranslationServer::_get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural, int p_n) const {
// Locale can be of the form 'll_CC', i.e. language code and regional code,
// e.g. 'en_US', 'en_GB', etc. It might also be simply 'll', e.g. 'en'.
// To find the relevant translation, we look for those with locale starting
@@ -1044,7 +1121,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
// logic, so be sure to propagate changes there when changing things here.
StringName res;
- String lang = get_language_code(locale);
+ String lang = get_language_code(p_locale);
bool near_match = false;
for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
@@ -1052,7 +1129,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
ERR_FAIL_COND_V(t.is_null(), p_message);
String l = t->get_locale();
- bool exact_match = (l == locale);
+ bool exact_match = (l == p_locale);
if (!exact_match) {
if (near_match) {
continue; // Only near-match once, but keep looking for exact matches.
@@ -1062,7 +1139,13 @@ StringName TranslationServer::translate(const StringName &p_message) const {
}
}
- StringName r = t->get_message(p_message);
+ StringName r;
+ if (!plural) {
+ r = t->get_message(p_message, p_context);
+ } else {
+ r = t->get_plural_message(p_message, p_message_plural, p_n, p_context);
+ }
+
if (!r) {
continue;
}
@@ -1075,44 +1158,6 @@ StringName TranslationServer::translate(const StringName &p_message) const {
}
}
- if (!res && fallback.length() >= 2) {
- // Try again with the fallback locale.
- String fallback_lang = get_language_code(fallback);
- near_match = false;
-
- for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
- const Ref<Translation> &t = E->get();
- ERR_FAIL_COND_V(t.is_null(), p_message);
- String l = t->get_locale();
-
- bool exact_match = (l == fallback);
- if (!exact_match) {
- if (near_match) {
- continue; // Only near-match once, but keep looking for exact matches.
- }
- if (get_language_code(l) != fallback_lang) {
- continue; // Language code does not match.
- }
- }
-
- StringName r = t->get_message(p_message);
- if (!r) {
- continue;
- }
- res = r;
-
- if (exact_match) {
- break;
- } else {
- near_match = true;
- }
- }
- }
-
- if (!res) {
- return p_message;
- }
-
return res;
}
@@ -1169,9 +1214,9 @@ void TranslationServer::set_tool_translation(const Ref<Translation> &p_translati
tool_translation = p_translation;
}
-StringName TranslationServer::tool_translate(const StringName &p_message) const {
+StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const {
if (tool_translation.is_valid()) {
- StringName r = tool_translation->get_message(p_message);
+ StringName r = tool_translation->get_message(p_message, p_context);
if (r) {
return r;
}
@@ -1179,13 +1224,27 @@ StringName TranslationServer::tool_translate(const StringName &p_message) const
return p_message;
}
+StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (tool_translation.is_valid()) {
+ StringName r = tool_translation->get_plural_message(p_message, p_message_plural, p_n, p_context);
+ if (r) {
+ return r;
+ }
+ }
+
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+}
+
void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) {
doc_translation = p_translation;
}
-StringName TranslationServer::doc_translate(const StringName &p_message) const {
+StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const {
if (doc_translation.is_valid()) {
- StringName r = doc_translation->get_message(p_message);
+ StringName r = doc_translation->get_message(p_message, p_context);
if (r) {
return r;
}
@@ -1193,16 +1252,32 @@ StringName TranslationServer::doc_translate(const StringName &p_message) const {
return p_message;
}
+StringName TranslationServer::doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (doc_translation.is_valid()) {
+ StringName r = doc_translation->get_plural_message(p_message, p_message_plural, p_n, p_context);
+ if (r) {
+ return r;
+ }
+ }
+
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+}
+
void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_locale", "locale"), &TranslationServer::set_locale);
ClassDB::bind_method(D_METHOD("get_locale"), &TranslationServer::get_locale);
ClassDB::bind_method(D_METHOD("get_locale_name", "locale"), &TranslationServer::get_locale_name);
- ClassDB::bind_method(D_METHOD("translate", "message"), &TranslationServer::translate);
+ ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationServer::translate, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("translate_plural", "message", "plural_message", "n", "context"), &TranslationServer::translate_plural, DEFVAL(""));
ClassDB::bind_method(D_METHOD("add_translation", "translation"), &TranslationServer::add_translation);
ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation);
+ ClassDB::bind_method(D_METHOD("get_translation_object", "locale"), &TranslationServer::get_translation_object);
ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear);