Skip to content

Commit

Permalink
Add option to add built-in strings in the POT generation
Browse files Browse the repository at this point in the history
  • Loading branch information
YeldhamDev committed Feb 28, 2024
1 parent df78c06 commit d70c45b
Show file tree
Hide file tree
Showing 23 changed files with 335 additions and 153 deletions.
1 change: 1 addition & 0 deletions core/config/project_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,6 +1514,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translations", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_add_builtin_strings_to_pot", false);

ProjectSettings::get_singleton()->add_hidden_prefix("input/");
}
Expand Down
18 changes: 14 additions & 4 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1483,10 +1483,15 @@ String Object::tr(const StringName &p_message, const StringName &p_context) cons
}

if (Engine::get_singleton()->is_editor_hint()) {
String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context);
if (!tr_msg.is_empty()) {
return tr_msg;
}

return TranslationServer::get_singleton()->tool_translate(p_message, p_context);
} else {
return TranslationServer::get_singleton()->translate(p_message, p_context);
}

return TranslationServer::get_singleton()->translate(p_message, p_context);
}

String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
Expand All @@ -1499,10 +1504,15 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu
}

if (Engine::get_singleton()->is_editor_hint()) {
String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context);
if (!tr_msg.is_empty()) {
return tr_msg;
}

return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context);
} else {
return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context);
}

return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context);
}

void Object::_clear_internal_resource_paths(const Variant &p_var) {
Expand Down
38 changes: 33 additions & 5 deletions core/string/translation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,20 @@ StringName TranslationServer::tool_translate_plural(const StringName &p_message,
return p_message_plural;
}

void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) {
property_translation = p_translation;
}

StringName TranslationServer::property_translate(const StringName &p_message) const {
if (property_translation.is_valid()) {
StringName r = property_translation->get_message(p_message);
if (r) {
return r;
}
}
return p_message;
}

void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) {
doc_translation = p_translation;
}
Expand Down Expand Up @@ -800,20 +814,34 @@ StringName TranslationServer::doc_translate_plural(const StringName &p_message,
return p_message_plural;
}

void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) {
property_translation = p_translation;
void TranslationServer::set_extractable_translation(const Ref<Translation> &p_translation) {
extractable_translation = p_translation;
}

StringName TranslationServer::property_translate(const StringName &p_message) const {
if (property_translation.is_valid()) {
StringName r = property_translation->get_message(p_message);
StringName TranslationServer::extractable_translate(const StringName &p_message, const StringName &p_context) const {
if (extractable_translation.is_valid()) {
StringName r = extractable_translation->get_message(p_message, p_context);
if (r) {
return r;
}
}
return p_message;
}

StringName TranslationServer::extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
if (extractable_translation.is_valid()) {
StringName r = extractable_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;
}

bool TranslationServer::is_pseudolocalization_enabled() const {
return pseudolocalization_enabled;
}
Expand Down
10 changes: 7 additions & 3 deletions core/string/translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ class TranslationServer : public Object {

HashSet<Ref<Translation>> translations;
Ref<Translation> tool_translation;
Ref<Translation> doc_translation;
Ref<Translation> property_translation;
Ref<Translation> doc_translation;
Ref<Translation> extractable_translation;

bool enabled = true;

Expand Down Expand Up @@ -181,11 +182,14 @@ class TranslationServer : public Object {
Ref<Translation> get_tool_translation() const;
StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
void set_property_translation(const Ref<Translation> &p_translation);
StringName property_translate(const StringName &p_message) const;
void set_doc_translation(const Ref<Translation> &p_translation);
StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
void set_property_translation(const Ref<Translation> &p_translation);
StringName property_translate(const StringName &p_message) const;
void set_extractable_translation(const Ref<Translation> &p_translation);
StringName extractable_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;

void setup();

Expand Down
21 changes: 7 additions & 14 deletions core/string/ustring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5391,9 +5391,7 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St

/**
* "Run-time TRanslate". Performs string replacement for internationalization
* within a running project. The translation string must be supplied by the
* project, as Godot does not provide built-in translations for `RTR()` strings
* to keep binary size low. A translation context can optionally be specified to
* without the editor. A translation context can optionally be specified to
* disambiguate between identical source strings in translations. When
* placeholders are desired, use `vformat(RTR("Example: %s"), some_string)`.
* If a string mentions a quantity (and may therefore need a dynamic plural form),
Expand All @@ -5407,23 +5405,19 @@ String RTR(const String &p_text, const String &p_context) {
String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context);
if (rtr.is_empty() || rtr == p_text) {
return TranslationServer::get_singleton()->translate(p_text, p_context);
} else {
return rtr;
}
return rtr;
}

return p_text;
}

/**
* "Run-time TRanslate for N items". Performs string replacement for
* internationalization within a running project. The translation string must be
* supplied by the project, as Godot does not provide built-in translations for
* `RTRN()` strings to keep binary size low. A translation context can
* optionally be specified to disambiguate between identical source strings in
* translations. Use `RTR()` if the string doesn't need dynamic plural form.
* When placeholders are desired, use
* `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`.
* internationalization without the editor. A translation context can optionally
* be specified to disambiguate between identical source strings in translations.
* Use `RTR()` if the string doesn't need dynamic plural form. When placeholders
* are desired, use `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`.
* The placeholder must be present in both strings to avoid run-time warnings in `vformat()`.
*
* NOTE: Do not use `RTRN()` in editor-only code (typically within the `editor/`
Expand All @@ -5434,9 +5428,8 @@ String RTRN(const String &p_text, const String &p_text_plural, int p_n, const St
String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context);
if (rtr.is_empty() || rtr == p_text || rtr == p_text_plural) {
return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context);
} else {
return rtr;
}
return rtr;
}

// Return message based on English plural rule if translation is not possible.
Expand Down
37 changes: 37 additions & 0 deletions core/string/ustring.h
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,43 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St
String RTR(const String &p_text, const String &p_context = "");
String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");

/**
* "Extractable TRanslate". Used for strings that can appear inside an exported
* project (such as the ones in nodes like `FileDialog`), which are made possible
* to add in the POT generator. A translation context can optionally be specified
* to disambiguate between identical source strings in translations.
* When placeholders are desired, use vformat(ETR("Example: %s"), some_string)`.
* If a string mentions a quantity (and may therefore need a dynamic plural form),
* use `ETRN()` instead of `ETR()`.
*
* NOTE: This function is for string extraction only, and will just return the
* string it was given. The translation itself should be done internally by nodes
* with `atr()` instead.
*/
_FORCE_INLINE_ String ETR(const String &p_text, const String &p_context = "") {
return p_text;
}

/**
* "Extractable TRanslate for N items". Used for strings that can appear inside an
* exported project (such as the ones in nodes like `FileDialog`), which are made
* possible to add in the POT generator. A translation context can optionally be
* specified to disambiguate between identical source strings in translations.
* Use `ETR()` if the string doesn't need dynamic plural form. When placeholders
* are desired, use `vformat(ETRN("%d item", "%d items", some_integer), some_integer)`.
* The placeholder must be present in both strings to avoid run-time warnings in `vformat()`.
*
* NOTE: This function is for string extraction only, and will just return the
* string it was given. The translation itself should be done internally by nodes
* with `atr()` instead.
*/
_FORCE_INLINE_ String ETRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "") {
if (p_n == 1) {
return p_text;
}
return p_text_plural;
}

bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end);

_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr) {
Expand Down
9 changes: 9 additions & 0 deletions editor/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ if env.editor_build:
env.Run(editor_builders.make_doc_translations_header, "Generating translations header."),
)

# Extractable translations
tlist = glob.glob(env.Dir("#editor/translations/extractable").abspath + "/*.po")
env.Depends("#editor/extractable_translations.gen.h", tlist)
env.CommandNoCache(
"#editor/extractable_translations.gen.h",
tlist,
env.Run(editor_builders.make_extractable_translations_header, "Generating extractable translations header."),
)

env.add_source_files(env.editor_sources, "*.cpp")
env.add_source_files(env.editor_sources, "register_exporters.gen.cpp")

Expand Down
4 changes: 4 additions & 0 deletions editor/editor_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,9 @@ def make_doc_translations_header(target, source, env):
make_translations_header(target, source, env, "doc")


def make_extractable_translations_header(target, source, env):
make_translations_header(target, source, env, "extractable")


if __name__ == "__main__":
subprocess_main(globals())
3 changes: 3 additions & 0 deletions editor/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,9 @@ void EditorSettings::setup_language() {

// Load class reference translation.
load_doc_translations(lang);

// Load extractable translation for projects.
load_extractable_translations(lang);
}

void EditorSettings::setup_network() {
Expand Down
59 changes: 56 additions & 3 deletions editor/editor_translation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "core/io/translation_loader_po.h"
#include "editor/doc_translations.gen.h"
#include "editor/editor_translations.gen.h"
#include "editor/extractable_translations.gen.h"
#include "editor/property_translations.gen.h"

Vector<String> get_editor_locales() {
Expand Down Expand Up @@ -77,6 +78,32 @@ void load_editor_translations(const String &p_locale) {
}
}

void load_property_translations(const String &p_locale) {
PropertyTranslationList *etl = _property_translations;
while (etl->data) {
if (etl->lang == p_locale) {
Vector<uint8_t> data;
data.resize(etl->uncomp_size);
int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");

Ref<FileAccessMemory> fa;
fa.instantiate();
fa->open_custom(data.ptr(), data.size());

Ref<Translation> tr = TranslationLoaderPO::load_translation(fa);

if (tr.is_valid()) {
tr->set_locale(etl->lang);
TranslationServer::get_singleton()->set_property_translation(tr);
break;
}
}

etl++;
}
}

void load_doc_translations(const String &p_locale) {
DocTranslationList *dtl = _doc_translations;
while (dtl->data) {
Expand All @@ -103,8 +130,8 @@ void load_doc_translations(const String &p_locale) {
}
}

void load_property_translations(const String &p_locale) {
PropertyTranslationList *etl = _property_translations;
void load_extractable_translations(const String &p_locale) {
ExtractableTranslationList *etl = _extractable_translations;
while (etl->data) {
if (etl->lang == p_locale) {
Vector<uint8_t> data;
Expand All @@ -120,11 +147,37 @@ void load_property_translations(const String &p_locale) {

if (tr.is_valid()) {
tr->set_locale(etl->lang);
TranslationServer::get_singleton()->set_property_translation(tr);
TranslationServer::get_singleton()->set_extractable_translation(tr);
break;
}
}

etl++;
}
}

List<StringName> get_extractable_message_list() {
ExtractableTranslationList *etl = _extractable_translations;
List<StringName> msgids;
while (etl->data) {
Vector<uint8_t> data;
data.resize(etl->uncomp_size);
int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
ERR_FAIL_COND_V_MSG(ret == -1, msgids, "Compressed file is corrupt.");

Ref<FileAccessMemory> fa;
fa.instantiate();
fa->open_custom(data.ptr(), data.size());

Ref<Translation> tr = TranslationLoaderPO::load_translation(fa);

if (tr.is_valid()) {
tr->get_message_list(&msgids);
break;
}

etl++;
}

return msgids;
}
5 changes: 4 additions & 1 deletion editor/editor_translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@
#define EDITOR_TRANSLATION_H

#include "core/string/ustring.h"
#include "core/templates/list.h"
#include "core/templates/vector.h"

Vector<String> get_editor_locales();
void load_editor_translations(const String &p_locale);
void load_doc_translations(const String &p_locale);
void load_property_translations(const String &p_locale);
void load_doc_translations(const String &p_locale);
void load_extractable_translations(const String &p_locale);
List<StringName> get_extractable_message_list();

#endif // EDITOR_TRANSLATION_H
Loading

0 comments on commit d70c45b

Please sign in to comment.