diff options
Diffstat (limited to 'core/translation.cpp')
-rw-r--r-- | core/translation.cpp | 96 |
1 files changed, 62 insertions, 34 deletions
diff --git a/core/translation.cpp b/core/translation.cpp index a0902d71fc..cf76de1c9e 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -792,11 +792,6 @@ static const char *locale_renames[][2] = { { NULL, NULL } }; -static String get_trimmed_locale(const String &p_locale) { - - return p_locale.substr(0, 2); -} - /////////////////////////////////////////////// PoolVector<String> Translation::_get_messages() const { @@ -846,7 +841,7 @@ void Translation::set_locale(const String &p_locale) { String univ_locale = TranslationServer::standardize_locale(p_locale); if (!TranslationServer::is_locale_valid(univ_locale)) { - String trimmed_locale = get_trimmed_locale(univ_locale); + String trimmed_locale = TranslationServer::get_language_code(univ_locale); ERR_FAIL_COND_MSG(!TranslationServer::is_locale_valid(trimmed_locale), "Invalid locale: " + trimmed_locale + "."); @@ -945,16 +940,33 @@ String TranslationServer::standardize_locale(const String &p_locale) { return univ_locale; } +String TranslationServer::get_language_code(const String &p_locale) { + + ERR_FAIL_COND_V_MSG(p_locale.length() < 2, p_locale, "Invalid locale '" + p_locale + "'."); + // Most language codes are two letters, but some are three, + // so we have to look for a regional code separator ('_' or '-') + // to extract the left part. + // For example we get 'nah_MX' as input and should return 'nah'. + int split = p_locale.find("_"); + if (split == -1) { + split = p_locale.find("-"); + } + if (split == -1) { // No separator, so the locale is already only a language code. + return p_locale; + } + return p_locale.left(split); +} + void TranslationServer::set_locale(const String &p_locale) { String univ_locale = standardize_locale(p_locale); if (!is_locale_valid(univ_locale)) { - String trimmed_locale = get_trimmed_locale(univ_locale); + String trimmed_locale = get_language_code(univ_locale); print_verbose(vformat("Unsupported locale '%s', falling back to '%s'.", p_locale, trimmed_locale)); if (!is_locale_valid(trimmed_locale)) { - ERR_PRINTS(vformat("Unsupported locale '%s', falling back to 'en'.", trimmed_locale)); + ERR_PRINT(vformat("Unsupported locale '%s', falling back to 'en'.", trimmed_locale)); locale = "en"; } else { locale = trimmed_locale; @@ -986,6 +998,7 @@ Array TranslationServer::get_loaded_locales() const { 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(), Array()); String l = t->get_locale(); locales.push_back(l); @@ -1038,11 +1051,13 @@ void TranslationServer::clear() { StringName TranslationServer::translate(const StringName &p_message) const { - //translate using locale + // Match given message against the translation catalog for the project locale. if (!enabled) return p_message; + ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid."); + // 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 @@ -1050,65 +1065,78 @@ StringName TranslationServer::translate(const StringName &p_message) const { // form. If not found, we fall back to a near match (another locale with // same language code). + // Note: ResourceLoader::_path_remap reproduces this locale near matching + // logic, so be sure to propagate changes there when changing things here. + StringName res; + String lang = get_language_code(locale); bool near_match = false; - const CharType *lptr = &locale[0]; 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(); - if (lptr[0] != l[0] || lptr[1] != l[1]) - continue; // Language code does not match. bool exact_match = (l == locale); - if (!exact_match && near_match) - continue; // Only near-match once, but keep looking for exact matches. + if (!exact_match) { + if (near_match) { + continue; // Only near-match once, but keep looking for exact matches. + } + if (get_language_code(l) != lang) { + continue; // Language code does not match. + } + } StringName r = t->get_message(p_message); - - if (!r) + if (!r) { continue; - + } res = r; - if (exact_match) + if (exact_match) { break; - else + } else { near_match = true; + } } if (!res && fallback.length() >= 2) { // Try again with the fallback locale. - const CharType *fptr = &fallback[0]; + String fallback_lang = get_language_code(fallback); near_match = false; - for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) { + 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(); - if (fptr[0] != l[0] || fptr[1] != l[1]) - continue; // Language code does not match. bool exact_match = (l == fallback); - if (!exact_match && near_match) - continue; // Only near-match once, but keep looking for exact matches. + 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) + if (!r) { continue; - + } res = r; - if (exact_match) + if (exact_match) { break; - else + } else { near_match = true; + } } } - if (!res) + if (!res) { return p_message; + } return res; } |