From 3b4ffd7199d990d1cbd0e7cbe23fa41f04d38e74 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Wed, 5 Apr 2017 19:03:59 +0300 Subject: Add chat command for translate message from player language to english. Also add po field into languages.xml. --- src/actions/chat.cpp | 45 ++++++++++++++++++++++++++++ src/actions/chat.h | 1 + src/being/being.h | 3 ++ src/being/playerinfo.cpp | 17 +++++++++++ src/being/playerinfo.h | 4 +++ src/client.cpp | 4 +++ src/dyetool/actions/chat.cpp | 1 + src/dyetool/client.cpp | 2 ++ src/enums/input/inputaction.h | 1 + src/input/inputactionmap.h | 6 ++++ src/net/eathena/beingrecv.cpp | 2 ++ src/resources/db/languagedb.cpp | 37 +++++++++++++++++++---- src/resources/db/languagedb.h | 2 ++ src/utils/langs.cpp | 25 ++++++++++++++++ src/utils/langs.h | 2 ++ src/utils/translation/podict.cpp | 5 ++++ src/utils/translation/podict.h | 2 ++ src/utils/translation/translationmanager.cpp | 8 ++++- src/utils/translation/translationmanager.h | 2 ++ 19 files changed, 163 insertions(+), 6 deletions(-) diff --git a/src/actions/chat.cpp b/src/actions/chat.cpp index 037b25942..4da242569 100644 --- a/src/actions/chat.cpp +++ b/src/actions/chat.cpp @@ -49,6 +49,8 @@ #include "utils/booleanoptions.h" #include "utils/chatutils.h" +#include "utils/translation/podict.h" + #include "debug.h" const int DEFAULT_CHAT_WINDOW_SCROLL = 7; @@ -671,4 +673,47 @@ impHandler(guildNotice) return true; } +impHandler(translate) +{ + if (reverseDictionary == nullptr || + localPlayer == nullptr || + event.args.empty()) + { + return false; + } + + ChatTab *const tab = event.tab; + if (tab == nullptr) + return false; + + std::string srcStr = event.args; + std::string enStr; + toLower(srcStr); + if (localPlayer->getLanguageId() > 0) + { + if (reverseDictionary->haveStr(srcStr)) + enStr = reverseDictionary->getStr(srcStr); + else if (dictionary->haveStr(srcStr)) + enStr = srcStr; + } + else + { + if (dictionary->haveStr(srcStr)) + enStr = srcStr; + } + + if (enStr.empty()) + { + tab->chatLog( + // TRANSLATORS: translation error message + strprintf(_("No translation found for string: %s"), + srcStr.c_str()), + ChatMsgType::BY_SERVER); + return true; + } + + tab->chatInput(enStr); + return true; +} + } // namespace Actions diff --git a/src/actions/chat.h b/src/actions/chat.h index 0794ec9ed..ba33806a3 100644 --- a/src/actions/chat.h +++ b/src/actions/chat.h @@ -61,6 +61,7 @@ namespace Actions decHandler(hat); decHandler(chatClipboard); decHandler(guildNotice); + decHandler(translate); } // namespace Actions #undef decHandler diff --git a/src/being/being.h b/src/being/being.h index 0110f3141..79f9a4d83 100644 --- a/src/being/being.h +++ b/src/being/being.h @@ -1063,6 +1063,9 @@ class Being notfinal : public ActorSprite, void setLanguageId(const int lang) restrict2 noexcept2; + int getLanguageId() restrict2 noexcept2 A_WARN_UNUSED + { return mLanguageId; } + uint16_t getTeamId() const restrict2 noexcept2 A_WARN_UNUSED { return mTeamId; } diff --git a/src/being/playerinfo.cpp b/src/being/playerinfo.cpp index 25620d5ba..8a9c55c5e 100644 --- a/src/being/playerinfo.cpp +++ b/src/being/playerinfo.cpp @@ -42,6 +42,8 @@ #include "utils/delete2.h" +#include "utils/translation/translationmanager.h" + #include "debug.h" namespace PlayerInfo @@ -64,6 +66,7 @@ BeingId mElementalId = BeingId_zero; Trading mTrading = Trading_false; bool mVending = false; int mLevelProgress = 0; +int mServerLanguage = -1; std::set mProtectedItems; // --- Triggers --------------------------------------------------------------- @@ -639,4 +642,18 @@ bool isVending() return mVending; } +void setServerLanguage(const int lang) +{ + if (lang != mServerLanguage) + { + mServerLanguage = lang; + TranslationManager::loadDictionaryLang(); + } +} + +int getServerLanguage() +{ + return mServerLanguage; +} + } // namespace PlayerInfo diff --git a/src/being/playerinfo.h b/src/being/playerinfo.h index 0372bafc4..1c81d7761 100644 --- a/src/being/playerinfo.h +++ b/src/being/playerinfo.h @@ -297,6 +297,10 @@ namespace PlayerInfo void enableVending(const bool b); bool isVending() A_WARN_UNUSED; + + void setServerLanguage(const int lang); + + int getServerLanguage() A_WARN_UNUSED; } // namespace PlayerInfo #endif // BEING_PLAYERINFO_H diff --git a/src/client.cpp b/src/client.cpp index 64744e49e..c8530da94 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -432,6 +432,7 @@ void Client::gameInit() VirtFs::mountDir(settings.localDataDir, Append_false); TranslationManager::loadCurrentLang(); + TranslationManager::loadDictionaryLang(); #ifdef ENABLE_CUSTOMNLS TranslationManager::loadGettextLang(); #endif // ENABLE_CUSTOMNLS @@ -1152,6 +1153,7 @@ int Client::gameExec() _("Connecting to server"), State::SWITCH_SERVER); TranslationManager::loadCurrentLang(); + TranslationManager::loadDictionaryLang(); BLOCK_END("Client::gameExec State::CONNECT_SERVER") break; @@ -1218,6 +1220,7 @@ int Client::gameExec() logger->log1("State: WORLD SELECT"); { TranslationManager::loadCurrentLang(); + TranslationManager::loadDictionaryLang(); if (!loginHandler) { BLOCK_END("Client::gameExec State::WORLD_SELECT") @@ -1346,6 +1349,7 @@ int Client::gameExec() initFeatures(); TranslationManager::loadCurrentLang(); + TranslationManager::loadDictionaryLang(); PlayerInfo::stateChange(mState); delete spellManager; diff --git a/src/dyetool/actions/chat.cpp b/src/dyetool/actions/chat.cpp index 150f3d7fb..940ded31c 100644 --- a/src/dyetool/actions/chat.cpp +++ b/src/dyetool/actions/chat.cpp @@ -61,5 +61,6 @@ impHandlerVoid(chatGuildTab) impHandlerVoid(hat) impHandlerVoid(chatClipboard) impHandlerVoid(guildNotice) +impHandlerVoid(translate) } // namespace Actions diff --git a/src/dyetool/client.cpp b/src/dyetool/client.cpp index f618db321..cf3fceed6 100644 --- a/src/dyetool/client.cpp +++ b/src/dyetool/client.cpp @@ -282,6 +282,7 @@ void Client::gameInit() VirtFs::mountDir(settings.localDataDir, Append_false); TranslationManager::loadCurrentLang(); + TranslationManager::loadDictionaryLang(); #ifdef ENABLE_CUSTOMNLS TranslationManager::loadGettextLang(); #endif // ENABLE_CUSTOMNLS @@ -662,6 +663,7 @@ int Client::gameExec() paths.setDefaultValues(getPathsDefaults()); initPaths(); TranslationManager::loadCurrentLang(); + TranslationManager::loadDictionaryLang(); if (desktop) desktop->reloadWallpaper(); diff --git a/src/enums/input/inputaction.h b/src/enums/input/inputaction.h index ee5e1781c..b514805b6 100644 --- a/src/enums/input/inputaction.h +++ b/src/enums/input/inputaction.h @@ -686,6 +686,7 @@ enumStart(InputAction) PARTY_AUTO_ITEM_SHARE, CREATE_ITEM, COPY_OUTFIT_TO_CHAT, + COMMAND_TRANSLATE, TOTAL } enumEnd(InputAction); diff --git a/src/input/inputactionmap.h b/src/input/inputactionmap.h index 2301c1728..a717c7e5e 100644 --- a/src/input/inputactionmap.h +++ b/src/input/inputactionmap.h @@ -5606,6 +5606,12 @@ static const InputActionData inputActionData "outfittochat|copyoutfittochat", UseArgs_false, Protected_true}, + {"keyCommandTranslate", + defaultAction(&Actions::translate), + InputCondition::INGAME, + "translate|trans|tran", + UseArgs_false, + Protected_true}, }; #undef defaultAction diff --git a/src/net/eathena/beingrecv.cpp b/src/net/eathena/beingrecv.cpp index 6c78a8f40..52b1508da 100644 --- a/src/net/eathena/beingrecv.cpp +++ b/src/net/eathena/beingrecv.cpp @@ -1766,6 +1766,8 @@ void BeingRecv::processBeingAttrs(Net::MessageIn &msg) dstBeing->setHorse(mount); } dstBeing->setLanguageId(language); + if (dstBeing == localPlayer) + PlayerInfo::setServerLanguage(language); } } diff --git a/src/resources/db/languagedb.cpp b/src/resources/db/languagedb.cpp index e4bbffea4..b7e3ebc0e 100644 --- a/src/resources/db/languagedb.cpp +++ b/src/resources/db/languagedb.cpp @@ -31,7 +31,9 @@ namespace { std::string mDefaultIcon; - std::map mLanguages; + std::string mDefaultPo; + std::map mIcons; + std::map mPo; } // namespace void LanguageDb::load() @@ -74,7 +76,23 @@ void LanguageDb::loadXmlFile(const std::string &fileName, continue; } const std::string icon = XML::getProperty(node, "icon", ""); - mLanguages[id] = icon; + const std::string po = XML::getProperty(node, "po", ""); + if (icon.empty()) + { + reportAlways("LanguageDb: empty icon field"); + } + else + { + mIcons[id] = icon; + } + if (po.empty()) + { + reportAlways("LanguageDb: empty po field"); + } + else + { + mPo[id] = po; + } } } @@ -83,13 +101,22 @@ void LanguageDb::loadXmlFile(const std::string &fileName, void LanguageDb::unload() { - mLanguages.clear(); + mIcons.clear(); + mPo.clear(); } const std::string &LanguageDb::getIcon(const int id) { - std::map::const_iterator it = mLanguages.find(id); - if (it == mLanguages.end()) + std::map::const_iterator it = mIcons.find(id); + if (it == mIcons.end()) return mDefaultIcon; return (*it).second; } + +const std::string &LanguageDb::getPo(const int id) +{ + std::map::const_iterator it = mPo.find(id); + if (it == mPo.end()) + return mDefaultPo; + return (*it).second; +} diff --git a/src/resources/db/languagedb.h b/src/resources/db/languagedb.h index 18302a451..8f33576a6 100644 --- a/src/resources/db/languagedb.h +++ b/src/resources/db/languagedb.h @@ -37,6 +37,8 @@ namespace LanguageDb void unload(); const std::string &getIcon(const int id); + + const std::string &getPo(const int id); } // namespace LanguageDB #endif // RESOURCES_DB_LANGUAGEDB_H diff --git a/src/utils/langs.cpp b/src/utils/langs.cpp index 41545ac52..8aa452077 100644 --- a/src/utils/langs.cpp +++ b/src/utils/langs.cpp @@ -20,8 +20,16 @@ #include "utils/langs.h" +#include "logger.h" + #include "configuration.h" +#ifndef DYECMD +#include "being/playerinfo.h" + +#include "resources/db/languagedb.h" +#endif // DYECMD + #include "debug.h" static const char *getLangName() @@ -58,6 +66,23 @@ LangVect getLang() return langs; } +LangVect getServerLang() +{ + LangVect langs; +#ifndef DYECMD + const int id = PlayerInfo::getServerLanguage(); + std::string lang = LanguageDb::getPo(id); + if (lang.empty()) + return langs; + langs.push_back(lang); + const size_t idx = lang.find('_'); + if (idx != std::string::npos) + langs.push_back(lang.substr(0, idx)); +#endif // DYECMD + + return langs; +} + std::string getLangSimple() { const std::string lang = config.getStringValue("lang"); diff --git a/src/utils/langs.h b/src/utils/langs.h index dfbe65995..902dcf264 100644 --- a/src/utils/langs.h +++ b/src/utils/langs.h @@ -31,6 +31,8 @@ typedef LangVect::const_iterator LangIter; LangVect getLang() A_WARN_UNUSED; +LangVect getServerLang() A_WARN_UNUSED; + std::string getLangSimple() A_WARN_UNUSED; std::string getLangShort() A_WARN_UNUSED; diff --git a/src/utils/translation/podict.cpp b/src/utils/translation/podict.cpp index 37b1b2fe8..56fd42467 100644 --- a/src/utils/translation/podict.cpp +++ b/src/utils/translation/podict.cpp @@ -54,3 +54,8 @@ const char *PoDict::getChar(const char *const str) return str; return mPoLines[str].c_str(); } + +bool PoDict::haveStr(const std::string &str) const +{ + return mPoLines.find(str) != mPoLines.end(); +} diff --git a/src/utils/translation/podict.h b/src/utils/translation/podict.h index a8b18bba4..d40aa1499 100644 --- a/src/utils/translation/podict.h +++ b/src/utils/translation/podict.h @@ -41,6 +41,8 @@ class PoDict final const char *getChar(const char *const str); + bool haveStr(const std::string &str) const; + #ifndef UNITTESTS protected: #endif // UNITTESTS diff --git a/src/utils/translation/translationmanager.cpp b/src/utils/translation/translationmanager.cpp index f64d8e612..808ad5f2f 100644 --- a/src/utils/translation/translationmanager.cpp +++ b/src/utils/translation/translationmanager.cpp @@ -43,7 +43,13 @@ void TranslationManager::loadCurrentLang() delete translator; translator = loadLang(getLang(), ""); translator = loadLang(getLang(), "help/", translator); - dictionary = loadLang(getLang(), "dict/"); +} + +void TranslationManager::loadDictionaryLang() +{ + delete dictionary; + delete reverseDictionary; + dictionary = loadLang(getServerLang(), "dict/"); reverseDictionary = reverseLang(dictionary); } diff --git a/src/utils/translation/translationmanager.h b/src/utils/translation/translationmanager.h index 81ac4fda7..088d97449 100644 --- a/src/utils/translation/translationmanager.h +++ b/src/utils/translation/translationmanager.h @@ -43,6 +43,8 @@ class TranslationManager final static void loadCurrentLang(); + static void loadDictionaryLang(); + #ifdef ENABLE_CUSTOMNLS static void loadGettextLang(); #endif // ENABLE_CUSTOMNLS -- cgit v1.2.3-60-g2f50