diff options
Diffstat (limited to 'core/io')
-rw-r--r-- | core/io/resource_loader.cpp | 3 | ||||
-rw-r--r-- | core/io/translation_loader_po.cpp | 110 |
2 files changed, 102 insertions, 11 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 534f3e44de..8b3a1f6637 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -999,6 +999,9 @@ void ResourceLoader::load_translation_remaps() { void ResourceLoader::clear_translation_remaps() { translation_remaps.clear(); + while (remapped_list.first() != nullptr) { + remapped_list.remove(remapped_list.first()); + } } void ResourceLoader::load_path_remaps() { diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 11aeddee09..d8ddb213c3 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -32,26 +32,34 @@ #include "core/os/file_access.h" #include "core/translation.h" +#include "core/translation_po.h" RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { enum Status { STATUS_NONE, STATUS_READING_ID, STATUS_READING_STRING, + STATUS_READING_CONTEXT, + STATUS_READING_PLURAL, }; Status status = STATUS_NONE; String msg_id; String msg_str; + String msg_context; + Vector<String> msgs_plural; String config; if (r_error) { *r_error = ERR_FILE_CORRUPT; } - Ref<Translation> translation = Ref<Translation>(memnew(Translation)); + Ref<TranslationPO> translation = Ref<TranslationPO>(memnew(TranslationPO)); int line = 1; + int plural_forms = 0; + int plural_index = -1; + bool entered_context = false; bool skip_this = false; bool skip_next = false; bool is_eof = false; @@ -63,40 +71,107 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { // If we reached last line and it's not a content line, break, otherwise let processing that last loop if (is_eof && l.empty()) { - if (status == STATUS_READING_ID) { + if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) { memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading 'msgid' at: " + path + ":" + itos(line)); + ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line)); } else { break; } } - if (l.begins_with("msgid")) { + if (l.begins_with("msgctxt")) { + if (status != STATUS_READING_STRING && status != STATUS_READING_PLURAL) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line)); + } + + // In PO file, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read + // and set "entered_context" to true to prevent adding twice. + if (!skip_this && msg_id != "") { + if (status == STATUS_READING_STRING) { + translation->add_message(msg_id, msg_str, msg_context); + } else if (status == STATUS_READING_PLURAL) { + if (plural_index != plural_forms - 1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); + } + translation->add_plural_message(msg_id, msgs_plural, msg_context); + } + } + msg_context = ""; + l = l.substr(7, l.length()).strip_edges(); + status = STATUS_READING_CONTEXT; + entered_context = true; + } + + if (l.begins_with("msgid_plural")) { + if (plural_forms == 0) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "PO file uses 'msgid_plural' but 'Plural-Forms' is invalid or missing in header: " + path + ":" + itos(line)); + } else if (status != STATUS_READING_ID) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line)); + } + // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already. + // We just have to reset variables related to plurals for "msgstr[]" later on. + l = l.substr(12, l.length()).strip_edges(); + plural_index = -1; + msgs_plural.clear(); + msgs_plural.resize(plural_forms); + status = STATUS_READING_PLURAL; + } else if (l.begins_with("msgid")) { if (status == STATUS_READING_ID) { memdelete(f); ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line)); } if (msg_id != "") { - if (!skip_this) { - translation->add_message(msg_id, msg_str); + if (!skip_this && !entered_context) { + if (status == STATUS_READING_STRING) { + translation->add_message(msg_id, msg_str, msg_context); + } else if (status == STATUS_READING_PLURAL) { + if (plural_index != plural_forms - 1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); + } + translation->add_plural_message(msg_id, msgs_plural, msg_context); + } } } else if (config == "") { config = msg_str; + // Record plural rule. + int p_start = config.find("Plural-Forms"); + if (p_start != -1) { + int p_end = config.find("\n", p_start); + translation->set_plural_rule(config.substr(p_start, p_end - p_start)); + plural_forms = translation->get_plural_forms(); + } } l = l.substr(5, l.length()).strip_edges(); status = STATUS_READING_ID; + // If we did not encounter msgctxt, we reset context to empty to reset it. + if (!entered_context) { + msg_context = ""; + } msg_id = ""; msg_str = ""; skip_this = skip_next; skip_next = false; + entered_context = false; } - if (l.begins_with("msgstr")) { + if (l.begins_with("msgstr[")) { + if (status != STATUS_READING_PLURAL) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line)); + } + plural_index++; // Increment to add to the next slot in vector msgs_plural. + l = l.substr(9, l.length()).strip_edges(); + } else if (l.begins_with("msgstr")) { if (status != STATUS_READING_ID) { memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' while parsing: " + path + ":" + itos(line)); + ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line)); } l = l.substr(6, l.length()).strip_edges(); @@ -108,7 +183,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { skip_next = true; } line++; - continue; //nothing to read or comment + continue; // Nothing to read or comment. } if (!l.begins_with("\"") || status == STATUS_NONE) { @@ -146,8 +221,12 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { if (status == STATUS_READING_ID) { msg_id += l; - } else { + } else if (status == STATUS_READING_STRING) { msg_str += l; + } else if (status == STATUS_READING_CONTEXT) { + msg_context += l; + } else if (status == STATUS_READING_PLURAL && plural_index >= 0) { + msgs_plural.write[plural_index] = msgs_plural[plural_index] + l; } line++; @@ -155,14 +234,23 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { memdelete(f); + // Add the last set of data from last iteration. if (status == STATUS_READING_STRING) { if (msg_id != "") { if (!skip_this) { - translation->add_message(msg_id, msg_str); + translation->add_message(msg_id, msg_str, msg_context); } } else if (config == "") { config = msg_str; } + } else if (status == STATUS_READING_PLURAL) { + if (!skip_this && msg_id != "") { + if (plural_index != plural_forms - 1) { + memdelete(f); + ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); + } + translation->add_plural_message(msg_id, msgs_plural, msg_context); + } } ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + path + "."); |