Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to add built-in strings in the POT generation #86222

Merged
merged 1 commit into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
YeldhamDev marked this conversation as resolved.
Show resolved Hide resolved
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);
Comment on lines 39 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is starting to look like something that could be refactored in a single method, using an enum parameter to define whether it's editor, property, doc, or extractable.

But that can be for future rework.

List<StringName> get_extractable_message_list();

#endif // EDITOR_TRANSLATION_H
Loading
Loading