aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Utilities/Util.h18
-rw-r--r--src/server/game/Chat/LanguageMgr.cpp185
-rw-r--r--src/server/game/Chat/LanguageMgr.h7
-rw-r--r--src/server/game/Entities/Player/Player.cpp7
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h2
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiersImpl.h2
-rw-r--r--src/server/game/Texts/ChatTextBuilder.cpp4
7 files changed, 176 insertions, 49 deletions
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h
index 1060f5d090f..78672c22b12 100644
--- a/src/common/Utilities/Util.h
+++ b/src/common/Utilities/Util.h
@@ -291,6 +291,24 @@ inline wchar_t wcharToLower(wchar_t wchar)
return wchar;
}
+inline bool isLower(wchar_t wchar)
+{
+ if (wchar >= L'a' && wchar <= L'z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
+ return true;
+ if (wchar >= 0x00E0 && wchar <= 0x00FF) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER Y WITH DIAERESIS
+ return true;
+ if (wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
+ return true;
+ if (wchar == 0x0451) // CYRILLIC SMALL LETTER IO
+ return true;
+ return false;
+}
+
+inline bool isUpper(wchar_t wchar)
+{
+ return !isLower(wchar);
+}
+
TC_COMMON_API std::wstring wstrCaseAccentInsensitiveParse(std::wstring const& wstr, LocaleConstant locale);
TC_COMMON_API void wstrToUpper(std::wstring& str);
diff --git a/src/server/game/Chat/LanguageMgr.cpp b/src/server/game/Chat/LanguageMgr.cpp
index 5e81ed35193..ec2a65f9013 100644
--- a/src/server/game/Chat/LanguageMgr.cpp
+++ b/src/server/game/Chat/LanguageMgr.cpp
@@ -106,60 +106,169 @@ LanguageMgr::WordList const* LanguageMgr::FindWordGroup(uint32 language, uint32
return Trinity::Containers::MapGetValuePtr(_wordsMap, WordKey(language, wordLen));
}
-std::string LanguageMgr::Translate(std::string const& msg, uint32 sourcePlayerLanguage) const
+namespace
{
- std::stringstream result;
- Tokenizer tokens(msg, ' ');
- bool first = true;
- for (char const* str : tokens)
+ void StripHyperlinks(std::string const& source, std::string& dest)
{
- const char* nextPart = str;
- uint32 wordLen = std::min(18U, (uint32)strlen(str));
- LanguageMgr::WordList const* wordGroup = FindWordGroup(sourcePlayerLanguage, wordLen);
- if (!wordGroup)
- nextPart = "";
- else
+ dest.resize(source.length());
+ size_t destSize = 0;
+ bool skipSquareBrackets = false;
+ for (size_t i = 0; i < source.length(); ++i)
{
- uint32 wordHash = SStrHash(str, true);
- uint8 idxInsideGroup = wordHash % wordGroup->size();
- nextPart = wordGroup->at(idxInsideGroup);
+ char c = source[i];
+ if (c != '|')
+ {
+ if (!skipSquareBrackets || (c != '[' && c != ']'))
+ dest[destSize++] = source[i];
+
+ continue;
+ }
+
+ if (i + 1 >= source.length())
+ break;
+
+ switch (source[i + 1])
+ {
+ case 'c':
+ case 'C':
+ // skip color
+ i += 9;
+ break;
+ case 'r':
+ ++i;
+ break;
+ case 'H':
+ // skip just past first |h
+ i = source.find("|h", i);
+ if (i != std::string::npos)
+ i += 2;
+ skipSquareBrackets = true;
+ break;
+ case 'h':
+ ++i;
+ skipSquareBrackets = false;
+ break;
+ case 'T':
+ // skip just past closing |t
+ i = source.find("|t", i);
+ if (i != std::string::npos)
+ i += 2;
+ break;
+ default:
+ break;
+ }
}
- if (first)
- first = false;
- else
- result << " ";
+ dest.resize(destSize);
+ }
+
+ void ReplaceUntranslatableCharactersWithSpace(std::string& text)
+ {
+ std::wstring wstrText;
+ if (!Utf8toWStr(text, wstrText))
+ return;
- result << nextPart;
+ for (wchar_t& w : wstrText)
+ if (!isExtendedLatinCharacter(w) && !isNumeric(w) && w <= 0xFF && w != L'\\')
+ w = L' ';
+
+ WStrToUtf8(wstrText, text);
+ }
+
+ static char upper_backslash(char c)
+ {
+ return c == '/' ? '\\' : char(toupper(c));
}
- return result.str();
-}
-static char upper_backslash(char c) { return c == '/' ? '\\' : toupper(c); }
+ static uint32 const sstr_hashtable[16] =
+ {
+ 0x486E26EE, 0xDCAA16B3, 0xE1918EEF, 0x202DAFDB,
+ 0x341C7DC7, 0x1C365303, 0x40EF2D37, 0x65FD5E49,
+ 0xD6057177, 0x904ECE93, 0x1C38024F, 0x98FD323B,
+ 0xE3061AE7, 0xA39B0FA1, 0x9797F25F, 0xE4444563,
+ };
+
+ uint32 SStrHash(char const* string, bool caseInsensitive, uint32 seed = 0x7FED7FED)
+ {
+ ASSERT(string);
+
+ uint32 shift = 0xEEEEEEEE;
+ while (*string)
+ {
+ char c = *string++;
-static uint32 const s_hashtable[16] = {
- 0x486E26EE, 0xDCAA16B3, 0xE1918EEF, 0x202DAFDB,
- 0x341C7DC7, 0x1C365303, 0x40EF2D37, 0x65FD5E49,
- 0xD6057177, 0x904ECE93, 0x1C38024F, 0x98FD323B,
- 0xE3061AE7, 0xA39B0FA1, 0x9797F25F, 0xE4444563,
-};
+ if (caseInsensitive)
+ c = upper_backslash(c);
+
+ seed = (sstr_hashtable[c >> 4] - sstr_hashtable[c & 0xF]) ^ (shift + seed);
+ shift = c + seed + 33 * shift + 3;
+ }
+
+ return seed ? seed : 1;
+ }
+}
-uint32 LanguageMgr::SStrHash(char const* string, bool caseInsensitive, uint32 seed) const
+std::string LanguageMgr::Translate(std::string const& msg, uint32 language, LocaleConstant locale) const
{
- ASSERT(string);
+ std::string textToTranslate;
+ StripHyperlinks(msg, textToTranslate);
+ ReplaceUntranslatableCharactersWithSpace(textToTranslate);
- uint32 shift = 0xEEEEEEEE;
- while (*string) {
- char c = *string++;
+ std::string result;
+ result.reserve(textToTranslate.length());
+ Tokenizer tokens(textToTranslate, ' ');
+ for (char const* str : tokens)
+ {
+ uint32 wordLen = std::min(18u, uint32(strlen(str)));
+ if (LanguageMgr::WordList const* wordGroup = FindWordGroup(language, wordLen))
+ {
+ uint32 wordHash = SStrHash(str, true);
+ uint8 idxInsideGroup = wordHash % wordGroup->size();
- if (caseInsensitive)
- c = upper_backslash(c);
+ char const* replacementWord = (*wordGroup)[idxInsideGroup];
- seed = (s_hashtable[c >> 4] - s_hashtable[c & 0xF]) ^ (shift + seed);
- shift = c + seed + 33 * shift + 3;
+ switch (locale)
+ {
+ case LOCALE_koKR:
+ case LOCALE_zhCN:
+ case LOCALE_zhTW:
+ {
+ size_t length = std::min(strlen(str), strlen(replacementWord));
+ for (size_t i = 0; i < length; ++i)
+ {
+ if (str[i] >= 'A' && str[i] <= 'Z')
+ result += char(toupper(replacementWord[i]));
+ else
+ result += replacementWord[i];
+ }
+ break;
+ }
+ default:
+ {
+ std::wstring wstrSourceWord;
+ if (Utf8toWStr(str, wstrSourceWord))
+ {
+ size_t length = std::min(wstrSourceWord.length(), strlen(replacementWord));
+ for (size_t i = 0; i < length; ++i)
+ {
+ if (isUpper(wstrSourceWord[i]))
+ result += char(toupper(replacementWord[i]));
+ else
+ result += char(tolower(replacementWord[i]));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ result += ' ';
}
- return seed ? seed : 1;
+ if (!result.empty())
+ result.pop_back();
+
+ return result;
}
bool LanguageMgr::IsLanguageExist(uint32 languageId) const
diff --git a/src/server/game/Chat/LanguageMgr.h b/src/server/game/Chat/LanguageMgr.h
index 26010bfbcf8..7d1d4df123e 100644
--- a/src/server/game/Chat/LanguageMgr.h
+++ b/src/server/game/Chat/LanguageMgr.h
@@ -18,11 +18,10 @@
#ifndef _LANGUAGE_MGR_H
#define _LANGUAGE_MGR_H
-#include "Define.h"
+#include "Common.h"
#include "Hash.h"
#include "IteratorPair.h"
#include "SharedDefines.h"
-#include <string>
#include <vector>
#include <unordered_map>
@@ -60,9 +59,7 @@ class TC_GAME_API LanguageMgr
static LanguageMgr* instance();
//
- std::string Translate(std::string const& msg, uint32 sourcePlayerLanguage) const;
-
- uint32 SStrHash(char const* string, bool caseInsensitive, uint32 seed = 0x7FED7FED) const;
+ std::string Translate(std::string const& msg, uint32 language, LocaleConstant locale) const;
bool IsLanguageExist(uint32 languageId) const;
Trinity::IteratorPair<LanguagesMap::const_iterator> GetLanguageDescById(Language languageId) const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f2ceb6bfd1a..4f0b622f4b9 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -21972,13 +21972,14 @@ void Player::Say(std::string const& text, Language language, WorldObject const*
void Player::SendChatMessageToSetInRange(ChatMsg chatMsg, Language language, std::string&& text, float range)
{
- Trinity::ChatPacketSender sender(chatMsg, language, this, this, std::move(text));
+ Trinity::CustomChatTextBuilder builder(this, chatMsg, std::move(text), language, this);
+ Trinity::LocalizedDo<Trinity::CustomChatTextBuilder> localizer(builder);
// Send to self
- sender(this);
+ localizer(this);
// Send to players
- Trinity::MessageDistDeliverer<Trinity::ChatPacketSender> notifier(this, sender, range);
+ Trinity::MessageDistDeliverer<Trinity::LocalizedDo<Trinity::CustomChatTextBuilder>> notifier(this, localizer, range);
Cell::VisitWorldObjects(this, notifier, range);
}
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 366abe3e8c5..6713698e1a2 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -1612,7 +1612,7 @@ namespace Trinity
public:
explicit LocalizedDo(Localizer& localizer) : _localizer(localizer) { }
- void operator()(Player* p);
+ void operator()(Player const* p);
private:
Localizer& _localizer;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
index 60c7f43a207..63daf6b6482 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
@@ -750,7 +750,7 @@ void Trinity::PlayerLastSearcher<Check>::Visit(PlayerMapType& m)
}
template<typename Localizer>
-void Trinity::LocalizedDo<Localizer>::operator()(Player* p)
+void Trinity::LocalizedDo<Localizer>::operator()(Player const* p)
{
LocaleConstant loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
uint32 cache_idx = loc_idx + 1;
diff --git a/src/server/game/Texts/ChatTextBuilder.cpp b/src/server/game/Texts/ChatTextBuilder.cpp
index ea564c2aa7f..2c3166775a5 100644
--- a/src/server/game/Texts/ChatTextBuilder.cpp
+++ b/src/server/game/Texts/ChatTextBuilder.cpp
@@ -21,6 +21,7 @@
#include "LanguageMgr.h"
#include "ObjectMgr.h"
#include "Player.h"
+#include "WorldSession.h"
#include <cstdarg>
namespace Trinity
@@ -44,7 +45,8 @@ void ChatPacketSender::operator()(Player const* player) const
if (!TranslatedPacket)
{
TranslatedPacket.emplace();
- TranslatedPacket->Initialize(Type, Language, Sender, Receiver, sLanguageMgr->Translate(Text, Language), AchievementId, "", Locale);
+ TranslatedPacket->Initialize(Type, Language, Sender, Receiver, sLanguageMgr->Translate(Text, Language, player->GetSession()->GetSessionDbcLocale()),
+ AchievementId, "", Locale);
TranslatedPacket->Write();
}