Path: blob/master/tests/core/string/test_translation.h
21151 views
/**************************************************************************/1/* test_translation.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "core/string/optimized_translation.h"33#include "core/string/plural_rules.h"34#include "core/string/translation.h"35#include "core/string/translation_server.h"3637#ifdef TOOLS_ENABLED38#include "editor/import/resource_importer_csv_translation.h"39#endif4041#include "tests/test_macros.h"42#include "tests/test_utils.h"4344namespace TestTranslation {4546TEST_CASE("[Translation] Messages") {47Ref<Translation> translation;48translation.instantiate();49translation->set_locale("fr");50translation->add_message("Hello", "Bonjour");51CHECK(translation->get_message("Hello") == "Bonjour");5253translation->erase_message("Hello");54// The message no longer exists, so it returns an empty string instead.55CHECK(translation->get_message("Hello") == "");5657List<StringName> messages;58translation->get_message_list(&messages);59CHECK(translation->get_message_count() == 0);60CHECK(messages.size() == 0);6162translation->add_message("Hello2", "Bonjour2");63translation->add_message("Hello3", "Bonjour3");64messages.clear();65translation->get_message_list(&messages);66CHECK(translation->get_message_count() == 2);67CHECK(messages.size() == 2);68// Messages are stored in a Map, don't assume ordering.69CHECK(messages.find("Hello2"));70CHECK(messages.find("Hello3"));71}7273TEST_CASE("[Translation] Messages with context") {74Ref<Translation> translation;75translation.instantiate();76translation->set_locale("fr");77translation->add_message("Hello", "Bonjour");78translation->add_message("Hello", "Salut", "friendly");79CHECK(translation->get_message("Hello") == "Bonjour");80CHECK(translation->get_message("Hello", "friendly") == "Salut");81CHECK(translation->get_message("Hello", "nonexistent_context") == "");8283// Only remove the message for the default context, not the "friendly" context.84translation->erase_message("Hello");85// The message no longer exists, so it returns an empty string instead.86CHECK(translation->get_message("Hello") == "");87CHECK(translation->get_message("Hello", "friendly") == "Salut");88CHECK(translation->get_message("Hello", "nonexistent_context") == "");8990List<StringName> messages;91translation->get_message_list(&messages);9293CHECK(translation->get_message_count() == 1);94CHECK(messages.size() == 1);9596translation->add_message("Hello2", "Bonjour2");97translation->add_message("Hello2", "Salut2", "friendly");98translation->add_message("Hello3", "Bonjour3");99messages.clear();100translation->get_message_list(&messages);101102CHECK(translation->get_message_count() == 4);103CHECK(messages.size() == 4);104// Messages are stored in a Map, don't assume ordering.105CHECK(messages.find("Hello2"));106CHECK(messages.find("Hello3"));107// Context and untranslated string are separated by EOT.108CHECK(messages.find("friendly\x04Hello2"));109}110111TEST_CASE("[Translation] Plural messages") {112{113Ref<Translation> translation;114translation.instantiate();115translation->set_locale("fr");116CHECK(translation->get_nplurals() == 2);117}118119{120Ref<Translation> translation;121translation.instantiate();122translation->set_locale("invalid");123CHECK(translation->get_nplurals() == 2);124}125126{127Ref<Translation> translation;128translation.instantiate();129translation->set_plural_rules_override("Plural-Forms: nplurals=2; plural=(n >= 2);");130CHECK(translation->get_nplurals() == 2);131132PackedStringArray plurals;133plurals.push_back("Il y a %d pomme");134plurals.push_back("Il y a %d pommes");135translation->add_plural_message("There are %d apples", plurals);136ERR_PRINT_OFF;137// This is invalid, as the number passed to `get_plural_message()` may not be negative.138CHECK(vformat(translation->get_plural_message("There are %d apples", "", -1), -1) == "");139ERR_PRINT_ON;140CHECK(vformat(translation->get_plural_message("There are %d apples", "", 0), 0) == "Il y a 0 pomme");141CHECK(vformat(translation->get_plural_message("There are %d apples", "", 1), 1) == "Il y a 1 pomme");142CHECK(vformat(translation->get_plural_message("There are %d apples", "", 2), 2) == "Il y a 2 pommes");143}144}145146TEST_CASE("[Translation] Plural rules parsing") {147ERR_PRINT_OFF;148{149CHECK(PluralRules::parse("") == nullptr);150151CHECK(PluralRules::parse("plurals=(n != 1);") == nullptr);152CHECK(PluralRules::parse("nplurals; plurals=(n != 1);") == nullptr);153CHECK(PluralRules::parse("nplurals=; plurals=(n != 1);") == nullptr);154CHECK(PluralRules::parse("nplurals=0; plurals=(n != 1);") == nullptr);155CHECK(PluralRules::parse("nplurals=-1; plurals=(n != 1);") == nullptr);156157CHECK(PluralRules::parse("nplurals=2;") == nullptr);158CHECK(PluralRules::parse("nplurals=2; plurals;") == nullptr);159CHECK(PluralRules::parse("nplurals=2; plurals=;") == nullptr);160}161ERR_PRINT_ON;162163{164PluralRules *pr = PluralRules::parse("nplurals=3; plural=(n==0 ? 0 : n==1 ? 1 : 2);");165REQUIRE(pr != nullptr);166167CHECK(pr->get_nplurals() == 3);168CHECK(pr->get_plural() == "(n==0 ? 0 : n==1 ? 1 : 2)");169170CHECK(pr->evaluate(0) == 0);171CHECK(pr->evaluate(1) == 1);172CHECK(pr->evaluate(2) == 2);173CHECK(pr->evaluate(3) == 2);174175memdelete(pr);176}177178{179PluralRules *pr = PluralRules::parse("nplurals=1; plural=0;");180REQUIRE(pr != nullptr);181182CHECK(pr->get_nplurals() == 1);183CHECK(pr->get_plural() == "0");184185CHECK(pr->evaluate(0) == 0);186CHECK(pr->evaluate(1) == 0);187CHECK(pr->evaluate(2) == 0);188CHECK(pr->evaluate(3) == 0);189190memdelete(pr);191}192}193194#ifdef TOOLS_ENABLED195TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages") {196Ref<Translation> translation = memnew(Translation);197translation->set_locale("fr");198translation->add_message("Hello", "Bonjour");199translation->add_message("Hello2", "Bonjour2");200translation->add_message("Hello3", "Bonjour3");201202Ref<OptimizedTranslation> optimized_translation = memnew(OptimizedTranslation);203optimized_translation->generate(translation);204CHECK(optimized_translation->get_message("Hello") == "Bonjour");205CHECK(optimized_translation->get_message("Hello2") == "Bonjour2");206CHECK(optimized_translation->get_message("Hello3") == "Bonjour3");207CHECK(optimized_translation->get_message("DoesNotExist") == "");208209List<StringName> messages;210// `get_message_list()` can't return the list of messages stored in an OptimizedTranslation.211optimized_translation->get_message_list(&messages);212CHECK(optimized_translation->get_message_count() == 0);213CHECK(messages.size() == 0);214}215216TEST_CASE("[TranslationCSV] CSV import") {217Ref<ResourceImporterCSVTranslation> import_csv_translation = memnew(ResourceImporterCSVTranslation);218219HashMap<StringName, Variant> options;220options["compress"] = false;221options["delimiter"] = 0;222223List<String> gen_files;224225Error result = import_csv_translation->import(0, TestUtils::get_data_path("translations.csv"),226"", options, nullptr, &gen_files);227CHECK(result == OK);228CHECK(gen_files.size() == 4);229230Ref<TranslationDomain> td = TranslationServer::get_singleton()->get_or_add_domain("godot.test");231for (const String &file : gen_files) {232Ref<Translation> translation = ResourceLoader::load(file);233CHECK(translation.is_valid());234td->add_translation(translation);235}236237td->set_locale_override("en");238239CHECK(td->translate("GOOD_MORNING", StringName()) == "Good Morning");240CHECK(td->translate("GOOD_EVENING", StringName()) == "Good Evening");241242td->set_locale_override("de");243244CHECK(td->translate("GOOD_MORNING", StringName()) == "Guten Morgen");245CHECK(td->translate("GOOD_EVENING", StringName()) == "Good Evening"); // Left blank in CSV, should source from 'en'.246247td->set_locale_override("ja");248249CHECK(td->translate("GOOD_MORNING", StringName()) == String::utf8("おはよう"));250CHECK(td->translate("GOOD_EVENING", StringName()) == String::utf8("こんばんは"));251252/* FIXME: This passes, but triggers a chain reaction that makes test_viewport253* and test_text_edit explode in a billion glittery Unicode particles.254td->set_locale_override("fa");255256CHECK(td->translate("GOOD_MORNING", String()) == String::utf8("صبح بخیر"));257CHECK(td->translate("GOOD_EVENING", String()) == String::utf8("عصر بخیر"));258*/259260TranslationServer::get_singleton()->remove_domain("godot.test");261}262#endif // TOOLS_ENABLED263264} // namespace TestTranslation265266267