]> git.lizzy.rs Git - minetest.git/commitdiff
Localize error messages in mainmenu (#11495)
authorRiceball LEE <snowyu.lee@gmail.com>
Mon, 1 Nov 2021 12:27:46 +0000 (20:27 +0800)
committerGitHub <noreply@github.com>
Mon, 1 Nov 2021 12:27:46 +0000 (12:27 +0000)
Co-authored-by: sfan5 <sfan5@live.de>
Co-authored-by: rubenwardy <rw@rubenwardy.com>
builtin/fstk/ui.lua
src/client/camera.cpp
src/client/camera.h
src/client/game.cpp
src/gettext.h
src/unittest/CMakeLists.txt
src/unittest/test_gettext.cpp [new file with mode: 0644]
util/updatepo.sh

index 976659ed364bda029f57496eae169727225d57a2..13f9cbec2554eb571d063241934b4d7296733ad4 100644 (file)
@@ -63,7 +63,7 @@ function ui.update()
        -- handle errors
        if gamedata ~= nil and gamedata.reconnect_requested then
                local error_message = core.formspec_escape(
-                               gamedata.errormessage or "<none available>")
+                               gamedata.errormessage or fgettext("<none available>"))
                formspec = {
                        "size[14,8]",
                        "real_coordinates[true]",
index 1ce92f196dac6aedcafebce52596657754fbb233..3712d77eaea13064386e58740a05472c69c48260 100644 (file)
@@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "constants.h"
 #include "fontengine.h"
 #include "script/scripting_client.h"
+#include "gettext.h"
 
 #define CAMERA_OFFSET_STEP 200
 #define WIELDMESH_OFFSET_X 55.0f
@@ -133,28 +134,6 @@ void Camera::notifyFovChange()
        }
 }
 
-bool Camera::successfullyCreated(std::string &error_message)
-{
-       if (!m_playernode) {
-               error_message = "Failed to create the player scene node";
-       } else if (!m_headnode) {
-               error_message = "Failed to create the head scene node";
-       } else if (!m_cameranode) {
-               error_message = "Failed to create the camera scene node";
-       } else if (!m_wieldmgr) {
-               error_message = "Failed to create the wielded item scene manager";
-       } else if (!m_wieldnode) {
-               error_message = "Failed to create the wielded item scene node";
-       } else {
-               error_message.clear();
-       }
-
-       if (m_client->modsLoaded())
-               m_client->getScript()->on_camera_ready(this);
-
-       return error_message.empty();
-}
-
 // Returns the fractional part of x
 inline f32 my_modf(f32 x)
 {
index bea9ab3330083771ea77cf632c37b07fafb8869a..3e1cb4fdffa3fd7c69d10a440d731dd93cfe81b3 100644 (file)
@@ -136,9 +136,6 @@ class Camera
        // Notify about new server-sent FOV and initialize smooth FOV transition
        void notifyFovChange();
 
-       // Checks if the constructor was able to create the scene nodes
-       bool successfullyCreated(std::string &error_message);
-
        // Step the camera: updates the viewing range and view bobbing.
        void step(f32 dtime);
 
index 7f0aff49cb1354d9bbb24a9d1f2a2a6b336616ce..fb993d92ff7e8169d6093b69a4b402c9c64088bf 100644 (file)
@@ -1282,9 +1282,8 @@ bool Game::createSingleplayerServer(const std::string &map_dir,
        }
 
        if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
-               *error_message = "Unable to listen on " +
-                               bind_addr.serializeString() +
-                               " because IPv6 is disabled";
+               *error_message = fmtgettext("Unable to listen on %s because IPv6 is disabled",
+                       bind_addr.serializeString().c_str());
                errorstream << *error_message << std::endl;
                return false;
        }
@@ -1317,7 +1316,7 @@ bool Game::createClient(const GameStartData &start_data)
        if (!could_connect) {
                if (error_message->empty() && !connect_aborted) {
                        // Should not happen if error messages are set properly
-                       *error_message = "Connection failed for unknown reason";
+                       *error_message = gettext("Connection failed for unknown reason");
                        errorstream << *error_message << std::endl;
                }
                return false;
@@ -1326,7 +1325,7 @@ bool Game::createClient(const GameStartData &start_data)
        if (!getServerContent(&connect_aborted)) {
                if (error_message->empty() && !connect_aborted) {
                        // Should not happen if error messages are set properly
-                       *error_message = "Connection failed for unknown reason";
+                       *error_message = gettext("Connection failed for unknown reason");
                        errorstream << *error_message << std::endl;
                }
                return false;
@@ -1342,8 +1341,8 @@ bool Game::createClient(const GameStartData &start_data)
        /* Camera
         */
        camera = new Camera(*draw_control, client, m_rendering_engine);
-       if (!camera->successfullyCreated(*error_message))
-               return false;
+       if (client->modsLoaded())
+               client->getScript()->on_camera_ready(camera);
        client->setCamera(camera);
 
        /* Clouds
@@ -1456,15 +1455,14 @@ bool Game::connectToServer(const GameStartData &start_data,
                        local_server_mode = true;
                }
        } catch (ResolveError &e) {
-               *error_message = std::string("Couldn't resolve address: ") + e.what();
+               *error_message = fmtgettext("Couldn't resolve address: %s", e.what());
+
                errorstream << *error_message << std::endl;
                return false;
        }
 
        if (connect_address.isIPv6() && !g_settings->getBool("enable_ipv6")) {
-               *error_message = "Unable to connect to " +
-                               connect_address.serializeString() +
-                               " because IPv6 is disabled";
+               *error_message = fmtgettext("Unable to connect to %s because IPv6 is disabled", connect_address.serializeString().c_str());
                errorstream << *error_message << std::endl;
                return false;
        }
@@ -1518,8 +1516,7 @@ bool Game::connectToServer(const GameStartData &start_data,
                                break;
 
                        if (client->accessDenied()) {
-                               *error_message = "Access denied. Reason: "
-                                               + client->accessDeniedReason();
+                               *error_message = fmtgettext("Access denied. Reason: %s", client->accessDeniedReason().c_str());
                                *reconnect_requested = client->reconnectRequested();
                                errorstream << *error_message << std::endl;
                                break;
@@ -1545,7 +1542,7 @@ bool Game::connectToServer(const GameStartData &start_data,
                                wait_time += dtime;
                                // Only time out if we aren't waiting for the server we started
                                if (!start_data.address.empty() && wait_time > 10) {
-                                       *error_message = "Connection timed out.";
+                                       *error_message = gettext("Connection timed out.");
                                        errorstream << *error_message << std::endl;
                                        break;
                                }
@@ -1593,7 +1590,7 @@ bool Game::getServerContent(bool *aborted)
                        return false;
 
                if (client->getState() < LC_Init) {
-                       *error_message = "Client disconnected";
+                       *error_message = gettext("Client disconnected");
                        errorstream << *error_message << std::endl;
                        return false;
                }
@@ -1675,8 +1672,7 @@ inline void Game::updateInteractTimers(f32 dtime)
 inline bool Game::checkConnection()
 {
        if (client->accessDenied()) {
-               *error_message = "Access denied. Reason: "
-                               + client->accessDeniedReason();
+               *error_message = fmtgettext("Access denied. Reason: %s", client->accessDeniedReason().c_str());
                *reconnect_requested = client->reconnectRequested();
                errorstream << *error_message << std::endl;
                return false;
@@ -4351,14 +4347,15 @@ void the_game(bool *kill,
                }
 
        } catch (SerializationError &e) {
-               error_message = std::string("A serialization error occurred:\n")
-                               + e.what() + "\n\nThe server is probably "
-                               " running a different version of " PROJECT_NAME_C ".";
+               const std::string ver_err = fmtgettext("The server is probably running a different version of %s.", PROJECT_NAME_C);
+               error_message = strgettext("A serialization error occurred:") +"\n"
+                               + e.what() + "\n\n" + ver_err;
                errorstream << error_message << std::endl;
        } catch (ServerError &e) {
                error_message = e.what();
                errorstream << "ServerError: " << error_message << std::endl;
        } catch (ModError &e) {
+               // DO NOT TRANSLATE the `ModError`, it's used by ui.lua
                error_message = std::string("ModError: ") + e.what() +
                                strgettext("\nCheck debug.txt for details.");
                errorstream << error_message << std::endl;
index 5a3654be45e2a406f34f9949903ff6f9f7dfe700..67fd9244fc1e63f8084a032c4007830a011e6430 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "config.h" // for USE_GETTEXT
 #include <string>
+#include "porting.h"
 
 #if USE_GETTEXT
        #include <libintl.h>
@@ -77,3 +78,31 @@ inline std::wstring fwgettext(const char *src, Args&&... args)
        delete[] str;
        return std::wstring(buf);
 }
+
+/**
+ * Returns translated string with format args applied
+ *
+ * @tparam Args Template parameter for format args
+ * @param format Translation source string
+ * @param args Variable format args
+ * @return translated string.
+ */
+template <typename ...Args>
+inline std::string fmtgettext(const char *format, Args&&... args)
+{
+       std::string buf;
+       std::size_t buf_size = 256;
+       buf.resize(buf_size);
+
+       format = gettext(format);
+
+       int len = porting::mt_snprintf(&buf[0], buf_size, format, std::forward<Args>(args)...);
+       if (len <= 0) throw std::runtime_error("gettext format error: " + std::string(format));
+       if ((size_t)len >= buf.size()) {
+               buf.resize(len+1); // extra null byte
+               porting::mt_snprintf(&buf[0], buf.size(), format, std::forward<Args>(args)...);
+       }
+       buf.resize(len); // remove null bytes
+
+       return buf;
+}
index 52f8709014473b1fdc593b3269903a9af15dd78f..4d295e4ed1e21c64537505f1aca64723d205c777 100644 (file)
@@ -33,6 +33,7 @@ set (UNITTEST_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/test_voxelarea.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_voxelalgorithms.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_voxelmanipulator.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/test_gettext.cpp
        PARENT_SCOPE)
 
 set (UNITTEST_CLIENT_SRCS
diff --git a/src/unittest/test_gettext.cpp b/src/unittest/test_gettext.cpp
new file mode 100644 (file)
index 0000000..98f73ec
--- /dev/null
@@ -0,0 +1,47 @@
+#include "test.h"
+#include "porting.h"
+#include "gettext.h"
+
+class TestGettext : public TestBase
+{
+public:
+       TestGettext() {
+               TestManager::registerTestModule(this);
+  }
+
+       const char *getName() { return "TestGettext"; }
+
+       void runTests(IGameDef *gamedef);
+
+       void testSnfmtgettext();
+       void testFmtgettext();
+};
+
+static TestGettext g_test_instance;
+
+void TestGettext::runTests(IGameDef *gamedef)
+{
+       TEST(testFmtgettext);
+}
+
+void TestGettext::testFmtgettext()
+{
+  std::string buf = fmtgettext("Viewing range changed to %d",  12);
+  UASSERTEQ(std::string, buf, "Viewing range changed to 12");
+  buf = fmtgettext(
+    "You are about to join this server with the name \"%s\" for the "
+    "first time.\n"
+    "If you proceed, a new account using your credentials will be "
+    "created on this server.\n"
+    "Please retype your password and click 'Register and Join' to "
+    "confirm account creation, or click 'Cancel' to abort."
+    ,  "A");
+  UASSERTEQ(std::string, buf,
+    "You are about to join this server with the name \"A\" for the "
+    "first time.\n"
+    "If you proceed, a new account using your credentials will be "
+    "created on this server.\n"
+    "Please retype your password and click 'Register and Join' to "
+    "confirm account creation, or click 'Cancel' to abort."
+  );
+}
index 070a44be67bc20f4e2c196daf645ca17abdd6ec3..23e2c61e976599e3607c1d074f2782ccd5802173 100755 (executable)
@@ -61,6 +61,7 @@ xgettext --package-name=minetest \
        --keyword=wstrgettext \
        --keyword=core.gettext \
        --keyword=showTranslatedStatusText \
+       --keyword=fmtgettext \
        --output $potfile \
        --from-code=utf-8 \
        `find src/ -name '*.cpp' -o -name '*.h'` \