Skip to content

Fluent translation #4

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

Draft
wants to merge 4 commits into
base: 4.3-stable
Choose a base branch
from
Draft
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
20 changes: 10 additions & 10 deletions .github/workflows/linux_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ jobs:
fail-fast: false
matrix:
include:
- name: Editor w/ Mono (target=editor)
cache-name: linux-editor-mono
- name: Editor (target=editor)
cache-name: linux-editor
target: editor
sconsflags: module_mono_enabled=yes
bin: "./bin/godot.linuxbsd.editor.x86_64.mono"
build-mono: true
sconsflags:
bin: "./bin/godot.linuxbsd.editor.x86_64"
build-mono: false
tests: false # Disabled due freeze caused by mix Mono build and CI
doc-test: true
proj-conv: true
api-compat: true
api-compat: false # TODO: fix compatibility issues and enable again!
artifact: true

- name: Editor with doubles and GCC sanitizers (target=editor, tests=yes, dev_build=yes, scu_build=yes, precision=double, use_asan=yes, use_ubsan=yes, linker=gold)
Expand Down Expand Up @@ -71,10 +71,10 @@ jobs:
# Skip 2GiB artifact speeding up action.
artifact: false

- name: Template w/ Mono (target=template_release)
cache-name: linux-template-mono
- name: Template (target=template_release)
cache-name: linux-template
target: template_release
sconsflags: module_mono_enabled=yes tests=yes
sconsflags: tests=yes
bin: "./bin/godot.linuxbsd.template_release.x86_64.mono"
build-mono: false
tests: true
Expand All @@ -86,7 +86,7 @@ jobs:
sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no minizip=no tests=yes
bin: "./bin/godot.linuxbsd.template_release.x86_64"
tests: true
artifact: true
artifact: false

steps:
- uses: actions/checkout@v4
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/runner.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: 🔗 GHA
on: [push, pull_request]
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-runner
Expand Down
10 changes: 5 additions & 5 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,21 +1514,21 @@ void Object::initialize_class() {
initialized = true;
}

String Object::tr(const StringName &p_message, const StringName &p_context) const {
String Object::tr(const StringName &p_message, const Dictionary &p_args, const StringName &p_context) const {
if (!_can_translate || !TranslationServer::get_singleton()) {
return p_message;
}

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

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

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

String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
Expand Down Expand Up @@ -1699,7 +1699,7 @@ void Object::_bind_methods() {

ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("tr", "message", "args", "context"), &Object::tr, DEFVAL(Dictionary()), DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL(StringName()));

ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion);
Expand Down
2 changes: 1 addition & 1 deletion core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ class Object {
Variant::Type get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid = nullptr) const;

// Translate message (internationalization).
String tr(const StringName &p_message, const StringName &p_context = "") const;
String tr(const StringName &p_message, const Dictionary &p_args = Dictionary(), const StringName &p_context = "") const;
String tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;

bool _is_queued_for_deletion = false; // Set to true by SceneTree::queue_delete().
Expand Down
4 changes: 2 additions & 2 deletions core/string/optimized_translation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ bool OptimizedTranslation::_get(const StringName &p_name, Variant &r_ret) const
return true;
}

StringName OptimizedTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const {
StringName OptimizedTranslation::get_message(const StringName &p_src_text, const Dictionary &p_args, const StringName &p_context) const {
// p_context passed in is ignore. The use of context is not yet supported in OptimizedTranslation.

int htsize = hash_table.size();
Expand Down Expand Up @@ -302,7 +302,7 @@ Vector<String> OptimizedTranslation::get_translated_message_list() const {

StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
// The use of plurals translation is not yet supported in OptimizedTranslation.
return get_message(p_src_text, p_context);
return get_message(p_src_text, Dictionary(), p_context);
}

void OptimizedTranslation::_get_property_list(List<PropertyInfo> *p_list) const {
Expand Down
2 changes: 1 addition & 1 deletion core/string/optimized_translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class OptimizedTranslation : public Translation {
static void _bind_methods();

public:
virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations
virtual StringName get_message(const StringName &p_src_text, const Dictionary &p_args = Dictionary(), const StringName &p_context = "") const override; //overridable for other implementations
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
virtual Vector<String> get_translated_message_list() const override;
void generate(const Ref<Translation> &p_from);
Expand Down
43 changes: 23 additions & 20 deletions core/string/translation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,18 @@ void Translation::add_plural_message(const StringName &p_src_text, const Vector<
translation_map[p_src_text] = p_plural_xlated_texts[0];
}

StringName Translation::get_message(const StringName &p_src_text, const StringName &p_context) const {
StringName Translation::get_message(const StringName &p_src_text, const Dictionary &p_args, const StringName &p_context) const {
StringName ret;
if (GDVIRTUAL_CALL(_get_message, p_src_text, p_context, ret)) {
if (GDVIRTUAL_CALL(_get_message, p_src_text, p_args, p_context, ret)) {
return ret;
}

if (p_context != StringName()) {
WARN_PRINT("Translation class doesn't handle context. Using context in get_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class");
}
if (!p_args.is_empty()) {
WARN_PRINT("Translation class doesn't handle args. Using args in get_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationFluent class");
}

HashMap<StringName, StringName>::ConstIterator E = translation_map.find(p_src_text);
if (!E) {
Expand Down Expand Up @@ -158,7 +161,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_locale"), &Translation::get_locale);
ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message", "context"), &Translation::add_message, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("add_plural_message", "src_message", "xlated_messages", "context"), &Translation::add_plural_message, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("get_message", "src_message", "context"), &Translation::get_message, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("get_message", "src_message", "args", "context"), &Translation::get_message, DEFVAL(Dictionary()), DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
Expand All @@ -168,7 +171,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);

GDVIRTUAL_BIND(_get_plural_message, "src_message", "src_plural_message", "n", "context");
GDVIRTUAL_BIND(_get_message, "src_message", "context");
GDVIRTUAL_BIND(_get_message, "src_message", "args", "context");

ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale");
Expand Down Expand Up @@ -582,17 +585,17 @@ void TranslationServer::clear() {
translations.clear();
}

StringName TranslationServer::translate(const StringName &p_message, const StringName &p_context) const {
StringName TranslationServer::translate(const StringName &p_message, const Dictionary &p_args, const StringName &p_context) const {
// Match given message against the translation catalog for the project locale.

if (!enabled) {
return p_message;
}

StringName res = _get_message_from_translations(p_message, p_context, locale, false);
StringName res = _get_message_from_translations(p_message, p_args, p_context, locale, false);

if (!res && fallback.length() >= 2) {
res = _get_message_from_translations(p_message, p_context, fallback, false);
res = _get_message_from_translations(p_message, p_args, p_context, fallback, false);
}

if (!res) {
Expand All @@ -610,10 +613,10 @@ StringName TranslationServer::translate_plural(const StringName &p_message, cons
return p_message_plural;
}

StringName res = _get_message_from_translations(p_message, p_context, locale, true, p_message_plural, p_n);
StringName res = _get_message_from_translations(p_message, Dictionary(), p_context, locale, true, p_message_plural, p_n);

if (!res && fallback.length() >= 2) {
res = _get_message_from_translations(p_message, p_context, fallback, true, p_message_plural, p_n);
res = _get_message_from_translations(p_message, Dictionary(), p_context, fallback, true, p_message_plural, p_n);
}

if (!res) {
Expand All @@ -626,7 +629,7 @@ StringName TranslationServer::translate_plural(const StringName &p_message, cons
return res;
}

StringName TranslationServer::_get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural, int p_n) const {
StringName TranslationServer::_get_message_from_translations(const StringName &p_message, const Dictionary &p_args, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural, int p_n) const {
StringName res;
int best_score = 0;

Expand All @@ -639,7 +642,7 @@ StringName TranslationServer::_get_message_from_translations(const StringName &p
if (score > 0 && score >= best_score) {
StringName r;
if (!plural) {
r = t->get_message(p_message, p_context);
r = t->get_message(p_message, p_args, p_context);
} else {
r = t->get_plural_message(p_message, p_message_plural, p_n, p_context);
}
Expand Down Expand Up @@ -748,9 +751,9 @@ String TranslationServer::get_tool_locale() {
}
}

StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const {
StringName TranslationServer::tool_translate(const StringName &p_message, const Dictionary &p_args, const StringName &p_context) const {
if (tool_translation.is_valid()) {
StringName r = tool_translation->get_message(p_message, p_context);
StringName r = tool_translation->get_message(p_message, p_args, p_context);
if (r) {
return r;
}
Expand All @@ -776,9 +779,9 @@ void TranslationServer::set_property_translation(const Ref<Translation> &p_trans
property_translation = p_translation;
}

StringName TranslationServer::property_translate(const StringName &p_message, const StringName &p_context) const {
StringName TranslationServer::property_translate(const StringName &p_message, const Dictionary &p_args, const StringName &p_context) const {
if (property_translation.is_valid()) {
StringName r = property_translation->get_message(p_message, p_context);
StringName r = property_translation->get_message(p_message, p_args, p_context);
if (r) {
return r;
}
Expand All @@ -790,9 +793,9 @@ void TranslationServer::set_doc_translation(const Ref<Translation> &p_translatio
doc_translation = p_translation;
}

StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const {
StringName TranslationServer::doc_translate(const StringName &p_message, const Dictionary &p_args, const StringName &p_context) const {
if (doc_translation.is_valid()) {
StringName r = doc_translation->get_message(p_message, p_context);
StringName r = doc_translation->get_message(p_message, p_args, p_context);
if (r) {
return r;
}
Expand All @@ -818,9 +821,9 @@ void TranslationServer::set_extractable_translation(const Ref<Translation> &p_tr
extractable_translation = p_translation;
}

StringName TranslationServer::extractable_translate(const StringName &p_message, const StringName &p_context) const {
StringName TranslationServer::extractable_translate(const StringName &p_message, const Dictionary &p_args, const StringName &p_context) const {
if (extractable_translation.is_valid()) {
StringName r = extractable_translation->get_message(p_message, p_context);
StringName r = extractable_translation->get_message(p_message, p_args, p_context);
if (r) {
return r;
}
Expand Down Expand Up @@ -1050,7 +1053,7 @@ void TranslationServer::_bind_methods() {

ClassDB::bind_method(D_METHOD("get_locale_name", "locale"), &TranslationServer::get_locale_name);

ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationServer::translate, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("translate", "message", "args", "context"), &TranslationServer::translate, DEFVAL(Dictionary()), DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("translate_plural", "message", "plural_message", "n", "context"), &TranslationServer::translate_plural, DEFVAL(StringName()));

ClassDB::bind_method(D_METHOD("add_translation", "translation"), &TranslationServer::add_translation);
Expand Down
16 changes: 8 additions & 8 deletions core/string/translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Translation : public Resource {
static void _bind_compatibility_methods();
#endif

GDVIRTUAL2RC(StringName, _get_message, StringName, StringName);
GDVIRTUAL3RC(StringName, _get_message, StringName, Dictionary, StringName);
GDVIRTUAL4RC(StringName, _get_plural_message, StringName, StringName, int, StringName);

public:
Expand All @@ -64,7 +64,7 @@ class Translation : public Resource {

virtual void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "");
virtual void add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context = "");
virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const; //overridable for other implementations
virtual StringName get_message(const StringName &p_src_text, const Dictionary &p_args = Dictionary(), const StringName &p_context = "") const; //overridable for other implementations
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const;
virtual void erase_message(const StringName &p_src_text, const StringName &p_context = "");
virtual void get_message_list(List<StringName> *r_messages) const;
Expand Down Expand Up @@ -111,7 +111,7 @@ class TranslationServer : public Object {
bool _load_translations(const String &p_from);
String _standardize_locale(const String &p_locale, bool p_add_defaults) const;

StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const;
StringName _get_message_from_translations(const StringName &p_message, const Dictionary &p_args, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const;

static void _bind_methods();

Expand Down Expand Up @@ -162,7 +162,7 @@ class TranslationServer : public Object {
void add_translation(const Ref<Translation> &p_translation);
void remove_translation(const Ref<Translation> &p_translation);

StringName translate(const StringName &p_message, const StringName &p_context = "") const;
StringName translate(const StringName &p_message, const Dictionary &p_args = Dictionary(), const StringName &p_context = "") const;
StringName translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;

StringName pseudolocalize(const StringName &p_message) const;
Expand All @@ -178,15 +178,15 @@ class TranslationServer : public Object {
String get_tool_locale();
void set_tool_translation(const Ref<Translation> &p_translation);
Ref<Translation> get_tool_translation() const;
StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName tool_translate(const StringName &p_message, const Dictionary &p_args = Dictionary(), 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 StringName &p_context = "") const;
StringName property_translate(const StringName &p_message, const Dictionary &p_args = Dictionary(), const StringName &p_context = "") 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(const StringName &p_message, const Dictionary &p_args = Dictionary(), 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_extractable_translation(const Ref<Translation> &p_translation);
StringName extractable_translate(const StringName &p_message, const StringName &p_context = "") const;
StringName extractable_translate(const StringName &p_message, const Dictionary &p_args = Dictionary(), 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
5 changes: 4 additions & 1 deletion core/string/translation_po.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,13 @@ String TranslationPO::get_plural_rule() const {
return plural_rule;
}

StringName TranslationPO::get_message(const StringName &p_src_text, const StringName &p_context) const {
StringName TranslationPO::get_message(const StringName &p_src_text, const Dictionary &p_args, const StringName &p_context) const {
if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) {
return StringName();
}
if (!p_args.is_empty()) {
WARN_PRINT("TranslationPO class doesn't handle args. Using args in get_message() on a TranslationPO instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationFluent class");
}
ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].is_empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");

return translation_map[p_context][p_src_text][0];
Expand Down
Loading
Loading