summaryrefslogtreecommitdiff
path: root/core/io
diff options
context:
space:
mode:
Diffstat (limited to 'core/io')
-rw-r--r--core/io/resource_loader.cpp3
-rw-r--r--core/io/translation_loader_po.cpp110
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 + ".");